Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+39-31
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

+9
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

+14-3
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

+11-1
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)