mirror of
https://github.com/openssl/openssl.git
synced 2026-05-07 20:12:39 +00:00
Add ability to extract computed hash from hashtable
One thing we can do to speed up hash table lookups is to cache/reuse computed hash values when interrogating a hash table multiple times in rapid succession. We follow this pattern frequently when using hashtables: value = lookup_hash(key) if (value == NULL) value = new_value() insert_to_hash(key, value) Note that we use the same key for the lookup and the insert. So if we had a way to preserve the value this key hashed to, we can avoid having to do a second hash computation during the lookup. These new macros give us that. The HT_KEY structure now stores the computed hash value in the key, which can be extracted and reused by the caller with the HT_INIT_KEY_CACHED macro. When set, the cached hash value is used, rather than needing to recompute the hash for any subsequent operations Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Saša Nedvědický <sashan@openssl.org> MergeDate: Tue Mar 24 16:23:05 2026 (Merged from https://github.com/openssl/openssl/pull/30254)
This commit is contained in:
committed by
Alexandr Nedvedicky
parent
5efde2afed
commit
060193019a
@@ -700,12 +700,15 @@ int ossl_ht_insert(HT *h, HT_KEY *key, HT_VALUE *data, HT_VALUE **olddata)
|
||||
if (newval == NULL)
|
||||
goto out;
|
||||
|
||||
if (key->cached_hash)
|
||||
hash = key->cached_hash;
|
||||
else
|
||||
hash = key->cached_hash = newval->value.key.cached_hash = h->config.ht_hash_fn(key);
|
||||
|
||||
/*
|
||||
* we have to take our lock here to prevent other changes
|
||||
* to the bucket list
|
||||
*/
|
||||
hash = h->config.ht_hash_fn(key);
|
||||
|
||||
for (i = 0;
|
||||
(rc = ossl_ht_insert_locked(h, hash, newval, olddata)) == -1
|
||||
&& i < 4;
|
||||
@@ -733,7 +736,10 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key)
|
||||
uint64_t ehash;
|
||||
int lockless_reads = h->config.lockless_reads;
|
||||
|
||||
hash = h->config.ht_hash_fn(key);
|
||||
if (key->cached_hash)
|
||||
hash = key->cached_hash;
|
||||
else
|
||||
hash = key->cached_hash = h->config.ht_hash_fn(key);
|
||||
|
||||
if (!h->config.no_rcu)
|
||||
md = ossl_rcu_deref(&h->md);
|
||||
@@ -792,7 +798,10 @@ int ossl_ht_delete(HT *h, HT_KEY *key)
|
||||
if (h->config.lockless_reads)
|
||||
return 0;
|
||||
|
||||
hash = h->config.ht_hash_fn(key);
|
||||
if (key->cached_hash)
|
||||
hash = key->cached_hash;
|
||||
else
|
||||
hash = key->cached_hash = h->config.ht_hash_fn(key);
|
||||
|
||||
neigh_idx = hash & h->md->neighborhood_mask;
|
||||
PREFETCH_NEIGHBORHOOD(h->md->neighborhoods[neigh_idx]);
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef struct ht_internal_st HT;
|
||||
* Represents a key to a hashtable
|
||||
*/
|
||||
typedef struct ht_key_header_st {
|
||||
uint64_t cached_hash;
|
||||
size_t keysize;
|
||||
size_t bufsize;
|
||||
uint8_t *keybuf;
|
||||
@@ -169,10 +170,22 @@ static ossl_inline ossl_unused int ossl_key_raw_copy(HT_KEY *key, const uint8_t
|
||||
(key)->keysize += tmplen; \
|
||||
} while (0)
|
||||
|
||||
#define HT_INIT_KEY_CACHED(key, hash) \
|
||||
do { \
|
||||
HT_INIT_KEY((key)); \
|
||||
(key)->key_header.cached_hash = hash; \
|
||||
} while (0)
|
||||
|
||||
#define HT_KEY_GET_HASH(key) (key)->key_header.cached_hash
|
||||
|
||||
/*
|
||||
* Resets a hash table key to a known state
|
||||
*/
|
||||
#define HT_KEY_RESET(key) memset((key)->key_header.keybuf, 0, (key)->key_header.keysize)
|
||||
#define HT_KEY_RESET(key) \
|
||||
do { \
|
||||
memset((key)->key_header.keybuf, 0, (key)->key_header.keysize); \
|
||||
(key)->key_header.cached_hash = 0; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Sets a scalar field in a hash table key
|
||||
|
||||
@@ -244,6 +244,7 @@ static int test_int_hashtable(int idx)
|
||||
/* insert */
|
||||
HT_INIT_KEY(&key);
|
||||
for (i = 0; i < n_int_tests; i++) {
|
||||
HT_KEY_RESET(&key);
|
||||
HT_SET_KEY_FIELD(&key, mykey, int_tests[i]);
|
||||
if (!TEST_int_eq(ossl_ht_test_int_insert(ht, TO_HT_KEY(&key),
|
||||
&int_tests[i], NULL),
|
||||
@@ -280,6 +281,7 @@ static int test_int_hashtable(int idx)
|
||||
|
||||
/* delete */
|
||||
for (i = 0; i < n_dels; i++) {
|
||||
HT_KEY_RESET(&key);
|
||||
HT_SET_KEY_FIELD(&key, mykey, dels[i].data);
|
||||
todel = ossl_ht_delete(ht, TO_HT_KEY(&key));
|
||||
if (dels[i].should_del) {
|
||||
@@ -439,6 +441,7 @@ static int test_hashtable_stress(int idx)
|
||||
goto end;
|
||||
}
|
||||
*p = 3 * i + 1;
|
||||
HT_KEY_RESET(&key);
|
||||
HT_SET_KEY_FIELD(&key, mykey, *p);
|
||||
if (!TEST_int_eq(ossl_ht_test_int_insert(h, TO_HT_KEY(&key),
|
||||
p, NULL),
|
||||
@@ -455,6 +458,7 @@ static int test_hashtable_stress(int idx)
|
||||
/* delete or get in a different order */
|
||||
for (i = 0; i < n; i++) {
|
||||
const int j = (7 * i + 4) % n * 3 + 1;
|
||||
HT_KEY_RESET(&key);
|
||||
HT_SET_KEY_FIELD(&key, mykey, j);
|
||||
|
||||
switch (idx % 2) {
|
||||
|
||||
Reference in New Issue
Block a user