From 2ea10ae333022b777904e3e64da7f62485a44c90 Mon Sep 17 00:00:00 2001 From: "duankunren.dkr" Date: Thu, 19 Mar 2026 22:07:51 +0800 Subject: [PATCH] Fix multixact compat logic via unconditional zero --- src/backend/access/transam/multixact.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 26b8d4e1230..a9a64d6c9c4 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -897,10 +897,21 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, * multixid was assigned. If we're replaying WAL that was generated by * such a version, the next page might not be initialized yet. Initialize * it now. + * + * The previous condition checked latest_page_number == pageno, but that + * fails after a crash-restart: StartupMultiXact() sets + * latest_page_number to page(checkPoint.nextMulti), which can be + * next_pageno or even higher when the checkpoint captured an advanced + * nextMXact. In that case, the == check doesn't match and we skip + * initialization, causing SimpleLruReadPage(next_pageno) to fail with + * "read too few bytes" because the page doesn't exist on disk. + * + * Use an unconditional check instead: during recovery, whenever we cross + * a page boundary, always ensure the next page is initialized. + * SimpleLruZeroPage is idempotent, and we use pre_initialized_offsets_page + * to skip the subsequent ZERO_OFF_PAGE replay, so this is safe. */ - if (InRecovery && - next_pageno != pageno && - MultiXactOffsetCtl->shared->latest_page_number == pageno) + if (InRecovery && next_pageno != pageno) { elog(DEBUG1, "next offsets page is not initialized, initializing it now"); -- 2.32.0.3.g01195cf9f