Re: Implement waiting for wal lsn replay: reloaded
Andres Freund <andres@anarazel.de>
On 2026-04-09 18:21:24 +0300, Alexander Korotkov wrote:
> I've assembled all the pending patches together.
> 0001 adds memory barrier to GetWalRcvWriteRecPtr() as suggested by
> Andres off-list.
I'd make it a pg_atomic_read_membarrier_u64().
> 0002 is basically [1] by Xuneng, but revised given we have a memory
> barrier in 0001, and my proposal to do ResetLatch() unconditionally
> similar to our other Latch-based loops.
> 0003 and 0004 are [2] by Xuneng.
> 0005 is [3] by Xuneng.
>
> I'm going to add them to Commitfest to run CI over them, and have a
> closer look over them tomorrow.
Briefly skimming the patches, none makes the writes to writtenUpto use
something bearing barrier semantics. I'd just make both of them a
pg_atomic_write_membarrier_u64().
I think this also needs a few more tests, e.g. for the scenario that
29e7dbf5e4d fixed. I think it'd also be good to do some testing for
off-by-one dangers. E.g. making sure that we don't stop waiting too early /
too late. Another one that I think might deserve more testing is waits on the
standby while crossing timeline boundaries.
> From 0e5b4d1b9311a628a70218d89abf12308c9d782f Mon Sep 17 00:00:00 2001
> From: Alexander Korotkov <akorotkov@postgresql.org>
> Date: Thu, 9 Apr 2026 16:49:04 +0300
> Subject: [PATCH v3 1/5] Add a memory barrier to GetWalRcvWriteRecPtr()
>
> Add pg_memory_barrier() before reading writtenUpto so that callers see
> up-to-date shared memory state. This matches the barrier semantics that
> GetWalRcvFlushRecPtr() and other LSN-position functions get implicitly from
> their spinlock acquire/release, and in turn protects from bugs caused by
> expectations of similar barrier guarantees from different LSN-position functions.
>
> Reported-by: Andres Freund <andres@anarazel.de>
> Discussion: https://postgr.es/m/zqbppucpmkeqecfy4s5kscnru4tbk6khp3ozqz6ad2zijz354k%40w4bdf4z3wqoz
> ---
> src/backend/replication/walreceiverfuncs.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
> index bd5d47be964..0408ddff43e 100644
> --- a/src/backend/replication/walreceiverfuncs.c
> +++ b/src/backend/replication/walreceiverfuncs.c
> @@ -363,14 +363,22 @@ GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI)
>
> /*
> * Returns the last+1 byte position that walreceiver has written.
> - * This returns a recently written value without taking a lock.
> + *
> + * Use a memory barrier to ensure that callers see up-to-date shared memory
> + * state, matching the barrier semantics provided by the spinlock in
> + * GetWalRcvFlushRecPtr() and other LSN-position functions.
> */
> XLogRecPtr
> GetWalRcvWriteRecPtr(void)
> {
> WalRcvData *walrcv = WalRcv;
> + XLogRecPtr recptr;
> +
> + pg_memory_barrier();
>
> - return pg_atomic_read_u64(&walrcv->writtenUpto);
> + recptr = pg_atomic_read_u64(&walrcv->writtenUpto);
> +
> + return recptr;
> }
>
> /*
> --
> 2.39.5 (Apple Git-154)
>
> Subject: [PATCH v3 2/5] Fix memory ordering in WAIT FOR LSN wakeup mechanism
> + /*
> + * Ensure the waker's prior position store (writtenUpto, flushedUpto,
> + * lastReplayedEndRecPtr, etc.) is globally visible before we read
> + * minWaitedLSN. Without this barrier, the CPU could load minWaitedLSN
> + * before draining the position store, leaving the position invisible to a
> + * concurrently-registering waiter.
> + *
> + * This is the waker side of a Dekker-style handshake; pairs with
> + * pg_memory_barrier() in GetCurrentLSNForWaitType() on the waiter side.
> + */
> + pg_memory_barrier();
> +
> /*
> * Fast path check. Skip if currentLSN is InvalidXLogRecPtr, which means
> * "wake all waiters" (e.g., during promotion when recovery ends).
I'd also make this a pg_atomic_read_membarrier_u64() and the write a
pg_atomic_write_membarrier_u64(). It's a lot easier to reason about this
stuff if you make sure that the individual reads / write pair and have
ordering implied.
Greetings,
Andres Freund
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Clean up 019_replslot_limit.pl comments
- 0b866bb90368 19 (unreleased) landed
-
Stabilize 019_replslot_limit.pl: wait on slot restart_lsn
- cdb1d1cf1de6 19 (unreleased) landed
-
Fix memory ordering in WAIT FOR LSN wakeup mechanism
- a80a593ab636 19 (unreleased) landed
-
Improve WAIT FOR LSN test coverage
- cb096e6d6981 19 (unreleased) landed
-
Remove redundant WAIT FOR LSN caller-side pre-checks
- df9f938ca2ec 19 (unreleased) landed
-
Use barrier semantics when reading/writing writtenUpto
- dfb690dd5237 19 (unreleased) landed
-
Use replay position as floor for WAIT FOR LSN standby_(write|flush)
- cba67b5b87f9 19 (unreleased) landed
-
Wake standby_write/standby_flush waiters from the WAL replay loop
- e7cd592174d9 19 (unreleased) landed
-
Minimal fix for WAIT FOR ... MODE 'standby_flush'
- 29e7dbf5e4da 19 (unreleased) landed
-
Avoid syscache lookup while building a WAIT FOR tuple descriptor
- 834038c1f8d5 19 (unreleased) landed
-
Document that WAIT FOR may be interrupted by recovery conflicts
- 10484c2cc75b 19 (unreleased) landed
-
Use WAIT FOR LSN in PostgreSQL::Test::Cluster::wait_for_catchup()
- 7e8aeb9e483d 19 (unreleased) landed
- f30848cb05d4 19 (unreleased) landed
-
Wake LSN waiters before recovery target stop
- 20a8f783e15c 19 (unreleased) landed
-
Remove redundant pg_unreachable() after elog(ERROR) from ExecWaitStmt()
- 30776ca46865 19 (unreleased) landed
-
Revert "Use WAIT FOR LSN in PostgreSQL::Test::Cluster::wait_for_catchup()"
- e54ce0b2da62 19 (unreleased) landed
-
Fix variable usage in wakeupWaiters()
- bf308639bfcf 19 (unreleased) landed
-
Add tab completion for the WAIT FOR LSN MODE option
- 76948337f724 19 (unreleased) landed
-
Add the MODE option to the WAIT FOR LSN command
- 49a181b5d634 19 (unreleased) landed
-
Extend xlogwait infrastructure with write and flush wait types
- 7a39f43d885b 19 (unreleased) landed
-
Unify error messages
- 502e256f2262 19 (unreleased) cited
-
Optimize shared memory usage for WaitLSNProcInfo
- 75e82b2f5a6f 19 (unreleased) landed
-
Fix WaitLSNWakeup() fast-path check for InvalidXLogRecPtr
- ede6acef4967 19 (unreleased) landed
-
Fix incorrect function name in comments
- 23792d738158 19 (unreleased) landed
-
Add infrastructure for efficient LSN waiting
- 3b4e53a075ea 19 (unreleased) landed
-
Add pairingheap_initialize() for shared memory usage
- 8af3ae0d4b36 19 (unreleased) landed
-
Implement WAIT FOR command
- 447aae13b030 19 (unreleased) landed