From d0f020037e19c33c74d683eb7e0c7cc5725294b4 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Wed, 7 Aug 2024 06:51:16 +0300 Subject: [PATCH] Introduce hash_search_with_hash_value() function 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 | 38 +++++++++++++++++++++++++++++++ src/include/utils/hsearch.h | 5 ++++ 2 files changed, 43 insertions(+) diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c index 145e058fe6..8040416a13 100644 --- a/src/backend/utils/hash/dynahash.c +++ b/src/backend/utils/hash/dynahash.c @@ -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... */ diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h index da26941f6d..d2919677a2 100644 --- a/src/include/utils/hsearch.h +++ b/src/include/utils/hsearch.h @@ -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);