postgres.git / summary / log / commit / refs

commit    d28cdf46e6a4d55cd324b8db6148f6ebc552f52e
Author:   Robert Haas <rhaas@postgresql.org>
Date:     Wed Jul 22 12:47:44 2026 +0000
First released in: 17.11, 18.6

    walsummarizer: Guard against WAL files whose tail ends are not valid.
    
    SummarizeWAL documents that maximum_lsn should be passed as "the switch
    point when reading a historic timeline, or the most-recently-measured end of
    WAL when reading the current timeline." But the caller always passed the
    most recently measured end-of-WAL even when reading from a historic
    timeline, due to an oversight on my part. Fix that.
    
    As far as I can determine, for this to become an issue in practice, it's
    necessary to have a corrupted WAL file in the archive.  SummarizeWAL checks
    that every record it processes both starts and ends before switch_lsn; so if
    all the WAL files in the archive are valid, SummarizeWAL will still discover
    where it should stop summarizing and do the right thing.  However, if
    there's a corrupted file in the WAL archive, and if it is also the case that
    the end of the current timeline has advanced past the switch point, then the
    incorrect maximum_lsn value can result in trying to read an invalid record
    and erroring out, which leads repeatedly retrying and failing with an error
    every time.
    
    One way this could occur is if a new primary is promoted and creates a
    .partial file, and the user manually renames that file to remove the suffix,
    and it is then archived. In that situation, the tail end of the file need
    not be valid WAL, and that could lead to a stuck WAL summarizer.
    
    Reported-by: Fabrice Chapuis <fabrice636861@gmail.com>
    Analyzed-by: Thom Brown <thom@linux.com> (using claude)
    Discussion: http://postgr.es/m/CAA5-nLDdvGMkN6Z-GaHGHG5T7QWEgv4YoHO7XvOJbeD00cghNg@mail.gmail.com
    Backpatch-through: 17


src/backend/postmaster/walsummarizer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c index 63a84d0c0b5..b4a64e4d892 100644 --- a/src/backend/postmaster/walsummarizer.c +++ b/src/backend/postmaster/walsummarizer.c @@ -350,6 +350,7 @@ WalSummarizerMain(char *startup_data, size_t startup_data_len) { XLogRecPtr latest_lsn; TimeLineID latest_tli; + XLogRecPtr maximum_lsn; XLogRecPtr end_of_summary_lsn; /* Flush any leaked data in the top-level context */ @@ -414,9 +415,10 @@ WalSummarizerMain(char *startup_data, size_t startup_data_len) } /* Summarize WAL. */ + maximum_lsn = XLogRecPtrIsValid(switch_lsn) ? switch_lsn : latest_lsn; end_of_summary_lsn = SummarizeWAL(current_tli, current_lsn, exact, - switch_lsn, latest_lsn); + switch_lsn, maximum_lsn); Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn)); Assert(end_of_summary_lsn >= current_lsn); [parent: 2b1054be851f]