Re: Implement waiting for wal lsn replay: reloaded
Xuneng Zhou <xunengzhou@gmail.com>
Attachments
- v1-0001-Remove-redundant-WAIT-FOR-LSN-caller-side-pre-che.patch (application/x-patch) patch v1-0001
- v1-0002-Use-replay-position-as-floor-for-WAIT-FOR-LSN-sta.patch (application/octet-stream) patch v1-0002
On Wed, Apr 8, 2026 at 7:23 AM Alexander Korotkov <aekorotkov@gmail.com> wrote: > > Hi, Xuneng! > > > Here is some analysis of the issue reported by Tom: > > > > 1) The problem > > > > WAIT FOR LSN with standby_write or standby_flush mode can block > > indefinitely on an idle primary even when the target LSN is already > > satisfied by WAL on disk. > > > > The walreceiver initializes its process-local LogstreamResult.Write > > and LogstreamResult.Flush from GetXLogReplayRecPtr() at connect time, > > reflecting all WAL already present on the standby (from a base backup, > > archive restore, or prior streaming). The shared-memory positions used > > by WAIT FOR LSN, however, are not seeded from this value: > > > > WalRcv->writtenUpto is zero-initialized by ShmemInitStruct and remains > > 0 until XLogWalRcvWrite() processes incoming streaming data. > > WalRcv->flushedUpto is initialized to the segment-aligned streaming > > start point by RequestXLogStreaming(), which may be significantly > > behind the replay position. It advances only when XLogWalRcvFlush() > > processes new data — which itself requires LogstreamResult.Flush < > > LogstreamResult.Write, a condition that never holds at startup since > > both fields are initialized to the same value. > > > > When the primary is idle and sends no new WAL, both positions stay at > > their initial stale values indefinitely. > > > > 2) The fix > > Seed writtenUpto and flushedUpto from LogstreamResult immediately > > after the walreceiver initializes those process-local fields, then > > call WaitLSNWakeup() to wake any already-blocked waiters. > > > > This broadens the semantics of these fields. writtenUpto and > > flushedUpto used to track only WAL written or flushed by the current > > walreceiver session — WAL received from the primary since the most > > recent connect. After this change, they are initialized to the replay > > position, so they also cover WAL that was already on disk before > > streaming began. This affects pg_stat_wal_receiver.written_lsn and > > flushed_lsn, which will now report the replay position immediately at > > walreceiver startup rather than 0 and the segment boundary > > respectively. I am still considering whether this semantic change is > > acceptable though it does shorten the runtime of the tap tests > > reported by Tom in my test. Another approach is to modify the logic of > > GetCurrentLSNForWaitType to cope with this special case and leave the > > publisher side alone without changing the semantics. But this seems to > > be more subtle. > > Patch 0001 looks OK for me. > Regarding patch 0002. Changes made for GetCurrentLSNForWaitType() > looks reliable for me. PerformWalRecovery() sets replayed positions > before starting recovery, and in turn before standby can accept > connections. So, changes to WalReceiverMain() don't look necessary to > me. Yeah, GetCurrentLSNForWaitType seems to be the right place to place the fix. Please see the attached patch 2. I also noticed another relevent problem: During pure archive recovery (no walreceiver), a backend that issues 'WAIT FOR LSN ... MODE 'standby_write' with a target ahead of the current replay position will sleep forever; the startup process replays past the target but only wakes 'STANDBY_REPLAY' waiters. This also affects mixed scenarios: the walreceiver may lag behind replay (e.g., archive restore has delivered WAL faster than streaming), so a 'standby_write' waiter could be waiting on WAL that replay has already consumed. I will write a patch to address this soon. -- Best, Xuneng
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