88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.72 2008/01/01 19:45:46 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.73 2008/03/15 20:46:31 tgl Exp $
1212 *
1313 * NOTES
1414 * Postgres hash pages look like ordinary relation pages. The opaque
@@ -312,15 +312,17 @@ _hash_chgbufaccess(Relation rel,
312312
313313/*
314314 * _hash_metapinit() -- Initialize the metadata page of a hash index,
315- * the two buckets that we begin with and the initial
316- * bitmap page.
315+ * the initial buckets, and the initial bitmap page.
316+ *
317+ * The initial number of buckets is dependent on num_tuples, an estimate
318+ * of the number of tuples to be loaded into the index initially.
317319 *
318320 * We are fairly cavalier about locking here, since we know that no one else
319321 * could be accessing this index. In particular the rule about not holding
320322 * multiple buffer locks is ignored.
321323 */
322324void
323- _hash_metapinit (Relation rel )
325+ _hash_metapinit (Relation rel , double num_tuples )
324326{
325327 HashMetaPage metap ;
326328 HashPageOpaque pageopaque ;
@@ -330,7 +332,10 @@ _hash_metapinit(Relation rel)
330332 int32 data_width ;
331333 int32 item_width ;
332334 int32 ffactor ;
333- uint16 i ;
335+ double dnumbuckets ;
336+ uint32 num_buckets ;
337+ uint32 log2_num_buckets ;
338+ uint32 i ;
334339
335340 /* safety check */
336341 if (RelationGetNumberOfBlocks (rel ) != 0 )
@@ -354,7 +359,26 @@ _hash_metapinit(Relation rel)
354359 ffactor = 10 ;
355360
356361 /*
357- * We initialize the metapage, the first two bucket pages, and the first
362+ * Choose the number of initial bucket pages to match the fill factor
363+ * given the estimated number of tuples. We round up the result to the
364+ * next power of 2, however, and always force at least 2 bucket pages.
365+ * The upper limit is determined by considerations explained in
366+ * _hash_expandtable().
367+ */
368+ dnumbuckets = num_tuples / ffactor ;
369+ if (dnumbuckets <= 2.0 )
370+ num_buckets = 2 ;
371+ else if (dnumbuckets >= (double ) 0x40000000 )
372+ num_buckets = 0x40000000 ;
373+ else
374+ num_buckets = ((uint32 ) 1 ) << _hash_log2 ((uint32 ) dnumbuckets );
375+
376+ log2_num_buckets = _hash_log2 (num_buckets );
377+ Assert (num_buckets == (((uint32 ) 1 ) << log2_num_buckets ));
378+ Assert (log2_num_buckets < HASH_MAX_SPLITPOINTS );
379+
380+ /*
381+ * We initialize the metapage, the first N bucket pages, and the first
358382 * bitmap page in sequence, using _hash_getnewbuf to cause smgrextend()
359383 * calls to occur. This ensures that the smgr level has the right idea of
360384 * the physical index length.
@@ -398,23 +422,25 @@ _hash_metapinit(Relation rel)
398422 metap -> hashm_procid = index_getprocid (rel , 1 , HASHPROC );
399423
400424 /*
401- * We initialize the index with two buckets, 0 and 1, occupying physical
402- * blocks 1 and 2. The first freespace bitmap page is in block 3.
425+ * We initialize the index with N buckets, 0 .. N-1, occupying physical
426+ * blocks 1 to N. The first freespace bitmap page is in block N+1.
427+ * Since N is a power of 2, we can set the masks this way:
403428 */
404- metap -> hashm_maxbucket = metap -> hashm_lowmask = 1 ; /* nbuckets - 1 */
405- metap -> hashm_highmask = 3 ; /* (nbuckets << 1) - 1 */
429+ metap -> hashm_maxbucket = metap -> hashm_lowmask = num_buckets - 1 ;
430+ metap -> hashm_highmask = ( num_buckets << 1 ) - 1 ;
406431
407432 MemSet (metap -> hashm_spares , 0 , sizeof (metap -> hashm_spares ));
408433 MemSet (metap -> hashm_mapp , 0 , sizeof (metap -> hashm_mapp ));
409434
410- metap -> hashm_spares [1 ] = 1 ; /* the first bitmap page is only spare */
411- metap -> hashm_ovflpoint = 1 ;
435+ /* Set up mapping for one spare page after the initial splitpoints */
436+ metap -> hashm_spares [log2_num_buckets ] = 1 ;
437+ metap -> hashm_ovflpoint = log2_num_buckets ;
412438 metap -> hashm_firstfree = 0 ;
413439
414440 /*
415- * Initialize the first two buckets
441+ * Initialize the first N buckets
416442 */
417- for (i = 0 ; i <= 1 ; i ++ )
443+ for (i = 0 ; i < num_buckets ; i ++ )
418444 {
419445 buf = _hash_getnewbuf (rel , BUCKET_TO_BLKNO (metap , i ));
420446 pg = BufferGetPage (buf );
@@ -430,7 +456,7 @@ _hash_metapinit(Relation rel)
430456 /*
431457 * Initialize first bitmap page
432458 */
433- _hash_initbitmap (rel , metap , 3 );
459+ _hash_initbitmap (rel , metap , num_buckets + 1 );
434460
435461 /* all done */
436462 _hash_wrtbuf (rel , metabuf );
@@ -511,6 +537,9 @@ _hash_expandtable(Relation rel, Buffer metabuf)
511537 * index with 2^32 buckets would certainly overflow BlockNumber and hence
512538 * _hash_alloc_buckets() would fail, but if we supported buckets smaller
513539 * than a disk block then this would be an independent constraint.
540+ *
541+ * If you change this, see also the maximum initial number of buckets
542+ * in _hash_metapinit().
514543 */
515544 if (metap -> hashm_maxbucket >= (uint32 ) 0x7FFFFFFE )
516545 goto fail ;
0 commit comments