From cdff70751e7b146a73a72842f7be2ada44cfbb73 Mon Sep 17 00:00:00 2001 From: Nitin Motiani Date: Fri, 12 Sep 2025 08:49:07 +0000 Subject: [PATCH v1] Fix "unexpected zero page" in pgstattuple for hash and gist indexes * pgstattuple calls check functions for all the pages in hash and gist indexes. These calls are made from pgstat_hash_page() and pgstat_gist_page(). For zero pages, these call lead to ERRCODE_INDEX_CORRUPTED. * Since zero pages are normal after a crash, these errors are false alarms. pgstat_btree_page() avoids these errors by not running these checks. * In this patch, we do the same for gist and hash indexes. For hash index, ReadBufferExtended() replaces _hash_getbuf_with_strategy() which was calling _hash_check_page(). Instead we do the required check for special size explicitly for the non-PageIsNew() cases. * Similarly for gist index, we remove gistcheckpage() and explicitly checks the special size for the non-PageIsNew() cases before checking if the page is a leaf. * The comments in the else clauses have been updated accordingly. Reported-by: Noah Misch --- contrib/pgstattuple/pgstattuple.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c index b5de68b7232..cb0c6c70758 100644 --- a/contrib/pgstattuple/pgstattuple.c +++ b/contrib/pgstattuple/pgstattuple.c @@ -458,10 +458,12 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, Buffer buf; Page page; - buf = _hash_getbuf_with_strategy(rel, blkno, HASH_READ, 0, bstrategy); + buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); + LockBuffer(buf, HASH_READ); page = BufferGetPage(buf); - if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) + if (!PageIsNew(page) && + PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData))) { HashPageOpaque opaque; @@ -484,7 +486,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, } else { - /* maybe corrupted */ + /* maybe corrupted or a zero page */ } _hash_relbuf(rel, buf); @@ -502,17 +504,18 @@ pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno, buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buf, GIST_SHARE); - gistcheckpage(rel, buf); page = BufferGetPage(buf); - if (GistPageIsLeaf(page)) + if (!PageIsNew(page) && + PageGetSpecialSize(page) == MAXALIGN(sizeof(GISTPageOpaqueData)) && + GistPageIsLeaf(page)) { pgstat_index_page(stat, page, FirstOffsetNumber, PageGetMaxOffsetNumber(page)); } else { - /* root or node */ + /* root or node or zero page or corrupted */ } UnlockReleaseBuffer(buf); -- 2.51.0.384.g4c02a37b29-goog