*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 722,728 **** WriteTruncateXlogRec(int pageno)
  	rdata.buffer = InvalidBuffer;
  	rdata.next = NULL;
  	recptr = XLogInsert(RM_CLOG_ID, CLOG_TRUNCATE, &rdata);
! 	XLogFlush(recptr);
  }
  
  /*
--- 722,728 ----
  	rdata.buffer = InvalidBuffer;
  	rdata.next = NULL;
  	recptr = XLogInsert(RM_CLOG_ID, CLOG_TRUNCATE, &rdata);
! 	XLogFlush(recptr, true, false);
  }
  
  /*
*** a/src/backend/access/transam/slru.c
--- b/src/backend/access/transam/slru.c
***************
*** 696,704 **** SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
  			 * XLogFlush were to fail, we must PANIC.  This isn't much of a
  			 * restriction because XLogFlush is just about all critical
  			 * section anyway, but let's make sure.
  			 */
  			START_CRIT_SECTION();
! 			XLogFlush(max_lsn);
  			END_CRIT_SECTION();
  		}
  	}
--- 696,706 ----
  			 * XLogFlush were to fail, we must PANIC.  This isn't much of a
  			 * restriction because XLogFlush is just about all critical
  			 * section anyway, but let's make sure.
+ 			 * Also wait for the synchronous standby to receive WAL upto
+ 			 * max_lsn.
  			 */
  			START_CRIT_SECTION();
! 			XLogFlush(max_lsn, true, true);
  			END_CRIT_SECTION();
  		}
  	}
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
***************
*** 1049,1055 **** EndPrepare(GlobalTransaction gxact)
  
  	gxact->prepare_lsn = XLogInsert(RM_XACT_ID, XLOG_XACT_PREPARE,
  									records.head);
! 	XLogFlush(gxact->prepare_lsn);
  
  	/* If we crash now, we have prepared: WAL replay will fix things */
  
--- 1049,1062 ----
  
  	gxact->prepare_lsn = XLogInsert(RM_XACT_ID, XLOG_XACT_PREPARE,
  									records.head);
! 
! 	/*
! 	 * Wait for synchronous replication, if required.
! 	 *
! 	 * Note that at this stage we have marked the prepare, but still show as
! 	 * running in the procarray (twice!) and continue to hold locks.
! 	 */
! 	XLogFlush(gxact->prepare_lsn, false, true);
  
  	/* If we crash now, we have prepared: WAL replay will fix things */
  
***************
*** 1090,1103 **** EndPrepare(GlobalTransaction gxact)
  
  	END_CRIT_SECTION();
  
- 	/*
- 	 * Wait for synchronous replication, if required.
- 	 *
- 	 * Note that at this stage we have marked the prepare, but still show as
- 	 * running in the procarray (twice!) and continue to hold locks.
- 	 */
- 	SyncRepWaitForLSN(gxact->prepare_lsn);
- 
  	records.tail = records.head = NULL;
  }
  
--- 1097,1102 ----
***************
*** 2046,2053 **** RecordTransactionCommitPrepared(TransactionId xid,
  	 * a contradiction)
  	 */
  
! 	/* Flush XLOG to disk */
! 	XLogFlush(recptr);
  
  	/* Mark the transaction committed in pg_clog */
  	TransactionIdCommitTree(xid, nchildren, children);
--- 2045,2058 ----
  	 * a contradiction)
  	 */
  
! 	/*
! 	 * Flush XLOG to disk,
! 	 * Wait for synchronous replication, if required.
! 	 *
! 	 * Note that at this stage we have marked clog, but still show as running
! 	 * in the procarray and continue to hold locks.
! 	 */
! 	XLogFlush(recptr, false, true);
  
  	/* Mark the transaction committed in pg_clog */
  	TransactionIdCommitTree(xid, nchildren, children);
***************
*** 2056,2069 **** RecordTransactionCommitPrepared(TransactionId xid,
  	MyPgXact->delayChkpt = false;
  
  	END_CRIT_SECTION();
- 
- 	/*
- 	 * Wait for synchronous replication, if required.
- 	 *
- 	 * Note that at this stage we have marked clog, but still show as running
- 	 * in the procarray and continue to hold locks.
- 	 */
- 	SyncRepWaitForLSN(recptr);
  }
  
  /*
--- 2061,2066 ----
***************
*** 2126,2133 **** RecordTransactionAbortPrepared(TransactionId xid,
  
  	recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT_PREPARED, rdata);
  
! 	/* Always flush, since we're about to remove the 2PC state file */
! 	XLogFlush(recptr);
  
  	/*
  	 * Mark the transaction aborted in clog.  This is not absolutely necessary
--- 2123,2136 ----
  
  	recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT_PREPARED, rdata);
  
! 	/*
! 	 * Always flush, since we're about to remove the 2PC state file.
! 	 * Wait for synchronous replication, if required.
! 	 *
! 	 * Note that at this stage we have marked clog, but still show as running
! 	 * in the procarray and continue to hold locks.
! 	 */
! 	XLogFlush(recptr, false, true);
  
  	/*
  	 * Mark the transaction aborted in clog.  This is not absolutely necessary
***************
*** 2136,2147 **** RecordTransactionAbortPrepared(TransactionId xid,
  	TransactionIdAbortTree(xid, nchildren, children);
  
  	END_CRIT_SECTION();
- 
- 	/*
- 	 * Wait for synchronous replication, if required.
- 	 *
- 	 * Note that at this stage we have marked clog, but still show as running
- 	 * in the procarray and continue to hold locks.
- 	 */
- 	SyncRepWaitForLSN(recptr);
  }
--- 2139,2142 ----
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 965,970 **** RecordTransactionCommit(void)
--- 965,971 ----
  	SharedInvalidationMessage *invalMessages = NULL;
  	bool		RelcacheInitFileInval = false;
  	bool		wrote_xlog;
+ 	bool		ret = false;
  
  	/* Get data needed for commit record */
  	nrels = smgrGetPendingDeletes(true, &rels);
***************
*** 1143,1150 **** RecordTransactionCommit(void)
  	if ((wrote_xlog && synchronous_commit > SYNCHRONOUS_COMMIT_OFF) ||
  		forceSyncCommit || nrels > 0)
  	{
! 		XLogFlush(XactLastRecEnd);
! 
  		/*
  		 * Now we may update the CLOG, if we wrote a COMMIT record above
  		 */
--- 1144,1151 ----
  	if ((wrote_xlog && synchronous_commit > SYNCHRONOUS_COMMIT_OFF) ||
  		forceSyncCommit || nrels > 0)
  	{
! 		XLogFlush(XactLastRecEnd, false, true);
! 		ret = true;
  		/*
  		 * Now we may update the CLOG, if we wrote a COMMIT record above
  		 */
***************
*** 1195,1201 **** RecordTransactionCommit(void)
  	 * in the procarray and continue to hold locks.
  	 */
  	if (wrote_xlog)
! 		SyncRepWaitForLSN(XactLastRecEnd);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
  	XactLastRecEnd = 0;
--- 1196,1202 ----
  	 * in the procarray and continue to hold locks.
  	 */
  	if (wrote_xlog)
! 		SyncRepWaitForLSN(XactLastRecEnd, false, !ret);
  
  	/* Reset XactLastRecEnd until the next transaction writes something */
  	XactLastRecEnd = 0;
***************
*** 4663,4669 **** xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
  		 * after deletion, but that would leave a small window where the
  		 * WAL-first rule would be violated.
  		 */
! 		XLogFlush(lsn);
  
  		for (i = 0; i < nrels; i++)
  		{
--- 4664,4670 ----
  		 * after deletion, but that would leave a small window where the
  		 * WAL-first rule would be violated.
  		 */
! 		XLogFlush(lsn, true, true);
  
  		for (i = 0; i < nrels; i++)
  		{
***************
*** 4690,4696 **** xact_redo_commit_internal(TransactionId xid, XLogRecPtr lsn,
  	 * for any user that requested ForceSyncCommit().
  	 */
  	if (XactCompletionForceSyncCommit(xinfo))
! 		XLogFlush(lsn);
  
  }
  
--- 4691,4697 ----
  	 * for any user that requested ForceSyncCommit().
  	 */
  	if (XactCompletionForceSyncCommit(xinfo))
! 		XLogFlush(lsn, true, false);
  
  }
  
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 1898,1904 **** UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
   * already held, and we try to avoid acquiring it if possible.
   */
  void
! XLogFlush(XLogRecPtr record)
  {
  	XLogRecPtr	WriteRqstPtr;
  	XLogwrtRqst WriteRqst;
--- 1898,1904 ----
   * already held, and we try to avoid acquiring it if possible.
   */
  void
! XLogFlush(XLogRecPtr record, bool ForDataFlush, bool Wait)
  {
  	XLogRecPtr	WriteRqstPtr;
  	XLogwrtRqst WriteRqst;
***************
*** 2033,2038 **** XLogFlush(XLogRecPtr record)
--- 2033,2040 ----
  	/* wake up walsenders now that we've released heavily contended locks */
  	WalSndWakeupProcessRequests();
  
+ 	SyncRepWaitForLSN(WriteRqstPtr, ForDataFlush, Wait);
+ 
  	/*
  	 * If we still haven't flushed to the request point then we have a
  	 * problem; most likely, the requested flush point is past end of XLOG.
***************
*** 7092,7098 **** CreateCheckPoint(int flags)
  						XLOG_CHECKPOINT_ONLINE,
  						&rdata);
  
! 	XLogFlush(recptr);
  
  	/*
  	 * We mustn't write any new WAL after a shutdown checkpoint, or it will be
--- 7094,7105 ----
  						XLOG_CHECKPOINT_ONLINE,
  						&rdata);
  
! 	/*
! 	 * At this point, ensure that the synchronous standby has received the
! 	 * checkpoint WAL. Otherwise failure after the control file update will
! 	 * cause the master to start from a location not known to the standby
! 	 */
! 	XLogFlush(recptr, true, !shutdown);
  
  	/*
  	 * We mustn't write any new WAL after a shutdown checkpoint, or it will be
***************
*** 7249,7255 **** CreateEndOfRecoveryRecord(void)
  
  	recptr = XLogInsert(RM_XLOG_ID, XLOG_END_OF_RECOVERY, &rdata);
  
! 	XLogFlush(recptr);
  
  	/*
  	 * Update the control file so that crash recovery can follow the timeline
--- 7256,7262 ----
  
  	recptr = XLogInsert(RM_XLOG_ID, XLOG_END_OF_RECOVERY, &rdata);
  
! 	XLogFlush(recptr, true, true);
  
  	/*
  	 * Update the control file so that crash recovery can follow the timeline
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 285,293 **** RelationTruncate(Relation rel, BlockNumber nblocks)
  		 * or visibility map. If we crashed during that window, we'd be left
  		 * with a truncated heap, but the FSM or visibility map would still
  		 * contain entries for the non-existent heap pages.
  		 */
  		if (fsm || vm)
! 			XLogFlush(lsn);
  	}
  
  	/* Do the real work */
--- 285,297 ----
  		 * or visibility map. If we crashed during that window, we'd be left
  		 * with a truncated heap, but the FSM or visibility map would still
  		 * contain entries for the non-existent heap pages.
+ 		 *
+ 		 * Also ensure that the WAL is received by the synchronous standby.
+ 		 * Otherwise, we may have a situation where the heap is truncated, but
+ 		 * the action never replayed on the standby
  		 */
  		if (fsm || vm)
! 			XLogFlush(lsn, true, true);
  	}
  
  	/* Do the real work */
***************
*** 519,525 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
  		 * after truncation, but that would leave a small window where the
  		 * WAL-first rule could be violated.
  		 */
! 		XLogFlush(lsn);
  
  		smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
  
--- 523,529 ----
  		 * after truncation, but that would leave a small window where the
  		 * WAL-first rule could be violated.
  		 */
! 		XLogFlush(lsn, true, false);
  
  		smgrtruncate(reln, MAIN_FORKNUM, xlrec->blkno);
  
*** a/src/backend/replication/syncrep.c
--- b/src/backend/replication/syncrep.c
***************
*** 65,70 **** char	   *SyncRepStandbyNames;
--- 65,72 ----
  static bool announce_next_takeover = true;
  
  static int	SyncRepWaitMode = SYNC_REP_NO_WAIT;
+ static int	SyncTransferMode = SYNC_REP_NO_WAIT;
+ int		synchronous_transfer = SYNCHRONOUS_TRANSFER_COMMIT;
  
  static void SyncRepQueueInsert(int mode);
  static void SyncRepCancelWait(void);
***************
*** 85,109 **** static bool SyncRepQueueIsOrderedByLSN(int mode);
   * Wait for synchronous replication, if requested by user.
   *
   * Initially backends start in state SYNC_REP_NOT_WAITING and then
!  * change that state to SYNC_REP_WAITING before adding ourselves
!  * to the wait queue. During SyncRepWakeQueue() a WALSender changes
!  * the state to SYNC_REP_WAIT_COMPLETE once replication is confirmed.
!  * This backend then resets its state to SYNC_REP_NOT_WAITING.
   */
! void
! SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
  {
  	char	   *new_status = NULL;
  	const char *old_status;
! 	int			mode = SyncRepWaitMode;
  
  	/*
  	 * Fast exit if user has not requested sync replication, or there are no
  	 * sync replication standby names defined. Note that those standbys don't
  	 * need to be connected.
  	 */
! 	if (!SyncRepRequested() || !SyncStandbysDefined())
! 		return;
  
  	Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks)));
  	Assert(WalSndCtl != NULL);
--- 87,147 ----
   * Wait for synchronous replication, if requested by user.
   *
   * Initially backends start in state SYNC_REP_NOT_WAITING and then
!  * change that state to SYNC_REP_WAITING/SYNC_REP_WAITING_FOR_DATA_FLUSH
!  * before adding ourselves to the wait queue. During SyncRepWakeQueue() a
!  * WALSender changes the state to SYNC_REP_WAIT_COMPLETE once replication is
!  * confirmed. This backend then resets its state to SYNC_REP_NOT_WAITING.
!  *
!  * ForDataFlush - if TRUE, we wait for the flushing data page.
!  * Otherwise wait for the sync standby
!  *
!  * Wait - if FALSE, we don't actually wait, but tell the caller whether or not
!  * the standby has already made progressed upto the given XactCommitLSN
!  *
!  * Return TRUE if either the sync standby is not
!  * configured/turned off OR the standby has made enough progress
   */
! bool
! SyncRepWaitForLSN(XLogRecPtr XactCommitLSN, bool ForDataFlush, bool Wait)
  {
  	char	   *new_status = NULL;
  	const char *old_status;
! 	int			mode = !ForDataFlush ? SyncRepWaitMode : SyncTransferMode;
! 	bool		ret;
  
  	/*
  	 * Fast exit if user has not requested sync replication, or there are no
  	 * sync replication standby names defined. Note that those standbys don't
  	 * need to be connected.
  	 */
! 	if ((!SyncRepRequested() || !SyncStandbysDefined()) &&
! 	    !SyncTransRequested() && !ForDataFlush)
! 		return true;
! 
! 	/*
! 	 * If the caller has specified ForDataFlush, but synchronous transfer
! 	 * is not specified or its turned off, exit.
! 	 *
! 	 * We would like to allow the failback safe mechanism even for cascaded
! 	 * standbys as well. But we can't really wait for the standby to catch
! 	 * up until we reach a consistent state since the standbys won't be
! 	 * even able to connect without us reaching in that state (XXX Confirm)
! 	 */
! 	if ((!SyncTransRequested()) && ForDataFlush)
! 		return true;
! 
! 	/*
! 	 * If the caller has not specified ForDataFlush, but synchronous commit
! 	 * is skipped by values of synchronous_transfer, exit.
! 	 */
! 	if (IsSyncRepSkipped() && !ForDataFlush)
! 		return true;
! 
! 	/*
! 	 *Exit if we are told not to block on the standby.
! 	 */
! 	if (!Wait)
! 		return false;
  
  	Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks)));
  	Assert(WalSndCtl != NULL);
***************
*** 119,129 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
  	 * condition but we'll be fetching that cache line anyway so its likely to
  	 * be a low cost check.
  	 */
! 	if (!WalSndCtl->sync_standbys_defined ||
! 		XactCommitLSN <= WalSndCtl->lsn[mode])
  	{
  		LWLockRelease(SyncRepLock);
! 		return;
  	}
  
  	/*
--- 157,166 ----
  	 * condition but we'll be fetching that cache line anyway so its likely to
  	 * be a low cost check.
  	 */
! 	if ((!ForDataFlush && !WalSndCtl->sync_standbys_defined) || XactCommitLSN <= WalSndCtl->lsn[mode])
  	{
  		LWLockRelease(SyncRepLock);
! 		return true;
  	}
  
  	/*
***************
*** 150,155 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
--- 187,194 ----
  		new_status[len] = '\0'; /* truncate off " waiting ..." */
  	}
  
+ 	ret = false;
+ 
  	/*
  	 * Wait for specified LSN to be confirmed.
  	 *
***************
*** 186,192 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
--- 225,234 ----
  			LWLockRelease(SyncRepLock);
  		}
  		if (syncRepState == SYNC_REP_WAIT_COMPLETE)
+ 		{
+ 			ret = true;
  			break;
+ 		}
  
  		/*
  		 * If a wait for synchronous replication is pending, we can neither
***************
*** 263,268 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
--- 305,312 ----
  		set_ps_display(new_status, false);
  		pfree(new_status);
  	}
+ 
+ 	return ret;
  }
  
  /*
***************
*** 370,375 **** SyncRepReleaseWaiters(void)
--- 414,420 ----
  	volatile WalSnd *syncWalSnd = NULL;
  	int			numwrite = 0;
  	int			numflush = 0;
+ 	int			numdataflush = 0;
  	int			priority = 0;
  	int			i;
  
***************
*** 379,389 **** SyncRepReleaseWaiters(void)
  	 * up, still running base backup or the current flush position is still
  	 * invalid, then leave quickly also.
  	 */
! 	if (MyWalSnd->sync_standby_priority == 0 ||
! 		MyWalSnd->state < WALSNDSTATE_STREAMING ||
  		XLogRecPtrIsInvalid(MyWalSnd->flush))
  		return;
- 
  	/*
  	 * We're a potential sync standby. Release waiters if we are the highest
  	 * priority standby. If there are multiple standbys with same priorities
--- 424,433 ----
  	 * up, still running base backup or the current flush position is still
  	 * invalid, then leave quickly also.
  	 */
! 
! 	if (MyWalSnd->state < WALSNDSTATE_STREAMING ||
  		XLogRecPtrIsInvalid(MyWalSnd->flush))
  		return;
  	/*
  	 * We're a potential sync standby. Release waiters if we are the highest
  	 * priority standby. If there are multiple standbys with same priorities
***************
*** 399,405 **** SyncRepReleaseWaiters(void)
  
  		if (walsnd->pid != 0 &&
  			walsnd->state == WALSNDSTATE_STREAMING &&
- 			walsnd->sync_standby_priority > 0 &&
  			(priority == 0 ||
  			 priority > walsnd->sync_standby_priority) &&
  			!XLogRecPtrIsInvalid(walsnd->flush))
--- 443,448 ----
***************
*** 428,449 **** SyncRepReleaseWaiters(void)
  	 * Set the lsn first so that when we wake backends they will release up to
  	 * this location.
  	 */
! 	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] < MyWalSnd->write)
  	{
  		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = MyWalSnd->write;
  		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
  	}
! 	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] < MyWalSnd->flush)
  	{
  		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = MyWalSnd->flush;
  		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
  	}
  
  	LWLockRelease(SyncRepLock);
  
  	elog(DEBUG3, "released %d procs up to write %X/%X, %d procs up to flush %X/%X",
  		 numwrite, (uint32) (MyWalSnd->write >> 32), (uint32) MyWalSnd->write,
! 	   numflush, (uint32) (MyWalSnd->flush >> 32), (uint32) MyWalSnd->flush);
  
  	/*
  	 * If we are managing the highest priority standby, though we weren't
--- 471,497 ----
  	 * Set the lsn first so that when we wake backends they will release up to
  	 * this location.
  	 */
! 	if (walsndctl->lsn[SYNC_REP_WAIT_WRITE] <= MyWalSnd->write)
  	{
  		walsndctl->lsn[SYNC_REP_WAIT_WRITE] = MyWalSnd->write;
  		numwrite = SyncRepWakeQueue(false, SYNC_REP_WAIT_WRITE);
  	}
! 	if (walsndctl->lsn[SYNC_REP_WAIT_FLUSH] <= MyWalSnd->flush)
  	{
  		walsndctl->lsn[SYNC_REP_WAIT_FLUSH] = MyWalSnd->flush;
  		numflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_FLUSH);
  	}
+ 	if (walsndctl->lsn[SYNC_REP_WAIT_DATA_FLUSH] <= MyWalSnd->flush)
+ 	{
+ 		walsndctl->lsn[SYNC_REP_WAIT_DATA_FLUSH] = MyWalSnd->flush;
+ 		numdataflush = SyncRepWakeQueue(false, SYNC_REP_WAIT_DATA_FLUSH);
+ 	}
  
  	LWLockRelease(SyncRepLock);
  
  	elog(DEBUG3, "released %d procs up to write %X/%X, %d procs up to flush %X/%X",
  		 numwrite, (uint32) (MyWalSnd->write >> 32), (uint32) MyWalSnd->write,
! 		 numflush, (uint32) (MyWalSnd->flush >> 32), (uint32) MyWalSnd->flush);
  
  	/*
  	 * If we are managing the highest priority standby, though we weren't
***************
*** 709,711 **** assign_synchronous_commit(int newval, void *extra)
--- 757,774 ----
  			break;
  	}
  }
+ 
+ void
+ assign_synchronous_transfer(int newval, void *extra)
+ {
+ 	switch (newval)
+ 	{
+ 		case SYNCHRONOUS_TRANSFER_ALL:
+ 		case SYNCHRONOUS_TRANSFER_DATA_FLUSH:
+ 			SyncTransferMode = SYNC_REP_WAIT_DATA_FLUSH;
+ 			break;
+ 		default:
+ 			SyncTransferMode = SYNC_REP_NO_WAIT;
+ 			break;
+ 	}
+ }
*** a/src/backend/storage/buffer/bufmgr.c
--- b/src/backend/storage/buffer/bufmgr.c
***************
*** 41,46 ****
--- 41,47 ----
  #include "pg_trace.h"
  #include "pgstat.h"
  #include "postmaster/bgwriter.h"
+ #include "replication/syncrep.h"
  #include "storage/buf_internals.h"
  #include "storage/bufmgr.h"
  #include "storage/ipc.h"
***************
*** 1975,1981 **** FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
  	 * skip the flush if the buffer isn't permanent.
  	 */
  	if (buf->flags & BM_PERMANENT)
! 		XLogFlush(recptr);
  
  	/*
  	 * Now it's safe to write buffer to disk. Note that no one else should
--- 1976,1982 ----
  	 * skip the flush if the buffer isn't permanent.
  	 */
  	if (buf->flags & BM_PERMANENT)
! 		XLogFlush(recptr, true, true);
  
  	/*
  	 * Now it's safe to write buffer to disk. Note that no one else should
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
***************
*** 721,727 **** write_relmap_file(bool shared, RelMapFile *newmap,
  		lsn = XLogInsert(RM_RELMAP_ID, XLOG_RELMAP_UPDATE, rdata);
  
  		/* As always, WAL must hit the disk before the data update does */
! 		XLogFlush(lsn);
  	}
  
  	errno = 0;
--- 721,732 ----
  		lsn = XLogInsert(RM_RELMAP_ID, XLOG_RELMAP_UPDATE, rdata);
  
  		/* As always, WAL must hit the disk before the data update does */
! 		XLogFlush(lsn, true, false);
! 
! 		/*
! 		 * XXX Should we also wait for the failback safe standby to receive the
! 		 * WAL ?
! 		 */
  	}
  
  	errno = 0;
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 381,386 **** static const struct config_enum_entry synchronous_commit_options[] = {
--- 381,398 ----
  };
  
  /*
+  * Although only "all", "data_flush", and "commit" are documented, we
+  * accept all the likely variants of "off".
+  */
+ static const struct config_enum_entry synchronous_transfer_options[] = {
+ 	{"all", SYNCHRONOUS_TRANSFER_ALL, false},
+ 	{"data_flush", SYNCHRONOUS_TRANSFER_DATA_FLUSH, false},
+ 	{"commit", SYNCHRONOUS_TRANSFER_COMMIT, true},
+ 	{"0", SYNCHRONOUS_TRANSFER_COMMIT, true},
+ 	{NULL, 0, false}
+ };
+ 
+ /*
   * Options for enum values stored in other modules
   */
  extern const struct config_enum_entry wal_level_options[];
***************
*** 3266,3271 **** static struct config_enum ConfigureNamesEnum[] =
--- 3278,3293 ----
  	},
  
  	{
+ 		{"synchronous_transfer", PGC_SIGHUP, WAL_SETTINGS,
+ 			gettext_noop("Sets the data flush synchronization level"),
+ 			NULL
+ 		},
+ 		&synchronous_transfer,
+ 		SYNCHRONOUS_TRANSFER_COMMIT, synchronous_transfer_options,
+ 		NULL, assign_synchronous_transfer, NULL
+ 	},
+ 
+ 	{
  		{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
  			gettext_noop("Enables logging of recovery-related debugging information."),
  			gettext_noop("Each level includes all the levels that follow it. The later"
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 220,225 ****
--- 220,227 ----
  #synchronous_standby_names = ''	# standby servers that provide sync rep
  				# comma-separated list of application_name
  				# from standby(s); '*' = all
+ #synchronous_transfer = commit	# data page synchronization level
+ 				# commit, data_flush or all
  #vacuum_defer_cleanup_age = 0	# number of xacts by which cleanup is delayed
  
  # - Standby Servers -
*** a/src/backend/utils/time/tqual.c
--- b/src/backend/utils/time/tqual.c
***************
*** 62,67 ****
--- 62,68 ----
  #include "access/subtrans.h"
  #include "access/transam.h"
  #include "access/xact.h"
+ #include "replication/syncrep.h"
  #include "storage/bufmgr.h"
  #include "storage/procarray.h"
  #include "utils/tqual.h"
***************
*** 118,123 **** SetHintBits(HeapTupleHeader tuple, Buffer buffer,
--- 119,133 ----
  
  		if (XLogNeedsFlush(commitLSN) && BufferIsPermanent(buffer))
  			return;				/* not flushed yet, so don't set hint */
+ 
+ 		/*
+ 		 * If synchronous_transfer is configured to data_flush or all, we should
+ 		 * also check if the commit WAL record has made to the standby before
+ 		 * allowing hint bit updates. We should not wait for the standby to receive
+ 		 * the WAL since its OK to delay hint bit updates
+ 		 */
+ 		if (!SyncRepWaitForLSN(commitLSN, true, false))
+ 			return;
  	}
  
  	tuple->t_infomask |= infomask;
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 261,267 **** typedef struct CheckpointStatsData
  extern CheckpointStatsData CheckpointStats;
  
  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
! extern void XLogFlush(XLogRecPtr RecPtr);
  extern bool XLogBackgroundFlush(void);
  extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
  extern int	XLogFileInit(XLogSegNo segno, bool *use_existent, bool use_lock);
--- 261,267 ----
  extern CheckpointStatsData CheckpointStats;
  
  extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
! extern void XLogFlush(XLogRecPtr RecPtr, bool ForDataFush, bool Wait);
  extern bool XLogBackgroundFlush(void);
  extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
  extern int	XLogFileInit(XLogSegNo segno, bool *use_existent, bool use_lock);
*** a/src/include/replication/syncrep.h
--- b/src/include/replication/syncrep.h
***************
*** 19,41 ****
  #define SyncRepRequested() \
  	(max_wal_senders > 0 && synchronous_commit > SYNCHRONOUS_COMMIT_LOCAL_FLUSH)
  
  /* SyncRepWaitMode */
! #define SYNC_REP_NO_WAIT		-1
! #define SYNC_REP_WAIT_WRITE		0
! #define SYNC_REP_WAIT_FLUSH		1
  
! #define NUM_SYNC_REP_WAIT_MODE	2
  
  /* syncRepState */
! #define SYNC_REP_NOT_WAITING		0
! #define SYNC_REP_WAITING			1
! #define SYNC_REP_WAIT_COMPLETE		2
  
  /* user-settable parameters for synchronous replication */
  extern char *SyncRepStandbyNames;
  
  /* called by user backend */
! extern void SyncRepWaitForLSN(XLogRecPtr XactCommitLSN);
  
  /* called at backend exit */
  extern void SyncRepCleanupAtProcExit(void);
--- 19,60 ----
  #define SyncRepRequested() \
  	(max_wal_senders > 0 && synchronous_commit > SYNCHRONOUS_COMMIT_LOCAL_FLUSH)
  
+ #define SyncTransRequested() \
+ 	(max_wal_senders > 0 && synchronous_transfer > SYNCHRONOUS_TRANSFER_COMMIT)
+ 
+ #define IsSyncRepSkipped() \
+ 	(max_wal_senders > 0 && synchronous_transfer ==  SYNCHRONOUS_TRANSFER_DATA_FLUSH)
+ 
  /* SyncRepWaitMode */
! #define SYNC_REP_NO_WAIT					-1
! #define SYNC_REP_WAIT_WRITE					0
! #define SYNC_REP_WAIT_FLUSH					1
! #define SYNC_REP_WAIT_DATA_FLUSH	2
  
! #define NUM_SYNC_REP_WAIT_MODE				3
  
  /* syncRepState */
! #define SYNC_REP_NOT_WAITING					0
! #define SYNC_REP_WAITING						1
! #define SYNC_REP_WAIT_COMPLETE					2
! 
! typedef enum
! {
! 	SYNCHRONOUS_TRANSFER_COMMIT,		/* no wait for flush data page */
! 	SYNCHRONOUS_TRANSFER_DATA_FLUSH,	/* wait for data page flush only
! 										 * no wait for WAL */
! 	SYNCHRONOUS_TRANSFER_ALL	        /* wait for data page flush */
! }	SynchronousTransferLevel;
  
  /* user-settable parameters for synchronous replication */
  extern char *SyncRepStandbyNames;
  
+ /* user-settable parameters for failback safe replication */
+ extern int	synchronous_transfer;
+ 
  /* called by user backend */
! extern bool SyncRepWaitForLSN(XLogRecPtr XactCommitLSN,
! 		bool ForDataFlush, bool Wait);
  
  /* called at backend exit */
  extern void SyncRepCleanupAtProcExit(void);
***************
*** 52,56 **** extern int	SyncRepWakeQueue(bool all, int mode);
--- 71,76 ----
  
  extern bool check_synchronous_standby_names(char **newval, void **extra, GucSource source);
  extern void assign_synchronous_commit(int newval, void *extra);
+ extern void assign_synchronous_transfer(int newval, void *extra);
  
  #endif   /* _SYNCREP_H */
