v2-0001-Fix-unexpected-zero-page-in-pgstattuple-for-hash-.patch
application/octet-stream
Filename: v2-0001-Fix-unexpected-zero-page-in-pgstattuple-for-hash-.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v2-0001
Subject: Fix "unexpected zero page" in pgstattuple for hash and gist indexes
| File | + | − |
|---|---|---|
| contrib/pgstattuple/pgstattuple.c | 16 | 6 |
From 214b5d69dd9e8fa9c31c4987ffe8efce2dc5dc79 Mon Sep 17 00:00:00 2001
From: Nitin Motiani <nitinmotiani@google.com>
Date: Fri, 12 Sep 2025 08:49:07 +0000
Subject: [PATCH v2] 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 <noah@leadboat.com>
---
contrib/pgstattuple/pgstattuple.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index b5de68b7232..89ef6a26783 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -458,10 +458,16 @@ 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))
+ {
+ /* fully empty page */
+ stat->free_space += BLCKSZ;
+ }
+ else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
{
HashPageOpaque opaque;
@@ -502,17 +508,21 @@ 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))
+ {
+ /* fully empty page */
+ stat->free_space += BLCKSZ;
+ }
+ else if (PageGetSpecialSize(page) == MAXALIGN(sizeof(GISTPageOpaqueData)) &&
+ GistPageIsLeaf(page))
{
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
}
else
{
- /* root or node */
+ /* root or node or corrupted */
}
UnlockReleaseBuffer(buf);
--
2.51.0.618.g983fd99d29-goog