From 613b58d2aa3fc1b39fe79e1f474582f9aa4b5eaa Mon Sep 17 00:00:00 2001 From: alterego655 <824662526@qq.com> Date: Thu, 22 Oct 2026 17:36:14 +0800 Subject: [PATCH v1 1/2] Fix timeline selection for backward WAL reads XLogReadDetermineTimeline() caches the timeline it chose last and reuses it through fast paths. The cache records where a historical timeline ends but not where it begins, so reusing it is safe only when reading forward. The fast path for the current timeline already requires this; the one for a historical timeline did not. As a result, a backward read could keep a historical timeline for a segment before that timeline's first segment, where no file exists under its name. The read then failed with "requested WAL segment ... has already been removed", although the needed segment was still present under an older timeline. XLogFindNextRecord() reads a record and then rewinds to its start. pg_walinspect can therefore hit this when a record crosses into the first segment of a timeline that is no longer current, which needs at least two timeline switches. Fix by applying the same forward-read requirement to the historical-timeline fast path. The defect dates back to 1148e22a82e. It became reachable from core when 2258e76f90b made XLogFindNextRecord() available to backend code. --- src/backend/access/transam/xlogutils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index ff71e14015d..ae215601513 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -777,6 +777,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, if (XLogRecPtrIsValid(state->currTLIValidUntil) && state->currTLI != currTLI && state->currTLI != 0 && + wantPage >= lastReadPage && ((wantPage + wantLength) / state->segcxt.ws_segsize) < (state->currTLIValidUntil / state->segcxt.ws_segsize)) return; -- 2.51.0