Refactor initial hash lookup in dynahash.c
authorMichael Paquier <michael@paquier.xyz>
Thu, 14 Mar 2024 22:57:17 +0000 (07:57 +0900)
committerMichael Paquier <michael@paquier.xyz>
Thu, 14 Mar 2024 22:57:17 +0000 (07:57 +0900)
The same pattern is used three times in dynahash.c to retrieve a bucket
number and a hash bucket from a hash value.  This has popped up while
discussing improvements for the type cache, where this piece of
refactoring would become useful.

Note that hash_search_with_hash_value() does not need the bucket number,
just the hash bucket.

Author: Teodor Sigaev
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/5812a6e5-68ae-4d84-9d85-b443176966a1@sigaev.ru

src/backend/utils/hash/dynahash.c

index a4152080b5d15eddec100fed6b7b2ce33235dd7d..4080833df0fecf4d6ff9f90f9fe3973b12e5bfa8 100644 (file)
@@ -273,6 +273,8 @@ static void hdefault(HTAB *hashp);
 static int     choose_nelem_alloc(Size entrysize);
 static bool init_htab(HTAB *hashp, long nelem);
 static void hash_corrupted(HTAB *hashp);
+static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue,
+                                                                 HASHBUCKET **bucketptr);
 static long next_pow2_long(long num);
 static int     next_pow2_int(long num);
 static void register_seq_scan(HTAB *hashp);
@@ -972,10 +974,6 @@ hash_search_with_hash_value(HTAB *hashp,
        HASHHDR    *hctl = hashp->hctl;
        int                     freelist_idx = FREELIST_IDX(hctl, hashvalue);
        Size            keysize;
-       uint32          bucket;
-       long            segment_num;
-       long            segment_ndx;
-       HASHSEGMENT segp;
        HASHBUCKET      currBucket;
        HASHBUCKET *prevBucketPtr;
        HashCompareFunc match;
@@ -1008,17 +1006,7 @@ hash_search_with_hash_value(HTAB *hashp,
        /*
         * Do the initial lookup
         */
-       bucket = calc_bucket(hctl, hashvalue);
-
-       segment_num = bucket >> hashp->sshift;
-       segment_ndx = MOD(bucket, hashp->ssize);
-
-       segp = hashp->dir[segment_num];
-
-       if (segp == NULL)
-               hash_corrupted(hashp);
-
-       prevBucketPtr = &segp[segment_ndx];
+       (void) hash_initial_lookup(hashp, hashvalue, &prevBucketPtr);
        currBucket = *prevBucketPtr;
 
        /*
@@ -1159,14 +1147,10 @@ hash_update_hash_key(HTAB *hashp,
                                         const void *newKeyPtr)
 {
        HASHELEMENT *existingElement = ELEMENT_FROM_KEY(existingEntry);
-       HASHHDR    *hctl = hashp->hctl;
        uint32          newhashvalue;
        Size            keysize;
        uint32          bucket;
        uint32          newbucket;
-       long            segment_num;
-       long            segment_ndx;
-       HASHSEGMENT segp;
        HASHBUCKET      currBucket;
        HASHBUCKET *prevBucketPtr;
        HASHBUCKET *oldPrevPtr;
@@ -1187,17 +1171,8 @@ hash_update_hash_key(HTAB *hashp,
         * this to be able to unlink it from its hash chain, but as a side benefit
         * we can verify the validity of the passed existingEntry pointer.
         */
-       bucket = calc_bucket(hctl, existingElement->hashvalue);
-
-       segment_num = bucket >> hashp->sshift;
-       segment_ndx = MOD(bucket, hashp->ssize);
-
-       segp = hashp->dir[segment_num];
-
-       if (segp == NULL)
-               hash_corrupted(hashp);
-
-       prevBucketPtr = &segp[segment_ndx];
+       bucket = hash_initial_lookup(hashp, existingElement->hashvalue,
+                                                                &prevBucketPtr);
        currBucket = *prevBucketPtr;
 
        while (currBucket != NULL)
@@ -1219,18 +1194,7 @@ hash_update_hash_key(HTAB *hashp,
         * chain we want to put the entry into.
         */
        newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
-
-       newbucket = calc_bucket(hctl, newhashvalue);
-
-       segment_num = newbucket >> hashp->sshift;
-       segment_ndx = MOD(newbucket, hashp->ssize);
-
-       segp = hashp->dir[segment_num];
-
-       if (segp == NULL)
-               hash_corrupted(hashp);
-
-       prevBucketPtr = &segp[segment_ndx];
+       newbucket = hash_initial_lookup(hashp, newhashvalue, &prevBucketPtr);
        currBucket = *prevBucketPtr;
 
        /*
@@ -1741,6 +1705,33 @@ element_alloc(HTAB *hashp, int nelem, int freelist_idx)
        return true;
 }
 
+/*
+ * Do initial lookup of a bucket for the given hash value, retrieving its
+ * bucket number and its hash bucket.
+ */
+static inline uint32
+hash_initial_lookup(HTAB *hashp, uint32 hashvalue, HASHBUCKET **bucketptr)
+{
+       HASHHDR    *hctl = hashp->hctl;
+       HASHSEGMENT segp;
+       long            segment_num;
+       long            segment_ndx;
+       uint32          bucket;
+
+       bucket = calc_bucket(hctl, hashvalue);
+
+       segment_num = bucket >> hashp->sshift;
+       segment_ndx = MOD(bucket, hashp->ssize);
+
+       segp = hashp->dir[segment_num];
+
+       if (segp == NULL)
+               hash_corrupted(hashp);
+
+       *bucketptr = &segp[segment_ndx];
+       return bucket;
+}
+
 /* complain when we have detected a corrupted hashtable */
 static void
 hash_corrupted(HTAB *hashp)