From b29620302d364a1bd7b4d7e6e22b5f262c9e71a5 Mon Sep 17 00:00:00 2001 From: Aidar Imamov Date: Thu, 15 Oct 2026 17:01:46 +0300 Subject: [PATCH v2] Disable startup progress timeout during standby WAL replay The server disables periodic recovery progress logging controlled by log_startup_progress_interval in standby mode, because a standby remains in recovery until promotion and would otherwise emit recovery progress messages indefinitely. However, startup operations executed afterward, such as ResetUnloggedRelations(), can re-enable the startup progress timeout. As a result, the timeout could previously remain active during standby WAL replay. This caused no user-visible issue because recovery progress messages are not emitted during standby WAL replay. However, the timeout still generated unnecessary periodic wakeups. Fix this by disabling the startup progress timeout again when WAL replay starts in standby mode. This preserves progress reporting for earlier startup operations while keeping the timeout disabled during standby WAL replay as intended. Also clarify the log_startup_progress_interval documentation to describe which startup operations emit progress messages, and that WAL replay progress is not reported on standby servers. Separately, ResolveRecoveryConflictWithLock() and ResolveRecoveryConflictWithBufferPin() end with disable_all_timeouts(false), which cancels every timeout the startup process has, not just the two these functions enable. Since commit 9ce346eabf3 the startup process also has STARTUP_PROGRESS_TIMEOUT, so a single recovery conflict stops "redo in progress" messages for the rest of the redo, even though redo keeps going. Cancel only the two timeouts each function enables. --- doc/src/sgml/config.sgml | 4 +++- src/backend/access/transam/xlogrecovery.c | 12 ++++++++++++ src/backend/storage/ipc/standby.c | 20 ++++++++++---------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index e537b3b0043..35447fa6260 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -7736,7 +7736,9 @@ local0.* /var/log/postgresql operation. The default is 10 seconds. A setting of 0 disables the feature. If this value is specified without units, it is taken as milliseconds. This setting is applied separately to - each operation. + each operation, such as WAL replay, syncing the data + directory, and resetting unlogged relations. On a standby server, + however, it does not apply during WAL replay. This parameter can only be set in the postgresql.conf file or on the server command line. diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 20be788da78..5f071382f8b 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -1669,6 +1669,18 @@ PerformWalRecovery(void) */ CheckRecoveryConsistency(); + /* + * EnableStandbyMode() disables periodic recovery progress logging, + * because a standby remains in recovery until promotion and would + * otherwise emit recovery progress messages indefinitely. + * + * However, earlier startup phases executed afterward, such as + * ResetUnloggedRelations(), may have re-enabled the timeout. Therefore, + * disable it again before entering WAL replay. + */ + if (StandbyMode) + disable_startup_progress_timeout(); + /* * Find the first record that logically follows the checkpoint --- it * might physically precede it, though. diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 7f011e04990..32b19814c6f 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -754,12 +754,12 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict) cleanup: /* - * Clear any timeout requests established above. We assume here that the - * Startup process doesn't have any other outstanding timeouts than those - * used by this function. If that stops being true, we could cancel the - * timeouts individually, but that'd be slower. + * Cancel only the timeouts established above. The startup process also + * has STARTUP_PROGRESS_TIMEOUT, which must not be canceled here, or + * recovery progress reporting would stop for the rest of the redo. */ - disable_all_timeouts(false); + disable_timeout(STANDBY_LOCK_TIMEOUT, false); + disable_timeout(STANDBY_DEADLOCK_TIMEOUT, false); got_standby_lock_timeout = false; got_standby_deadlock_timeout = false; } @@ -865,12 +865,12 @@ ResolveRecoveryConflictWithBufferPin(void) } /* - * Clear any timeout requests established above. We assume here that the - * Startup process doesn't have any other timeouts than what this function - * uses. If that stops being true, we could cancel the timeouts - * individually, but that'd be slower. + * Cancel only the timeouts established above. The startup process also + * has STARTUP_PROGRESS_TIMEOUT, which must not be canceled here, or + * recovery progress reporting would stop for the rest of the redo. */ - disable_all_timeouts(false); + disable_timeout(STANDBY_TIMEOUT, false); + disable_timeout(STANDBY_DEADLOCK_TIMEOUT, false); got_standby_delay_timeout = false; got_standby_deadlock_timeout = false; } -- 2.47.1