From 2f8ad41814c86884156fe1cdfbd11feaf62fc848 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Tue, 20 Oct 2026 07:44:09 -0400 Subject: [PATCH v2 1/2] Fix stale XLogReceiptTime on a standby that keeps up When the startup process found more than one new chunk of streamed WAL, XLogReceiptTime was not advanced, so a standby keeping up with a busy primary canceled conflicting queries at once. Use the time of the previous flush position check instead, as the WAL was not yet flushed then. Reported-by: Andres Freund Discussion: https://postgr.es/m/ymyivl5bw7qwd3bhduxmv5kytsl6q4nstjtledw5l6nr7sdwcw@nl7egmss5l2m --- src/backend/access/transam/xlogrecovery.c | 25 ++++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 20be788da78..f4d6f6b1e24 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -263,8 +263,9 @@ static bool pendingWalRcvRestart = false; static TimestampTz XLogReceiptTime = 0; static XLogSource XLogReceiptSource = XLOG_FROM_ANY; -/* Local copy of WalRcv->flushedUpto */ +/* Local copy of WalRcv->flushedUpto, and when we read it */ static XLogRecPtr flushedUpto = InvalidXLogRecPtr; +static TimestampTz flushedUptoTime = 0; static TimeLineID receiveTLI = 0; /* @@ -3880,6 +3881,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, PrimarySlotName, wal_receiver_create_temp_slot); flushedUpto = InvalidXLogRecPtr; + flushedUptoTime = 0; } /* @@ -3894,30 +3896,33 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, /* * Walreceiver is active, so see if new data has arrived. * - * We only advance XLogReceiptTime when we obtain fresh - * WAL from walreceiver and observe that we had already - * processed everything before the most recent "chunk" - * that it flushed to disk. In steady state where we are - * keeping up with the incoming data, XLogReceiptTime will - * be updated on each cycle. When we are behind, - * XLogReceiptTime will not advance, so the grace time - * allotted to conflicting queries will decrease. + * When we obtain fresh WAL from walreceiver, the WAL at + * RecPtr was not yet flushed at our previous check, so + * use the time of that check as its receipt time, unless + * it is in the most recent "chunk", which arrived just + * now. When we are behind, XLogReceiptTime falls behind + * too, so the grace time allotted to conflicting queries + * decreases. */ if (RecPtr < flushedUpto) havedata = true; else { XLogRecPtr latestChunkStart; + TimestampTz prevFlushedUptoTime = flushedUptoTime; + flushedUptoTime = GetCurrentTimestamp(); flushedUpto = GetWalRcvFlushRecPtr(&latestChunkStart, &receiveTLI); if (RecPtr < flushedUpto && receiveTLI == curFileTLI) { havedata = true; if (latestChunkStart <= RecPtr) { - XLogReceiptTime = GetCurrentTimestamp(); + XLogReceiptTime = flushedUptoTime; SetCurrentChunkStartTime(XLogReceiptTime); } + else if (prevFlushedUptoTime > XLogReceiptTime) + XLogReceiptTime = prevFlushedUptoTime; } else havedata = false; -- 2.37.1 (Apple Git-137.1)