Commit 633e15ea authored by Robert Haas's avatar Robert Haas

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
parent 6785fbd6
...@@ -56,13 +56,12 @@ static Page ...@@ -56,13 +56,12 @@ static Page
verify_hash_page(bytea *raw_page, int flags) verify_hash_page(bytea *raw_page, int flags)
{ {
Page page = get_page_from_raw(raw_page); Page page = get_page_from_raw(raw_page);
int pagetype; int pagetype = LH_UNUSED_PAGE;
HashPageOpaque pageopaque;
if (PageIsNew(page)) /* Treat new pages as unused. */
ereport(ERROR, if (!PageIsNew(page))
(errcode(ERRCODE_INDEX_CORRUPTED), {
errmsg("index table contains zero page"))); HashPageOpaque pageopaque;
if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData))) if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
ereport(ERROR, ereport(ERROR,
...@@ -77,10 +76,13 @@ verify_hash_page(bytea *raw_page, int flags) ...@@ -77,10 +76,13 @@ verify_hash_page(bytea *raw_page, int flags)
errdetail("Expected %08x, got %08x.", errdetail("Expected %08x, got %08x.",
HASHO_PAGE_ID, pageopaque->hasho_page_id))); HASHO_PAGE_ID, pageopaque->hasho_page_id)));
/* Check that page type is sane. */
pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE; pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
}
/* Check that page type is sane. */
if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE && if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE) pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE &&
pagetype != LH_UNUSED_PAGE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid hash page type %08x", pagetype))); errmsg("invalid hash page type %08x", pagetype)));
...@@ -190,6 +192,11 @@ hash_page_type(PG_FUNCTION_ARGS) ...@@ -190,6 +192,11 @@ hash_page_type(PG_FUNCTION_ARGS)
(errmsg("must be superuser to use raw page functions")))); (errmsg("must be superuser to use raw page functions"))));
page = verify_hash_page(raw_page, 0); page = verify_hash_page(raw_page, 0);
if (PageIsNew(page))
type = "unused";
else
{
opaque = (HashPageOpaque) PageGetSpecialPointer(page); opaque = (HashPageOpaque) PageGetSpecialPointer(page);
/* page type (flags) */ /* page type (flags) */
...@@ -203,6 +210,7 @@ hash_page_type(PG_FUNCTION_ARGS) ...@@ -203,6 +210,7 @@ hash_page_type(PG_FUNCTION_ARGS)
type = "bitmap"; type = "bitmap";
else else
type = "unused"; type = "unused";
}
PG_RETURN_TEXT_P(cstring_to_text(type)); PG_RETURN_TEXT_P(cstring_to_text(type));
} }
......
...@@ -697,11 +697,20 @@ hash_xlog_squeeze_page(XLogReaderState *record) ...@@ -697,11 +697,20 @@ hash_xlog_squeeze_page(XLogReaderState *record)
if (XLogReadBufferForRedo(record, 2, &ovflbuf) == BLK_NEEDS_REDO) if (XLogReadBufferForRedo(record, 2, &ovflbuf) == BLK_NEEDS_REDO)
{ {
Page ovflpage; Page ovflpage;
HashPageOpaque ovflopaque;
ovflpage = BufferGetPage(ovflbuf); ovflpage = BufferGetPage(ovflbuf);
_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf)); _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
ovflopaque->hasho_bucket = -1;
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
PageSetLSN(ovflpage, lsn); PageSetLSN(ovflpage, lsn);
MarkBufferDirty(ovflbuf); MarkBufferDirty(ovflbuf);
} }
......
...@@ -590,11 +590,22 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf, ...@@ -590,11 +590,22 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
} }
/* /*
* Initialize the freed overflow page. Just zeroing the page won't work, * Reinitialize the freed overflow page. Just zeroing the page won't
* because WAL replay routines expect pages to be initialized. See * work, because WAL replay routines expect pages to be initialized. See
* explanation of RBM_NORMAL mode atop XLogReadBufferExtended. * explanation of RBM_NORMAL mode atop XLogReadBufferExtended. We are
* careful to make the special space valid here so that tools like
* pageinspect won't get confused.
*/ */
_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf)); _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
ovflopaque->hasho_bucket = -1;
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
MarkBufferDirty(ovflbuf); MarkBufferDirty(ovflbuf);
if (BufferIsValid(prevbuf)) if (BufferIsValid(prevbuf))
......
...@@ -993,6 +993,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks) ...@@ -993,6 +993,7 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
BlockNumber lastblock; BlockNumber lastblock;
char zerobuf[BLCKSZ]; char zerobuf[BLCKSZ];
Page page; Page page;
HashPageOpaque ovflopaque;
lastblock = firstblock + nblocks - 1; lastblock = firstblock + nblocks - 1;
...@@ -1007,10 +1008,19 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks) ...@@ -1007,10 +1008,19 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
/* /*
* Initialize the page. Just zeroing the page won't work; see * Initialize the page. Just zeroing the page won't work; see
* _hash_freeovflpage for similar usage. * _hash_freeovflpage for similar usage. We take care to make the
* special space valid for the benefit of tools such as pageinspect.
*/ */
_hash_pageinit(page, BLCKSZ); _hash_pageinit(page, BLCKSZ);
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(page);
ovflopaque->hasho_prevblkno = InvalidBlockNumber;
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
ovflopaque->hasho_bucket = -1;
ovflopaque->hasho_flag = LH_UNUSED_PAGE;
ovflopaque->hasho_page_id = HASHO_PAGE_ID;
if (RelationNeedsWAL(rel)) if (RelationNeedsWAL(rel))
log_newpage(&rel->rd_node, log_newpage(&rel->rd_node,
MAIN_FORKNUM, MAIN_FORKNUM,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment