Skip to content

Commit 633e15e

Browse files
committed
Fix pageinspect failures on hash indexes.
Make every page in a hash index which isn't all-zeroes have a valid special space, so that tools like pageinspect don't error out. Also, make pageinspect cope with all-zeroes pages, because _hash_alloc_buckets can leave behind large numbers of those until they're consumed by splits. Ashutosh Sharma and Robert Haas, reviewed by Amit Kapila. Original trouble report from Jeff Janes. Discussion: http://postgr.es/m/CAMkU=1y6NjKmqbJ8wLMhr=F74WzcMALYWcVFhEpm7i=mV=XsOg@mail.gmail.com
1 parent 6785fbd commit 633e15e

File tree

4 files changed

+73
-35
lines changed

4 files changed

+73
-35
lines changed

contrib/pageinspect/hashfuncs.c

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,31 +56,33 @@ static Page
5656
verify_hash_page(bytea *raw_page, int flags)
5757
{
5858
Page page = get_page_from_raw(raw_page);
59-
int pagetype;
60-
HashPageOpaque pageopaque;
59+
int pagetype = LH_UNUSED_PAGE;
6160

62-
if (PageIsNew(page))
63-
ereport(ERROR,
64-
(errcode(ERRCODE_INDEX_CORRUPTED),
65-
errmsg("index table contains zero page")));
61+
/* Treat new pages as unused. */
62+
if (!PageIsNew(page))
63+
{
64+
HashPageOpaque pageopaque;
6665

67-
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
68-
ereport(ERROR,
69-
(errcode(ERRCODE_INDEX_CORRUPTED),
70-
errmsg("index table contains corrupted page")));
66+
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
67+
ereport(ERROR,
68+
(errcode(ERRCODE_INDEX_CORRUPTED),
69+
errmsg("index table contains corrupted page")));
7170

72-
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
73-
if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
74-
ereport(ERROR,
75-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
76-
errmsg("page is not a hash page"),
77-
errdetail("Expected %08x, got %08x.",
78-
HASHO_PAGE_ID, pageopaque->hasho_page_id)));
71+
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
72+
if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
73+
ereport(ERROR,
74+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
75+
errmsg("page is not a hash page"),
76+
errdetail("Expected %08x, got %08x.",
77+
HASHO_PAGE_ID, pageopaque->hasho_page_id)));
78+
79+
pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
80+
}
7981

8082
/* Check that page type is sane. */
81-
pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
8283
if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
83-
pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE)
84+
pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE &&
85+
pagetype != LH_UNUSED_PAGE)
8486
ereport(ERROR,
8587
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
8688
errmsg("invalid hash page type %08x", pagetype)));
@@ -190,19 +192,25 @@ hash_page_type(PG_FUNCTION_ARGS)
190192
(errmsg("must be superuser to use raw page functions"))));
191193

192194
page = verify_hash_page(raw_page, 0);
193-
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
194-
195-
/* page type (flags) */
196-
if (opaque->hasho_flag & LH_META_PAGE)
197-
type = "metapage";
198-
else if (opaque->hasho_flag & LH_OVERFLOW_PAGE)
199-
type = "overflow";
200-
else if (opaque->hasho_flag & LH_BUCKET_PAGE)
201-
type = "bucket";
202-
else if (opaque->hasho_flag & LH_BITMAP_PAGE)
203-
type = "bitmap";
204-
else
195+
196+
if (PageIsNew(page))
205197
type = "unused";
198+
else
199+
{
200+
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
201+
202+
/* page type (flags) */
203+
if (opaque->hasho_flag & LH_META_PAGE)
204+
type = "metapage";
205+
else if (opaque->hasho_flag & LH_OVERFLOW_PAGE)
206+
type = "overflow";
207+
else if (opaque->hasho_flag & LH_BUCKET_PAGE)
208+
type = "bucket";
209+
else if (opaque->hasho_flag & LH_BITMAP_PAGE)
210+
type = "bitmap";
211+
else
212+
type = "unused";
213+
}
206214

207215
PG_RETURN_TEXT_P(cstring_to_text(type));
208216
}

src/backend/access/hash/hash_xlog.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,11 +697,20 @@ hash_xlog_squeeze_page(XLogReaderState *record)
697697
if (XLogReadBufferForRedo(record, 2, &ovflbuf) == BLK_NEEDS_REDO)
698698
{
699699
Page ovflpage;
700+
HashPageOpaque ovflopaque;
700701

701702
ovflpage = BufferGetPage(ovflbuf);
702703

703704
_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
704705

706+
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
707+
708+
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
709+
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
710+
ovflopaque->hasho_bucket = -1;
711+
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
712+
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
713+
705714
PageSetLSN(ovflpage, lsn);
706715
MarkBufferDirty(ovflbuf);
707716
}

src/backend/access/hash/hashovfl.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -590,11 +590,22 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
590590
}
591591

592592
/*
593-
* Initialize the freed overflow page. Just zeroing the page won't work,
594-
* because WAL replay routines expect pages to be initialized. See
595-
* explanation of RBM_NORMAL mode atop XLogReadBufferExtended.
593+
* Reinitialize the freed overflow page. Just zeroing the page won't
594+
* work, because WAL replay routines expect pages to be initialized. See
595+
* explanation of RBM_NORMAL mode atop XLogReadBufferExtended. We are
596+
* careful to make the special space valid here so that tools like
597+
* pageinspect won't get confused.
596598
*/
597599
_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
600+
601+
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
602+
603+
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
604+
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
605+
ovflopaque->hasho_bucket = -1;
606+
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
607+
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
608+
598609
MarkBufferDirty(ovflbuf);
599610

600611
if (BufferIsValid(prevbuf))

src/backend/access/hash/hashpage.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
993993
BlockNumber lastblock;
994994
char zerobuf[BLCKSZ];
995995
Page page;
996+
HashPageOpaque ovflopaque;
996997

997998
lastblock = firstblock + nblocks - 1;
998999

@@ -1007,10 +1008,19 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
10071008

10081009
/*
10091010
* Initialize the page. Just zeroing the page won't work; see
1010-
* _hash_freeovflpage for similar usage.
1011+
* _hash_freeovflpage for similar usage. We take care to make the
1012+
* special space valid for the benefit of tools such as pageinspect.
10111013
*/
10121014
_hash_pageinit(page, BLCKSZ);
10131015

1016+
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(page);
1017+
1018+
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
1019+
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
1020+
ovflopaque->hasho_bucket = -1;
1021+
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
1022+
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
1023+
10141024
if (RelationNeedsWAL(rel))
10151025
log_newpage(&rel->rd_node,
10161026
MAIN_FORKNUM,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy