/*
- * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.26 2007/03/25 19:45:13 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.27 2007/05/03 16:45:58 tgl Exp $
*
* Copyright (c) 2001,2002 Tatsuo Ishii
*
Page page;
_hash_getlock(rel, blkno, HASH_SHARE);
- buf = _hash_getbuf(rel, blkno, HASH_READ);
+ buf = _hash_getbuf(rel, blkno, HASH_READ, 0);
page = BufferGetPage(buf);
if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.93 2007/01/20 18:43:35 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.94 2007/05/03 16:45:58 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
* array cannot change under us; and it beats rereading the metapage for
* each bucket.
*/
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- _hash_checkpage(rel, metabuf, LH_META_PAGE);
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf);
orig_maxbucket = metap->hashm_maxbucket;
orig_ntuples = metap->hashm_ntuples;
vacuum_delay_point();
- buf = _hash_getbuf(rel, blkno, HASH_WRITE);
- _hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ buf = _hash_getbuf(rel, blkno, HASH_WRITE,
+ LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf);
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(opaque->hasho_bucket == cur_bucket);
}
/* Write-lock metapage and check for split since we started */
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
- _hash_checkpage(rel, metabuf, LH_META_PAGE);
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf);
if (cur_maxbucket != metap->hashm_maxbucket)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.44 2007/01/05 22:19:22 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.45 2007/05/03 16:45:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
_hash_getlock(rel, 0, HASH_SHARE);
/* Read the metapage */
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- _hash_checkpage(rel, metabuf, LH_META_PAGE);
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf);
/*
_hash_droplock(rel, 0, HASH_SHARE);
/* Fetch the primary bucket page for the bucket */
- buf = _hash_getbuf(rel, blkno, HASH_WRITE);
- _hash_checkpage(rel, buf, LH_BUCKET_PAGE);
+ buf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BUCKET_PAGE);
page = BufferGetPage(buf);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(pageopaque->hasho_bucket == bucket);
* find out next pass through the loop test above.
*/
_hash_relbuf(rel, buf);
- buf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
+ buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
page = BufferGetPage(buf);
}
else
/* should fit now, given test above */
Assert(PageGetFreeSpace(page) >= itemsz);
}
- _hash_checkpage(rel, buf, LH_OVERFLOW_PAGE);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(pageopaque->hasho_flag == LH_OVERFLOW_PAGE);
Assert(pageopaque->hasho_bucket == bucket);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.56 2007/04/19 20:24:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.57 2007/05/03 16:45:58 tgl Exp $
*
* NOTES
* Overflow pages look like ordinary relation pages.
/* allocate and lock an empty overflow page */
ovflbuf = _hash_getovflpage(rel, metabuf);
- ovflpage = BufferGetPage(ovflbuf);
/*
* Write-lock the tail page. It is okay to hold two buffer locks here
*/
_hash_chgbufaccess(rel, buf, HASH_NOLOCK, HASH_WRITE);
+ /* probably redundant... */
+ _hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+
/* loop to find current tail page, in case someone else inserted too */
for (;;)
{
BlockNumber nextblkno;
- _hash_checkpage(rel, buf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
page = BufferGetPage(buf);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
nextblkno = pageopaque->hasho_nextblkno;
/* we assume we do not need to write the unmodified page */
_hash_relbuf(rel, buf);
- buf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
+ buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
}
/* now that we have correct backlink, initialize new overflow page */
- _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
+ ovflpage = BufferGetPage(ovflbuf);
ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
ovflopaque->hasho_prevblkno = BufferGetBlockNumber(buf);
ovflopaque->hasho_nextblkno = InvalidBlockNumber;
* _hash_getovflpage()
*
* Find an available overflow page and return it. The returned buffer
- * is pinned and write-locked, but its contents are not initialized.
+ * is pinned and write-locked, and has had _hash_pageinit() applied,
+ * but it is caller's responsibility to fill the special space.
*
* The caller must hold a pin, but no lock, on the metapage buffer.
* That buffer is left in the same state at exit.
/* Release exclusive lock on metapage while reading bitmap page */
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
- mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE);
- _hash_checkpage(rel, mapbuf, LH_BITMAP_PAGE);
+ mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE, LH_BITMAP_PAGE);
mappage = BufferGetPage(mapbuf);
freep = HashPageGetBitmap(mappage);
* with metapage write lock held; would be better to use a lock that
* doesn't block incoming searches.
*/
- newbuf = _hash_getnewbuf(rel, blkno, HASH_WRITE);
+ newbuf = _hash_getnewbuf(rel, blkno);
metap->hashm_spares[splitnum]++;
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
}
- /* Fetch and return the recycled page */
- return _hash_getbuf(rel, blkno, HASH_WRITE);
+ /* Fetch, init, and return the recycled page */
+ return _hash_getinitbuf(rel, blkno);
}
/*
*/
if (BlockNumberIsValid(prevblkno))
{
- Buffer prevbuf = _hash_getbuf(rel, prevblkno, HASH_WRITE);
+ Buffer prevbuf = _hash_getbuf(rel, prevblkno, HASH_WRITE,
+ LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
Page prevpage = BufferGetPage(prevbuf);
HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
- _hash_checkpage(rel, prevbuf, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
Assert(prevopaque->hasho_bucket == bucket);
prevopaque->hasho_nextblkno = nextblkno;
_hash_wrtbuf(rel, prevbuf);
}
if (BlockNumberIsValid(nextblkno))
{
- Buffer nextbuf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
+ Buffer nextbuf = _hash_getbuf(rel, nextblkno, HASH_WRITE,
+ LH_OVERFLOW_PAGE);
Page nextpage = BufferGetPage(nextbuf);
HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
- _hash_checkpage(rel, nextbuf, LH_OVERFLOW_PAGE);
Assert(nextopaque->hasho_bucket == bucket);
nextopaque->hasho_prevblkno = prevblkno;
_hash_wrtbuf(rel, nextbuf);
}
/* Read the metapage so we can determine which bitmap page to use */
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- _hash_checkpage(rel, metabuf, LH_META_PAGE);
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf);
/* Identify which bit to set */
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
/* Clear the bitmap bit to indicate that this overflow page is free */
- mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
- _hash_checkpage(rel, mapbuf, LH_BITMAP_PAGE);
+ mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BITMAP_PAGE);
mappage = BufferGetPage(mapbuf);
freep = HashPageGetBitmap(mappage);
Assert(ISSET(freep, bitmapbit));
* page while holding the metapage lock, but this path is taken so seldom
* that it's not worth worrying about.
*/
- buf = _hash_getnewbuf(rel, blkno, HASH_WRITE);
+ buf = _hash_getnewbuf(rel, blkno);
pg = BufferGetPage(buf);
- /* initialize the page */
- _hash_pageinit(pg, BufferGetPageSize(buf));
+ /* initialize the page's special space */
op = (HashPageOpaque) PageGetSpecialPointer(pg);
op->hasho_prevblkno = InvalidBlockNumber;
op->hasho_nextblkno = InvalidBlockNumber;
* start squeezing into the base bucket page.
*/
wblkno = bucket_blkno;
- wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
- _hash_checkpage(rel, wbuf, LH_BUCKET_PAGE);
+ wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE, LH_BUCKET_PAGE);
wpage = BufferGetPage(wbuf);
wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
rblkno = ropaque->hasho_nextblkno;
if (ropaque != wopaque)
_hash_relbuf(rel, rbuf);
- rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
- _hash_checkpage(rel, rbuf, LH_OVERFLOW_PAGE);
+ rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf);
ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
Assert(ropaque->hasho_bucket == bucket);
return;
}
- wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
- _hash_checkpage(rel, wbuf, LH_OVERFLOW_PAGE);
+ wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
wpage = BufferGetPage(wbuf);
wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
Assert(wopaque->hasho_bucket == bucket);
/* free this overflow page, then get the previous one */
_hash_freeovflpage(rel, rbuf);
- rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
- _hash_checkpage(rel, rbuf, LH_OVERFLOW_PAGE);
+ rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf);
ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
Assert(ropaque->hasho_bucket == bucket);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.66 2007/04/19 20:24:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.67 2007/05/03 16:45:58 tgl Exp $
*
* NOTES
* Postgres hash pages look like ordinary relation pages. The opaque
* _hash_getbuf() -- Get a buffer by block number for read or write.
*
* 'access' must be HASH_READ, HASH_WRITE, or HASH_NOLOCK.
+ * 'flags' is a bitwise OR of the allowed page types.
+ *
+ * This must be used only to fetch pages that are expected to be valid
+ * already. _hash_checkpage() is applied using the given flags.
*
* When this routine returns, the appropriate lock is set on the
* requested buffer and its reference count has been incremented
* (ie, the buffer is "locked and pinned").
*
- * P_NEW is disallowed because this routine should only be used
+ * P_NEW is disallowed because this routine can only be used
* to access pages that are known to be before the filesystem EOF.
* Extending the index should be done with _hash_getnewbuf.
- *
- * All call sites should call either _hash_checkpage or _hash_pageinit
- * on the returned page, depending on whether the block is expected
- * to be valid or not.
*/
Buffer
-_hash_getbuf(Relation rel, BlockNumber blkno, int access)
+_hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
{
Buffer buf;
LockBuffer(buf, access);
/* ref count and lock type are correct */
+
+ _hash_checkpage(rel, buf, flags);
+
+ return buf;
+}
+
+/*
+ * _hash_getinitbuf() -- Get and initialize a buffer by block number.
+ *
+ * This must be used only to fetch pages that are known to be before
+ * the index's filesystem EOF, but are to be filled from scratch.
+ * _hash_pageinit() is applied automatically. Otherwise it has
+ * effects similar to _hash_getbuf() with access = HASH_WRITE.
+ *
+ * When this routine returns, a write lock is set on the
+ * requested buffer and its reference count has been incremented
+ * (ie, the buffer is "locked and pinned").
+ *
+ * P_NEW is disallowed because this routine can only be used
+ * to access pages that are known to be before the filesystem EOF.
+ * Extending the index should be done with _hash_getnewbuf.
+ */
+Buffer
+_hash_getinitbuf(Relation rel, BlockNumber blkno)
+{
+ Buffer buf;
+
+ if (blkno == P_NEW)
+ elog(ERROR, "hash AM does not use P_NEW");
+
+ buf = ReadOrZeroBuffer(rel, blkno);
+
+ LockBuffer(buf, HASH_WRITE);
+
+ /* ref count and lock type are correct */
+
+ /* initialize the page */
+ _hash_pageinit(BufferGetPage(buf), BufferGetPageSize(buf));
+
return buf;
}
/*
* _hash_getnewbuf() -- Get a new page at the end of the index.
*
- * This has the same API as _hash_getbuf, except that we are adding
+ * This has the same API as _hash_getinitbuf, except that we are adding
* a page to the index, and hence expect the page to be past the
* logical EOF. (However, we have to support the case where it isn't,
* since a prior try might have crashed after extending the filesystem
*
* It is caller's responsibility to ensure that only one process can
* extend the index at a time.
- *
- * All call sites should call _hash_pageinit on the returned page.
- * Also, it's difficult to imagine why access would not be HASH_WRITE.
*/
Buffer
-_hash_getnewbuf(Relation rel, BlockNumber blkno, int access)
+_hash_getnewbuf(Relation rel, BlockNumber blkno)
{
BlockNumber nblocks = RelationGetNumberOfBlocks(rel);
Buffer buf;
BufferGetBlockNumber(buf), blkno);
}
else
- buf = ReadBuffer(rel, blkno);
+ buf = ReadOrZeroBuffer(rel, blkno);
- if (access != HASH_NOLOCK)
- LockBuffer(buf, access);
+ LockBuffer(buf, HASH_WRITE);
/* ref count and lock type are correct */
+
+ /* initialize the page */
+ _hash_pageinit(BufferGetPage(buf), BufferGetPageSize(buf));
+
return buf;
}
* smgrextend() calls to occur. This ensures that the smgr level
* has the right idea of the physical index length.
*/
- metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, HASH_WRITE);
+ metabuf = _hash_getnewbuf(rel, HASH_METAPAGE);
pg = BufferGetPage(metabuf);
- _hash_pageinit(pg, BufferGetPageSize(metabuf));
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
pageopaque->hasho_prevblkno = InvalidBlockNumber;
*/
for (i = 0; i <= 1; i++)
{
- buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), HASH_WRITE);
+ buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i));
pg = BufferGetPage(buf);
- _hash_pageinit(pg, BufferGetPageSize(buf));
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
pageopaque->hasho_prevblkno = InvalidBlockNumber;
pageopaque->hasho_nextblkno = InvalidBlockNumber;
* either bucket.
*/
oblkno = start_oblkno;
- obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
- _hash_checkpage(rel, obuf, LH_BUCKET_PAGE);
+ obuf = _hash_getbuf(rel, oblkno, HASH_WRITE, LH_BUCKET_PAGE);
opage = BufferGetPage(obuf);
oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
nblkno = start_nblkno;
- nbuf = _hash_getbuf(rel, nblkno, HASH_WRITE);
+ nbuf = _hash_getnewbuf(rel, nblkno);
npage = BufferGetPage(nbuf);
/* initialize the new bucket's primary page */
- _hash_pageinit(npage, BufferGetPageSize(nbuf));
nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
nopaque->hasho_prevblkno = InvalidBlockNumber;
nopaque->hasho_nextblkno = InvalidBlockNumber;
*/
_hash_wrtbuf(rel, obuf);
- obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
- _hash_checkpage(rel, obuf, LH_OVERFLOW_PAGE);
+ obuf = _hash_getbuf(rel, oblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
opage = BufferGetPage(obuf);
oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
ooffnum = FirstOffsetNumber;
_hash_chgbufaccess(rel, nbuf, HASH_WRITE, HASH_NOLOCK);
/* chain to a new overflow page */
nbuf = _hash_addovflpage(rel, metabuf, nbuf);
- _hash_checkpage(rel, nbuf, LH_OVERFLOW_PAGE);
npage = BufferGetPage(nbuf);
/* we don't need nopaque within the loop */
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.48 2007/01/30 01:33:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.49 2007/05/03 16:45:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*bufp = InvalidBuffer;
if (BlockNumberIsValid(blkno))
{
- *bufp = _hash_getbuf(rel, blkno, HASH_READ);
- _hash_checkpage(rel, *bufp, LH_OVERFLOW_PAGE);
+ *bufp = _hash_getbuf(rel, blkno, HASH_READ, LH_OVERFLOW_PAGE);
*pagep = BufferGetPage(*bufp);
*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
}
*bufp = InvalidBuffer;
if (BlockNumberIsValid(blkno))
{
- *bufp = _hash_getbuf(rel, blkno, HASH_READ);
- _hash_checkpage(rel, *bufp, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ *bufp = _hash_getbuf(rel, blkno, HASH_READ,
+ LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
*pagep = BufferGetPage(*bufp);
*opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
}
_hash_getlock(rel, 0, HASH_SHARE);
/* Read the metapage */
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- _hash_checkpage(rel, metabuf, LH_META_PAGE);
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
metap = (HashMetaPage) BufferGetPage(metabuf);
/*
so->hashso_bucket_blkno = blkno;
/* Fetch the primary bucket page for the bucket */
- buf = _hash_getbuf(rel, blkno, HASH_READ);
- _hash_checkpage(rel, buf, LH_BUCKET_PAGE);
+ buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE);
page = BufferGetPage(buf);
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
Assert(opaque->hasho_bucket == bucket);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.51 2007/01/30 01:33:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.52 2007/05/03 16:45:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* _hash_checkpage -- sanity checks on the format of all hash pages
+ *
+ * If flags is not zero, it is a bitwise OR of the acceptable values of
+ * hasho_flag.
*/
void
_hash_checkpage(Relation rel, Buffer buf, int flags)
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.79 2007/04/19 20:24:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.80 2007/05/03 16:45:58 tgl Exp $
*
* NOTES
* modeled after Margo Seltzer's hash implementation for unix.
extern void _hash_getlock(Relation rel, BlockNumber whichlock, int access);
extern bool _hash_try_getlock(Relation rel, BlockNumber whichlock, int access);
extern void _hash_droplock(Relation rel, BlockNumber whichlock, int access);
-extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access);
-extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, int access);
+extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno,
+ int access, int flags);
+extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno);
+extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno);
extern void _hash_relbuf(Relation rel, Buffer buf);
extern void _hash_dropbuf(Relation rel, Buffer buf);
extern void _hash_wrtbuf(Relation rel, Buffer buf);