summaryrefslogtreecommitdiff
path: root/contrib/pageinspect/hashfuncs.c
diff options
context:
space:
mode:
authorRobert Haas2017-02-09 19:02:58 +0000
committerRobert Haas2017-02-09 19:34:34 +0000
commitfc8219dc54c95ea673560b786aa8123ce6ec5977 (patch)
treea33bf5ea881e397242775e97df4a606ecc21c717 /contrib/pageinspect/hashfuncs.c
parent86d911ec0f9d4643e9a47db42510959dec0ed76b (diff)
pageinspect: Fix hash_bitmap_info not to read the underlying page.
It did that to verify that the page was an overflow page rather than anything else, but that means that checking the status of all the overflow bits requires reading the entire index. So don't do that. The new code validates that the page is not a primary bucket page or bitmap page by looking at the metapage, so that using this on large numbers of pages can be reasonably efficient. Ashutosh Sharma, per a complaint from me, and with further modifications by me.
Diffstat (limited to 'contrib/pageinspect/hashfuncs.c')
-rw-r--r--contrib/pageinspect/hashfuncs.c62
1 files changed, 36 insertions, 26 deletions
diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c
index 08663c109d1..88c807af5b2 100644
--- a/contrib/pageinspect/hashfuncs.c
+++ b/contrib/pageinspect/hashfuncs.c
@@ -380,21 +380,22 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
Oid indexRelid = PG_GETARG_OID(0);
uint64 ovflblkno = PG_GETARG_INT64(1);
HashMetaPage metap;
- Buffer buf,
- metabuf;
+ Buffer metabuf,
+ mapbuf;
BlockNumber bitmapblkno;
- Page page;
+ Page mappage;
bool bit = false;
- HashPageOpaque opaque;
TupleDesc tupleDesc;
Relation indexRel;
uint32 ovflbitno;
int32 bitmappage,
bitmapbit;
HeapTuple tuple;
- int j;
+ int i,
+ j;
Datum values[3];
bool nulls[3];
+ uint32 *freep;
if (!superuser())
ereport(ERROR,
@@ -418,30 +419,30 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"",
ovflblkno, RelationGetRelationName(indexRel))));
- buf = ReadBufferExtended(indexRel, MAIN_FORKNUM, (BlockNumber) ovflblkno,
- RBM_NORMAL, NULL);
- LockBuffer(buf, BUFFER_LOCK_SHARE);
- _hash_checkpage(indexRel, buf, LH_PAGE_TYPE);
- page = BufferGetPage(buf);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
-
- if (opaque->hasho_flag != LH_OVERFLOW_PAGE)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("page is not an overflow page"),
- errdetail("Expected %08x, got %08x.",
- LH_OVERFLOW_PAGE, opaque->hasho_flag)));
-
- if (BlockNumberIsValid(opaque->hasho_prevblkno))
- bit = true;
-
- UnlockReleaseBuffer(buf);
-
/* Read the metapage so we can determine which bitmap page to use */
metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
metap = HashPageGetMeta(BufferGetPage(metabuf));
- /* Identify overflow bit number */
+ /*
+ * Reject attempt to read the bit for a metapage or bitmap page; this is
+ * only meaningful for overflow pages.
+ */
+ if (ovflblkno == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid overflow block number %u",
+ (BlockNumber) ovflblkno)));
+ for (i = 0; i < metap->hashm_nmaps; i++)
+ if (metap->hashm_mapp[i] == ovflblkno)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid overflow block number %u",
+ (BlockNumber) ovflblkno)));
+
+ /*
+ * Identify overflow bit number. This will error out for primary bucket
+ * pages, and we've already rejected the metapage and bitmap pages above.
+ */
ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno);
bitmappage = ovflbitno >> BMPG_SHIFT(metap);
@@ -450,12 +451,21 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
if (bitmappage >= metap->hashm_nmaps)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid overflow bit number %u", ovflbitno)));
+ errmsg("invalid overflow block number %u",
+ (BlockNumber) ovflblkno)));
bitmapblkno = metap->hashm_mapp[bitmappage];
_hash_relbuf(indexRel, metabuf);
+ /* Check the status of bitmap bit for overflow page */
+ mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE);
+ mappage = BufferGetPage(mapbuf);
+ freep = HashPageGetBitmap(mappage);
+
+ bit = ISSET(freep, bitmapbit) != 0;
+
+ _hash_relbuf(indexRel, mapbuf);
index_close(indexRel, AccessShareLock);
/* Build a tuple descriptor for our result type */