Introduce hash_search_with_hash_value() function
authorAlexander Korotkov <[email protected]>
Wed, 7 Aug 2024 03:51:16 +0000 (06:51 +0300)
committerAlexander Korotkov <[email protected]>
Wed, 7 Aug 2024 04:06:17 +0000 (07:06 +0300)
This new function iterates hash entries with given hash values.  This function
is designed to avoid full sequential hash search in the syscache invalidation
callbacks.

Discussion: https://postgr.es/m/5812a6e5-68ae-4d84-9d85-b443176966a1%40sigaev.ru
Author: Teodor Sigaev
Reviewed-by: Aleksander Alekseev, Tom Lane, Michael Paquier, Roman Zharkov
Reviewed-by: Andrei Lepikhov
src/backend/utils/hash/dynahash.c
src/include/utils/hsearch.h

index 145e058fe675b880e34c9b1a549050e6f123860c..8040416a13c166b3fb585cda01d81afc12b7e3c7 100644 (file)
@@ -1387,10 +1387,30 @@ hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
        status->hashp = hashp;
        status->curBucket = 0;
        status->curEntry = NULL;
+       status->hasHashvalue = false;
        if (!hashp->frozen)
                register_seq_scan(hashp);
 }
 
+/*
+ * Same as above but scan by the given hash value.
+ * See also hash_seq_search().
+ */
+void
+hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp,
+                                                         uint32 hashvalue)
+{
+       HASHBUCKET *bucketPtr;
+
+       hash_seq_init(status, hashp);
+
+       status->hasHashvalue = true;
+       status->hashvalue = hashvalue;
+
+       status->curBucket = hash_initial_lookup(hashp, hashvalue, &bucketPtr);
+       status->curEntry = *bucketPtr;
+}
+
 void *
 hash_seq_search(HASH_SEQ_STATUS *status)
 {
@@ -1404,6 +1424,24 @@ hash_seq_search(HASH_SEQ_STATUS *status)
        uint32          curBucket;
        HASHELEMENT *curElem;
 
+       if (status->hasHashvalue)
+       {
+               /*
+                * Scan entries only in the current bucket because only this bucket
+                * can contain entries with the given hash value.
+                */
+               while ((curElem = status->curEntry) != NULL)
+               {
+                       status->curEntry = curElem->link;
+                       if (status->hashvalue != curElem->hashvalue)
+                               continue;
+                       return (void *) ELEMENTKEY(curElem);
+               }
+
+               hash_seq_term(status);
+               return NULL;
+       }
+
        if ((curElem = status->curEntry) != NULL)
        {
                /* Continuing scan of curBucket... */
index da26941f6db5ffda5bd3b960235c724000a319ad..d2919677a2d94a825982cba7fda2325fb45f2701 100644 (file)
@@ -122,6 +122,8 @@ typedef struct
        HTAB       *hashp;
        uint32          curBucket;              /* index of current bucket */
        HASHELEMENT *curEntry;          /* current entry in bucket */
+       bool            hasHashvalue;   /* true if hashvalue was provided */
+       uint32          hashvalue;              /* hashvalue to start seqscan over hash */
 } HASH_SEQ_STATUS;
 
 /*
@@ -141,6 +143,9 @@ extern bool hash_update_hash_key(HTAB *hashp, void *existingEntry,
                                                                 const void *newKeyPtr);
 extern long hash_get_num_entries(HTAB *hashp);
 extern void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp);
+extern void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status,
+                                                                                 HTAB *hashp,
+                                                                                 uint32 hashvalue);
 extern void *hash_seq_search(HASH_SEQ_STATUS *status);
 extern void hash_seq_term(HASH_SEQ_STATUS *status);
 extern void hash_freeze(HTAB *hashp);