From 032ef9071a47e40f1aae7c22845f9acb5ad8e6c1 Mon Sep 17 00:00:00 2001 From: Xuneng Zhou Date: Wed, 9 Sep 2026 12:56:05 +0800 Subject: [PATCH v3 4/4] Organize WAIT FOR documentation notes by topic Group execution restrictions and recovery caveats into named subsections, keeping the lock rules and their rationale together. Consolidate mode details under Parameters and move client LSN guidance beside the example. --- doc/src/sgml/ref/wait_for.sgml | 213 +++++++++++++++++---------------- 1 file changed, 108 insertions(+), 105 deletions(-) diff --git a/doc/src/sgml/ref/wait_for.sgml b/doc/src/sgml/ref/wait_for.sgml index 0042825e702..54accdc1af5 100644 --- a/doc/src/sgml/ref/wait_for.sgml +++ b/doc/src/sgml/ref/wait_for.sgml @@ -106,7 +106,8 @@ WAIT FOR LSN 'lsn' standby_write: Wait for the WAL containing the LSN to be written to disk on a standby server, but not yet - necessarily flushed. This is faster than + necessarily flushed, or to have already been replayed. + This is faster than standby_flush but provides weaker durability guarantees since the data may still be in operating system buffers. This is satisfied by WAL already present on the @@ -118,7 +119,8 @@ WAIT FOR LSN 'lsn' standby_flush: Wait for the WAL containing the - LSN to be flushed to disk on a standby server. This provides + LSN to be flushed to disk on a standby server, or to have + already been replayed from WAL present on the standby. This provides a durability guarantee without waiting for the WAL to be applied. This is satisfied by WAL already present on the standby from a base backup, archive restore, or prior @@ -216,116 +218,117 @@ WAIT FOR LSN 'lsn' Notes - - WAIT FOR must be executed as a top-level command. - It cannot be executed from a function, procedure, or - DO block. It also requires that no active or - registered snapshot be held, and therefore cannot be used in contexts - where such a snapshot must remain active, including transactions running - at isolation levels higher than READ COMMITTED. - - - - While recovery is in progress, a wait in standby_replay - (the default), standby_write, or - standby_flush mode is rejected when the session already - holds a lock and the target lsn has not been reached - yet. Such a lock can make the startup process wait for this session, either - directly or through another session, while this session waits for the - startup process to advance recovery. That cycle involves no lock wait on - this side, so deadlock detection does not see it and nothing breaks it. A - wait whose target has already been reached returns immediately and is - therefore always allowed. - - - - Issue WAIT FOR outside a transaction block, or as the - first statement of one, before running anything that takes locks. That is - also the natural order for the read-your-writes pattern shown in the - examples below: wait for the target lsn first, then - run the queries that have to see it. Note that a lock taken by an earlier - statement is still held at READ COMMITTED, even though - its snapshot is gone, so a wait placed after such a statement is rejected - even when the isolation level permits it. - - - The restriction covers standby_write and - standby_flush as well, even though streaming replication - can advance those positions without the startup process. Both positions are - at least the replay position, so without an active walreceiver replay can - be their only source of progress. If a held lock blocks replay, the session - waits for replay to advance while replay waits for the session to release - the lock. Under streaming replication the positions advance independently - only while WAL keeps arriving. If reception stops before the target is - reached, a blocked startup process cannot restart the walreceiver. It also - cannot replay newer checkpoint records needed to advance restartpoints and - recycle WAL, so pg_wal can fill up and reception can - stop before the target is reached. The restriction therefore also applies - when streaming is active at the start of the wait. - - - - WAIT FOR waits until the specified - lsn is reached according to the specified - mode. The standby_replay mode - waits for the LSN to be replayed (applied to the database), which is - useful to achieve read-your-writes consistency while using an async - replica for reads and the primary for writes. The - standby_flush mode waits for the WAL to be flushed - to durable storage on the replica, or to have already been replayed - from WAL present on the standby. The standby_write mode - waits for the WAL to be written to the operating system, or to have - already been replayed, which is faster than flush for newly received - WAL but provides weaker durability guarantees. The - primary_flush mode waits for WAL to be flushed on - a primary server. In all cases, the LSN of the last - modification should be stored on the client application side or the - connection pooler side. - + + Execution Restrictions - - The standby modes (standby_replay, - standby_write, standby_flush) - can only be used during recovery, and primary_flush - can only be used on a primary server. Using the wrong mode for the - current server state will result in an error. If a standby is promoted - while waiting with a standby mode, the command will return - not in recovery (or throw an error if - NO_THROW is not specified). Promotion creates a new - timeline, and the LSN being waited for may refer to WAL from the old - timeline. - + + + + WAIT FOR must be executed as a top-level command. + It cannot be executed from a function, procedure, or + DO block. It also requires that no active or + registered snapshot be held, and therefore cannot be used in contexts + where such a snapshot must remain active, including transactions running + at isolation levels higher than READ COMMITTED. + + + + + While recovery is in progress, a wait in standby_replay + (the default), standby_write, or + standby_flush mode is rejected when the session already + holds a lock and the target lsn has not been reached + yet. A wait whose target has already been reached returns immediately + and is therefore always allowed. + + + + + + Issue WAIT FOR outside a transaction block, or as the + first statement of one, before running anything that takes locks. That is + also the natural order for the read-your-writes pattern shown in the + examples below: wait for the target lsn first, then + run the queries that have to see it. Note that a lock taken by an earlier + statement is still held at READ COMMITTED, even though + its snapshot is gone, so a wait placed after such a statement is rejected + even when the isolation level permits it. + + + + Such a lock can make the startup process wait for this session, either + directly or through another session, while this session waits for the + startup process to advance recovery. That cycle involves no lock wait on + this side, so deadlock detection does not see it and nothing breaks it. + + + + The restriction covers standby_write and + standby_flush as well, even though streaming replication + can advance those positions without the startup process. Both positions are + at least the replay position, so without an active walreceiver replay can + be their only source of progress. If a held lock blocks replay, the session + waits for replay to advance while replay waits for the session to release + the lock. Under streaming replication the positions advance independently + only while WAL keeps arriving. If reception stops before the target is + reached, a blocked startup process cannot restart the walreceiver. It also + cannot replay newer checkpoint records needed to advance restartpoints and + recycle WAL, so pg_wal can fill up and reception can + stop before the target is reached. The restriction therefore also applies + when streaming is active at the start of the wait. + + + + + Recovery and Timelines + + + If a standby is promoted while waiting with a standby mode, the command + will return not in recovery (or throw an error if + NO_THROW is not specified). Promotion creates a new + timeline, and the LSN being waited for may refer to WAL from the old + timeline. + + + + WAIT FOR compares only the numeric + LSN; it has no notion of which timeline a WAL + record belongs to. This matters when a standby continues recovery + across an upstream timeline switch — for example, a cascading + standby whose upstream gets promoted. In that case + WAIT FOR will return success + as soon as the position used by the selected wait mode reaches or + passes the numeric LSN, regardless of which + timeline that LSN belongs to. Applications that need to + confirm the target refers to the expected timeline must validate + the timeline themselves. + + + + On a standby server, WAIT FOR sessions may be + interrupted by recovery conflicts. Some recovery conflicts are + unavoidable: for example, replaying a tablespace drop resolves + conflicts by terminating all backends, regardless of what they are + doing. Applications using WAIT FOR on a standby + should be prepared to handle such interruptions, for example by + retrying the command or falling back to an alternative mechanism. + + + - - WAIT FOR compares only the numeric - LSN; it has no notion of which timeline a WAL - record belongs to. This matters when a standby continues recovery - across an upstream timeline switch — for example, a cascading - standby whose upstream gets promoted. In that case - WAIT FOR will return success - as soon as the position used by the selected wait mode reaches or - passes the numeric LSN, regardless of which - timeline that LSN belongs to. Applications that need to - confirm the target refers to the expected timeline must validate - the timeline themselves. - + + Examples - On a standby server, WAIT FOR sessions may be - interrupted by recovery conflicts. Some recovery conflicts are - unavoidable: for example, replaying a tablespace drop resolves - conflicts by terminating all backends, regardless of what they are - doing. Applications using WAIT FOR on a standby - should be prepared to handle such interruptions, for example by - retrying the command or falling back to an alternative mechanism. + The standby_replay mode waits for the LSN to be replayed + (applied to the database), which is useful to achieve read-your-writes + consistency while using an async + replica for reads and the primary for writes. In all cases, the + LSN of the last modification should be stored on the + client application side or the connection pooler side. - - - - Examples - You can use WAIT FOR command to wait for the pg_lsn value. For example, an application could update -- 2.50.1 (Apple Git-155)