2020 * per-transaction state information.
2121 *
2222 * Replication is either synchronous or not synchronous (async). If it is
23- * async, we just fastpath out of here. If it is sync, then in 9.1 we wait
24- * for the flush location on the standby before releasing the waiting backend.
23+ * async, we just fastpath out of here. If it is sync, then we wait for
24+ * the write or flush location on the standby before releasing the waiting backend.
2525 * Further complexity in that interaction is expected in later releases.
2626 *
2727 * The best performing way to manage the waiting backends is to have a
@@ -67,13 +67,15 @@ char *SyncRepStandbyNames;
6767
6868static bool announce_next_takeover = true;
6969
70- static void SyncRepQueueInsert (void );
70+ static int SyncRepWaitMode = SYNC_REP_NO_WAIT ;
71+
72+ static void SyncRepQueueInsert (int mode );
7173static void SyncRepCancelWait (void );
7274
7375static int SyncRepGetStandbyPriority (void );
7476
7577#ifdef USE_ASSERT_CHECKING
76- static bool SyncRepQueueIsOrderedByLSN (void );
78+ static bool SyncRepQueueIsOrderedByLSN (int mode );
7779#endif
7880
7981/*
@@ -120,7 +122,7 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
120122 * be a low cost check.
121123 */
122124 if (!WalSndCtl -> sync_standbys_defined ||
123- XLByteLE (XactCommitLSN , WalSndCtl -> lsn ))
125+ XLByteLE (XactCommitLSN , WalSndCtl -> lsn [ SyncRepWaitMode ] ))
124126 {
125127 LWLockRelease (SyncRepLock );
126128 return ;
@@ -132,8 +134,8 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
132134 */
133135 MyProc -> waitLSN = XactCommitLSN ;
134136 MyProc -> syncRepState = SYNC_REP_WAITING ;
135- SyncRepQueueInsert ();
136- Assert (SyncRepQueueIsOrderedByLSN ());
137+ SyncRepQueueInsert (SyncRepWaitMode );
138+ Assert (SyncRepQueueIsOrderedByLSN (SyncRepWaitMode ));
137139 LWLockRelease (SyncRepLock );
138140
139141 /* Alter ps display to show waiting for sync rep. */
@@ -267,18 +269,19 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN)
267269}
268270
269271/*
270- * Insert MyProc into SyncRepQueue, maintaining sorted invariant.
272+ * Insert MyProc into the specified SyncRepQueue, maintaining sorted invariant.
271273 *
272274 * Usually we will go at tail of queue, though it's possible that we arrive
273275 * here out of order, so start at tail and work back to insertion point.
274276 */
275277static void
276- SyncRepQueueInsert (void )
278+ SyncRepQueueInsert (int mode )
277279{
278280 PGPROC * proc ;
279281
280- proc = (PGPROC * ) SHMQueuePrev (& (WalSndCtl -> SyncRepQueue ),
281- & (WalSndCtl -> SyncRepQueue ),
282+ Assert (mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE );
283+ proc = (PGPROC * ) SHMQueuePrev (& (WalSndCtl -> SyncRepQueue [mode ]),
284+ & (WalSndCtl -> SyncRepQueue [mode ]),
282285 offsetof(PGPROC , syncRepLinks ));
283286
284287 while (proc )
@@ -290,15 +293,15 @@ SyncRepQueueInsert(void)
290293 if (XLByteLT (proc -> waitLSN , MyProc -> waitLSN ))
291294 break ;
292295
293- proc = (PGPROC * ) SHMQueuePrev (& (WalSndCtl -> SyncRepQueue ),
296+ proc = (PGPROC * ) SHMQueuePrev (& (WalSndCtl -> SyncRepQueue [ mode ] ),
294297 & (proc -> syncRepLinks ),
295298 offsetof(PGPROC , syncRepLinks ));
296299 }
297300
298301 if (proc )
299302 SHMQueueInsertAfter (& (proc -> syncRepLinks ), & (MyProc -> syncRepLinks ));
300303 else
301- SHMQueueInsertAfter (& (WalSndCtl -> SyncRepQueue ), & (MyProc -> syncRepLinks ));
304+ SHMQueueInsertAfter (& (WalSndCtl -> SyncRepQueue [ mode ] ), & (MyProc -> syncRepLinks ));
302305}
303306
304307/*
@@ -368,7 +371,8 @@ SyncRepReleaseWaiters(void)
368371{
369372 volatile WalSndCtlData * walsndctl = WalSndCtl ;
370373 volatile WalSnd * syncWalSnd = NULL ;
371- int numprocs = 0 ;
374+ int numwrite = 0 ;
375+ int numflush = 0 ;
372376 int priority = 0 ;
373377 int i ;
374378
@@ -419,20 +423,28 @@ SyncRepReleaseWaiters(void)
419423 return ;
420424 }
421425
422- if (XLByteLT (walsndctl -> lsn , MyWalSnd -> flush ))
426+ /*
427+ * Set the lsn first so that when we wake backends they will release
428+ * up to this location.
429+ */
430+ if (XLByteLT (walsndctl -> lsn [SYNC_REP_WAIT_WRITE ], MyWalSnd -> write ))
423431 {
424- /*
425- * Set the lsn first so that when we wake backends they will release
426- * up to this location.
427- */
428- walsndctl -> lsn = MyWalSnd -> flush ;
429- numprocs = SyncRepWakeQueue (false);
432+ walsndctl -> lsn [SYNC_REP_WAIT_WRITE ] = MyWalSnd -> write ;
433+ numwrite = SyncRepWakeQueue (false, SYNC_REP_WAIT_WRITE );
434+ }
435+ if (XLByteLT (walsndctl -> lsn [SYNC_REP_WAIT_FLUSH ], MyWalSnd -> flush ))
436+ {
437+ walsndctl -> lsn [SYNC_REP_WAIT_FLUSH ] = MyWalSnd -> flush ;
438+ numflush = SyncRepWakeQueue (false, SYNC_REP_WAIT_FLUSH );
430439 }
431440
432441 LWLockRelease (SyncRepLock );
433442
434- elog (DEBUG3 , "released %d procs up to %X/%X" ,
435- numprocs ,
443+ elog (DEBUG3 , "released %d procs up to write %X/%X, %d procs up to flush %X/%X" ,
444+ numwrite ,
445+ MyWalSnd -> write .xlogid ,
446+ MyWalSnd -> write .xrecoff ,
447+ numflush ,
436448 MyWalSnd -> flush .xlogid ,
437449 MyWalSnd -> flush .xrecoff );
438450
@@ -507,40 +519,42 @@ SyncRepGetStandbyPriority(void)
507519}
508520
509521/*
510- * Walk queue from head. Set the state of any backends that need to be woken,
511- * remove them from the queue, and then wake them. Pass all = true to wake
512- * whole queue; otherwise, just wake up to the walsender's LSN.
522+ * Walk the specified queue from head. Set the state of any backends that
523+ * need to be woken, remove them from the queue, and then wake them.
524+ * Pass all = true to wake whole queue; otherwise, just wake up to
525+ * the walsender's LSN.
513526 *
514527 * Must hold SyncRepLock.
515528 */
516529int
517- SyncRepWakeQueue (bool all )
530+ SyncRepWakeQueue (bool all , int mode )
518531{
519532 volatile WalSndCtlData * walsndctl = WalSndCtl ;
520533 PGPROC * proc = NULL ;
521534 PGPROC * thisproc = NULL ;
522535 int numprocs = 0 ;
523536
524- Assert (SyncRepQueueIsOrderedByLSN ());
537+ Assert (mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE );
538+ Assert (SyncRepQueueIsOrderedByLSN (mode ));
525539
526- proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue ),
527- & (WalSndCtl -> SyncRepQueue ),
540+ proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue [ mode ] ),
541+ & (WalSndCtl -> SyncRepQueue [ mode ] ),
528542 offsetof(PGPROC , syncRepLinks ));
529543
530544 while (proc )
531545 {
532546 /*
533547 * Assume the queue is ordered by LSN
534548 */
535- if (!all && XLByteLT (walsndctl -> lsn , proc -> waitLSN ))
549+ if (!all && XLByteLT (walsndctl -> lsn [ mode ] , proc -> waitLSN ))
536550 return numprocs ;
537551
538552 /*
539553 * Move to next proc, so we can delete thisproc from the queue.
540554 * thisproc is valid, proc may be NULL after this.
541555 */
542556 thisproc = proc ;
543- proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue ),
557+ proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue [ mode ] ),
544558 & (proc -> syncRepLinks ),
545559 offsetof(PGPROC , syncRepLinks ));
546560
@@ -588,7 +602,12 @@ SyncRepUpdateSyncStandbysDefined(void)
588602 * wants synchronous replication, we'd better wake them up.
589603 */
590604 if (!sync_standbys_defined )
591- SyncRepWakeQueue (true);
605+ {
606+ int i ;
607+
608+ for (i = 0 ; i < NUM_SYNC_REP_WAIT_MODE ; i ++ )
609+ SyncRepWakeQueue (true, i );
610+ }
592611
593612 /*
594613 * Only allow people to join the queue when there are synchronous
@@ -605,16 +624,18 @@ SyncRepUpdateSyncStandbysDefined(void)
605624
606625#ifdef USE_ASSERT_CHECKING
607626static bool
608- SyncRepQueueIsOrderedByLSN (void )
627+ SyncRepQueueIsOrderedByLSN (int mode )
609628{
610629 PGPROC * proc = NULL ;
611630 XLogRecPtr lastLSN ;
612631
632+ Assert (mode >= 0 && mode < NUM_SYNC_REP_WAIT_MODE );
633+
613634 lastLSN .xlogid = 0 ;
614635 lastLSN .xrecoff = 0 ;
615636
616- proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue ),
617- & (WalSndCtl -> SyncRepQueue ),
637+ proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue [ mode ] ),
638+ & (WalSndCtl -> SyncRepQueue [ mode ] ),
618639 offsetof(PGPROC , syncRepLinks ));
619640
620641 while (proc )
@@ -628,7 +649,7 @@ SyncRepQueueIsOrderedByLSN(void)
628649
629650 lastLSN = proc -> waitLSN ;
630651
631- proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue ),
652+ proc = (PGPROC * ) SHMQueueNext (& (WalSndCtl -> SyncRepQueue [ mode ] ),
632653 & (proc -> syncRepLinks ),
633654 offsetof(PGPROC , syncRepLinks ));
634655 }
@@ -675,3 +696,20 @@ check_synchronous_standby_names(char **newval, void **extra, GucSource source)
675696
676697 return true;
677698}
699+
700+ void
701+ assign_synchronous_commit (int newval , void * extra )
702+ {
703+ switch (newval )
704+ {
705+ case SYNCHRONOUS_COMMIT_REMOTE_WRITE :
706+ SyncRepWaitMode = SYNC_REP_WAIT_WRITE ;
707+ break ;
708+ case SYNCHRONOUS_COMMIT_REMOTE_FLUSH :
709+ SyncRepWaitMode = SYNC_REP_WAIT_FLUSH ;
710+ break ;
711+ default :
712+ SyncRepWaitMode = SYNC_REP_NO_WAIT ;
713+ break ;
714+ }
715+ }
0 commit comments