Skip to content

Commit 3830539

Browse files
committed
hash: Refactor hash index creation.
The primary goal here is to move all of the related page modifications to a single section of code, in preparation for adding write-ahead logging. In passing, rename _hash_metapinit to _hash_init, since it initializes more than just the metapage. Amit Kapila. The larger patch series of which this is a part has been reviewed and tested by Álvaro Herrera, Ashutosh Sharma, Mark Kirkwood, Jeff Janes, and Jesper Pedersen.
1 parent 2b87dd8 commit 3830539

File tree

4 files changed

+144
-135
lines changed

4 files changed

+144
-135
lines changed

src/backend/access/hash/hash.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
120120
estimate_rel_size(heap, NULL, &relpages, &reltuples, &allvisfrac);
121121

122122
/* Initialize the hash index metadata page and initial buckets */
123-
num_buckets = _hash_metapinit(index, reltuples, MAIN_FORKNUM);
123+
num_buckets = _hash_init(index, reltuples, MAIN_FORKNUM);
124124

125125
/*
126126
* If we just insert the tuples into the index in scan order, then
@@ -182,7 +182,7 @@ hashbuild(Relation heap, Relation index, IndexInfo *indexInfo)
182182
void
183183
hashbuildempty(Relation index)
184184
{
185-
_hash_metapinit(index, 0, INIT_FORKNUM);
185+
_hash_init(index, 0, INIT_FORKNUM);
186186
}
187187

188188
/*

src/backend/access/hash/hashovfl.c

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -570,68 +570,6 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
570570
}
571571

572572

573-
/*
574-
* _hash_initbitmap()
575-
*
576-
* Initialize a new bitmap page. The metapage has a write-lock upon
577-
* entering the function, and must be written by caller after return.
578-
*
579-
* 'blkno' is the block number of the new bitmap page.
580-
*
581-
* All bits in the new bitmap page are set to "1", indicating "in use".
582-
*/
583-
void
584-
_hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno,
585-
ForkNumber forkNum)
586-
{
587-
Buffer buf;
588-
Page pg;
589-
HashPageOpaque op;
590-
uint32 *freep;
591-
592-
/*
593-
* It is okay to write-lock the new bitmap page while holding metapage
594-
* write lock, because no one else could be contending for the new page.
595-
* Also, the metapage lock makes it safe to extend the index using
596-
* _hash_getnewbuf.
597-
*
598-
* There is some loss of concurrency in possibly doing I/O for the new
599-
* page while holding the metapage lock, but this path is taken so seldom
600-
* that it's not worth worrying about.
601-
*/
602-
buf = _hash_getnewbuf(rel, blkno, forkNum);
603-
pg = BufferGetPage(buf);
604-
605-
/* initialize the page's special space */
606-
op = (HashPageOpaque) PageGetSpecialPointer(pg);
607-
op->hasho_prevblkno = InvalidBlockNumber;
608-
op->hasho_nextblkno = InvalidBlockNumber;
609-
op->hasho_bucket = -1;
610-
op->hasho_flag = LH_BITMAP_PAGE;
611-
op->hasho_page_id = HASHO_PAGE_ID;
612-
613-
/* set all of the bits to 1 */
614-
freep = HashPageGetBitmap(pg);
615-
MemSet(freep, 0xFF, BMPGSZ_BYTE(metap));
616-
617-
/* dirty the new bitmap page, and release write lock and pin */
618-
MarkBufferDirty(buf);
619-
_hash_relbuf(rel, buf);
620-
621-
/* add the new bitmap page to the metapage's list of bitmaps */
622-
/* metapage already has a write lock */
623-
if (metap->hashm_nmaps >= HASH_MAX_BITMAPS)
624-
ereport(ERROR,
625-
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
626-
errmsg("out of overflow pages in hash index \"%s\"",
627-
RelationGetRelationName(rel))));
628-
629-
metap->hashm_mapp[metap->hashm_nmaps] = blkno;
630-
631-
metap->hashm_nmaps++;
632-
}
633-
634-
635573
/*
636574
* _hash_initbitmapbuffer()
637575
*

src/backend/access/hash/hashpage.c

Lines changed: 136 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,36 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno)
156156
return buf;
157157
}
158158

159+
/*
160+
* _hash_initbuf() -- Get and initialize a buffer by bucket number.
161+
*/
162+
void
163+
_hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket, uint32 flag,
164+
bool initpage)
165+
{
166+
HashPageOpaque pageopaque;
167+
Page page;
168+
169+
page = BufferGetPage(buf);
170+
171+
/* initialize the page */
172+
if (initpage)
173+
_hash_pageinit(page, BufferGetPageSize(buf));
174+
175+
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
176+
177+
/*
178+
* Set hasho_prevblkno with current hashm_maxbucket. This value will
179+
* be used to validate cached HashMetaPageData. See
180+
* _hash_getbucketbuf_from_hashkey().
181+
*/
182+
pageopaque->hasho_prevblkno = max_bucket;
183+
pageopaque->hasho_nextblkno = InvalidBlockNumber;
184+
pageopaque->hasho_bucket = num_bucket;
185+
pageopaque->hasho_flag = flag;
186+
pageopaque->hasho_page_id = HASHO_PAGE_ID;
187+
}
188+
159189
/*
160190
* _hash_getnewbuf() -- Get a new page at the end of the index.
161191
*
@@ -288,7 +318,7 @@ _hash_dropscanbuf(Relation rel, HashScanOpaque so)
288318

289319

290320
/*
291-
* _hash_metapinit() -- Initialize the metadata page of a hash index,
321+
* _hash_init() -- Initialize the metadata page of a hash index,
292322
* the initial buckets, and the initial bitmap page.
293323
*
294324
* The initial number of buckets is dependent on num_tuples, an estimate
@@ -300,19 +330,18 @@ _hash_dropscanbuf(Relation rel, HashScanOpaque so)
300330
* multiple buffer locks is ignored.
301331
*/
302332
uint32
303-
_hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
333+
_hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
304334
{
305-
HashMetaPage metap;
306-
HashPageOpaque pageopaque;
307335
Buffer metabuf;
308336
Buffer buf;
337+
Buffer bitmapbuf;
309338
Page pg;
339+
HashMetaPage metap;
340+
RegProcedure procid;
310341
int32 data_width;
311342
int32 item_width;
312343
int32 ffactor;
313-
double dnumbuckets;
314344
uint32 num_buckets;
315-
uint32 log2_num_buckets;
316345
uint32 i;
317346

318347
/* safety check */
@@ -334,6 +363,96 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
334363
if (ffactor < 10)
335364
ffactor = 10;
336365

366+
procid = index_getprocid(rel, 1, HASHPROC);
367+
368+
/*
369+
* We initialize the metapage, the first N bucket pages, and the first
370+
* bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
371+
* calls to occur. This ensures that the smgr level has the right idea of
372+
* the physical index length.
373+
*
374+
* Critical section not required, because on error the creation of the
375+
* whole relation will be rolled back.
376+
*/
377+
metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
378+
_hash_init_metabuffer(metabuf, num_tuples, procid, ffactor, false);
379+
MarkBufferDirty(metabuf);
380+
381+
pg = BufferGetPage(metabuf);
382+
metap = HashPageGetMeta(pg);
383+
384+
num_buckets = metap->hashm_maxbucket + 1;
385+
386+
/*
387+
* Release buffer lock on the metapage while we initialize buckets.
388+
* Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
389+
* won't accomplish anything. It's a bad idea to hold buffer locks for
390+
* long intervals in any case, since that can block the bgwriter.
391+
*/
392+
LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
393+
394+
/*
395+
* Initialize and WAL Log the first N buckets
396+
*/
397+
for (i = 0; i < num_buckets; i++)
398+
{
399+
BlockNumber blkno;
400+
401+
/* Allow interrupts, in case N is huge */
402+
CHECK_FOR_INTERRUPTS();
403+
404+
blkno = BUCKET_TO_BLKNO(metap, i);
405+
buf = _hash_getnewbuf(rel, blkno, forkNum);
406+
_hash_initbuf(buf, metap->hashm_maxbucket, i, LH_BUCKET_PAGE, false);
407+
MarkBufferDirty(buf);
408+
_hash_relbuf(rel, buf);
409+
}
410+
411+
/* Now reacquire buffer lock on metapage */
412+
LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE);
413+
414+
/*
415+
* Initialize bitmap page
416+
*/
417+
bitmapbuf = _hash_getnewbuf(rel, num_buckets + 1, forkNum);
418+
_hash_initbitmapbuffer(bitmapbuf, metap->hashm_bmsize, false);
419+
MarkBufferDirty(bitmapbuf);
420+
421+
/* add the new bitmap page to the metapage's list of bitmaps */
422+
/* metapage already has a write lock */
423+
if (metap->hashm_nmaps >= HASH_MAX_BITMAPS)
424+
ereport(ERROR,
425+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
426+
errmsg("out of overflow pages in hash index \"%s\"",
427+
RelationGetRelationName(rel))));
428+
429+
metap->hashm_mapp[metap->hashm_nmaps] = num_buckets + 1;
430+
431+
metap->hashm_nmaps++;
432+
MarkBufferDirty(metabuf);
433+
434+
/* all done */
435+
_hash_relbuf(rel, bitmapbuf);
436+
_hash_relbuf(rel, metabuf);
437+
438+
return num_buckets;
439+
}
440+
441+
/*
442+
* _hash_init_metabuffer() -- Initialize the metadata page of a hash index.
443+
*/
444+
void
445+
_hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid,
446+
uint16 ffactor, bool initpage)
447+
{
448+
HashMetaPage metap;
449+
HashPageOpaque pageopaque;
450+
Page page;
451+
double dnumbuckets;
452+
uint32 num_buckets;
453+
uint32 log2_num_buckets;
454+
uint32 i;
455+
337456
/*
338457
* Choose the number of initial bucket pages to match the fill factor
339458
* given the estimated number of tuples. We round up the result to the
@@ -353,30 +472,25 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
353472
Assert(num_buckets == (((uint32) 1) << log2_num_buckets));
354473
Assert(log2_num_buckets < HASH_MAX_SPLITPOINTS);
355474

356-
/*
357-
* We initialize the metapage, the first N bucket pages, and the first
358-
* bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
359-
* calls to occur. This ensures that the smgr level has the right idea of
360-
* the physical index length.
361-
*/
362-
metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
363-
pg = BufferGetPage(metabuf);
475+
page = BufferGetPage(buf);
476+
if (initpage)
477+
_hash_pageinit(page, BufferGetPageSize(buf));
364478

365-
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
479+
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
366480
pageopaque->hasho_prevblkno = InvalidBlockNumber;
367481
pageopaque->hasho_nextblkno = InvalidBlockNumber;
368482
pageopaque->hasho_bucket = -1;
369483
pageopaque->hasho_flag = LH_META_PAGE;
370484
pageopaque->hasho_page_id = HASHO_PAGE_ID;
371485

372-
metap = HashPageGetMeta(pg);
486+
metap = HashPageGetMeta(page);
373487

374488
metap->hashm_magic = HASH_MAGIC;
375489
metap->hashm_version = HASH_VERSION;
376490
metap->hashm_ntuples = 0;
377491
metap->hashm_nmaps = 0;
378492
metap->hashm_ffactor = ffactor;
379-
metap->hashm_bsize = HashGetMaxBitmapSize(pg);
493+
metap->hashm_bsize = HashGetMaxBitmapSize(page);
380494
/* find largest bitmap array size that will fit in page size */
381495
for (i = _hash_log2(metap->hashm_bsize); i > 0; --i)
382496
{
@@ -393,7 +507,7 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
393507
* pretty useless for normal operation (in fact, hashm_procid is not used
394508
* anywhere), but it might be handy for forensic purposes so we keep it.
395509
*/
396-
metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
510+
metap->hashm_procid = procid;
397511

398512
/*
399513
* We initialize the index with N buckets, 0 .. N-1, occupying physical
@@ -411,54 +525,9 @@ _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
411525
metap->hashm_ovflpoint = log2_num_buckets;
412526
metap->hashm_firstfree = 0;
413527

414-
/*
415-
* Release buffer lock on the metapage while we initialize buckets.
416-
* Otherwise, we'll be in interrupt holdoff and the CHECK_FOR_INTERRUPTS
417-
* won't accomplish anything. It's a bad idea to hold buffer locks for
418-
* long intervals in any case, since that can block the bgwriter.
419-
*/
420-
MarkBufferDirty(metabuf);
421-
LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
422-
423-
/*
424-
* Initialize the first N buckets
425-
*/
426-
for (i = 0; i < num_buckets; i++)
427-
{
428-
/* Allow interrupts, in case N is huge */
429-
CHECK_FOR_INTERRUPTS();
430-
431-
buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), forkNum);
432-
pg = BufferGetPage(buf);
433-
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
434-
435-
/*
436-
* Set hasho_prevblkno with current hashm_maxbucket. This value will
437-
* be used to validate cached HashMetaPageData. See
438-
* _hash_getbucketbuf_from_hashkey().
439-
*/
440-
pageopaque->hasho_prevblkno = metap->hashm_maxbucket;
441-
pageopaque->hasho_nextblkno = InvalidBlockNumber;
442-
pageopaque->hasho_bucket = i;
443-
pageopaque->hasho_flag = LH_BUCKET_PAGE;
444-
pageopaque->hasho_page_id = HASHO_PAGE_ID;
445-
MarkBufferDirty(buf);
446-
_hash_relbuf(rel, buf);
447-
}
448-
449-
/* Now reacquire buffer lock on metapage */
450-
LockBuffer(metabuf, BUFFER_LOCK_EXCLUSIVE);
451-
452-
/*
453-
* Initialize first bitmap page
454-
*/
455-
_hash_initbitmap(rel, metap, num_buckets + 1, forkNum);
456-
457-
/* all done */
458-
MarkBufferDirty(metabuf);
459-
_hash_relbuf(rel, metabuf);
460-
461-
return num_buckets;
528+
/* Set pd_lower just past the end of the metadata. */
529+
((PageHeader) page)->pd_lower =
530+
((char *) metap + sizeof(HashMetaPageData)) - (char *) page;
462531
}
463532

464533
/*
@@ -535,7 +604,7 @@ _hash_expandtable(Relation rel, Buffer metabuf)
535604
* than a disk block then this would be an independent constraint.
536605
*
537606
* If you change this, see also the maximum initial number of buckets in
538-
* _hash_metapinit().
607+
* _hash_init().
539608
*/
540609
if (metap->hashm_maxbucket >= (uint32) 0x7FFFFFFE)
541610
goto fail;

src/include/access/hash.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,6 @@ extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool r
311311
extern BlockNumber _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
312312
Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets,
313313
Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy);
314-
extern void _hash_initbitmap(Relation rel, HashMetaPage metap,
315-
BlockNumber blkno, ForkNumber forkNum);
316314
extern void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage);
317315
extern void _hash_squeezebucket(Relation rel,
318316
Bucket bucket, BlockNumber bucket_blkno,
@@ -331,6 +329,8 @@ extern Buffer _hash_getbucketbuf_from_hashkey(Relation rel, uint32 hashkey,
331329
int access,
332330
HashMetaPage *cachedmetap);
333331
extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno);
332+
extern void _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket,
333+
uint32 flag, bool initpage);
334334
extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno,
335335
ForkNumber forkNum);
336336
extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
@@ -339,8 +339,10 @@ extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
339339
extern void _hash_relbuf(Relation rel, Buffer buf);
340340
extern void _hash_dropbuf(Relation rel, Buffer buf);
341341
extern void _hash_dropscanbuf(Relation rel, HashScanOpaque so);
342-
extern uint32 _hash_metapinit(Relation rel, double num_tuples,
343-
ForkNumber forkNum);
342+
extern uint32 _hash_init(Relation rel, double num_tuples,
343+
ForkNumber forkNum);
344+
extern void _hash_init_metabuffer(Buffer buf, double num_tuples,
345+
RegProcedure procid, uint16 ffactor, bool initpage);
344346
extern void _hash_pageinit(Page page, Size size);
345347
extern void _hash_expandtable(Relation rel, Buffer metabuf);
346348
extern void _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy