From e2702666279f693716b097afc9084d412d5f4aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 28 Aug 2023 10:08:59 +0200 Subject: [PATCH] Refactor isc_hashmap to accept custom match function Refactor isc_hashmap to allow custom matching functions. This allows us to have better tailored keys that don't require fixed uint8_t arrays, but can be composed of more fields from the stored data structure. --- lib/dns/adb.c | 165 ++++++++++++----------- lib/dns/resolver.c | 125 +++++++++--------- lib/dns/transport.c | 18 ++- lib/dns/tsig.c | 26 +++- lib/dns/zone.c | 29 +++-- lib/isc/hashmap.c | 142 +++++++------------- lib/isc/include/isc/hashmap.h | 39 +++--- tests/bench/load-names.c | 19 ++- tests/isc/hashmap_test.c | 237 ++++++++++++++++++++++------------ 9 files changed, 425 insertions(+), 375 deletions(-) diff --git a/lib/dns/adb.c b/lib/dns/adb.c index fb99b4cf86..beab25b57d 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -127,18 +128,6 @@ struct dns_adb { double atr_discount; }; -typedef struct adbnamekey adbnamekey_t; -struct adbnamekey { - size_t size; - union { - struct { - bool start_at_zone; - uint8_t name[DNS_NAME_MAXWIRE]; - }; - char key[sizeof(bool) + DNS_NAME_MAXWIRE]; - }; -} __attribute__((__packed__)); - /*% * dns_adbname structure: * @@ -152,9 +141,8 @@ struct dns_adbname { unsigned int magic; isc_refcount_t references; dns_adb_t *adb; - isc_buffer_t buffer; - adbnamekey_t key; - dns_name_t name; + dns_fixedname_t fname; + dns_name_t *name; unsigned int partial_result; unsigned int flags; dns_name_t target; @@ -308,6 +296,10 @@ static dns_adbname_t * new_adbname(dns_adb_t *adb, const dns_name_t *, bool start_at_zone); static void destroy_adbname(dns_adbname_t *); +static bool +match_adbname(void *node, const void *key); +static uint32_t +hash_adbname(const dns_adbname_t *adbname); static dns_adbnamehook_t * new_adbnamehook(dns_adb_t *adb); static void @@ -320,6 +312,8 @@ static dns_adbentry_t * new_adbentry(dns_adb_t *adb, const isc_sockaddr_t *addr); static void destroy_adbentry(dns_adbentry_t *entry); +static bool +match_adbentry(void *node, const void *key); static dns_adbfind_t * new_adbfind(dns_adb_t *, in_port_t); static void @@ -682,6 +676,11 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, return (ISC_R_SUCCESS); } +static bool +match_ptr(void *node, const void *key) { + return (node == key); +} + /* * Requires the name to be locked. */ @@ -720,8 +719,8 @@ expire_name(dns_adbname_t *adbname, dns_adbstatus_t astat) { /* * Remove the adbname from the hashtable... */ - result = isc_hashmap_delete(adb->names, NULL, &adbname->key.key, - adbname->key.size); + result = isc_hashmap_delete(adb->names, hash_adbname(adbname), + match_ptr, adbname); RUNTIME_CHECK(result == ISC_R_SUCCESS); /* ... and LRU list */ ISC_LIST_UNLINK(adb->names_lru, adbname, link); @@ -1018,16 +1017,12 @@ new_adbname(dns_adb_t *adb, const dns_name_t *dnsname, bool start_at_zone) { isc_mutex_init(&name->lock); - dns_name_init(&name->name, NULL); - isc_buffer_init(&name->buffer, name->key.name, DNS_NAME_MAXWIRE); - dns_name_setbuffer(&name->name, &name->buffer); - dns_name_copy(dnsname, &name->name); + name->name = dns_fixedname_initname(&name->fname); + dns_name_copy(dnsname, name->name); dns_name_init(&name->target, NULL); - name->key.size = dnsname->length + sizeof(bool); if (start_at_zone) { name->flags |= DNS_ADBFIND_STARTATZONE; - name->key.start_at_zone = true; } inc_adbstats(adb, dns_adbstats_namescnt); @@ -1320,6 +1315,32 @@ free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) { isc_mem_put(adb->mctx, ai, sizeof(*ai)); } +static bool +match_adbname(void *node, const void *key) { + const dns_adbname_t *adbname0 = node; + const dns_adbname_t *adbname1 = key; + + if ((adbname0->flags & DNS_ADBFIND_STARTATZONE) != + (adbname1->flags & DNS_ADBFIND_STARTATZONE)) + { + return (false); + } + + return (dns_name_equal(adbname0->name, adbname1->name)); +} + +static uint32_t +hash_adbname(const dns_adbname_t *adbname) { + isc_hash32_t hash; + bool start_at_zone = adbname->flags & DNS_ADBFIND_STARTATZONE; + + isc_hash32_init(&hash); + isc_hash32_hash(&hash, adbname->name->ndata, adbname->name->length, + false); + isc_hash32_hash(&hash, &start_at_zone, sizeof(start_at_zone), true); + return (isc_hash32_finalize(&hash)); +} + /* * Search for the name in the hash table. */ @@ -1328,20 +1349,17 @@ get_attached_and_locked_name(dns_adb_t *adb, const dns_name_t *name, bool start_at_zone, isc_stdtime_t now) { isc_result_t result; dns_adbname_t *adbname = NULL; - uint32_t hashval; isc_time_t timenow; isc_stdtime_t last_update; - adbnamekey_t key; + dns_adbname_t key = { + .name = UNCONST(name), + .flags = (start_at_zone) ? DNS_ADBFIND_STARTATZONE : 0, + }; + uint32_t hashval = hash_adbname(&key); isc_rwlocktype_t locktype = isc_rwlocktype_read; isc_time_set(&timenow, now, 0); - key.start_at_zone = start_at_zone; - memmove(&key.name, name->ndata, name->length); - key.size = name->length + sizeof(bool); - - hashval = isc_hashmap_hash(adb->names, &key.key, key.size); - RWLOCK(&adb->names_lock, locktype); last_update = adb->names_last_update; @@ -1354,8 +1372,8 @@ get_attached_and_locked_name(dns_adb_t *adb, const dns_name_t *name, adb->names_last_update = last_update; } - result = isc_hashmap_find(adb->names, &hashval, key.key, key.size, - (void **)&adbname); + result = isc_hashmap_find(adb->names, hashval, match_adbname, + (void *)&key, (void **)&adbname); switch (result) { case ISC_R_NOTFOUND: UPGRADELOCK(&adb->names_lock, locktype); @@ -1363,14 +1381,13 @@ get_attached_and_locked_name(dns_adb_t *adb, const dns_name_t *name, /* Allocate a new name and add it to the hash table. */ adbname = new_adbname(adb, name, start_at_zone); - result = isc_hashmap_add(adb->names, &hashval, - &adbname->key.key, adbname->key.size, - adbname); + void *found = NULL; + result = isc_hashmap_add(adb->names, hashval, match_adbname, + (void *)&key, adbname, &found); if (result == ISC_R_EXISTS) { destroy_adbname(adbname); - adbname = NULL; - result = isc_hashmap_find(adb->names, &hashval, key.key, - key.size, (void **)&adbname); + adbname = found; + result = ISC_R_SUCCESS; ISC_LIST_UNLINK(adb->names_lru, adbname, link); } INSIST(result == ISC_R_SUCCESS); @@ -1415,6 +1432,13 @@ upgrade_entries_lock(dns_adb_t *adb, isc_rwlocktype_t *locktypep, } } +static bool +match_adbentry(void *node, const void *key) { + dns_adbentry_t *adbentry = node; + + return (isc_sockaddr_equal(&adbentry->sockaddr, key)); +} + /* * Find the entry in the adb->entries hashtable. */ @@ -1425,8 +1449,7 @@ get_attached_and_locked_entry(dns_adb_t *adb, isc_stdtime_t now, dns_adbentry_t *adbentry = NULL; isc_time_t timenow; isc_stdtime_t last_update; - uint32_t hashval = isc_hashmap_hash( - adb->entries, (const unsigned char *)addr, sizeof(*addr)); + uint32_t hashval = isc_sockaddr_hash(addr, true); isc_rwlocktype_t locktype = isc_rwlocktype_read; isc_time_set(&timenow, now, 0); @@ -1442,8 +1465,8 @@ get_attached_and_locked_entry(dns_adb_t *adb, isc_stdtime_t now, upgrade_entries_lock(adb, &locktype, now); } - result = isc_hashmap_find(adb->entries, &hashval, - (const unsigned char *)addr, sizeof(*addr), + result = isc_hashmap_find(adb->entries, hashval, match_adbentry, + (const unsigned char *)addr, (void **)&adbentry); if (result == ISC_R_NOTFOUND) { upgrade_entries_lock(adb, &locktype, now); @@ -1454,18 +1477,15 @@ get_attached_and_locked_entry(dns_adb_t *adb, isc_stdtime_t now, /* Allocate a new entry and add it to the hash table. */ adbentry = new_adbentry(adb, addr); - result = isc_hashmap_add(adb->entries, &hashval, - &adbentry->sockaddr, - sizeof(adbentry->sockaddr), adbentry); + void *found = NULL; + result = isc_hashmap_add(adb->entries, hashval, match_adbentry, + &adbentry->sockaddr, adbentry, &found); if (result == ISC_R_SUCCESS) { ISC_LIST_PREPEND(adb->entries_lru, adbentry, link); } else if (result == ISC_R_EXISTS) { dns_adbentry_detach(&adbentry); - - result = isc_hashmap_find(adb->entries, &hashval, - (const unsigned char *)addr, - sizeof(*addr), - (void **)&adbentry); + adbentry = found; + result = ISC_R_SUCCESS; } } INSIST(result == ISC_R_SUCCESS); @@ -1684,9 +1704,10 @@ expire_entry(dns_adbentry_t *adbentry) { if (!ENTRY_DEAD(adbentry)) { adbentry->flags |= ENTRY_IS_DEAD; - result = isc_hashmap_delete(adb->entries, NULL, - &adbentry->sockaddr, - sizeof(adbentry->sockaddr)); + result = isc_hashmap_delete( + adb->entries, + isc_sockaddr_hash(&adbentry->sockaddr, true), match_ptr, + adbentry); RUNTIME_CHECK(result == ISC_R_SUCCESS); ISC_LIST_UNLINK(adb->entries_lru, adbentry, link); } @@ -1992,12 +2013,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_loopmgr_t *loopmgr, isc_mem_create(&adb->hmctx); isc_mem_setname(adb->hmctx, "ADB_hashmaps"); - isc_hashmap_create(adb->hmctx, ADB_HASH_BITS, - ISC_HASHMAP_CASE_INSENSITIVE, &adb->names); + isc_hashmap_create(adb->hmctx, ADB_HASH_BITS, &adb->names); isc_rwlock_init(&adb->names_lock); - isc_hashmap_create(adb->hmctx, ADB_HASH_BITS, - ISC_HASHMAP_CASE_SENSITIVE, &adb->entries); + isc_hashmap_create(adb->hmctx, ADB_HASH_BITS, &adb->entries); isc_rwlock_init(&adb->entries_lock); isc_mutex_init(&adb->lock); @@ -2506,7 +2525,7 @@ dump_adb(dns_adb_t *adb, FILE *f, bool debug, isc_stdtime_t now) { name->flags); } fprintf(f, "; "); - dns_name_print(&name->name, f); + dns_name_print(name->name, f); if (dns_name_countlabels(&name->target) > 0) { fprintf(f, " alias "); dns_name_print(&name->target, f); @@ -2786,7 +2805,7 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) { * the configuration on which server we should send queries to. */ result = dns_view_find( - adb->view, &adbname->name, rdtype, now, DNS_DBFIND_GLUEOK, true, + adb->view, adbname->name, rdtype, now, DNS_DBFIND_GLUEOK, true, ((adbname->flags & DNS_ADBFIND_STARTATZONE) != 0), NULL, NULL, fname, &rdataset, NULL); @@ -2873,7 +2892,7 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) { rdataset.ttl = ttlclamp(rdataset.ttl); clean_target(adb, &adbname->target); adbname->expire_target = INT_MAX; - result = set_target(adb, &adbname->name, fname, &rdataset, + result = set_target(adb, adbname->name, fname, &rdataset, &adbname->target); if (result == ISC_R_SUCCESS) { result = DNS_R_ALIAS; @@ -2997,7 +3016,7 @@ fetch_callback(void *arg) { resp->rdataset->ttl = ttlclamp(resp->rdataset->ttl); clean_target(adb, &name->target); name->expire_target = INT_MAX; - result = set_target(adb, &name->name, resp->foundname, + result = set_target(adb, name->name, resp->foundname, resp->rdataset, &name->target); if (result == ISC_R_SUCCESS) { DP(NCACHE_LEVEL, @@ -3014,7 +3033,7 @@ fetch_callback(void *arg) { if (resp->result != ISC_R_SUCCESS) { char buf[DNS_NAME_FORMATSIZE]; - dns_name_format(&name->name, buf, sizeof(buf)); + dns_name_format(name->name, buf, sizeof(buf)); DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", isc_result_totext(resp->result)); @@ -3095,7 +3114,7 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, unsigned int depth, DP(ENTER_LEVEL, "fetch_name: starting at zone for name %p", adbname); name = dns_fixedname_initname(&fixed); - result = dns_view_findzonecut(adb->view, &adbname->name, name, + result = dns_view_findzonecut(adb->view, adbname->name, name, NULL, 0, 0, true, false, &rdataset, NULL); if (result != ISC_R_SUCCESS && result != DNS_R_HINT) { @@ -3116,8 +3135,8 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, unsigned int depth, * domain and nameservers. */ result = dns_resolver_createfetch( - adb->res, &adbname->name, type, name, nameservers, NULL, NULL, - 0, options, depth, qc, isc_loop_current(adb->loopmgr), + adb->res, adbname->name, type, name, nameservers, NULL, NULL, 0, + options, depth, qc, isc_loop_current(adb->loopmgr), fetch_callback, adbname, &fetch->rdataset, NULL, &fetch->fetch); if (result != ISC_R_SUCCESS) { DP(ENTER_LEVEL, "fetch_name: createfetch failed with %s", @@ -3579,7 +3598,7 @@ dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) { dns_adbname_t *adbname = NULL; isc_result_t result; bool start_at_zone = false; - adbnamekey_t key; + dns_adbname_t key = { .name = UNCONST(name) }; REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(name != NULL); @@ -3593,16 +3612,14 @@ again: /* * Delete both entries - without and with DNS_ADBFIND_STARTATZONE set. */ - key.start_at_zone = start_at_zone; - memmove(&key.name, name->ndata, name->length); - key.size = name->length + sizeof(bool); + key.flags = (start_at_zone) ? DNS_ADBFIND_STARTATZONE : 0; - result = isc_hashmap_find(adb->names, NULL, key.key, key.size, - (void **)&adbname); + result = isc_hashmap_find(adb->names, hash_adbname(&key), match_adbname, + (void *)&key, (void **)&adbname); if (result == ISC_R_SUCCESS) { dns_adbname_ref(adbname); LOCK(&adbname->lock); - if (dns_name_equal(name, &adbname->name)) { + if (dns_name_equal(name, adbname->name)) { expire_name(adbname, DNS_ADB_CANCELED); } UNLOCK(&adbname->lock); @@ -3633,7 +3650,7 @@ dns_adb_flushnames(dns_adb_t *adb, const dns_name_t *name) { next = ISC_LIST_NEXT(adbname, link); dns_adbname_ref(adbname); LOCK(&adbname->lock); - if (dns_name_issubdomain(&adbname->name, name)) { + if (dns_name_issubdomain(adbname->name, name)) { expire_name(adbname, DNS_ADB_CANCELED); } UNLOCK(&adbname->lock); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 94b78a91e2..c21513dda8 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -305,20 +305,6 @@ typedef enum { badns_forwarder, } badnstype_t; -typedef struct fctxkey fctxkey_t; -struct fctxkey { - size_t size; - union { - struct { - unsigned int options; /* 32 bits */ - dns_rdatatype_t type; /* 16 bits */ - uint8_t name[DNS_NAME_MAXWIRE]; - }; - char key[sizeof(unsigned int) + sizeof(dns_rdatatype_t) + - DNS_NAME_MAXWIRE]; - }; -} __attribute__((__packed__)); - #define FCTXCOUNT_MAGIC ISC_MAGIC('F', 'C', 'n', 't') #define VALID_FCTXCOUNT(counter) ISC_MAGIC_VALID(counter, FCTXCOUNT_MAGIC) @@ -343,7 +329,6 @@ struct fetchctx { dns_name_t *name; dns_rdatatype_t type; unsigned int options; - fctxkey_t key; fctxcount_t *counter; char *info; isc_mem_t *mctx; @@ -1401,6 +1386,14 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter, bool final) { counter->logged = now; } +static bool +fcount_match(void *node, const void *key) { + const fctxcount_t *counter = node; + const dns_name_t *domain = key; + + return (dns_name_equal(counter->domain, domain)); +} + static isc_result_t fcount_incr(fetchctx_t *fctx, bool force) { isc_result_t result = ISC_R_SUCCESS; @@ -1420,12 +1413,11 @@ fcount_incr(fetchctx_t *fctx, bool force) { return (ISC_R_SUCCESS); } - hashval = isc_hashmap_hash(res->counters, fctx->domain->ndata, - fctx->domain->length); + hashval = dns_name_hash(fctx->domain); RWLOCK(&res->counters_lock, locktype); - result = isc_hashmap_find(res->counters, &hashval, fctx->domain->ndata, - fctx->domain->length, (void **)&counter); + result = isc_hashmap_find(res->counters, hashval, fcount_match, + fctx->domain, (void **)&counter); switch (result) { case ISC_R_SUCCESS: break; @@ -1443,17 +1435,15 @@ fcount_incr(fetchctx_t *fctx, bool force) { UPGRADELOCK(&res->counters_lock, locktype); - result = isc_hashmap_add(res->counters, &hashval, - counter->domain->ndata, - counter->domain->length, counter); + void *found = NULL; + result = isc_hashmap_add(res->counters, hashval, fcount_match, + counter->domain, counter, &found); if (result == ISC_R_EXISTS) { isc_mutex_destroy(&counter->lock); isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter)); - counter = NULL; - result = isc_hashmap_find( - res->counters, &hashval, fctx->domain->ndata, - fctx->domain->length, (void **)&counter); + counter = found; + result = ISC_R_SUCCESS; } INSIST(result == ISC_R_SUCCESS); @@ -1481,6 +1471,11 @@ fcount_incr(fetchctx_t *fctx, bool force) { return (result); } +static bool +match_ptr(void *node, const void *key) { + return (node == key); +} + static void fcount_decr(fetchctx_t *fctx) { REQUIRE(fctx != NULL); @@ -1508,9 +1503,9 @@ fcount_decr(fetchctx_t *fctx) { return; } - isc_result_t result = isc_hashmap_delete(fctx->res->counters, NULL, - counter->domain->ndata, - counter->domain->length); + isc_result_t result = isc_hashmap_delete(fctx->res->counters, + dns_name_hash(counter->domain), + match_ptr, counter); INSIST(result == ISC_R_SUCCESS); fcount_logspill(fctx, counter, true); @@ -4523,8 +4518,6 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name, .fwdpolicy = dns_fwdpolicy_none, .result = ISC_R_FAILURE, .loop = loop, - .key = { .size = sizeof(unsigned int) + - sizeof(dns_rdatatype_t) + name->length }, }; isc_mem_attach(mctx, &fctx->mctx); @@ -4532,10 +4525,6 @@ fctx_create(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name, isc_mutex_init(&fctx->lock); - fctx->key.options = options; - fctx->key.type = type; - isc_ascii_lowercopy(fctx->key.name, name->ndata, name->length); - if (qc != NULL) { isc_counter_attach(qc, &fctx->qc); } else { @@ -6999,21 +6988,39 @@ ISC_REFCOUNT_TRACE_IMPL(fetchctx, fctx_destroy); ISC_REFCOUNT_IMPL(fetchctx, fctx_destroy); #endif +static uint32_t +fctx_hash(fetchctx_t *fctx) { + isc_hash32_t hash32; + isc_hash32_init(&hash32); + isc_hash32_hash(&hash32, fctx->name->ndata, fctx->name->length, false); + isc_hash32_hash(&hash32, &fctx->options, sizeof(fctx->options), true); + isc_hash32_hash(&hash32, &fctx->type, sizeof(fctx->type), true); + return (isc_hash32_finalize(&hash32)); +} + +static bool +fctx_match(void *node, const void *key) { + const fetchctx_t *fctx0 = node; + const fetchctx_t *fctx1 = key; + + return (fctx0->options == fctx1->options && + fctx0->type == fctx1->type && + dns_name_equal(fctx0->name, fctx1->name)); +} + /* Must be fctx locked */ static void release_fctx(fetchctx_t *fctx) { isc_result_t result; dns_resolver_t *res = fctx->res; - uint32_t hashval = isc_hashmap_hash(res->fctxs, fctx->key.key, - fctx->key.size); if (!fctx->hashed) { return; } RWLOCK(&res->fctxs_lock, isc_rwlocktype_write); - result = isc_hashmap_delete(res->fctxs, &hashval, fctx->key.key, - fctx->key.size); + result = isc_hashmap_delete(res->fctxs, fctx_hash(fctx), match_ptr, + fctx); INSIST(result == ISC_R_SUCCESS); fctx->hashed = false; RWUNLOCK(&res->fctxs_lock, isc_rwlocktype_write); @@ -9974,13 +9981,10 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr, res->badcache = dns_badcache_new(res->mctx); - /* This needs to be case sensitive to not lowercase options and type */ - isc_hashmap_create(view->mctx, RES_DOMAIN_HASH_BITS, - ISC_HASHMAP_CASE_SENSITIVE, &res->fctxs); + isc_hashmap_create(view->mctx, RES_DOMAIN_HASH_BITS, &res->fctxs); isc_rwlock_init(&res->fctxs_lock); - isc_hashmap_create(view->mctx, RES_DOMAIN_HASH_BITS, - ISC_HASHMAP_CASE_INSENSITIVE, &res->counters); + isc_hashmap_create(view->mctx, RES_DOMAIN_HASH_BITS, &res->counters); isc_rwlock_init(&res->counters_lock); if (dispatchv4 != NULL) { @@ -10294,34 +10298,23 @@ get_attached_fctx(dns_resolver_t *res, isc_loop_t *loop, const dns_name_t *name, unsigned int options, unsigned int depth, isc_counter_t *qc, fetchctx_t **fctxp, bool *new_fctx) { isc_result_t result; - uint32_t hashval; - fctxkey_t key = { - .size = sizeof(unsigned int) + sizeof(dns_rdatatype_t) + - name->length, + fetchctx_t key = { + .name = UNCONST(name), + .options = options, + .type = type, }; fetchctx_t *fctx = NULL; isc_rwlocktype_t locktype = isc_rwlocktype_read; - - STATIC_ASSERT(sizeof(key.options) == sizeof(options), - "key options size mismatch"); - STATIC_ASSERT(sizeof(key.type) == sizeof(type), - "key type size mismatch"); - - key.options = options; - key.type = type; - isc_ascii_lowercopy(key.name, name->ndata, name->length); - - hashval = isc_hashmap_hash(res->fctxs, key.key, key.size); + uint32_t hashval = fctx_hash(&key); again: RWLOCK(&res->fctxs_lock, locktype); - result = isc_hashmap_find(res->fctxs, &hashval, key.key, key.size, + result = isc_hashmap_find(res->fctxs, hashval, fctx_match, &key, (void **)&fctx); switch (result) { case ISC_R_SUCCESS: break; case ISC_R_NOTFOUND: - /* FIXME: pass key to fctx_create(?) */ result = fctx_create(res, loop, name, type, domain, nameservers, client, options, depth, qc, &fctx); if (result != ISC_R_SUCCESS) { @@ -10329,15 +10322,17 @@ again: } UPGRADELOCK(&res->fctxs_lock, locktype); - result = isc_hashmap_add(res->fctxs, &hashval, fctx->key.key, - fctx->key.size, fctx); + + void *found = NULL; + result = isc_hashmap_add(res->fctxs, hashval, fctx_match, fctx, + fctx, &found); if (result == ISC_R_SUCCESS) { *new_fctx = true; fctx->hashed = true; } else { fctx_done_detach(&fctx, result); - result = isc_hashmap_find(res->fctxs, &hashval, key.key, - key.size, (void **)&fctx); + fctx = found; + result = ISC_R_SUCCESS; } INSIST(result == ISC_R_SUCCESS); break; diff --git a/lib/dns/transport.c b/lib/dns/transport.c index f961f6a3b8..010bff7de0 100644 --- a/lib/dns/transport.c +++ b/lib/dns/transport.c @@ -67,6 +67,13 @@ struct dns_transport { } doh; }; +static bool +transport_match(void *node, const void *key) { + dns_transport_t *transport = node; + + return (dns_name_equal(transport->name, key)); +} + static isc_result_t list_add(dns_transport_list_t *list, const dns_name_t *name, const dns_transport_type_t type, dns_transport_t *transport) { @@ -79,8 +86,8 @@ list_add(dns_transport_list_t *list, const dns_name_t *name, transport->name = dns_fixedname_initname(&transport->fn); dns_name_copy(name, transport->name); - result = isc_hashmap_add(hm, NULL, transport->name->ndata, - transport->name->length, transport); + result = isc_hashmap_add(hm, dns_name_hash(name), transport_match, name, + transport, NULL); RWUNLOCK(&list->lock, isc_rwlocktype_write); return (result); @@ -631,8 +638,8 @@ dns_transport_find(const dns_transport_type_t type, const dns_name_t *name, hm = list->transports[type]; RWLOCK(&list->lock, isc_rwlocktype_read); - result = isc_hashmap_find(hm, NULL, name->ndata, name->length, - (void **)&transport); + result = isc_hashmap_find(hm, dns_name_hash(name), transport_match, + name, (void **)&transport); if (result == ISC_R_SUCCESS) { isc_refcount_increment(&transport->references); } @@ -655,8 +662,7 @@ dns_transport_list_new(isc_mem_t *mctx) { list->magic = TRANSPORT_LIST_MAGIC; for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) { - isc_hashmap_create(list->mctx, 10, ISC_HASHMAP_CASE_INSENSITIVE, - &list->transports[type]); + isc_hashmap_create(list->mctx, 10, &list->transports[type]); } return (list); diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index fbefeb3ba4..8b03b2dba6 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -154,13 +154,25 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) { } } +static bool +tkey_match(void *node, const void *key) { + dns_tsigkey_t *tkey = node; + + return (dns_name_equal(tkey->name, key)); +} + +static bool +match_ptr(void *node, const void *key) { + return (node == key); +} + static void rm_hashmap(dns_tsigkey_t *tkey) { REQUIRE(VALID_TSIGKEY(tkey)); REQUIRE(VALID_TSIGKEYRING(tkey->ring)); - (void)isc_hashmap_delete(tkey->ring->keys, NULL, tkey->name->ndata, - tkey->name->length); + (void)isc_hashmap_delete(tkey->ring->keys, dns_name_hash(tkey->name), + match_ptr, tkey); dns_tsigkey_detach(&tkey); } @@ -1534,8 +1546,8 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name, REQUIRE(tsigkey != NULL && *tsigkey == NULL); RWLOCK(&ring->lock, isc_rwlocktype_read); - result = isc_hashmap_find(ring->keys, NULL, name->ndata, name->length, - (void **)&key); + result = isc_hashmap_find(ring->keys, dns_name_hash(name), tkey_match, + name, (void **)&key); if (result == ISC_R_NOTFOUND) { RWUNLOCK(&ring->lock, isc_rwlocktype_read); return (result); @@ -1574,7 +1586,7 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp) { .lru = ISC_LIST_INITIALIZER, }; - isc_hashmap_create(mctx, 12, ISC_HASHMAP_CASE_INSENSITIVE, &ring->keys); + isc_hashmap_create(mctx, 12, &ring->keys); isc_rwlock_init(&ring->lock); isc_mem_attach(mctx, &ring->mctx); isc_refcount_init(&ring->references, 1); @@ -1592,8 +1604,8 @@ dns_tsigkeyring_add(dns_tsigkeyring_t *ring, dns_tsigkey_t *tkey) { REQUIRE(tkey->ring == NULL); RWLOCK(&ring->lock, isc_rwlocktype_write); - result = isc_hashmap_add(ring->keys, NULL, tkey->name->ndata, - tkey->name->length, tkey); + result = isc_hashmap_add(ring->keys, dns_name_hash(tkey->name), + tkey_match, tkey->name, tkey, NULL); if (result == ISC_R_SUCCESS) { dns_tsigkey_ref(tkey); tkey->ring = ring; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index d65680b9eb..9a87540586 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -18121,8 +18121,7 @@ zonemgr_keymgmt_init(dns_zonemgr_t *zmgr) { isc_mem_attach(zmgr->mctx, &mgmt->mctx); isc_rwlock_init(&mgmt->lock); - isc_hashmap_create(mgmt->mctx, DNS_KEYMGMT_HASH_BITS, - ISC_HASHMAP_CASE_SENSITIVE, &mgmt->table); + isc_hashmap_create(mgmt->mctx, DNS_KEYMGMT_HASH_BITS, &mgmt->table); zmgr->keymgmt = mgmt; } @@ -18144,6 +18143,13 @@ zonemgr_keymgmt_destroy(dns_zonemgr_t *zmgr) { isc_mem_putanddetach(&mgmt->mctx, mgmt, sizeof(dns_keymgmt_t)); } +static bool +kfio_match(void *node, const void *key) { + const dns_keyfileio_t *kfio = node; + + return (dns_name_equal(kfio->name, key)); +} + static void zonemgr_keymgmt_add(dns_zonemgr_t *zmgr, dns_zone_t *zone, dns_keyfileio_t **added) { @@ -18161,8 +18167,8 @@ zonemgr_keymgmt_add(dns_zonemgr_t *zmgr, dns_zone_t *zone, RWLOCK(&mgmt->lock, isc_rwlocktype_write); - result = isc_hashmap_find(mgmt->table, NULL, name->ndata, name->length, - (void **)&kfio); + result = isc_hashmap_find(mgmt->table, dns_name_hash(name), kfio_match, + name, (void **)&kfio); switch (result) { case ISC_R_SUCCESS: isc_refcount_increment(&kfio->references); @@ -18177,8 +18183,8 @@ zonemgr_keymgmt_add(dns_zonemgr_t *zmgr, dns_zone_t *zone, dns_name_copy(name, kfio->name); isc_mutex_init(&kfio->lock); - result = isc_hashmap_add(mgmt->table, NULL, kfio->name->ndata, - kfio->name->length, kfio); + result = isc_hashmap_add(mgmt->table, dns_name_hash(kfio->name), + kfio_match, kfio->name, kfio, NULL); INSIST(result == ISC_R_SUCCESS); break; default: @@ -18188,6 +18194,11 @@ zonemgr_keymgmt_add(dns_zonemgr_t *zmgr, dns_zone_t *zone, RWUNLOCK(&mgmt->lock, isc_rwlocktype_write); } +static bool +match_ptr(void *node, const void *key) { + return (node == key); +} + static void zonemgr_keymgmt_delete(dns_zonemgr_t *zmgr, dns_keyfileio_t **deleted) { REQUIRE(DNS_KEYMGMT_VALID(zmgr->keymgmt)); @@ -18206,9 +18217,9 @@ zonemgr_keymgmt_delete(dns_zonemgr_t *zmgr, dns_keyfileio_t **deleted) { kfio->magic = 0; isc_mutex_destroy(&kfio->lock); - result = isc_hashmap_delete(mgmt->table, NULL, - kfio->name->ndata, - kfio->name->length); + result = isc_hashmap_delete(mgmt->table, + dns_name_hash(kfio->name), + match_ptr, kfio); INSIST(result == ISC_R_SUCCESS); isc_mem_put(mgmt->mctx, kfio, sizeof(*kfio)); diff --git a/lib/isc/hashmap.c b/lib/isc/hashmap.c index b54e61137e..3316bac6c3 100644 --- a/lib/isc/hashmap.c +++ b/lib/isc/hashmap.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -68,11 +67,10 @@ #define HASHMAP_MAX_BITS 32U typedef struct hashmap_node { - const uint8_t *key; + const void *key; void *value; uint32_t hashval; uint32_t psl; - uint16_t keysize; } hashmap_node_t; typedef struct hashmap_table { @@ -84,12 +82,10 @@ typedef struct hashmap_table { struct isc_hashmap { unsigned int magic; - bool case_sensitive; uint8_t hindex; uint32_t hiter; /* rehashing iterator */ isc_mem_t *mctx; size_t count; - uint8_t hash_key[16]; hashmap_table_t tables[HASHMAP_NUM_TABLES]; }; @@ -101,8 +97,9 @@ struct isc_hashmap_iter { }; static isc_result_t -hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, const uint8_t *key, - const uint32_t keysize, void *value, uint8_t idx); +hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, + isc_hashmap_match_fn match, const uint8_t *key, void *value, + void **foundp, uint8_t idx); static void hashmap_rehash_one(isc_hashmap_t *hashmap); @@ -133,14 +130,11 @@ try_nexttable(const isc_hashmap_t *hashmap, uint8_t idx) { static void hashmap_node_init(hashmap_node_t *node, const uint32_t hashval, - const uint8_t *key, const uint32_t keysize, void *value) { - REQUIRE(key != NULL && keysize <= UINT16_MAX); - + const uint8_t *key, void *value) { *node = (hashmap_node_t){ .value = value, .hashval = hashval, .key = key, - .keysize = keysize, .psl = 0, }; } @@ -210,10 +204,8 @@ hashmap_free_table(isc_hashmap_t *hashmap, const uint8_t idx, bool cleanup) { } void -isc_hashmap_create(isc_mem_t *mctx, uint8_t bits, unsigned int options, - isc_hashmap_t **hashmapp) { +isc_hashmap_create(isc_mem_t *mctx, uint8_t bits, isc_hashmap_t **hashmapp) { isc_hashmap_t *hashmap = isc_mem_get(mctx, sizeof(*hashmap)); - bool case_sensitive = ((options & ISC_HASHMAP_CASE_INSENSITIVE) == 0); REQUIRE(hashmapp != NULL && *hashmapp == NULL); REQUIRE(mctx != NULL); @@ -221,15 +213,9 @@ isc_hashmap_create(isc_mem_t *mctx, uint8_t bits, unsigned int options, *hashmap = (isc_hashmap_t){ .magic = ISC_HASHMAP_MAGIC, - .hash_key = { 0, 1 }, - .case_sensitive = case_sensitive, }; isc_mem_attach(mctx, &hashmap->mctx); -#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(UNIT_TESTING) - isc_entropy_get(hashmap->hash_key, sizeof(hashmap->hash_key)); -#endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ - hashmap_create_table(hashmap, 0, bits); hashmap->magic = ISC_HASHMAP_MAGIC; @@ -259,18 +245,9 @@ isc_hashmap_destroy(isc_hashmap_t **hashmapp) { isc_mem_putanddetach(&hashmap->mctx, hashmap, sizeof(*hashmap)); } -static bool -hashmap_match(hashmap_node_t *node, const uint32_t hashval, const uint8_t *key, - const uint32_t keysize, const bool case_sensitive) { - return (node->hashval == hashval && node->keysize == keysize && - (case_sensitive - ? (memcmp(node->key, key, keysize) == 0) - : (isc_ascii_lowerequal(node->key, key, keysize)))); -} - static hashmap_node_t * hashmap_find(const isc_hashmap_t *hashmap, const uint32_t hashval, - const uint8_t *key, uint32_t keysize, uint32_t *pslp, + isc_hashmap_match_fn match, const uint8_t *key, uint32_t *pslp, uint8_t *idxp) { uint32_t hash; uint32_t psl; @@ -292,12 +269,12 @@ nexttable: break; } - if (hashmap_match(node, hashval, key, keysize, - hashmap->case_sensitive)) - { - *pslp = psl; - *idxp = idx; - return (node); + if (node->hashval == hashval) { + if (match(node->value, key)) { + *pslp = psl; + *idxp = idx; + return (node); + } } psl++; @@ -310,34 +287,15 @@ nexttable: return (NULL); } -uint32_t -isc_hashmap_hash(const isc_hashmap_t *hashmap, const void *key, - uint32_t keysize) { - REQUIRE(ISC_HASHMAP_VALID(hashmap)); - - uint32_t hashval; - - isc_halfsiphash24(hashmap->hash_key, key, keysize, - hashmap->case_sensitive, (uint8_t *)&hashval); - - return (hashval); -} - isc_result_t -isc_hashmap_find(const isc_hashmap_t *hashmap, const uint32_t *hashvalp, - const void *key, uint32_t keysize, void **valuep) { +isc_hashmap_find(const isc_hashmap_t *hashmap, const uint32_t hashval, + isc_hashmap_match_fn match, const void *key, void **valuep) { REQUIRE(ISC_HASHMAP_VALID(hashmap)); - REQUIRE(key != NULL && keysize <= UINT16_MAX); REQUIRE(valuep == NULL || *valuep == NULL); - hashmap_node_t *node = NULL; uint8_t idx = hashmap->hindex; - uint32_t hashval = (hashvalp != NULL) - ? *hashvalp - : isc_hashmap_hash(hashmap, key, keysize); - - node = hashmap_find(hashmap, hashval, key, keysize, &(uint32_t){ 0 }, - &idx); + hashmap_node_t *node = hashmap_find(hashmap, hashval, match, key, + &(uint32_t){ 0 }, &idx); if (node == NULL) { return (ISC_R_NOTFOUND); } @@ -384,7 +342,6 @@ hashmap_rehash_one(isc_hashmap_t *hashmap) { uint32_t oldsize = hashmap->tables[oldidx].size; hashmap_node_t *oldtable = hashmap->tables[oldidx].table; hashmap_node_t node; - isc_result_t result; /* Find first non-empty node */ while (hashmap->hiter < oldsize && oldtable[hashmap->hiter].key == NULL) @@ -406,8 +363,8 @@ hashmap_rehash_one(isc_hashmap_t *hashmap) { hashmap_delete_node(hashmap, &oldtable[hashmap->hiter], node.hashval, node.psl, oldidx); - result = hashmap_add(hashmap, node.hashval, node.key, node.keysize, - node.value, hashmap->hindex); + isc_result_t result = hashmap_add(hashmap, node.hashval, NULL, node.key, + node.value, NULL, hashmap->hindex); INSIST(result == ISC_R_SUCCESS); /* @@ -478,18 +435,15 @@ hashmap_rehash_start_shrink(isc_hashmap_t *hashmap) { } isc_result_t -isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t *hashvalp, - const void *key, uint32_t keysize) { +isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t hashval, + isc_hashmap_match_fn match, const void *key) { REQUIRE(ISC_HASHMAP_VALID(hashmap)); - REQUIRE(key != NULL && keysize <= UINT16_MAX); + REQUIRE(key != NULL); hashmap_node_t *node; isc_result_t result = ISC_R_NOTFOUND; uint32_t psl = 0; uint8_t idx; - uint32_t hashval = (hashvalp != NULL) - ? *hashvalp - : isc_hashmap_hash(hashmap, key, keysize); if (rehashing_in_progress(hashmap)) { hashmap_rehash_one(hashmap); @@ -501,7 +455,7 @@ isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t *hashvalp, /* Initialize idx after possible shrink start */ idx = hashmap->hindex; - node = hashmap_find(hashmap, hashval, key, keysize, &psl, &idx); + node = hashmap_find(hashmap, hashval, match, key, &psl, &idx); if (node != NULL) { INSIST(node->key != NULL); hashmap_delete_node(hashmap, node, hashval, psl, idx); @@ -532,8 +486,9 @@ under_threshold(isc_hashmap_t *hashmap) { } static isc_result_t -hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, const uint8_t *key, - const uint32_t keysize, void *value, uint8_t idx) { +hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, + isc_hashmap_match_fn match, const uint8_t *key, void *value, + void **foundp, uint8_t idx) { uint32_t hash; uint32_t psl = 0; hashmap_node_t node; @@ -543,7 +498,7 @@ hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, const uint8_t *key, hash = isc_hash_bits32(hashval, hashmap->tables[idx].hashbits); /* Initialize the node to be store to 'node' */ - hashmap_node_init(&node, hashval, key, keysize, value); + hashmap_node_init(&node, hashval, key, value); psl = 0; while (true) { @@ -556,11 +511,13 @@ hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, const uint8_t *key, break; } - if (hashmap_match(current, hashval, key, keysize, - hashmap->case_sensitive)) - { - return (ISC_R_EXISTS); + if (current->hashval == hashval) { + if (match != NULL && match(current->value, key)) { + SET_IF_NOT_NULL(foundp, current->value); + return (ISC_R_EXISTS); + } } + /* Found rich node */ if (node.psl > current->psl) { /* Swap the poor with the rich node */ @@ -591,15 +548,11 @@ hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, const uint8_t *key, } isc_result_t -isc_hashmap_add(isc_hashmap_t *hashmap, const uint32_t *hashvalp, - const void *key, uint32_t keysize, void *value) { +isc_hashmap_add(isc_hashmap_t *hashmap, const uint32_t hashval, + isc_hashmap_match_fn match, const void *key, void *value, + void **foundp) { REQUIRE(ISC_HASHMAP_VALID(hashmap)); - REQUIRE(key != NULL && keysize <= UINT16_MAX); - - isc_result_t result; - uint32_t hashval = (hashvalp != NULL) - ? *hashvalp - : isc_hashmap_hash(hashmap, key, keysize); + REQUIRE(key != NULL); if (rehashing_in_progress(hashmap)) { hashmap_rehash_one(hashmap); @@ -613,20 +566,17 @@ isc_hashmap_add(isc_hashmap_t *hashmap, const uint32_t *hashvalp, uint32_t psl; /* Look for the value in the old table */ - if (hashmap_find(hashmap, hashval, key, keysize, &psl, &fidx)) { + hashmap_node_t *found = hashmap_find(hashmap, hashval, match, + key, &psl, &fidx); + if (found != NULL) { + INSIST(found->key != NULL); + SET_IF_NOT_NULL(foundp, found->value); return (ISC_R_EXISTS); } } - result = hashmap_add(hashmap, hashval, key, keysize, value, - hashmap->hindex); - switch (result) { - case ISC_R_SUCCESS: - case ISC_R_EXISTS: - return (result); - default: - UNREACHABLE(); - } + return (hashmap_add(hashmap, hashval, match, key, value, foundp, + hashmap->hindex)); } void @@ -727,14 +677,12 @@ isc_hashmap_iter_current(isc_hashmap_iter_t *it, void **valuep) { } void -isc_hashmap_iter_currentkey(isc_hashmap_iter_t *it, const unsigned char **key, - size_t *keysize) { +isc_hashmap_iter_currentkey(isc_hashmap_iter_t *it, const unsigned char **key) { REQUIRE(it != NULL); REQUIRE(it->cur != NULL); REQUIRE(key != NULL && *key == NULL); *key = it->cur->key; - *keysize = it->cur->keysize; } unsigned int diff --git a/lib/isc/include/isc/hashmap.h b/lib/isc/include/isc/hashmap.h index 8af0c6b7e3..abd41e1fa0 100644 --- a/lib/isc/include/isc/hashmap.h +++ b/lib/isc/include/isc/hashmap.h @@ -24,7 +24,7 @@ typedef struct isc_hashmap isc_hashmap_t; typedef struct isc_hashmap_iter isc_hashmap_iter_t; -enum { ISC_HASHMAP_CASE_SENSITIVE = 0x00, ISC_HASHMAP_CASE_INSENSITIVE = 0x01 }; +typedef bool (*isc_hashmap_match_fn)(void *node, const void *key); /*% * Create hashmap at *hashmapp, using memory context and size of (1<key, key, 16) == 0); +} + +static bool +long_nodes_match(void *node0, const void *key) { + struct test_node *node = node0; + size_t len = strlen(key); + + return (memcmp(node->key, key, len) == 0); +} + +static bool +upper_nodes_match(void *node0, const void *key) { + struct test_node *node = node0; + + return (isc_ascii_lowerequal((uint8_t *)node->key, key, 16)); +} + static void test_hashmap_full(uint8_t init_bits, uintptr_t count) { isc_hashmap_t *hashmap = NULL; @@ -52,8 +74,7 @@ test_hashmap_full(uint8_t init_bits, uintptr_t count) { long_nodes = isc_mem_cget(mctx, count, sizeof(nodes[0])); upper_nodes = isc_mem_cget(mctx, count, sizeof(nodes[0])); - isc_hashmap_create(mctx, init_bits, ISC_HASHMAP_CASE_SENSITIVE, - &hashmap); + isc_hashmap_create(mctx, init_bits, &hashmap); assert_non_null(hashmap); /* @@ -62,55 +83,67 @@ test_hashmap_full(uint8_t init_bits, uintptr_t count) { */ for (size_t i = 0; i < count; i++) { /* short keys */ - snprintf(nodes[i].key, 16, "%u", (unsigned int)i); - strlcat(nodes[i].key, " key of a raw hashmap!!", 16); + snprintf((char *)nodes[i].key, 16, "%u", (unsigned int)i); + strlcat((char *)nodes[i].key, " key of a raw hashmap!!", 16); + nodes[i].hashval = isc_hash32(nodes[i].key, 16, true); /* long keys */ - snprintf(long_nodes[i].key, sizeof(long_nodes[i].key), "%u", - (unsigned int)i); - strlcat(long_nodes[i].key, " key of a raw hashmap!!", + snprintf((char *)long_nodes[i].key, sizeof(long_nodes[i].key), + "%u", (unsigned int)i); + strlcat((char *)long_nodes[i].key, " key of a raw hashmap!!", sizeof(long_nodes[i].key)); + long_nodes[i].hashval = isc_hash32( + long_nodes[i].key, + strlen((const char *)long_nodes[i].key), true); /* (some) uppercase keys */ - snprintf(upper_nodes[i].key, 16, "%u", (unsigned int)i); - strlcat(upper_nodes[i].key, " KEY of a raw hashmap!!", 16); + snprintf((char *)upper_nodes[i].key, 16, "%u", (unsigned int)i); + strlcat((char *)upper_nodes[i].key, " KEY of a raw hashmap!!", + 16); + upper_nodes[i].hashval = isc_hash32(upper_nodes[i].key, 16, + false); } /* insert short nodes */ for (size_t i = 0; i < count; i++) { - nodes[i].hashval = isc_hashmap_hash(hashmap, nodes[i].key, 16); - result = isc_hashmap_add(hashmap, &(nodes[i]).hashval, - nodes[i].key, 16, &nodes[i]); + void *f = NULL; + result = isc_hashmap_add(hashmap, nodes[i].hashval, nodes_match, + nodes[i].key, &nodes[i], &f); assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, NULL); } /* check if the short nodes were insert */ for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_find(hashmap, &(nodes[i]).hashval, - nodes[i].key, 16, &f); + result = isc_hashmap_find(hashmap, nodes[i].hashval, + nodes_match, nodes[i].key, &f); assert_int_equal(result, ISC_R_SUCCESS); assert_ptr_equal(&nodes[i], f); } /* check for double inserts */ for (size_t i = 0; i < count; i++) { - result = isc_hashmap_add(hashmap, NULL, nodes[i].key, 16, - &nodes[i]); + void *f = NULL; + result = isc_hashmap_add(hashmap, nodes[i].hashval, nodes_match, + nodes[i].key, &nodes[i], &f); assert_int_equal(result, ISC_R_EXISTS); - } - - for (size_t i = 0; i < count; i++) { - result = - isc_hashmap_add(hashmap, NULL, long_nodes[i].key, - strlen((const char *)long_nodes[i].key), - &long_nodes[i]); - assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, &nodes[i]); } for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_find(hashmap, NULL, upper_nodes[i].key, 16, + result = isc_hashmap_add(hashmap, long_nodes[i].hashval, + long_nodes_match, long_nodes[i].key, + &long_nodes[i], &f); + assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, NULL); + } + + for (size_t i = 0; i < count; i++) { + void *f = NULL; + result = isc_hashmap_find(hashmap, upper_nodes[i].hashval, + long_nodes_match, upper_nodes[i].key, &f); assert_int_equal(result, ISC_R_NOTFOUND); assert_null(f); @@ -118,45 +151,50 @@ test_hashmap_full(uint8_t init_bits, uintptr_t count) { for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_find( - hashmap, NULL, long_nodes[i].key, - strlen((const char *)long_nodes[i].key), &f); + result = isc_hashmap_find(hashmap, long_nodes[i].hashval, + long_nodes_match, long_nodes[i].key, + &f); assert_int_equal(result, ISC_R_SUCCESS); assert_ptr_equal(f, &long_nodes[i]); } for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_delete(hashmap, &nodes[i].hashval, - nodes[i].key, 16); + result = isc_hashmap_delete(hashmap, nodes[i].hashval, + nodes_match, nodes[i].key); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_hashmap_find(hashmap, NULL, nodes[i].key, 16, &f); - assert_int_equal(result, ISC_R_NOTFOUND); - assert_null(f); - } - - for (size_t i = 0; i < count; i++) { - result = isc_hashmap_add(hashmap, NULL, upper_nodes[i].key, 16, - &upper_nodes[i]); - assert_int_equal(result, ISC_R_SUCCESS); - } - - for (size_t i = 0; i < count; i++) { - void *f = NULL; - result = isc_hashmap_delete( - hashmap, NULL, long_nodes[i].key, - strlen((const char *)long_nodes[i].key)); - assert_int_equal(result, ISC_R_SUCCESS); - result = isc_hashmap_find( - hashmap, NULL, long_nodes[i].key, - strlen((const char *)long_nodes[i].key), &f); + result = isc_hashmap_find(hashmap, nodes[i].hashval, + nodes_match, nodes[i].key, &f); assert_int_equal(result, ISC_R_NOTFOUND); assert_null(f); } for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_find(hashmap, NULL, upper_nodes[i].key, 16, + result = isc_hashmap_add(hashmap, upper_nodes[i].hashval, + upper_nodes_match, upper_nodes[i].key, + &upper_nodes[i], &f); + assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, NULL); + } + + for (size_t i = 0; i < count; i++) { + void *f = NULL; + result = isc_hashmap_delete(hashmap, long_nodes[i].hashval, + long_nodes_match, + long_nodes[i].key); + assert_int_equal(result, ISC_R_SUCCESS); + result = isc_hashmap_find(hashmap, long_nodes[i].hashval, + long_nodes_match, long_nodes[i].key, + &f); + assert_int_equal(result, ISC_R_NOTFOUND); + assert_null(f); + } + + for (size_t i = 0; i < count; i++) { + void *f = NULL; + result = isc_hashmap_find(hashmap, upper_nodes[i].hashval, + upper_nodes_match, upper_nodes[i].key, &f); assert_int_equal(result, ISC_R_SUCCESS); assert_ptr_equal(f, &upper_nodes[i]); @@ -164,7 +202,8 @@ test_hashmap_full(uint8_t init_bits, uintptr_t count) { for (size_t i = 0; i < count; i++) { void *f = NULL; - result = isc_hashmap_find(hashmap, NULL, nodes[i].key, 16, &f); + result = isc_hashmap_find(hashmap, nodes[i].hashval, + nodes_match, nodes[i].key, &f); assert_int_equal(result, ISC_R_NOTFOUND); assert_null(f); } @@ -184,25 +223,26 @@ test_hashmap_iterator(void) { isc_hashmap_iter_t *iter = NULL; size_t count = 7600; uint32_t walked; - size_t tksize; test_node_t *nodes; nodes = isc_mem_cget(mctx, count, sizeof(nodes[0])); - isc_hashmap_create(mctx, HASHMAP_MIN_BITS, ISC_HASHMAP_CASE_SENSITIVE, - &hashmap); + isc_hashmap_create(mctx, HASHMAP_MIN_BITS, &hashmap); assert_non_null(hashmap); for (size_t i = 0; i < count; i++) { /* short keys */ - snprintf(nodes[i].key, 16, "%u", (unsigned int)i); - strlcat(nodes[i].key, " key of a raw hashmap!!", 16); + snprintf((char *)nodes[i].key, 16, "%u", (unsigned int)i); + strlcat((char *)nodes[i].key, " key of a raw hashmap!!", 16); + nodes[i].hashval = isc_hash32(nodes[i].key, 16, true); } for (size_t i = 0; i < count; i++) { - result = isc_hashmap_add(hashmap, NULL, nodes[i].key, 16, - &nodes[i]); + void *f = NULL; + result = isc_hashmap_add(hashmap, nodes[i].hashval, nodes_match, + nodes[i].key, &nodes[i], &f); assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, NULL); } /* We want to iterate while rehashing is in progress */ @@ -220,8 +260,7 @@ test_hashmap_iterator(void) { test_node_t *v = NULL; isc_hashmap_iter_current(iter, (void *)&v); - isc_hashmap_iter_currentkey(iter, &tkey, &tksize); - assert_int_equal(tksize, 16); + isc_hashmap_iter_currentkey(iter, &tkey); i = v - &nodes[0]; @@ -245,8 +284,7 @@ test_hashmap_iterator(void) { test_node_t *v = NULL; isc_hashmap_iter_current(iter, (void *)&v); - isc_hashmap_iter_currentkey(iter, &tkey, &tksize); - assert_int_equal(tksize, 16); + isc_hashmap_iter_currentkey(iter, &tkey); i = v - nodes; snprintf(key, 16, "%u", (unsigned int)i); @@ -273,8 +311,7 @@ test_hashmap_iterator(void) { test_node_t *v = NULL; isc_hashmap_iter_current(iter, (void *)&v); - isc_hashmap_iter_currentkey(iter, &tkey, &tksize); - assert_int_equal(tksize, 16); + isc_hashmap_iter_currentkey(iter, &tkey); i = v - nodes; snprintf(key, 16, "%u", (unsigned int)i); @@ -356,15 +393,15 @@ ISC_RUN_TEST_IMPL(isc_hashmap_hash_zero_length) { bool again = false; again: - isc_hashmap_create(mctx, 1, ISC_HASHMAP_CASE_SENSITIVE, &hashmap); + isc_hashmap_create(mctx, 1, &hashmap); - hashval = isc_hashmap_hash(hashmap, "", 0); + hashval = isc_hash32("", 0, true); isc_hashmap_destroy(&hashmap); if (hashval == 0 && !again) { /* - * We could be extremely unlock and the siphash could hash the + * We could be extremely unlucky and the siphash could hash the * zero length string to 0, so try one more time. */ again = true; @@ -374,50 +411,78 @@ again: assert_int_not_equal(hashval, 0); } +static bool +case_match(void *node0, const void *key) { + struct test_node *node = node0; + size_t len = strlen(key); + + return (memcmp(node->key, key, len) == 0); +} + +static bool +nocase_match(void *node0, const void *key) { + struct test_node *node = node0; + size_t len = strlen(key); + + return (isc_ascii_lowerequal((uint8_t *)node->key, key, len)); +} + ISC_RUN_TEST_IMPL(isc_hashmap_case) { isc_result_t result; isc_hashmap_t *hashmap = NULL; test_node_t lower = { .key = "isc_hashmap_case" }; + test_node_t same = { .key = "isc_hashmap_case" }; test_node_t upper = { .key = "ISC_HASHMAP_CASE" }; test_node_t mixed = { .key = "IsC_hAsHmAp_CaSe" }; + void *f = NULL; - isc_hashmap_create(mctx, 1, ISC_HASHMAP_CASE_SENSITIVE, &hashmap); + isc_hashmap_create(mctx, 1, &hashmap); - result = isc_hashmap_add(hashmap, NULL, lower.key, strlen(lower.key), - &lower); + result = isc_hashmap_add(hashmap, + isc_hash32(lower.key, strlen(lower.key), true), + case_match, lower.key, &lower, NULL); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_hashmap_add(hashmap, NULL, lower.key, strlen(lower.key), - &lower); + result = isc_hashmap_add(hashmap, + isc_hash32(same.key, strlen(same.key), true), + case_match, same.key, &same, NULL); assert_int_equal(result, ISC_R_EXISTS); - result = isc_hashmap_add(hashmap, NULL, upper.key, strlen(upper.key), - &upper); + result = isc_hashmap_add(hashmap, + isc_hash32(upper.key, strlen(upper.key), true), + case_match, upper.key, &upper, NULL); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_hashmap_find(hashmap, NULL, mixed.key, strlen(mixed.key), - &(void *){ NULL }); + result = isc_hashmap_find( + hashmap, isc_hash32(mixed.key, strlen(mixed.key), true), + case_match, mixed.key, &f); assert_int_equal(result, ISC_R_NOTFOUND); + assert_ptr_equal(f, NULL); isc_hashmap_destroy(&hashmap); - isc_hashmap_create(mctx, 1, ISC_HASHMAP_CASE_INSENSITIVE, &hashmap); + isc_hashmap_create(mctx, 1, &hashmap); - result = isc_hashmap_add(hashmap, NULL, lower.key, strlen(lower.key), - &lower); + result = isc_hashmap_add( + hashmap, isc_hash32(lower.key, strlen(lower.key), false), + nocase_match, lower.key, &lower, NULL); assert_int_equal(result, ISC_R_SUCCESS); - result = isc_hashmap_add(hashmap, NULL, lower.key, strlen(lower.key), - &lower); + result = isc_hashmap_add(hashmap, + isc_hash32(same.key, strlen(same.key), false), + nocase_match, same.key, &same, NULL); assert_int_equal(result, ISC_R_EXISTS); - result = isc_hashmap_add(hashmap, NULL, upper.key, strlen(upper.key), - &upper); + result = isc_hashmap_add( + hashmap, isc_hash32(upper.key, strlen(upper.key), false), + nocase_match, upper.key, &upper, NULL); assert_int_equal(result, ISC_R_EXISTS); - result = isc_hashmap_find(hashmap, NULL, mixed.key, strlen(mixed.key), - &(void *){ NULL }); + result = isc_hashmap_find( + hashmap, isc_hash32(mixed.key, strlen(mixed.key), false), + nocase_match, mixed.key, &f); assert_int_equal(result, ISC_R_SUCCESS); + assert_ptr_equal(f, &lower); isc_hashmap_destroy(&hashmap); }