Commit 766dc45d authored by Tom Lane's avatar Tom Lane

Add defenses to btree and hash index AMs to do simple sanity checks

on every index page they read; in particular to catch the case of an
all-zero page, which PageHeaderIsValid allows to pass.  It turns out
hash already had this idea, but it was just Assert()ing things rather
than doing a straight error check, and the Asserts were partially
redundant with PageHeaderIsValid anyway.  Per recent failure example
from Jim Nasby.  (gist still needs the same treatment.)
parent 18691d8e
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.81 2005/10/15 02:49:08 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.82 2005/11/06 19:29:00 tgl Exp $
* *
* NOTES * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -513,8 +513,8 @@ hashbulkdelete(PG_FUNCTION_ARGS) ...@@ -513,8 +513,8 @@ hashbulkdelete(PG_FUNCTION_ARGS)
* each bucket. * each bucket.
*/ */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
orig_maxbucket = metap->hashm_maxbucket; orig_maxbucket = metap->hashm_maxbucket;
orig_ntuples = metap->hashm_ntuples; orig_ntuples = metap->hashm_ntuples;
memcpy(&local_metapage, metap, sizeof(local_metapage)); memcpy(&local_metapage, metap, sizeof(local_metapage));
...@@ -555,8 +555,8 @@ loop_top: ...@@ -555,8 +555,8 @@ loop_top:
vacuum_delay_point(); vacuum_delay_point();
buf = _hash_getbuf(rel, blkno, HASH_WRITE); buf = _hash_getbuf(rel, blkno, HASH_WRITE);
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
opaque = (HashPageOpaque) PageGetSpecialPointer(page); opaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(opaque->hasho_bucket == cur_bucket); Assert(opaque->hasho_bucket == cur_bucket);
...@@ -614,8 +614,8 @@ loop_top: ...@@ -614,8 +614,8 @@ loop_top:
/* Write-lock metapage and check for split since we started */ /* Write-lock metapage and check for split since we started */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE); metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
if (cur_maxbucket != metap->hashm_maxbucket) if (cur_maxbucket != metap->hashm_maxbucket)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.39 2005/10/18 01:06:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.40 2005/11/06 19:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -73,8 +73,8 @@ _hash_doinsert(Relation rel, HashItem hitem) ...@@ -73,8 +73,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
/* Read the metapage */ /* Read the metapage */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
/* /*
* Check whether the item can fit on a hash page at all. (Eventually, we * Check whether the item can fit on a hash page at all. (Eventually, we
...@@ -111,8 +111,8 @@ _hash_doinsert(Relation rel, HashItem hitem) ...@@ -111,8 +111,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
/* Fetch the primary bucket page for the bucket */ /* Fetch the primary bucket page for the bucket */
buf = _hash_getbuf(rel, blkno, HASH_WRITE); buf = _hash_getbuf(rel, blkno, HASH_WRITE);
_hash_checkpage(rel, buf, LH_BUCKET_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(pageopaque->hasho_bucket == bucket); Assert(pageopaque->hasho_bucket == bucket);
...@@ -151,7 +151,7 @@ _hash_doinsert(Relation rel, HashItem hitem) ...@@ -151,7 +151,7 @@ _hash_doinsert(Relation rel, HashItem hitem)
/* should fit now, given test above */ /* should fit now, given test above */
Assert(PageGetFreeSpace(page) >= itemsz); Assert(PageGetFreeSpace(page) >= itemsz);
} }
_hash_checkpage(rel, page, LH_OVERFLOW_PAGE); _hash_checkpage(rel, buf, LH_OVERFLOW_PAGE);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(pageopaque->hasho_bucket == bucket); Assert(pageopaque->hasho_bucket == bucket);
} }
...@@ -204,8 +204,8 @@ _hash_pgaddtup(Relation rel, ...@@ -204,8 +204,8 @@ _hash_pgaddtup(Relation rel,
OffsetNumber itup_off; OffsetNumber itup_off;
Page page; Page page;
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page)); itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
if (PageAddItem(page, (Item) hitem, itemsize, itup_off, LP_USED) if (PageAddItem(page, (Item) hitem, itemsize, itup_off, LP_USED)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.47 2005/10/15 02:49:08 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.48 2005/11/06 19:29:00 tgl Exp $
* *
* NOTES * NOTES
* Overflow pages look like ordinary relation pages. * Overflow pages look like ordinary relation pages.
...@@ -124,8 +124,8 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf) ...@@ -124,8 +124,8 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf)
{ {
BlockNumber nextblkno; BlockNumber nextblkno;
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
nextblkno = pageopaque->hasho_nextblkno; nextblkno = pageopaque->hasho_nextblkno;
...@@ -183,8 +183,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf) ...@@ -183,8 +183,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
/* Get exclusive lock on the meta page */ /* Get exclusive lock on the meta page */
_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
/* start search at hashm_firstfree */ /* start search at hashm_firstfree */
orig_firstfree = metap->hashm_firstfree; orig_firstfree = metap->hashm_firstfree;
...@@ -222,8 +222,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf) ...@@ -222,8 +222,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK); _hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE); mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE);
_hash_checkpage(rel, mapbuf, LH_BITMAP_PAGE);
mappage = BufferGetPage(mapbuf); mappage = BufferGetPage(mapbuf);
_hash_checkpage(rel, mappage, LH_BITMAP_PAGE);
freep = HashPageGetBitmap(mappage); freep = HashPageGetBitmap(mappage);
for (; bit <= last_inpage; j++, bit += BITS_PER_MAP) for (; bit <= last_inpage; j++, bit += BITS_PER_MAP)
...@@ -379,9 +379,9 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf) ...@@ -379,9 +379,9 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
Bucket bucket; Bucket bucket;
/* Get information from the doomed page */ /* Get information from the doomed page */
_hash_checkpage(rel, ovflbuf, LH_OVERFLOW_PAGE);
ovflblkno = BufferGetBlockNumber(ovflbuf); ovflblkno = BufferGetBlockNumber(ovflbuf);
ovflpage = BufferGetPage(ovflbuf); ovflpage = BufferGetPage(ovflbuf);
_hash_checkpage(rel, ovflpage, LH_OVERFLOW_PAGE);
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage); ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
nextblkno = ovflopaque->hasho_nextblkno; nextblkno = ovflopaque->hasho_nextblkno;
prevblkno = ovflopaque->hasho_prevblkno; prevblkno = ovflopaque->hasho_prevblkno;
...@@ -403,7 +403,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf) ...@@ -403,7 +403,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
Page prevpage = BufferGetPage(prevbuf); Page prevpage = BufferGetPage(prevbuf);
HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage); HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
_hash_checkpage(rel, prevpage, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE); _hash_checkpage(rel, prevbuf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
Assert(prevopaque->hasho_bucket == bucket); Assert(prevopaque->hasho_bucket == bucket);
prevopaque->hasho_nextblkno = nextblkno; prevopaque->hasho_nextblkno = nextblkno;
_hash_wrtbuf(rel, prevbuf); _hash_wrtbuf(rel, prevbuf);
...@@ -414,7 +414,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf) ...@@ -414,7 +414,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
Page nextpage = BufferGetPage(nextbuf); Page nextpage = BufferGetPage(nextbuf);
HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage); HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
_hash_checkpage(rel, nextpage, LH_OVERFLOW_PAGE); _hash_checkpage(rel, nextbuf, LH_OVERFLOW_PAGE);
Assert(nextopaque->hasho_bucket == bucket); Assert(nextopaque->hasho_bucket == bucket);
nextopaque->hasho_prevblkno = prevblkno; nextopaque->hasho_prevblkno = prevblkno;
_hash_wrtbuf(rel, nextbuf); _hash_wrtbuf(rel, nextbuf);
...@@ -422,8 +422,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf) ...@@ -422,8 +422,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
/* Read the metapage so we can determine which bitmap page to use */ /* Read the metapage so we can determine which bitmap page to use */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
/* Identify which bit to set */ /* Identify which bit to set */
ovflbitno = blkno_to_bitno(metap, ovflblkno); ovflbitno = blkno_to_bitno(metap, ovflblkno);
...@@ -440,8 +440,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf) ...@@ -440,8 +440,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
/* Clear the bitmap bit to indicate that this overflow page is free */ /* Clear the bitmap bit to indicate that this overflow page is free */
mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE); mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
_hash_checkpage(rel, mapbuf, LH_BITMAP_PAGE);
mappage = BufferGetPage(mapbuf); mappage = BufferGetPage(mapbuf);
_hash_checkpage(rel, mappage, LH_BITMAP_PAGE);
freep = HashPageGetBitmap(mappage); freep = HashPageGetBitmap(mappage);
Assert(ISSET(freep, bitmapbit)); Assert(ISSET(freep, bitmapbit));
CLRBIT(freep, bitmapbit); CLRBIT(freep, bitmapbit);
...@@ -569,8 +569,8 @@ _hash_squeezebucket(Relation rel, ...@@ -569,8 +569,8 @@ _hash_squeezebucket(Relation rel,
*/ */
wblkno = bucket_blkno; wblkno = bucket_blkno;
wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE); wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
_hash_checkpage(rel, wbuf, LH_BUCKET_PAGE);
wpage = BufferGetPage(wbuf); wpage = BufferGetPage(wbuf);
_hash_checkpage(rel, wpage, LH_BUCKET_PAGE);
wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
/* /*
...@@ -593,8 +593,8 @@ _hash_squeezebucket(Relation rel, ...@@ -593,8 +593,8 @@ _hash_squeezebucket(Relation rel,
if (ropaque != wopaque) if (ropaque != wopaque)
_hash_relbuf(rel, rbuf); _hash_relbuf(rel, rbuf);
rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE); rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
_hash_checkpage(rel, rbuf, LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf); rpage = BufferGetPage(rbuf);
_hash_checkpage(rel, rpage, LH_OVERFLOW_PAGE);
ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage); ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
Assert(ropaque->hasho_bucket == bucket); Assert(ropaque->hasho_bucket == bucket);
} while (BlockNumberIsValid(ropaque->hasho_nextblkno)); } while (BlockNumberIsValid(ropaque->hasho_nextblkno));
...@@ -635,8 +635,8 @@ _hash_squeezebucket(Relation rel, ...@@ -635,8 +635,8 @@ _hash_squeezebucket(Relation rel,
} }
wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE); wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
_hash_checkpage(rel, wbuf, LH_OVERFLOW_PAGE);
wpage = BufferGetPage(wbuf); wpage = BufferGetPage(wbuf);
_hash_checkpage(rel, wpage, LH_OVERFLOW_PAGE);
wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage); wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
Assert(wopaque->hasho_bucket == bucket); Assert(wopaque->hasho_bucket == bucket);
} }
...@@ -688,8 +688,8 @@ _hash_squeezebucket(Relation rel, ...@@ -688,8 +688,8 @@ _hash_squeezebucket(Relation rel,
_hash_freeovflpage(rel, rbuf); _hash_freeovflpage(rel, rbuf);
rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE); rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
_hash_checkpage(rel, rbuf, LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf); rpage = BufferGetPage(rbuf);
_hash_checkpage(rel, rpage, LH_OVERFLOW_PAGE);
ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage); ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
Assert(ropaque->hasho_bucket == bucket); Assert(ropaque->hasho_bucket == bucket);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.52 2005/10/15 02:49:08 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.53 2005/11/06 19:29:00 tgl Exp $
* *
* NOTES * NOTES
* Postgres hash pages look like ordinary relation pages. The opaque * Postgres hash pages look like ordinary relation pages. The opaque
...@@ -103,9 +103,11 @@ _hash_droplock(Relation rel, BlockNumber whichlock, int access) ...@@ -103,9 +103,11 @@ _hash_droplock(Relation rel, BlockNumber whichlock, int access)
* (ie, the buffer is "locked and pinned"). * (ie, the buffer is "locked and pinned").
* *
* XXX P_NEW is not used because, unlike the tree structures, we * XXX P_NEW is not used because, unlike the tree structures, we
* need the bucket blocks to be at certain block numbers. we must * need the bucket blocks to be at certain block numbers.
* depend on the caller to call _hash_pageinit on the block if it *
* knows that this is a new block. * All call sites should call either _hash_pageinit or _hash_checkpage
* on the returned page, depending on whether the block is expected
* to be new or not.
*/ */
Buffer Buffer
_hash_getbuf(Relation rel, BlockNumber blkno, int access) _hash_getbuf(Relation rel, BlockNumber blkno, int access)
...@@ -380,8 +382,8 @@ _hash_expandtable(Relation rel, Buffer metabuf) ...@@ -380,8 +382,8 @@ _hash_expandtable(Relation rel, Buffer metabuf)
/* Write-lock the meta page */ /* Write-lock the meta page */
_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE); _hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
/* /*
* Check to see if split is still needed; someone else might have already * Check to see if split is still needed; someone else might have already
...@@ -555,15 +557,15 @@ _hash_splitbucket(Relation rel, ...@@ -555,15 +557,15 @@ _hash_splitbucket(Relation rel,
* either bucket. * either bucket.
*/ */
oblkno = start_oblkno; oblkno = start_oblkno;
nblkno = start_nblkno;
obuf = _hash_getbuf(rel, oblkno, HASH_WRITE); obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
nbuf = _hash_getbuf(rel, nblkno, HASH_WRITE); _hash_checkpage(rel, obuf, LH_BUCKET_PAGE);
opage = BufferGetPage(obuf); opage = BufferGetPage(obuf);
npage = BufferGetPage(nbuf);
_hash_checkpage(rel, opage, LH_BUCKET_PAGE);
oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
nblkno = start_nblkno;
nbuf = _hash_getbuf(rel, nblkno, HASH_WRITE);
npage = BufferGetPage(nbuf);
/* initialize the new bucket's primary page */ /* initialize the new bucket's primary page */
_hash_pageinit(npage, BufferGetPageSize(nbuf)); _hash_pageinit(npage, BufferGetPageSize(nbuf));
nopaque = (HashPageOpaque) PageGetSpecialPointer(npage); nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
...@@ -602,8 +604,8 @@ _hash_splitbucket(Relation rel, ...@@ -602,8 +604,8 @@ _hash_splitbucket(Relation rel,
_hash_wrtbuf(rel, obuf); _hash_wrtbuf(rel, obuf);
obuf = _hash_getbuf(rel, oblkno, HASH_WRITE); obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
_hash_checkpage(rel, obuf, LH_OVERFLOW_PAGE);
opage = BufferGetPage(obuf); opage = BufferGetPage(obuf);
_hash_checkpage(rel, opage, LH_OVERFLOW_PAGE);
oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
ooffnum = FirstOffsetNumber; ooffnum = FirstOffsetNumber;
omaxoffnum = PageGetMaxOffsetNumber(opage); omaxoffnum = PageGetMaxOffsetNumber(opage);
...@@ -642,8 +644,8 @@ _hash_splitbucket(Relation rel, ...@@ -642,8 +644,8 @@ _hash_splitbucket(Relation rel,
_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK); _hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
/* chain to a new overflow page */ /* chain to a new overflow page */
nbuf = _hash_addovflpage(rel, metabuf, nbuf); nbuf = _hash_addovflpage(rel, metabuf, nbuf);
_hash_checkpage(rel, nbuf, LH_OVERFLOW_PAGE);
npage = BufferGetPage(nbuf); npage = BufferGetPage(nbuf);
_hash_checkpage(rel, npage, LH_OVERFLOW_PAGE);
/* we don't need nopaque within the loop */ /* we don't need nopaque within the loop */
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.41 2005/10/18 01:06:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.42 2005/11/06 19:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,8 +53,8 @@ _hash_next(IndexScanDesc scan, ScanDirection dir) ...@@ -53,8 +53,8 @@ _hash_next(IndexScanDesc scan, ScanDirection dir)
/* if we're here, _hash_step found a valid tuple */ /* if we're here, _hash_step found a valid tuple */
current = &(scan->currentItemData); current = &(scan->currentItemData);
offnum = ItemPointerGetOffsetNumber(current); offnum = ItemPointerGetOffsetNumber(current);
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
itup = &hitem->hash_itup; itup = &hitem->hash_itup;
scan->xs_ctup.t_self = itup->t_tid; scan->xs_ctup.t_self = itup->t_tid;
...@@ -77,8 +77,8 @@ _hash_readnext(Relation rel, ...@@ -77,8 +77,8 @@ _hash_readnext(Relation rel,
if (BlockNumberIsValid(blkno)) if (BlockNumberIsValid(blkno))
{ {
*bufp = _hash_getbuf(rel, blkno, HASH_READ); *bufp = _hash_getbuf(rel, blkno, HASH_READ);
_hash_checkpage(rel, *bufp, LH_OVERFLOW_PAGE);
*pagep = BufferGetPage(*bufp); *pagep = BufferGetPage(*bufp);
_hash_checkpage(rel, *pagep, LH_OVERFLOW_PAGE);
*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
} }
} }
...@@ -98,8 +98,8 @@ _hash_readprev(Relation rel, ...@@ -98,8 +98,8 @@ _hash_readprev(Relation rel,
if (BlockNumberIsValid(blkno)) if (BlockNumberIsValid(blkno))
{ {
*bufp = _hash_getbuf(rel, blkno, HASH_READ); *bufp = _hash_getbuf(rel, blkno, HASH_READ);
_hash_checkpage(rel, *bufp, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
*pagep = BufferGetPage(*bufp); *pagep = BufferGetPage(*bufp);
_hash_checkpage(rel, *pagep, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep); *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
} }
} }
...@@ -168,8 +168,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) ...@@ -168,8 +168,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
/* Read the metapage */ /* Read the metapage */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ); metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
_hash_checkpage(rel, metabuf, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf); metap = (HashMetaPage) BufferGetPage(metabuf);
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
/* /*
* Compute the target bucket number, and convert to block number. * Compute the target bucket number, and convert to block number.
...@@ -198,8 +198,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) ...@@ -198,8 +198,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
/* Fetch the primary bucket page for the bucket */ /* Fetch the primary bucket page for the bucket */
buf = _hash_getbuf(rel, blkno, HASH_READ); buf = _hash_getbuf(rel, blkno, HASH_READ);
_hash_checkpage(rel, buf, LH_BUCKET_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE);
opaque = (HashPageOpaque) PageGetSpecialPointer(page); opaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(opaque->hasho_bucket == bucket); Assert(opaque->hasho_bucket == bucket);
...@@ -216,8 +216,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir) ...@@ -216,8 +216,8 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
/* if we're here, _hash_step found a valid tuple */ /* if we're here, _hash_step found a valid tuple */
offnum = ItemPointerGetOffsetNumber(current); offnum = ItemPointerGetOffsetNumber(current);
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum)); hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
itup = &hitem->hash_itup; itup = &hitem->hash_itup;
scan->xs_ctup.t_self = itup->t_tid; scan->xs_ctup.t_self = itup->t_tid;
...@@ -254,8 +254,8 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir) ...@@ -254,8 +254,8 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
current = &(scan->currentItemData); current = &(scan->currentItemData);
buf = *bufP; buf = *bufP;
_hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf); page = BufferGetPage(buf);
_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
opaque = (HashPageOpaque) PageGetSpecialPointer(page); opaque = (HashPageOpaque) PageGetSpecialPointer(page);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.42 2005/05/11 01:26:01 neilc Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.43 2005/11/06 19:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -110,12 +110,50 @@ _hash_log2(uint32 num) ...@@ -110,12 +110,50 @@ _hash_log2(uint32 num)
* _hash_checkpage -- sanity checks on the format of all hash pages * _hash_checkpage -- sanity checks on the format of all hash pages
*/ */
void void
_hash_checkpage(Relation rel, Page page, int flags) _hash_checkpage(Relation rel, Buffer buf, int flags)
{ {
Assert(page); Page page = BufferGetPage(buf);
/* /*
* When checking the metapage, always verify magic number and version. * ReadBuffer verifies that every newly-read page passes PageHeaderIsValid,
* which means it either contains a reasonably sane page header or is
* all-zero. We have to defend against the all-zero case, however.
*/
if (PageIsNew(page))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" contains unexpected zero page at block %u",
RelationGetRelationName(rel),
BufferGetBlockNumber(buf)),
errhint("Please REINDEX it.")));
/*
* Additionally check that the special area looks sane.
*/
if (((PageHeader) (page))->pd_special !=
(BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData))))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" contains corrupted page at block %u",
RelationGetRelationName(rel),
BufferGetBlockNumber(buf)),
errhint("Please REINDEX it.")));
if (flags)
{
HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
if ((opaque->hasho_flag & flags) == 0)
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" contains corrupted page at block %u",
RelationGetRelationName(rel),
BufferGetBlockNumber(buf)),
errhint("Please REINDEX it.")));
}
/*
* When checking the metapage, also verify magic number and version.
*/ */
if (flags == LH_META_PAGE) if (flags == LH_META_PAGE)
{ {
...@@ -130,25 +168,8 @@ _hash_checkpage(Relation rel, Page page, int flags) ...@@ -130,25 +168,8 @@ _hash_checkpage(Relation rel, Page page, int flags)
if (metap->hashm_version != HASH_VERSION) if (metap->hashm_version != HASH_VERSION)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED), (errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" has wrong hash version", RelationGetRelationName(rel)), errmsg("index \"%s\" has wrong hash version",
RelationGetRelationName(rel)),
errhint("Please REINDEX it."))); errhint("Please REINDEX it.")));
} }
/*
* These other checks are for debugging purposes only.
*/
#ifdef USE_ASSERT_CHECKING
Assert(((PageHeader) (page))->pd_lower >= SizeOfPageHeaderData);
Assert(((PageHeader) (page))->pd_upper <=
(BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData))));
Assert(((PageHeader) (page))->pd_special ==
(BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData))));
Assert(PageGetPageSize(page) == BLCKSZ);
if (flags)
{
HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(opaque->hasho_flag & flags);
}
#endif /* USE_ASSERT_CHECKING */
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.127 2005/10/15 02:49:09 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.128 2005/11/06 19:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -672,7 +672,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright, ...@@ -672,7 +672,7 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
rightpage = BufferGetPage(rbuf); rightpage = BufferGetPage(rbuf);
_bt_pageinit(leftpage, BufferGetPageSize(buf)); _bt_pageinit(leftpage, BufferGetPageSize(buf));
_bt_pageinit(rightpage, BufferGetPageSize(rbuf)); /* rightpage was already initialized by _bt_getbuf */
/* init btree private data */ /* init btree private data */
oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage); oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.88 2005/10/15 02:49:09 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.89 2005/11/06 19:29:00 tgl Exp $
* *
* NOTES * NOTES
* Postgres btree pages look like ordinary relation pages. The opaque * Postgres btree pages look like ordinary relation pages. The opaque
...@@ -222,8 +222,6 @@ _bt_getroot(Relation rel, int access) ...@@ -222,8 +222,6 @@ _bt_getroot(Relation rel, int access)
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE); rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
rootblkno = BufferGetBlockNumber(rootbuf); rootblkno = BufferGetBlockNumber(rootbuf);
rootpage = BufferGetPage(rootbuf); rootpage = BufferGetPage(rootbuf);
_bt_pageinit(rootpage, BufferGetPageSize(rootbuf));
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage); rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE; rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT); rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);
...@@ -405,14 +403,50 @@ _bt_gettrueroot(Relation rel) ...@@ -405,14 +403,50 @@ _bt_gettrueroot(Relation rel)
return rootbuf; return rootbuf;
} }
/*
* _bt_checkpage() -- Verify that a freshly-read page looks sane.
*/
void
_bt_checkpage(Relation rel, Buffer buf)
{
Page page = BufferGetPage(buf);
/*
* ReadBuffer verifies that every newly-read page passes PageHeaderIsValid,
* which means it either contains a reasonably sane page header or is
* all-zero. We have to defend against the all-zero case, however.
*/
if (PageIsNew(page))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" contains unexpected zero page at block %u",
RelationGetRelationName(rel),
BufferGetBlockNumber(buf)),
errhint("Please REINDEX it.")));
/*
* Additionally check that the special area looks sane.
*/
if (((PageHeader) (page))->pd_special !=
(BLCKSZ - MAXALIGN(sizeof(BTPageOpaqueData))))
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" contains corrupted page at block %u",
RelationGetRelationName(rel),
BufferGetBlockNumber(buf)),
errhint("Please REINDEX it.")));
}
/* /*
* _bt_getbuf() -- Get a buffer by block number for read or write. * _bt_getbuf() -- Get a buffer by block number for read or write.
* *
* blkno == P_NEW means to get an unallocated index page. * blkno == P_NEW means to get an unallocated index page. The page
* will be initialized before returning it.
* *
* When this routine returns, the appropriate lock is set on the * When this routine returns, the appropriate lock is set on the
* requested buffer and its reference count has been incremented * requested buffer and its reference count has been incremented
* (ie, the buffer is "locked and pinned"). * (ie, the buffer is "locked and pinned"). Also, we apply
* _bt_checkpage to sanity-check the page (except in P_NEW case).
*/ */
Buffer Buffer
_bt_getbuf(Relation rel, BlockNumber blkno, int access) _bt_getbuf(Relation rel, BlockNumber blkno, int access)
...@@ -424,6 +458,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access) ...@@ -424,6 +458,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
/* Read an existing block of the relation */ /* Read an existing block of the relation */
buf = ReadBuffer(rel, blkno); buf = ReadBuffer(rel, blkno);
LockBuffer(buf, access); LockBuffer(buf, access);
_bt_checkpage(rel, buf);
} }
else else
{ {
...@@ -538,6 +573,7 @@ _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access) ...@@ -538,6 +573,7 @@ _bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access)
LockBuffer(obuf, BUFFER_LOCK_UNLOCK); LockBuffer(obuf, BUFFER_LOCK_UNLOCK);
buf = ReleaseAndReadBuffer(obuf, rel, blkno); buf = ReleaseAndReadBuffer(obuf, rel, blkno);
LockBuffer(buf, access); LockBuffer(buf, access);
_bt_checkpage(rel, buf);
return buf; return buf;
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.132 2005/10/15 02:49:09 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.133 2005/11/06 19:29:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -734,8 +734,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -734,8 +734,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
* buffer and it will be fully initialized before we can examine it. (See * buffer and it will be fully initialized before we can examine it. (See
* also vacuumlazy.c, which has the same issue.) * also vacuumlazy.c, which has the same issue.)
* *
* We can skip locking for new or temp relations, however, since no one else * We can skip locking for new or temp relations, however, since no one
* could be accessing them. * else could be accessing them.
*/ */
needLock = !RELATION_IS_LOCAL(rel); needLock = !RELATION_IS_LOCAL(rel);
...@@ -772,9 +772,17 @@ btvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -772,9 +772,17 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
Page page; Page page;
BTPageOpaque opaque; BTPageOpaque opaque;
buf = _bt_getbuf(rel, blkno, BT_READ); /*
* We can't use _bt_getbuf() here because it always applies
* _bt_checkpage(), which will barf on an all-zero page.
* We want to recycle all-zero pages, not fail.
*/
buf = ReadBuffer(rel, blkno);
LockBuffer(buf, BT_READ);
page = BufferGetPage(buf); page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (!PageIsNew(page))
_bt_checkpage(rel, buf);
if (_bt_page_recyclable(page)) if (_bt_page_recyclable(page))
{ {
/* Okay to recycle this page */ /* Okay to recycle this page */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.63 2005/10/15 02:49:42 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.64 2005/11/06 19:29:01 tgl Exp $
* *
* NOTES * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
...@@ -310,7 +310,7 @@ extern uint32 _hash_datum2hashkey(Relation rel, Datum key); ...@@ -310,7 +310,7 @@ extern uint32 _hash_datum2hashkey(Relation rel, Datum key);
extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
uint32 highmask, uint32 lowmask); uint32 highmask, uint32 lowmask);
extern uint32 _hash_log2(uint32 num); extern uint32 _hash_log2(uint32 num);
extern void _hash_checkpage(Relation rel, Page page, int flags); extern void _hash_checkpage(Relation rel, Buffer buf, int flags);
/* hash.c */ /* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record); extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.87 2005/10/15 02:49:42 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.88 2005/11/06 19:29:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -429,6 +429,7 @@ extern void _bt_metapinit(Relation rel); ...@@ -429,6 +429,7 @@ extern void _bt_metapinit(Relation rel);
extern void _bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level); extern void _bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level);
extern Buffer _bt_getroot(Relation rel, int access); extern Buffer _bt_getroot(Relation rel, int access);
extern Buffer _bt_gettrueroot(Relation rel); extern Buffer _bt_gettrueroot(Relation rel);
extern void _bt_checkpage(Relation rel, Buffer buf);
extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access); extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access);
extern Buffer _bt_relandgetbuf(Relation rel, Buffer obuf, extern Buffer _bt_relandgetbuf(Relation rel, Buffer obuf,
BlockNumber blkno, int access); BlockNumber blkno, int access);
......
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