diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 196a49ccec7..70cb88a7fee 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9015,10 +9015,7 @@ void XLogShutdownWalRcv(void) { ShutdownWalRcv(); - - LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); - XLogCtl->InstallXLogFileSegmentActive = false; - LWLockRelease(ControlFileLock); + ResetInstallXLogFileSegmentActive(); } /* Enable WAL file recycling and preallocation. */ @@ -9030,6 +9027,15 @@ SetInstallXLogFileSegmentActive(void) LWLockRelease(ControlFileLock); } +/* Disable WAL file recycling and preallocation. */ +void +ResetInstallXLogFileSegmentActive(void) +{ + LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + XLogCtl->InstallXLogFileSegmentActive = false; + LWLockRelease(ControlFileLock); +} + bool IsInstallXLogFileSegmentActive(void) { diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 0cc1ef22a66..de49bd65c06 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -3613,8 +3613,19 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, * Before we leave XLOG_FROM_STREAM state, make sure that * walreceiver is not active, so that it won't overwrite * WAL that we restore from archive. + * + * If walreceiver is actively streaming (or attempting to + * connect), we must shut it down. However, if it's + * already in WAITING state (e.g., due to timeline + * divergence), we only need to reset the install flag to + * allow archive restoration. */ - XLogShutdownWalRcv(); + if (WalRcvStreaming()) + XLogShutdownWalRcv(); + else + { + ResetInstallXLogFileSegmentActive(); + } /* * Before we sleep, re-scan for possible new timelines if diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 48ca8523810..ebb9eaade0a 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -257,6 +257,7 @@ extern void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI extern void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli); extern void SetInstallXLogFileSegmentActive(void); extern bool IsInstallXLogFileSegmentActive(void); +extern void ResetInstallXLogFileSegmentActive(void); extern void XLogShutdownWalRcv(void); /* diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl index edaef918454..6702fd2d09e 100644 --- a/src/test/recovery/t/004_timeline_switch.pl +++ b/src/test/recovery/t/004_timeline_switch.pl @@ -68,6 +68,14 @@ my $result = $node_standby_2->safe_psql('postgres', "SELECT count(*) FROM tab_int"); is($result, qq(2000), 'check content of standby 2'); +# Check the logs, WAL receiver should not have been stopped while +# transitioning to its new timeline. There is no need to rely on an +# offset in this check of the server logs: a new log file is used on +# node restart when primary_conninfo is updated above. +ok( !$node_standby_2->log_contains( + "FATAL: .* terminating walreceiver process due to administrator command" + ), + 'WAL receiver should not be stopped across timeline jumps'); # Ensure that a standby is able to follow a primary on a newer timeline # when WAL archiving is enabled.