1212 * This file implements waiting for WAL operations to reach specific LSNs
1313 * on both physical standby and primary servers. The core idea is simple:
1414 * every process that wants to wait publishes the LSN it needs to the
15- * shared memory, and the appropriate process (startup on standby, or
16- * WAL writer/backend on primary) wakes it once that LSN has been reached.
15+ * shared memory, and the appropriate process (startup on standby,
16+ * walreceiver on standby, or WAL writer/backend on primary) wakes it
17+ * once that LSN has been reached.
1718 *
1819 * The shared memory used by this module comprises a procInfos
1920 * per-backend array with the information of the awaited LSN for each
2021 * of the backend processes. The elements of that array are organized
21- * into a pairing heap waitersHeap, which allows for very fast finding
22- * of the least awaited LSN.
22+ * into pairing heaps ( waitersHeap), one for each WaitLSNType, which
23+ * allows for very fast finding of the least awaited LSN for each type .
2324 *
24- * In addition, the least-awaited LSN is cached as minWaitedLSN. The
25- * waiter process publishes information about itself to the shared
26- * memory and waits on the latch until it is woken up by the appropriate
27- * process, standby is promoted, or the postmaster dies. Then, it cleans
28- * information about itself in the shared memory.
25+ * In addition, the least-awaited LSN for each type is cached in the
26+ * minWaitedLSN array. The waiter process publishes information about
27+ * itself to the shared memory and waits on the latch until it is woken
28+ * up by the appropriate process, standby is promoted, or the postmaster
29+ * dies. Then, it cleans information about itself in the shared memory.
2930 *
30- * On standby servers: After replaying a WAL record, the startup process
31- * first performs a fast path check minWaitedLSN > replayLSN. If this
32- * check is negative, it checks waitersHeap and wakes up the backend
33- * whose awaited LSNs are reached.
31+ * On standby servers:
32+ * - After replaying a WAL record, the startup process performs a fast
33+ * path check minWaitedLSN[REPLAY] > replayLSN. If this check is
34+ * negative, it checks waitersHeap[REPLAY] and wakes up the backends
35+ * whose awaited LSNs are reached.
36+ * - After receiving WAL, the walreceiver process performs similar checks
37+ * against the flush and write LSNs, waking up waiters in the FLUSH
38+ * and WRITE heaps respectively.
3439 *
3540 * On primary servers: After flushing WAL, the WAL writer or backend
3641 * process performs a similar check against the flush LSN and wakes up
4954#include "access/xlogwait.h"
5055#include "miscadmin.h"
5156#include "pgstat.h"
57+ #include "replication/walreceiver.h"
5258#include "storage/latch.h"
5359#include "storage/proc.h"
5460#include "storage/shmem.h"
@@ -62,6 +68,48 @@ static int waitlsn_cmp(const pairingheap_node *a, const pairingheap_node *b,
6268
6369struct WaitLSNState * waitLSNState = NULL ;
6470
71+ /*
72+ * Wait event for each WaitLSNType, used with WaitLatch() to report
73+ * the wait in pg_stat_activity.
74+ */
75+ static const uint32 WaitLSNWaitEvents [] = {
76+ [WAIT_LSN_TYPE_REPLAY_STANDBY ] = WAIT_EVENT_WAIT_FOR_WAL_REPLAY ,
77+ [WAIT_LSN_TYPE_WRITE_STANDBY ] = WAIT_EVENT_WAIT_FOR_WAL_WRITE ,
78+ [WAIT_LSN_TYPE_FLUSH_STANDBY ] = WAIT_EVENT_WAIT_FOR_WAL_FLUSH ,
79+ [WAIT_LSN_TYPE_FLUSH_PRIMARY ] = WAIT_EVENT_WAIT_FOR_WAL_FLUSH ,
80+ };
81+
82+ StaticAssertDecl (lengthof (WaitLSNWaitEvents ) == WAIT_LSN_TYPE_COUNT ,
83+ "WaitLSNWaitEvents must match WaitLSNType enum" );
84+
85+ /*
86+ * Get the current LSN for the specified wait type.
87+ */
88+ XLogRecPtr
89+ GetCurrentLSNForWaitType (WaitLSNType lsnType )
90+ {
91+ switch (lsnType )
92+ {
93+ case WAIT_LSN_TYPE_REPLAY_STANDBY :
94+ return GetXLogReplayRecPtr (NULL );
95+
96+ case WAIT_LSN_TYPE_WRITE_STANDBY :
97+ return GetWalRcvWriteRecPtr ();
98+
99+ case WAIT_LSN_TYPE_FLUSH_STANDBY :
100+ return GetWalRcvFlushRecPtr (NULL , NULL );
101+
102+ case WAIT_LSN_TYPE_FLUSH_PRIMARY :
103+ return GetFlushRecPtr (NULL );
104+
105+ case WAIT_LSN_TYPE_COUNT :
106+ break ;
107+ }
108+
109+ elog (ERROR , "invalid LSN wait type: %d" , lsnType );
110+ pg_unreachable ();
111+ }
112+
65113/* Report the amount of shared memory space needed for WaitLSNState. */
66114Size
67115WaitLSNShmemSize (void )
@@ -341,13 +389,11 @@ WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout)
341389 int rc ;
342390 long delay_ms = -1 ;
343391
344- if (lsnType == WAIT_LSN_TYPE_REPLAY )
345- currentLSN = GetXLogReplayRecPtr (NULL );
346- else
347- currentLSN = GetFlushRecPtr (NULL );
392+ /* Get current LSN for the wait type */
393+ currentLSN = GetCurrentLSNForWaitType (lsnType );
348394
349395 /* Check that recovery is still in-progress */
350- if (lsnType == WAIT_LSN_TYPE_REPLAY && !RecoveryInProgress ())
396+ if (lsnType != WAIT_LSN_TYPE_FLUSH_PRIMARY && !RecoveryInProgress ())
351397 {
352398 /*
353399 * Recovery was ended, but check if target LSN was already
@@ -376,7 +422,7 @@ WaitForLSN(WaitLSNType lsnType, XLogRecPtr targetLSN, int64 timeout)
376422 CHECK_FOR_INTERRUPTS ();
377423
378424 rc = WaitLatch (MyLatch , wake_events , delay_ms ,
379- ( lsnType == WAIT_LSN_TYPE_REPLAY ) ? WAIT_EVENT_WAIT_FOR_WAL_REPLAY : WAIT_EVENT_WAIT_FOR_WAL_FLUSH );
425+ WaitLSNWaitEvents [ lsnType ] );
380426
381427 /*
382428 * Emergency bailout if postmaster has died. This is to avoid the
0 commit comments