Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fc8219d

Browse files
committed
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.
1 parent 86d911e commit fc8219d

File tree

3 files changed

+53
-40
lines changed

3 files changed

+53
-40
lines changed

contrib/pageinspect/expected/hash.out

+6-12
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,17 @@ hash_page_type | bitmap
3030
SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6));
3131
ERROR: block number 6 is out of range for relation "test_hash_a_idx"
3232
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0);
33-
ERROR: page is not an overflow page
34-
DETAIL: Expected 00000001, got 00000008.
33+
ERROR: invalid overflow block number 0
3534
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1);
36-
ERROR: page is not an overflow page
37-
DETAIL: Expected 00000001, got 00000002.
35+
ERROR: invalid overflow block number 1
3836
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2);
39-
ERROR: page is not an overflow page
40-
DETAIL: Expected 00000001, got 00000002.
37+
ERROR: invalid overflow block number 2
4138
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3);
42-
ERROR: page is not an overflow page
43-
DETAIL: Expected 00000001, got 00000002.
39+
ERROR: invalid overflow block number 3
4440
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4);
45-
ERROR: page is not an overflow page
46-
DETAIL: Expected 00000001, got 00000002.
41+
ERROR: invalid overflow block number 4
4742
SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5);
48-
ERROR: page is not an overflow page
49-
DETAIL: Expected 00000001, got 00000004.
43+
ERROR: invalid overflow block number 5
5044
SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
5145
lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
5246
hash_metapage_info(get_raw_page('test_hash_a_idx', 0));

contrib/pageinspect/hashfuncs.c

+36-26
Original file line numberDiff line numberDiff line change
@@ -380,21 +380,22 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
380380
Oid indexRelid = PG_GETARG_OID(0);
381381
uint64 ovflblkno = PG_GETARG_INT64(1);
382382
HashMetaPage metap;
383-
Buffer buf,
384-
metabuf;
383+
Buffer metabuf,
384+
mapbuf;
385385
BlockNumber bitmapblkno;
386-
Page page;
386+
Page mappage;
387387
bool bit = false;
388-
HashPageOpaque opaque;
389388
TupleDesc tupleDesc;
390389
Relation indexRel;
391390
uint32 ovflbitno;
392391
int32 bitmappage,
393392
bitmapbit;
394393
HeapTuple tuple;
395-
int j;
394+
int i,
395+
j;
396396
Datum values[3];
397397
bool nulls[3];
398+
uint32 *freep;
398399

399400
if (!superuser())
400401
ereport(ERROR,
@@ -418,30 +419,30 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
418419
errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"",
419420
ovflblkno, RelationGetRelationName(indexRel))));
420421

421-
buf = ReadBufferExtended(indexRel, MAIN_FORKNUM, (BlockNumber) ovflblkno,
422-
RBM_NORMAL, NULL);
423-
LockBuffer(buf, BUFFER_LOCK_SHARE);
424-
_hash_checkpage(indexRel, buf, LH_PAGE_TYPE);
425-
page = BufferGetPage(buf);
426-
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
427-
428-
if (opaque->hasho_flag != LH_OVERFLOW_PAGE)
429-
ereport(ERROR,
430-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
431-
errmsg("page is not an overflow page"),
432-
errdetail("Expected %08x, got %08x.",
433-
LH_OVERFLOW_PAGE, opaque->hasho_flag)));
434-
435-
if (BlockNumberIsValid(opaque->hasho_prevblkno))
436-
bit = true;
437-
438-
UnlockReleaseBuffer(buf);
439-
440422
/* Read the metapage so we can determine which bitmap page to use */
441423
metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
442424
metap = HashPageGetMeta(BufferGetPage(metabuf));
443425

444-
/* Identify overflow bit number */
426+
/*
427+
* Reject attempt to read the bit for a metapage or bitmap page; this is
428+
* only meaningful for overflow pages.
429+
*/
430+
if (ovflblkno == 0)
431+
ereport(ERROR,
432+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
433+
errmsg("invalid overflow block number %u",
434+
(BlockNumber) ovflblkno)));
435+
for (i = 0; i < metap->hashm_nmaps; i++)
436+
if (metap->hashm_mapp[i] == ovflblkno)
437+
ereport(ERROR,
438+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
439+
errmsg("invalid overflow block number %u",
440+
(BlockNumber) ovflblkno)));
441+
442+
/*
443+
* Identify overflow bit number. This will error out for primary bucket
444+
* pages, and we've already rejected the metapage and bitmap pages above.
445+
*/
445446
ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno);
446447

447448
bitmappage = ovflbitno >> BMPG_SHIFT(metap);
@@ -450,12 +451,21 @@ hash_bitmap_info(PG_FUNCTION_ARGS)
450451
if (bitmappage >= metap->hashm_nmaps)
451452
ereport(ERROR,
452453
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
453-
errmsg("invalid overflow bit number %u", ovflbitno)));
454+
errmsg("invalid overflow block number %u",
455+
(BlockNumber) ovflblkno)));
454456

455457
bitmapblkno = metap->hashm_mapp[bitmappage];
456458

457459
_hash_relbuf(indexRel, metabuf);
458460

461+
/* Check the status of bitmap bit for overflow page */
462+
mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE);
463+
mappage = BufferGetPage(mapbuf);
464+
freep = HashPageGetBitmap(mappage);
465+
466+
bit = ISSET(freep, bitmapbit) != 0;
467+
468+
_hash_relbuf(indexRel, mapbuf);
459469
index_close(indexRel, AccessShareLock);
460470

461471
/* Build a tuple descriptor for our result type */

src/backend/access/hash/hashovfl.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,20 @@ _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
6969
if (ovflblkno <= (BlockNumber) (1 << i))
7070
break; /* oops */
7171
bitnum = ovflblkno - (1 << i);
72-
if (bitnum <= metap->hashm_spares[i])
72+
73+
/*
74+
* bitnum has to be greater than number of overflow page added in
75+
* previous split point. The overflow page at this splitnum (i) if any
76+
* should start from ((2 ^ i) + metap->hashm_spares[i - 1] + 1).
77+
*/
78+
if (bitnum > metap->hashm_spares[i - 1] &&
79+
bitnum <= metap->hashm_spares[i])
7380
return bitnum - 1; /* -1 to convert 1-based to 0-based */
7481
}
7582

76-
elog(ERROR, "invalid overflow block number %u", ovflblkno);
83+
ereport(ERROR,
84+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
85+
errmsg("invalid overflow block number %u", ovflblkno)));
7786
return 0; /* keep compiler quiet */
7887
}
7988

0 commit comments

Comments
 (0)