From 2d81d0d6194fb6df98f37f624943e80e37a27fc4 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Wed, 29 Apr 2026 12:08:26 -0400 Subject: [PATCH v6 3/3] xlog: Verify all block references are used during replay It's unclear if this makes sense to actually commit. It requires that blocks read during recovery go through XLogReadBufferForRedoExtended() and has a special case for handling XLOG_FPI_FOR_HINT when full page writes are disabled. Author: Andres Freund Co-authored-by: Melanie Plageman Discussion: https://postgr.es/m/oqcsevg35xjan2327x5kdfth6q4fgeqboxfo3v3imeyih2uiny%406sez5dzxl6nt --- src/backend/access/transam/xlog.c | 10 ++++++++++ src/backend/access/transam/xlogreader.c | 4 ++++ src/backend/access/transam/xlogrecovery.c | 16 ++++++++++++++++ src/backend/access/transam/xlogutils.c | 6 ++++++ src/include/access/xlogreader.h | 4 ++++ 5 files changed, 40 insertions(+) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f8b939853e9..40ba0ac7279 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9084,6 +9084,16 @@ xlog_redo(XLogReaderState *record) { if (info == XLOG_FPI) elog(ERROR, "XLOG_FPI record did not contain a full-page image"); + +#ifdef USE_ASSERT_CHECKING + + /* + * If full_page_writes are disabled, we don't want to error + * out because we didn't read the block. + */ + if (info == XLOG_FPI_FOR_HINT) + record->record->blocks[block_id].used_read = true; +#endif continue; } diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index 946907a2507..8679a2435ed 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -1796,6 +1796,10 @@ DecodeXLogRecord(XLogReaderState *state, blk = &decoded->blocks[block_id]; blk->in_use = true; +#ifdef USE_ASSERT_CHECKING + blk->used_read = false; +#endif + blk->apply_image = false; COPY_HEADER_FIELD(&fork_flags, sizeof(uint8)); diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index a9ebac2d0ef..a5dfbfbdcef 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -1965,6 +1965,22 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl /* Now apply the WAL record itself */ GetRmgr(record->xl_rmid).rm_redo(xlogreader); + /* + * Verify that all block references were used during replay. This helps + * detect bugs in redo routines. Every referenced block needs to be + * replayed with XLogReadBufferForRedoExtended(), possibly via a helper, + * to ensure that we replay FPIs, extend the relation if necessary, and + * other perform other similar protections. + */ +#ifdef USE_ASSERT_CHECKING + for (int block_id = 0; block_id <= xlogreader->record->max_block_id; block_id++) + { + DecodedBkpBlock *blk = &xlogreader->record->blocks[block_id]; + + Assert(!blk->in_use || blk->used_read); + } +#endif + /* * After redo, check whether the backup pages associated with the WAL * record are consistent with the existing pages. This check is done only diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 58b9dab6a90..cc7c8a06089 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -381,6 +381,12 @@ XLogReadBufferForRedoExtended(XLogReaderState *record, block_id); } +#ifdef USE_ASSERT_CHECKING + /* Shouldn't have multiple read references to block */ + Assert(!record->record->blocks[block_id].used_read); + record->record->blocks[block_id].used_read = true; +#endif + /* * Make sure that if the block is marked with WILL_INIT, the caller is * going to initialize it. And vice versa. diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h index 4a9a687e879..5b598b20859 100644 --- a/src/include/access/xlogreader.h +++ b/src/include/access/xlogreader.h @@ -145,6 +145,10 @@ typedef struct bool has_data; char *data; uint16 data_len; + +#ifdef USE_ASSERT_CHECKING + bool used_read; +#endif } DecodedBkpBlock; /* -- 2.47.3