diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out index 7eb1537..fb0caee 100644 --- a/contrib/pageinspect/expected/hash.out +++ b/contrib/pageinspect/expected/hash.out @@ -30,23 +30,21 @@ hash_page_type | bitmap SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); ERROR: block number 6 is out of range for relation "test_hash_a_idx" SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000008. +ERROR: invalid overflow block number 0 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 1 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 2 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 3 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 4 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000004. +-[ RECORD 1 ]-- +bitmapblkno | 5 +bitmapbit | 0 +bitstatus | t + SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0)); diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 08663c1..af25506 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -170,6 +170,45 @@ GetHashPageStatistics(Page page, HashPageStat * stat) stat->free_size = PageGetFreeSpace(page); } +/* + * _hash_ovflblkno_to_bitno + * + * Convert overflow page block number to bit number for free-page bitmap. + * We already have similar function defined in hashovfl.c but which does + * return value for some of the bucket pages along with overflow and bit- + * map pages and it is seems to be buggy to me. This function has been + * designed such that it only returns the value for overflow and bitmap + * pages. + */ +static uint32 +_hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno) +{ + uint32 splitnum = metap->hashm_ovflpoint; + uint32 i; + uint32 bitnum; + + /* Determine the split number containing this page */ + for (i = 1; i <= splitnum; i++) + { + if (ovflblkno <= (BlockNumber) (1 << i)) + break; /* oops */ + bitnum = ovflblkno - (1 << i); + /* + * bitnum has to be greater than number of overflow + * page added in previous split point. The overflow + * page at this splitnum (i) if any should start from + * ((2 ^ i) + metap->hashm_spares[i -1] + 1). + */ + if (bitnum > metap->hashm_spares[i -1] && + bitnum <= metap->hashm_spares[i]) + return bitnum - 1; /* -1 to convert 1-based to 0-based */ + } + + elog(ERROR, "invalid overflow block number %u", ovflblkno); + return 0; /* keep compiler quiet */ +} + + /* --------------------------------------------------- * hash_page_type() * @@ -380,12 +419,11 @@ 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; @@ -395,6 +433,7 @@ hash_bitmap_info(PG_FUNCTION_ARGS) int j; Datum values[3]; bool nulls[3]; + uint32 *freep = NULL; if (!superuser()) ereport(ERROR, @@ -418,25 +457,6 @@ 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)); @@ -456,6 +476,14 @@ hash_bitmap_info(PG_FUNCTION_ARGS) _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 */ diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c index 753c8a6..e8928ef 100644 --- a/src/backend/access/hash/hashovfl.c +++ b/src/backend/access/hash/hashovfl.c @@ -52,12 +52,10 @@ bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum) } /* - * _hash_ovflblkno_to_bitno - * * Convert overflow page block number to bit number for free-page bitmap. */ -uint32 -_hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno) +static uint32 +blkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno) { uint32 splitnum = metap->hashm_ovflpoint; uint32 i; @@ -487,7 +485,7 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, Buffer wbuf, metap = HashPageGetMeta(BufferGetPage(metabuf)); /* Identify which bit to set */ - ovflbitno = _hash_ovflblkno_to_bitno(metap, ovflblkno); + ovflbitno = blkno_to_bitno(metap, ovflblkno); bitmappage = ovflbitno >> BMPG_SHIFT(metap); bitmapbit = ovflbitno & BMPG_MASK(metap); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index c045585..acbe0ea 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -313,7 +313,6 @@ extern void _hash_squeezebucket(Relation rel, Bucket bucket, BlockNumber bucket_blkno, Buffer bucket_buf, BufferAccessStrategy bstrategy); -extern uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno); /* hashpage.c */ extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno,