7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.22 1999/05/25 16:12:28 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.23 1999/05/31 17:01:52 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
52
52
#include "utils/memutils.h"
53
53
54
54
/*
55
- * Fast arithmetic, relying on powers of 2,
56
- * and on pre-processor concatenation property
55
+ * Fast MOD arithmetic, assuming that y is a power of 2 !
57
56
*/
58
57
59
58
#define MOD (x ,y ) ((x) & ((y)-1))
60
59
61
- /*
62
- * external routines
63
- */
64
-
65
60
/*
66
61
* Private function prototypes
67
62
*/
68
63
static long * DynaHashAlloc (unsigned int size );
69
64
static void DynaHashFree (Pointer ptr );
70
- static uint32 call_hash (HTAB * hashp , char * k , int len );
65
+ static uint32 call_hash (HTAB * hashp , char * k );
71
66
static SEG_OFFSET seg_alloc (HTAB * hashp );
72
67
static int bucket_alloc (HTAB * hashp );
73
68
static int dir_realloc (HTAB * hashp );
69
+ static int expand_table (HTAB * hashp );
70
+ static int hdefault (HTAB * hashp );
71
+ static int init_htab (HTAB * hashp , int nelem );
74
72
75
73
typedef long * ((* dhalloc_ptr ) ());
76
74
@@ -118,15 +116,6 @@ DynaHashFree(Pointer ptr)
118
116
119
117
#endif /* FRONTEND */
120
118
121
- /* ----------------
122
- * Internal routines
123
- * ----------------
124
- */
125
-
126
- static int expand_table (HTAB * hashp );
127
- static int hdefault (HTAB * hashp );
128
- static int init_htab (HTAB * hashp , int nelem );
129
-
130
119
131
120
/*
132
121
* pointer access macros. Shared memory implementation cannot
@@ -220,6 +209,8 @@ hash_create(int nelem, HASHCTL *info, int flags)
220
209
{
221
210
hctl -> ssize = info -> ssize ;
222
211
hctl -> sshift = my_log2 (info -> ssize );
212
+ /* ssize had better be a power of 2 */
213
+ Assert (hctl -> ssize == (1L << hctl -> sshift ));
223
214
}
224
215
if (flags & HASH_FFACTOR )
225
216
hctl -> ffactor = info -> ffactor ;
@@ -412,6 +403,8 @@ hash_estimate_size(long num_entries, long keysize, long datasize)
412
403
* XXX this sure looks thoroughly broken to me --- tgl 2/99.
413
404
* It's freeing every entry individually --- but they weren't
414
405
* allocated individually, see bucket_alloc!! Why doesn't it crash?
406
+ * ANSWER: it probably does crash, but is never invoked in normal
407
+ * operations...
415
408
*/
416
409
417
410
void
@@ -479,14 +472,13 @@ hash_stats(char *where, HTAB *hashp)
479
472
/*******************************SEARCH ROUTINES *****************************/
480
473
481
474
static uint32
482
- call_hash (HTAB * hashp , char * k , int len )
475
+ call_hash (HTAB * hashp , char * k )
483
476
{
477
+ HHDR * hctl = hashp -> hctl ;
484
478
long hash_val ,
485
479
bucket ;
486
- HHDR * hctl ;
487
480
488
- hctl = hashp -> hctl ;
489
- hash_val = hashp -> hash (k , len );
481
+ hash_val = hashp -> hash (k , (int ) hctl -> keysize );
490
482
491
483
bucket = hash_val & hctl -> high_mask ;
492
484
if (bucket > hctl -> max_bucket )
@@ -550,9 +542,9 @@ hash_search(HTAB *hashp,
550
542
}
551
543
else
552
544
{
553
- bucket = call_hash (hashp , keyPtr , hctl -> keysize );
545
+ bucket = call_hash (hashp , keyPtr );
554
546
segment_num = bucket >> hctl -> sshift ;
555
- segment_ndx = bucket & ( hctl -> ssize - 1 );
547
+ segment_ndx = MOD ( bucket , hctl -> ssize );
556
548
557
549
segp = GET_SEG (hashp , segment_num );
558
550
@@ -598,8 +590,10 @@ hash_search(HTAB *hashp,
598
590
Assert (hctl -> nkeys > 0 );
599
591
hctl -> nkeys -- ;
600
592
601
- /* add the bucket to the freelist for this table. */
593
+ /* remove record from hash bucket's chain. */
602
594
* prevIndexPtr = curr -> next ;
595
+
596
+ /* add the record to the freelist for this table. */
603
597
curr -> next = hctl -> freeBucketIndex ;
604
598
hctl -> freeBucketIndex = currIndex ;
605
599
@@ -639,7 +633,6 @@ hash_search(HTAB *hashp,
639
633
currIndex = hctl -> freeBucketIndex ;
640
634
if (currIndex == INVALID_INDEX )
641
635
{
642
-
643
636
/* no free elements. allocate another chunk of buckets */
644
637
if (!bucket_alloc (hashp ))
645
638
return NULL ;
@@ -722,7 +715,7 @@ hash_seq(HTAB *hashp)
722
715
* initialize the search within this bucket.
723
716
*/
724
717
segment_num = curBucket >> hctl -> sshift ;
725
- segment_ndx = curBucket & ( hctl -> ssize - 1 );
718
+ segment_ndx = MOD ( curBucket , hctl -> ssize );
726
719
727
720
/*
728
721
* first find the right segment in the table directory.
@@ -751,6 +744,10 @@ hash_seq(HTAB *hashp)
751
744
752
745
753
746
/********************************* UTILITIES ************************/
747
+
748
+ /*
749
+ * Expand the table by adding one more hash bucket.
750
+ */
754
751
static int
755
752
expand_table (HTAB * hashp )
756
753
{
@@ -790,19 +787,31 @@ expand_table(HTAB *hashp)
790
787
hctl -> nsegs ++ ;
791
788
}
792
789
793
- /* OK, we got a new bucket */
790
+ /* OK, we created a new bucket */
794
791
hctl -> max_bucket ++ ;
795
- old_bucket = (hctl -> max_bucket & hctl -> low_mask );
796
792
793
+ /*
794
+ * *Before* changing masks, find old bucket corresponding to same hash
795
+ * values; values in that bucket may need to be relocated to new bucket.
796
+ * Note that new_bucket is certainly larger than low_mask at this point,
797
+ * so we can skip the first step of the regular hash mask calc.
798
+ */
799
+ old_bucket = (new_bucket & hctl -> low_mask );
800
+
801
+ /*
802
+ * If we crossed a power of 2, readjust masks.
803
+ */
797
804
if (new_bucket > hctl -> high_mask )
798
805
{
799
- /* Starting a new doubling */
800
806
hctl -> low_mask = hctl -> high_mask ;
801
807
hctl -> high_mask = new_bucket | hctl -> low_mask ;
802
808
}
803
809
804
810
/*
805
- * Relocate records to the new bucket
811
+ * Relocate records to the new bucket. NOTE: because of the way the
812
+ * hash masking is done in call_hash, only one old bucket can need to
813
+ * be split at this point. With a different way of reducing the hash
814
+ * value, that might not be true!
806
815
*/
807
816
old_segnum = old_bucket >> hctl -> sshift ;
808
817
old_segndx = MOD (old_bucket , hctl -> ssize );
@@ -816,12 +825,9 @@ expand_table(HTAB *hashp)
816
825
chainIndex != INVALID_INDEX ;
817
826
chainIndex = nextIndex )
818
827
{
819
-
820
828
chain = GET_BUCKET (hashp , chainIndex );
821
829
nextIndex = chain -> next ;
822
- if (call_hash (hashp ,
823
- (char * ) & (chain -> key ),
824
- hctl -> keysize ) == old_bucket )
830
+ if (call_hash (hashp , (char * ) & (chain -> key )) == old_bucket )
825
831
{
826
832
* old = chainIndex ;
827
833
old = & chain -> next ;
@@ -831,8 +837,10 @@ expand_table(HTAB *hashp)
831
837
* newbi = chainIndex ;
832
838
newbi = & chain -> next ;
833
839
}
834
- chain -> next = INVALID_INDEX ;
835
840
}
841
+ /* don't forget to terminate the rebuilt hash chains... */
842
+ * old = INVALID_INDEX ;
843
+ * newbi = INVALID_INDEX ;
836
844
return 1 ;
837
845
}
838
846
@@ -907,15 +915,13 @@ bucket_alloc(HTAB *hashp)
907
915
/* make sure its aligned correctly */
908
916
bucketSize = MAXALIGN (bucketSize );
909
917
910
- /*
911
- * tmpIndex is the shmem offset into the first bucket of the array.
912
- */
913
918
tmpBucket = (ELEMENT * )
914
919
hashp -> alloc ((unsigned long ) BUCKET_ALLOC_INCR * bucketSize );
915
920
916
921
if (!tmpBucket )
917
922
return 0 ;
918
923
924
+ /* tmpIndex is the shmem offset into the first bucket of the array */
919
925
tmpIndex = MAKE_HASHOFFSET (hashp , tmpBucket );
920
926
921
927
/* set the freebucket list to point to the first bucket */
0 commit comments