]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor how ADB names and entries are stored in the dns_adb
authorEvan Hunt <each@isc.org>
Wed, 16 Mar 2022 20:58:55 +0000 (21:58 +0100)
committerOndřej Surý <ondrej@isc.org>
Wed, 30 Mar 2022 08:09:18 +0000 (10:09 +0200)
Replace adb->{names,entries} and related arrays (indexed by hashed
bucket) with a isc_ht hash tables storing the new struct
adb{name,entry}bucket_t that wraps all the variables that were
originally stored in arrays indexed by "bucket" number stored directly
in the struct dns_adb.

Previously, the task exclusive mode has been used to grow the internal
arrays used to store the named and entries objects.  The isc_ht hash
tables are now protected by the isc_rwlock instead and thus the usage of
the task exclusive mode has been removed from the dns_adb.

Co-authored-by: Ondřej Surý <ondrej@isc.org>
lib/dns/adb.c
lib/dns/include/dns/adb.h

index 9471bbfca0bb604d721ae3ef6ac9649eda9c5b96..027378136e513c34f5a85fcd3c5eb4dc9bfe9ff3 100644 (file)
@@ -24,6 +24,8 @@
 #include <limits.h>
 #include <stdbool.h>
 
+#include <isc/atomic.h>
+#include <isc/ht.h>
 #include <isc/mutexblock.h>
 #include <isc/netaddr.h>
 #include <isc/print.h>
 #define ADB_STALE_MARGIN 1800
 #endif /* ifndef ADB_STALE_MARGIN */
 
-#define FREE_ITEMS 64 /*%< free count for memory pools */
-#define FILL_COUNT 16 /*%< fill count for memory pools */
-
-#define DNS_ADB_INVALIDBUCKET (-1) /*%< invalid bucket address */
-
 #define DNS_ADB_MINADBSIZE (1024U * 1024U) /*%< 1 Megabyte */
 
 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
@@ -99,8 +96,6 @@ struct dns_adb {
        unsigned int magic;
 
        isc_mutex_t lock;
-       isc_mutex_t reflock;     /*%< Covers irefcnt, erefcnt */
-       isc_mutex_t overmemlock; /*%< Covers overmem */
        isc_mem_t *mctx;
        dns_view_t *view;
 
@@ -111,48 +106,23 @@ struct dns_adb {
        isc_interval_t tick_interval;
        int next_cleanbucket;
 
-       unsigned int irefcnt;
-       unsigned int erefcnt;
+       isc_refcount_t irefcnt;
+       isc_refcount_t erefcnt;
 
        isc_refcount_t ahrefcnt;
        isc_refcount_t nhrefcnt;
 
        /*!
         * Bucketized locks and lists for names.
-        *
-        * XXXRTH  Have a per-bucket structure that contains all of these?
-        */
-       unsigned int nnames;
-       isc_mutex_t namescntlock;
-       unsigned int namescnt;
-       dns_adbnamelist_t *names;
-       dns_adbnamelist_t *deadnames;
-       isc_mutex_t *namelocks;
-       bool *name_sd;
-       unsigned int *name_refcnt;
-
-       /*!
-        * Bucketized locks and lists for entries.
-        *
-        * XXXRTH  Have a per-bucket structure that contains all of these?
         */
-       unsigned int nentries;
-       isc_mutex_t entriescntlock;
-       unsigned int entriescnt;
-       dns_adbentrylist_t *entries;
-       dns_adbentrylist_t *deadentries;
-       isc_mutex_t *entrylocks;
-       bool *entry_sd; /*%< shutting down */
-       unsigned int *entry_refcnt;
+       /* FIXME: This needs RWLOCK */
+       isc_ht_t *namebuckets;
+       isc_ht_t *entrybuckets;
 
        isc_event_t cevent;
        bool cevent_out;
        atomic_bool shutting_down;
        isc_eventlist_t whenshutdown;
-       isc_event_t growentries;
-       bool growentries_sent;
-       isc_event_t grownames;
-       bool grownames_sent;
 
        uint32_t quota;
        uint32_t atr_freq;
@@ -172,7 +142,7 @@ struct dns_adbname {
        dns_adb_t *adb;
        unsigned int partial_result;
        unsigned int flags;
-       int lock_bucket;
+       dns_adbnamebucket_t *bucket;
        dns_name_t target;
        isc_stdtime_t expire_target;
        isc_stdtime_t expire_v4;
@@ -191,6 +161,15 @@ struct dns_adbname {
        ISC_LINK(dns_adbname_t) plink;
 };
 
+/*% dns_adbnamebucket structure */
+struct dns_adbnamebucket {
+       dns_adbnamelist_t names;
+       dns_adbnamelist_t deadnames;
+       isc_mutex_t lock;
+       bool shuttingdown;
+       isc_refcount_t references;
+};
+
 /*% The adbfetch structure */
 struct dns_adbfetch {
        unsigned int magic;
@@ -233,9 +212,10 @@ struct dns_adblameinfo {
 struct dns_adbentry {
        unsigned int magic;
 
-       int lock_bucket;
-       unsigned int refcnt;
-       unsigned int nh;
+       isc_refcount_t references;
+
+       dns_adb_t *adb;
+       dns_adbentrybucket_t *bucket;
 
        unsigned int flags;
        unsigned int srtt;
@@ -246,6 +226,7 @@ struct dns_adbentry {
        unsigned char plainto;
        unsigned char edns;
        unsigned char ednsto;
+       unsigned int nh;
 
        uint8_t mode;
        atomic_uint_fast32_t quota;
@@ -263,18 +244,29 @@ struct dns_adbentry {
         * persist until that time.  This allows entries found
         * using dns_adb_findaddrinfo() to persist for a limited time
         * even though they are not necessarily associated with a
-        * name.
+        * entry.
         */
 
        ISC_LIST(dns_adblameinfo_t) lameinfo;
        ISC_LINK(dns_adbentry_t) plink;
 };
 
+/*% dns_adbentrybucket_t structure */
+struct dns_adbentrybucket {
+       dns_adbentrylist_t entries;
+       dns_adbentrylist_t deadentries;
+       isc_mutex_t lock;
+       bool shuttingdown;
+       isc_refcount_t references;
+};
+
 /*
  * Internal functions (and prototypes).
  */
 static dns_adbname_t *
 new_adbname(dns_adb_t *, const dns_name_t *);
+static dns_adbnamebucket_t *
+new_adbnamebucket(dns_adb_t *);
 static void
 free_adbname(dns_adb_t *, dns_adbname_t **);
 static dns_adbnamehook_t *
@@ -288,7 +280,9 @@ free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
 static dns_adbentry_t *
 new_adbentry(dns_adb_t *);
 static void
-free_adbentry(dns_adb_t *, dns_adbentry_t **);
+free_adbentry(dns_adbentry_t **);
+static dns_adbentrybucket_t *
+new_adbentrybucket(dns_adb_t *adb);
 static dns_adbfind_t *
 new_adbfind(dns_adb_t *);
 static bool
@@ -300,9 +294,11 @@ new_adbfetch(dns_adb_t *);
 static void
 free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
 static dns_adbname_t *
-find_name_and_lock(dns_adb_t *, const dns_name_t *, unsigned int, int *);
+find_name_and_lock(dns_adb_t *, const dns_name_t *, unsigned int,
+                  dns_adbnamebucket_t **);
 static dns_adbentry_t *
-find_entry_and_lock(dns_adb_t *, const isc_sockaddr_t *, int *, isc_stdtime_t);
+find_entry_and_lock(dns_adb_t *, const isc_sockaddr_t *, isc_stdtime_t,
+                   dns_adbentrybucket_t **);
 static void
 dump_adb(dns_adb_t *, FILE *, bool debug, isc_stdtime_t);
 static void
@@ -319,9 +315,9 @@ inc_adb_irefcnt(dns_adb_t *);
 static void
 inc_adb_erefcnt(dns_adb_t *);
 static void
-inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, bool);
+inc_entry_refcnt(dns_adbentry_t *, bool);
 static bool
-dec_entry_refcnt(dns_adb_t *, bool, dns_adbentry_t *, bool);
+dec_entry_refcnt(dns_adbentry_t *, bool);
 static void
 violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
 static bool
@@ -333,7 +329,7 @@ clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
 static bool
 check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
 static bool
-check_expire_entry(dns_adb_t *, dns_adbentry_t **, isc_stdtime_t);
+check_expire_entry(dns_adbentry_t **, isc_stdtime_t);
 static void
 cancel_fetches_at_name(dns_adbname_t *);
 static isc_result_t
@@ -345,18 +341,18 @@ static void
 check_exit(dns_adb_t *);
 static void
 destroy(dns_adb_t *);
-static bool
+static void
 shutdown_names(dns_adb_t *);
-static bool
+static void
 shutdown_entries(dns_adb_t *);
 static void
-link_name(dns_adb_t *, int, dns_adbname_t *);
+link_name(dns_adbnamebucket_t *, dns_adbname_t *);
 static bool
-unlink_name(dns_adb_t *, dns_adbname_t *);
+unlink_name(dns_adbname_t *);
 static void
-link_entry(dns_adb_t *, int, dns_adbentry_t *);
+link_entry(dns_adbentrybucket_t *, dns_adbentry_t *);
 static bool
-unlink_entry(dns_adb_t *, dns_adbentry_t *);
+unlink_entry(dns_adbentry_t *);
 static bool
 kill_name(dns_adbname_t **, isc_eventtype_t);
 static void
@@ -543,346 +539,6 @@ ttlclamp(dns_ttl_t ttl) {
        return (ttl);
 }
 
-/*
- * Hashing is most efficient if the number of buckets is prime.
- * The sequence below is the closest previous primes to 2^n and
- * 1.5 * 2^n, for values of n from 10 to 28.  (The tables will
- * no longer grow beyond 2^28 entries.)
- */
-static const unsigned nbuckets[] = {
-       1021,      1531,     2039,     3067,      4093,      6143,
-       8191,      12281,    16381,    24571,     32749,     49193,
-       65521,     98299,    131071,   199603,    262139,    393209,
-       524287,    768431,   1048573,  1572853,   2097143,   3145721,
-       4194301,   6291449,  8388593,  12582893,  16777213,  25165813,
-       33554393,  50331599, 67108859, 100663291, 134217689, 201326557,
-       268535431, 0
-};
-
-static void
-grow_entries(isc_task_t *task, isc_event_t *ev) {
-       dns_adb_t *adb = (dns_adb_t *)ev->ev_arg;
-       dns_adbentry_t *e = NULL;
-       dns_adbentrylist_t *newdeadentries = NULL;
-       dns_adbentrylist_t *newentries = NULL;
-       bool *newentry_sd = NULL;
-       isc_mutex_t *newentrylocks = NULL;
-       isc_result_t result;
-       unsigned int *newentry_refcnt = NULL;
-       unsigned int i, n, bucket;
-
-       REQUIRE(DNS_ADB_VALID(adb));
-
-       isc_event_free(&ev);
-
-       result = isc_task_beginexclusive(task);
-       if (result != ISC_R_SUCCESS) {
-               goto check_exit;
-       }
-
-       i = 0;
-       while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i]) {
-               i++;
-       }
-       if (nbuckets[i] != 0) {
-               n = nbuckets[i];
-       } else {
-               goto done;
-       }
-
-       DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
-
-       /*
-        * Are we shutting down?
-        */
-       for (i = 0; i < adb->nentries; i++) {
-               if (adb->entry_sd[i]) {
-                       goto cleanup;
-
-                       /*
-                        * Grab all the resources we need.
-                        */
-               }
-       }
-
-       /*
-        * Grab all the resources we need.
-        */
-       newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
-       newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
-       newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
-       newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
-       newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
-
-       /*
-        * Initialise the new resources.
-        */
-       isc_mutexblock_init(newentrylocks, n);
-
-       for (i = 0; i < n; i++) {
-               ISC_LIST_INIT(newentries[i]);
-               ISC_LIST_INIT(newdeadentries[i]);
-               newentry_sd[i] = false;
-               newentry_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-
-       /*
-        * Move entries to new arrays.
-        */
-       for (i = 0; i < adb->nentries; i++) {
-               e = ISC_LIST_HEAD(adb->entries[i]);
-               while (e != NULL) {
-                       ISC_LIST_UNLINK(adb->entries[i], e, plink);
-                       bucket = isc_sockaddr_hash(&e->sockaddr, true) % n;
-                       e->lock_bucket = bucket;
-                       ISC_LIST_APPEND(newentries[bucket], e, plink);
-                       INSIST(adb->entry_refcnt[i] > 0);
-                       adb->entry_refcnt[i]--;
-                       newentry_refcnt[bucket]++;
-                       e = ISC_LIST_HEAD(adb->entries[i]);
-               }
-               e = ISC_LIST_HEAD(adb->deadentries[i]);
-               while (e != NULL) {
-                       ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
-                       bucket = isc_sockaddr_hash(&e->sockaddr, true) % n;
-                       e->lock_bucket = bucket;
-                       ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
-                       INSIST(adb->entry_refcnt[i] > 0);
-                       adb->entry_refcnt[i]--;
-                       newentry_refcnt[bucket]++;
-                       e = ISC_LIST_HEAD(adb->deadentries[i]);
-               }
-               INSIST(adb->entry_refcnt[i] == 0);
-               adb->irefcnt--;
-       }
-
-       /*
-        * Cleanup old resources.
-        */
-       isc_mutexblock_destroy(adb->entrylocks, adb->nentries);
-       isc_mem_put(adb->mctx, adb->entries,
-                   sizeof(*adb->entries) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->deadentries,
-                   sizeof(*adb->deadentries) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entrylocks,
-                   sizeof(*adb->entrylocks) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entry_sd,
-                   sizeof(*adb->entry_sd) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entry_refcnt,
-                   sizeof(*adb->entry_refcnt) * adb->nentries);
-
-       /*
-        * Install new resources.
-        */
-       adb->entries = newentries;
-       adb->deadentries = newdeadentries;
-       adb->entrylocks = newentrylocks;
-       adb->entry_sd = newentry_sd;
-       adb->entry_refcnt = newentry_refcnt;
-       adb->nentries = n;
-
-       set_adbstat(adb, adb->nentries, dns_adbstats_nentries);
-
-       /*
-        * Only on success do we set adb->growentries_sent to false.
-        * This will prevent us being continuously being called on error.
-        */
-       adb->growentries_sent = false;
-       goto done;
-
-cleanup:
-       if (newentries != NULL) {
-               isc_mem_put(adb->mctx, newentries, sizeof(*newentries) * n);
-       }
-       if (newdeadentries != NULL) {
-               isc_mem_put(adb->mctx, newdeadentries,
-                           sizeof(*newdeadentries) * n);
-       }
-       if (newentrylocks != NULL) {
-               isc_mem_put(adb->mctx, newentrylocks,
-                           sizeof(*newentrylocks) * n);
-       }
-       if (newentry_sd != NULL) {
-               isc_mem_put(adb->mctx, newentry_sd, sizeof(*newentry_sd) * n);
-       }
-       if (newentry_refcnt != NULL) {
-               isc_mem_put(adb->mctx, newentry_refcnt,
-                           sizeof(*newentry_refcnt) * n);
-       }
-done:
-       isc_task_endexclusive(task);
-
-check_exit:
-       LOCK(&adb->lock);
-       if (dec_adb_irefcnt(adb)) {
-               check_exit(adb);
-       }
-       UNLOCK(&adb->lock);
-       DP(ISC_LOG_INFO, "adb: grow_entries finished");
-}
-
-static void
-grow_names(isc_task_t *task, isc_event_t *ev) {
-       dns_adb_t *adb = ev->ev_arg;
-       dns_adbname_t *name = NULL;
-       dns_adbnamelist_t *newdeadnames = NULL;
-       dns_adbnamelist_t *newnames = NULL;
-       bool *newname_sd = NULL;
-       isc_mutex_t *newnamelocks = NULL;
-       isc_result_t result;
-       unsigned int *newname_refcnt = NULL;
-       unsigned int i, n;
-       unsigned int bucket;
-
-       REQUIRE(DNS_ADB_VALID(adb));
-
-       isc_event_free(&ev);
-
-       result = isc_task_beginexclusive(task);
-       if (result != ISC_R_SUCCESS) {
-               goto check_exit;
-       }
-
-       i = 0;
-       while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i]) {
-               i++;
-       }
-       if (nbuckets[i] != 0) {
-               n = nbuckets[i];
-       } else {
-               goto done;
-       }
-
-       DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
-
-       /*
-        * Are we shutting down?
-        */
-       for (i = 0; i < adb->nnames; i++) {
-               if (adb->name_sd[i]) {
-                       goto cleanup;
-
-                       /*
-                        * Grab all the resources we need.
-                        */
-               }
-       }
-
-       /*
-        * Grab all the resources we need.
-        */
-       newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
-       newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
-       newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
-       newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
-       newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
-
-       /*
-        * Initialise the new resources.
-        */
-       isc_mutexblock_init(newnamelocks, n);
-
-       for (i = 0; i < n; i++) {
-               ISC_LIST_INIT(newnames[i]);
-               ISC_LIST_INIT(newdeadnames[i]);
-               newname_sd[i] = false;
-               newname_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-
-       /*
-        * Move names to new arrays.
-        */
-       for (i = 0; i < adb->nnames; i++) {
-               name = ISC_LIST_HEAD(adb->names[i]);
-               while (name != NULL) {
-                       ISC_LIST_UNLINK(adb->names[i], name, plink);
-                       bucket = dns_name_fullhash(&name->name, true) % n;
-                       name->lock_bucket = bucket;
-                       ISC_LIST_APPEND(newnames[bucket], name, plink);
-                       INSIST(adb->name_refcnt[i] > 0);
-                       adb->name_refcnt[i]--;
-                       newname_refcnt[bucket]++;
-                       name = ISC_LIST_HEAD(adb->names[i]);
-               }
-               name = ISC_LIST_HEAD(adb->deadnames[i]);
-               while (name != NULL) {
-                       ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
-                       bucket = dns_name_fullhash(&name->name, true) % n;
-                       name->lock_bucket = bucket;
-                       ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
-                       INSIST(adb->name_refcnt[i] > 0);
-                       adb->name_refcnt[i]--;
-                       newname_refcnt[bucket]++;
-                       name = ISC_LIST_HEAD(adb->deadnames[i]);
-               }
-               INSIST(adb->name_refcnt[i] == 0);
-               adb->irefcnt--;
-       }
-
-       /*
-        * Cleanup old resources.
-        */
-       isc_mutexblock_destroy(adb->namelocks, adb->nnames);
-       isc_mem_put(adb->mctx, adb->names, sizeof(*adb->names) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->deadnames,
-                   sizeof(*adb->deadnames) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->namelocks,
-                   sizeof(*adb->namelocks) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->name_sd,
-                   sizeof(*adb->name_sd) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->name_refcnt,
-                   sizeof(*adb->name_refcnt) * adb->nnames);
-
-       /*
-        * Install new resources.
-        */
-       adb->names = newnames;
-       adb->deadnames = newdeadnames;
-       adb->namelocks = newnamelocks;
-       adb->name_sd = newname_sd;
-       adb->name_refcnt = newname_refcnt;
-       adb->nnames = n;
-
-       set_adbstat(adb, adb->nnames, dns_adbstats_nnames);
-
-       /*
-        * Only on success do we set adb->grownames_sent to false.
-        * This will prevent us being continuously being called on error.
-        */
-       adb->grownames_sent = false;
-       goto done;
-
-cleanup:
-       if (newnames != NULL) {
-               isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
-       }
-       if (newdeadnames != NULL) {
-               isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
-       }
-       if (newnamelocks != NULL) {
-               isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
-       }
-       if (newname_sd != NULL) {
-               isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
-       }
-       if (newname_refcnt != NULL) {
-               isc_mem_put(adb->mctx, newname_refcnt,
-                           sizeof(*newname_refcnt) * n);
-       }
-done:
-       isc_task_endexclusive(task);
-
-check_exit:
-       LOCK(&adb->lock);
-       if (dec_adb_irefcnt(adb)) {
-               check_exit(adb);
-       }
-       UNLOCK(&adb->lock);
-       DP(ISC_LOG_INFO, "adb: grow_names finished");
-}
-
 /*
  * Requires the adbname bucket be locked and that no entry buckets be locked.
  *
@@ -899,11 +555,11 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
        struct in_addr ina;
        struct in6_addr in6a;
        isc_sockaddr_t sockaddr;
-       dns_adbentry_t *foundentry = NULL; /* NO CLEAN UP! */
-       int addr_bucket;
+       dns_adbentry_t *entry = NULL; /* NO CLEAN UP! */
        bool new_addresses_added;
        dns_rdatatype_t rdtype;
        dns_adbnamehooklist_t *hookhead = NULL;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADBNAME_VALID(adbname));
 
@@ -914,7 +570,6 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
        rdtype = rdataset->type;
        REQUIRE((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
 
-       addr_bucket = DNS_ADB_INVALIDBUCKET;
        new_addresses_added = false;
 
        result = dns_rdataset_first(rdataset);
@@ -935,31 +590,28 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
 
                INSIST(nh == NULL);
                nh = new_adbnamehook(adb, NULL);
-               foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket,
-                                                now);
-               if (foundentry == NULL) {
-                       dns_adbentry_t *entry = NULL;
-
+               entry = find_entry_and_lock(adb, &sockaddr, now, &bucket);
+               if (entry == NULL) {
                        entry = new_adbentry(adb);
                        entry->sockaddr = sockaddr;
-                       entry->refcnt = 1;
                        entry->nh = 1;
 
                        nh->entry = entry;
 
-                       link_entry(adb, addr_bucket, entry);
+                       link_entry(bucket, entry);
+                       entry->nh = 1;
                } else {
                        for (anh = ISC_LIST_HEAD(*hookhead); anh != NULL;
                             anh = ISC_LIST_NEXT(anh, plink))
                        {
-                               if (anh->entry == foundentry) {
+                               if (anh->entry == entry) {
                                        break;
                                }
                        }
                        if (anh == NULL) {
-                               foundentry->refcnt++;
-                               foundentry->nh++;
-                               nh->entry = foundentry;
+                               entry->nh++;
+                               inc_entry_refcnt(entry, false);
+                               nh->entry = entry;
                        } else {
                                free_adbnamehook(adb, &nh);
                        }
@@ -973,8 +625,8 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
                result = dns_rdataset_next(rdataset);
        }
 
-       if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
-               UNLOCK(&adb->entrylocks[addr_bucket]);
+       if (bucket != NULL) {
+               UNLOCK(&bucket->lock);
        }
 
        if (rdataset->trust == dns_trust_glue ||
@@ -1017,35 +669,31 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
  */
 static bool
 kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
-       dns_adbname_t *name = NULL;
-       bool ret = false;
-       bool ret4 = false, ret6 = false;
-       int bucket;
+       dns_adbname_t *adbname = NULL;
        dns_adb_t *adb = NULL;
+       bool ret4 = false, ret6 = false;
+       bool ret = false;
 
        REQUIRE(n != NULL);
 
-       name = *n;
+       adbname = *n;
        *n = NULL;
 
-       REQUIRE(DNS_ADBNAME_VALID(name));
+       REQUIRE(DNS_ADBNAME_VALID(adbname));
 
-       adb = name->adb;
+       adb = adbname->adb;
 
        REQUIRE(DNS_ADB_VALID(adb));
 
-       DP(DEF_LEVEL, "killing name %p", name);
+       DP(DEF_LEVEL, "killing name %p", adbname);
 
        /*
         * If we're dead already, just check to see if we should go
         * away now or not.
         */
-       if (NAME_DEAD(name) && !NAME_FETCH(name)) {
-               ret = unlink_name(adb, name);
-               free_adbname(adb, &name);
-               if (ret) {
-                       ret = dec_adb_irefcnt(adb);
-               }
+       if (NAME_DEAD(adbname) && !NAME_FETCH(adbname)) {
+               ret = unlink_name(adbname);
+               free_adbname(adb, &adbname);
                return (ret);
        }
 
@@ -1053,33 +701,31 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
         * Clean up the name's various lists.  These two are destructive
         * in that they will always empty the list.
         */
-       clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
-       ret4 = clean_namehooks(adb, &name->v4);
-       ret6 = clean_namehooks(adb, &name->v6);
-       clean_target(adb, &name->target);
+       clean_finds_at_name(adbname, ev, DNS_ADBFIND_ADDRESSMASK);
+       ret4 = clean_namehooks(adb, &adbname->v4);
+       ret6 = clean_namehooks(adb, &adbname->v6);
+       clean_target(adb, &adbname->target);
        ret = (ret4 || ret6);
 
        /*
         * If fetches are running, cancel them.  If none are running, we can
         * just kill the name here.
         */
-       if (!NAME_FETCH(name)) {
-               INSIST(!ret);
-               ret = unlink_name(adb, name);
-               free_adbname(adb, &name);
-               if (ret) {
-                       ret = dec_adb_irefcnt(adb);
-               }
-       } else {
-               cancel_fetches_at_name(name);
-               if (!NAME_DEAD(name)) {
-                       bucket = name->lock_bucket;
-                       ISC_LIST_UNLINK(adb->names[bucket], name, plink);
-                       ISC_LIST_APPEND(adb->deadnames[bucket], name, plink);
-                       name->flags |= NAME_IS_DEAD;
-               }
+       if (!NAME_FETCH(adbname)) {
+               ret = unlink_name(adbname);
+               free_adbname(adb, &adbname);
+               return (ret);
        }
-       return (ret);
+
+       cancel_fetches_at_name(adbname);
+       if (!NAME_DEAD(adbname)) {
+               dns_adbnamebucket_t *bucket = adbname->bucket;
+               ISC_LIST_UNLINK(bucket->names, adbname, plink);
+               ISC_LIST_APPEND(bucket->deadnames, adbname, plink);
+               adbname->flags |= NAME_IS_DEAD;
+       }
+
+       return (false);
 }
 
 /*
@@ -1129,6 +775,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
                clean_target(adb, &name->target);
                name->expire_target = INT_MAX;
        }
+
        return (ret4 || ret6);
 }
 
@@ -1136,99 +783,82 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
  * Requires the name's bucket be locked.
  */
 static void
-link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
-       REQUIRE(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
+link_name(dns_adbnamebucket_t *bucket, dns_adbname_t *name) {
+       REQUIRE(name->bucket == NULL);
+
+       name->bucket = bucket;
 
-       ISC_LIST_PREPEND(adb->names[bucket], name, plink);
-       name->lock_bucket = bucket;
-       adb->name_refcnt[bucket]++;
+       ISC_LIST_PREPEND(bucket->names, name, plink);
+
+       isc_refcount_increment0(&bucket->references);
 }
 
 /*
  * Requires the name's bucket be locked.
  */
 static bool
-unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
-       int bucket;
-       bool ret = false;
+unlink_name(dns_adbname_t *name) {
+       dns_adbnamebucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADBNAME_VALID(name));
 
-       bucket = name->lock_bucket;
+       bucket = name->bucket;
 
-       REQUIRE(bucket != DNS_ADB_INVALIDBUCKET);
+       REQUIRE(bucket != NULL);
 
        if (NAME_DEAD(name)) {
-               ISC_LIST_UNLINK(adb->deadnames[bucket], name, plink);
+               ISC_LIST_UNLINK(bucket->deadnames, name, plink);
        } else {
-               ISC_LIST_UNLINK(adb->names[bucket], name, plink);
+               ISC_LIST_UNLINK(bucket->names, name, plink);
        }
-       name->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       INSIST(adb->name_refcnt[bucket] > 0);
-       adb->name_refcnt[bucket]--;
-       if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0) {
-               ret = true;
+
+       name->bucket = NULL;
+
+       if (isc_refcount_decrement(&bucket->references) == 1) {
+               return (bucket->shuttingdown);
        }
-       return (ret);
+       return (false);
 }
 
 /*
  * Requires the entry's bucket be locked.
  */
 static void
-link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
-       dns_adbentry_t *e = NULL;
-       int i;
+link_entry(dns_adbentrybucket_t *bucket, dns_adbentry_t *entry) {
+       REQUIRE(entry != NULL && entry->bucket == NULL);
 
-       if (isc_mem_isovermem(adb->mctx)) {
-               for (i = 0; i < 2; i++) {
-                       e = ISC_LIST_TAIL(adb->entries[bucket]);
-                       if (e == NULL) {
-                               break;
-                       }
-                       if (e->refcnt == 0) {
-                               unlink_entry(adb, e);
-                               free_adbentry(adb, &e);
-                               continue;
-                       }
-                       INSIST((e->flags & ENTRY_IS_DEAD) == 0);
-                       e->flags |= ENTRY_IS_DEAD;
-                       ISC_LIST_UNLINK(adb->entries[bucket], e, plink);
-                       ISC_LIST_PREPEND(adb->deadentries[bucket], e, plink);
-               }
-       }
+       entry->bucket = bucket;
 
-       ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
-       entry->lock_bucket = bucket;
-       adb->entry_refcnt[bucket]++;
+       ISC_LIST_PREPEND(bucket->entries, entry, plink);
+       isc_refcount_increment0(&bucket->references);
 }
 
 /*
  * Requires the entry's bucket be locked.
  */
 static bool
-unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
-       int bucket;
-       bool ret = false;
+unlink_entry(dns_adbentry_t *entry) {
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADBENTRY_VALID(entry));
 
-       bucket = entry->lock_bucket;
+       bucket = entry->bucket;
 
-       REQUIRE(bucket != DNS_ADB_INVALIDBUCKET);
+       REQUIRE(bucket != NULL);
 
        if ((entry->flags & ENTRY_IS_DEAD) != 0) {
-               ISC_LIST_UNLINK(adb->deadentries[bucket], entry, plink);
+               ISC_LIST_UNLINK(bucket->deadentries, entry, plink);
        } else {
-               ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
+               ISC_LIST_UNLINK(bucket->entries, entry, plink);
        }
-       entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       INSIST(adb->entry_refcnt[bucket] > 0);
-       adb->entry_refcnt[bucket]--;
-       if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0) {
-               ret = true;
+
+       entry->bucket = NULL;
+
+       if (isc_refcount_decrement(&bucket->references) == 1) {
+               return (bucket->shuttingdown);
        }
-       return (ret);
+
+       return (false);
 }
 
 static void
@@ -1244,90 +874,85 @@ violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
  * checked after calling this function.
  */
-static bool
+static void
 shutdown_names(dns_adb_t *adb) {
-       unsigned int bucket;
-       bool ret = false;
-       dns_adbname_t *name = NULL;
-       dns_adbname_t *next_name = NULL;
+       isc_result_t result;
+       isc_ht_iter_t *it = NULL;
 
-       for (bucket = 0; bucket < adb->nnames; bucket++) {
-               LOCK(&adb->namelocks[bucket]);
-               adb->name_sd[bucket] = true;
+       isc_ht_iter_create(adb->namebuckets, &it);
+       for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(it))
+       {
+               dns_adbnamebucket_t *bucket = NULL;
+               dns_adbname_t *name = NULL;
+               dns_adbname_t *next_name = NULL;
 
-               name = ISC_LIST_HEAD(adb->names[bucket]);
-               if (name == NULL) {
-                       /*
-                        * This bucket has no names.  We must decrement the
-                        * irefcnt ourselves, since it will not be
-                        * automatically triggered by a name being unlinked.
-                        */
-                       INSIST(!ret);
-                       ret = dec_adb_irefcnt(adb);
-               } else {
-                       /*
-                        * Run through the list.  For each name, clean up finds
-                        * found there, and cancel any fetches running.  When
-                        * all the fetches are canceled, the name will destroy
-                        * itself.
-                        */
-                       while (name != NULL) {
-                               next_name = ISC_LIST_NEXT(name, plink);
-                               INSIST(!ret);
-                               ret = kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
-                               name = next_name;
-                       }
+               isc_ht_iter_current(it, (void **)&bucket);
+               INSIST(bucket != NULL);
+
+               LOCK(&bucket->lock);
+               bucket->shuttingdown = true;
+
+               /*
+                * Run through the list.  For each name, clean up finds
+                * found there, and cancel any fetches running.  When
+                * all the fetches are canceled, the name will destroy
+                * itself.
+                */
+               name = ISC_LIST_HEAD(bucket->names);
+               while (name != NULL) {
+                       next_name = ISC_LIST_NEXT(name, plink);
+                       kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
+                       name = next_name;
                }
 
-               UNLOCK(&adb->namelocks[bucket]);
+               UNLOCK(&bucket->lock);
        }
-       return (ret);
+
+       isc_ht_iter_destroy(&it);
 }
 
 /*
  * The ADB _MUST_ be locked before calling.  Also, exit conditions must be
  * checked after calling this function.
  */
-static bool
+static void
 shutdown_entries(dns_adb_t *adb) {
-       unsigned int bucket;
-       bool ret = false;
-       dns_adbentry_t *entry = NULL;
-       dns_adbentry_t *next_entry;
+       isc_result_t result;
+       isc_ht_iter_t *iter = NULL;
 
-       for (bucket = 0; bucket < adb->nentries; bucket++) {
-               LOCK(&adb->entrylocks[bucket]);
-               adb->entry_sd[bucket] = true;
+       isc_ht_iter_create(adb->entrybuckets, &iter);
+       for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(iter))
+       {
+               dns_adbentrybucket_t *bucket = NULL;
+               dns_adbentry_t *entry = NULL;
+               dns_adbentry_t *next_entry = NULL;
 
-               entry = ISC_LIST_HEAD(adb->entries[bucket]);
-               if (adb->entry_refcnt[bucket] == 0) {
-                       /*
-                        * This bucket has no entries.  We must decrement the
-                        * irefcnt ourselves, since it will not be
-                        * automatically triggered by an entry being unlinked.
-                        */
-                       ret = dec_adb_irefcnt(adb);
-               } else {
+               isc_ht_iter_current(iter, (void **)&bucket);
+               INSIST(bucket != NULL);
+
+               LOCK(&bucket->lock);
+               bucket->shuttingdown = true;
+
+               entry = ISC_LIST_HEAD(bucket->entries);
+               while (entry != NULL) {
                        /*
                         * Run through the list.  Cleanup any entries not
                         * associated with names, and which are not in use.
                         */
-                       while (entry != NULL) {
-                               next_entry = ISC_LIST_NEXT(entry, plink);
-                               if (entry->refcnt == 0 && entry->expires != 0) {
-                                       ret = unlink_entry(adb, entry);
-                                       free_adbentry(adb, &entry);
-                                       if (ret) {
-                                               ret = dec_adb_irefcnt(adb);
-                                       }
-                               }
-                               entry = next_entry;
+                       next_entry = ISC_LIST_NEXT(entry, plink);
+                       if (entry->expires != 0) {
+                               unlink_entry(entry);
+                               dec_entry_refcnt(entry, false);
                        }
+                       entry = next_entry;
                }
 
-               UNLOCK(&adb->entrylocks[bucket]);
+               UNLOCK(&bucket->lock);
        }
-       return (ret);
+
+       isc_ht_iter_destroy(&iter);
 }
 
 /*
@@ -1350,12 +975,10 @@ cancel_fetches_at_name(dns_adbname_t *name) {
 static bool
 clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
        dns_adbentry_t *entry = NULL;
+       dns_adbentrybucket_t *bucket = NULL;
        dns_adbnamehook_t *namehook = NULL;
-       int addr_bucket;
        bool ret = false;
-       bool overmem = isc_mem_isovermem(adb->mctx);
 
-       addr_bucket = DNS_ADB_INVALIDBUCKET;
        namehook = ISC_LIST_HEAD(*namehooks);
        while (namehook != NULL) {
                INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
@@ -1367,17 +990,17 @@ clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
                if (entry != NULL) {
                        INSIST(DNS_ADBENTRY_VALID(entry));
 
-                       if (addr_bucket != entry->lock_bucket) {
-                               if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
-                                       UNLOCK(&adb->entrylocks[addr_bucket]);
+                       if (bucket != entry->bucket) {
+                               if (bucket != NULL) {
+                                       UNLOCK(&bucket->lock);
                                }
-                               addr_bucket = entry->lock_bucket;
-                               INSIST(addr_bucket != DNS_ADB_INVALIDBUCKET);
-                               LOCK(&adb->entrylocks[addr_bucket]);
+                               bucket = entry->bucket;
+                               INSIST(bucket != NULL);
+                               LOCK(&bucket->lock);
                        }
 
                        entry->nh--;
-                       ret = dec_entry_refcnt(adb, overmem, entry, false);
+                       ret = dec_entry_refcnt(entry, false);
                }
 
                /*
@@ -1390,9 +1013,10 @@ clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
                namehook = ISC_LIST_HEAD(*namehooks);
        }
 
-       if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
-               UNLOCK(&adb->entrylocks[addr_bucket]);
+       if (bucket != NULL) {
+               UNLOCK(&bucket->lock);
        }
+
        return (ret);
 }
 
@@ -1548,7 +1172,7 @@ clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
                         */
                        ISC_LIST_UNLINK(name->finds, find, plink);
                        find->adbname = NULL;
-                       find->name_bucket = DNS_ADB_INVALIDBUCKET;
+                       find->bucket = NULL;
 
                        INSIST(!FIND_EVENTSENT(find));
 
@@ -1604,12 +1228,7 @@ dec_adb_irefcnt(dns_adb_t *adb) {
        isc_task_t *etask = NULL;
        bool ret = false;
 
-       LOCK(&adb->reflock);
-
-       REQUIRE(adb->irefcnt > 0);
-       adb->irefcnt--;
-
-       if (adb->irefcnt == 0) {
+       if (isc_refcount_decrement(&adb->irefcnt) == 1) {
                event = ISC_LIST_HEAD(adb->whenshutdown);
                while (event != NULL) {
                        ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
@@ -1618,87 +1237,76 @@ dec_adb_irefcnt(dns_adb_t *adb) {
                        isc_task_sendanddetach(&etask, &event);
                        event = ISC_LIST_HEAD(adb->whenshutdown);
                }
+               if (isc_refcount_current(&adb->erefcnt) == 0) {
+                       ret = true;
+               }
        }
 
-       if (adb->irefcnt == 0 && adb->erefcnt == 0) {
-               ret = true;
-       }
-       UNLOCK(&adb->reflock);
        return (ret);
 }
 
 static void
 inc_adb_irefcnt(dns_adb_t *adb) {
-       LOCK(&adb->reflock);
-       adb->irefcnt++;
-       UNLOCK(&adb->reflock);
+       isc_refcount_increment0(&adb->irefcnt);
 }
 
 static void
 inc_adb_erefcnt(dns_adb_t *adb) {
-       LOCK(&adb->reflock);
-       adb->erefcnt++;
-       UNLOCK(&adb->reflock);
+       isc_refcount_increment(&adb->erefcnt);
 }
 
 static void
-inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, bool lock) {
-       int bucket;
-
-       bucket = entry->lock_bucket;
+inc_entry_refcnt(dns_adbentry_t *entry, bool lock) {
+       dns_adbentrybucket_t *bucket = entry->bucket;
 
        if (lock) {
-               LOCK(&adb->entrylocks[bucket]);
+               LOCK(&bucket->lock);
        }
 
-       entry->refcnt++;
+       isc_refcount_increment(&entry->references);
 
        if (lock) {
-               UNLOCK(&adb->entrylocks[bucket]);
+               UNLOCK(&bucket->lock);
        }
 }
 
 static bool
-dec_entry_refcnt(dns_adb_t *adb, bool overmem, dns_adbentry_t *entry,
-                bool lock) {
-       int bucket;
-       bool destroy_entry;
+dec_entry_refcnt(dns_adbentry_t *entry, bool lock) {
+       dns_adbentrybucket_t *bucket = NULL;
+       bool destroy_entry = false;
+       bool overmem = false;
        bool ret = false;
 
        REQUIRE(DNS_ADBENTRY_VALID(entry));
 
-       bucket = entry->lock_bucket;
+       bucket = entry->bucket;
+       overmem = isc_mem_isovermem(entry->adb->mctx);
 
        if (lock) {
-               LOCK(&adb->entrylocks[bucket]);
+               LOCK(&bucket->lock);
        }
 
-       REQUIRE(entry->refcnt > 0);
-       entry->refcnt--;
-
        destroy_entry = false;
-       if (entry->refcnt == 0 &&
-           (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
-            (entry->flags & ENTRY_IS_DEAD) != 0))
-       {
-               destroy_entry = true;
-               ret = unlink_entry(adb, entry);
+       if (isc_refcount_decrement(&entry->references) == 1) {
+               if (bucket->shuttingdown || entry->expires == 0 || overmem ||
+                   (entry->flags & ENTRY_IS_DEAD) != 0)
+               {
+                       destroy_entry = true;
+                       ret = unlink_entry(entry);
+               }
        }
 
        if (lock) {
-               UNLOCK(&adb->entrylocks[bucket]);
+               UNLOCK(&bucket->lock);
        }
 
        if (!destroy_entry) {
                return (ret);
        }
 
-       entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
+       entry->bucket = NULL;
 
-       free_adbentry(adb, &entry);
-       if (ret) {
-               ret = dec_adb_irefcnt(adb);
-       }
+       free_adbentry(&entry);
 
        return (ret);
 }
@@ -1708,40 +1316,30 @@ new_adbname(dns_adb_t *adb, const dns_name_t *dnsname) {
        dns_adbname_t *name = NULL;
 
        name = isc_mem_get(adb->mctx, sizeof(*name));
+       *name = (dns_adbname_t){
+               .adb = adb,
+               .expire_v4 = INT_MAX,
+               .expire_v6 = INT_MAX,
+               .expire_target = INT_MAX,
+               .fetch_err = FIND_ERR_UNEXPECTED,
+               .fetch6_err = FIND_ERR_UNEXPECTED,
+       };
 
        dns_name_init(&name->name, NULL);
        dns_name_dup(dnsname, adb->mctx, &name->name);
        dns_name_init(&name->target, NULL);
-       name->magic = DNS_ADBNAME_MAGIC;
-       name->adb = adb;
-       name->partial_result = 0;
-       name->flags = 0;
-       name->expire_v4 = INT_MAX;
-       name->expire_v6 = INT_MAX;
-       name->expire_target = INT_MAX;
-       name->chains = 0;
-       name->lock_bucket = DNS_ADB_INVALIDBUCKET;
+
        ISC_LIST_INIT(name->v4);
        ISC_LIST_INIT(name->v6);
-       name->fetch_a = NULL;
-       name->fetch_aaaa = NULL;
-       name->fetch_err = FIND_ERR_UNEXPECTED;
-       name->fetch6_err = FIND_ERR_UNEXPECTED;
+
        ISC_LIST_INIT(name->finds);
        ISC_LINK_INIT(name, plink);
 
-       LOCK(&adb->namescntlock);
-       adb->namescnt++;
+       name->magic = DNS_ADBNAME_MAGIC;
+
+       inc_adb_irefcnt(adb);
+
        inc_adbstats(adb, dns_adbstats_namescnt);
-       if (!adb->grownames_sent && adb->excl != NULL &&
-           adb->namescnt > (adb->nnames * 8))
-       {
-               isc_event_t *event = &adb->grownames;
-               inc_adb_irefcnt(adb);
-               isc_task_send(adb->excl, &event);
-               adb->grownames_sent = true;
-       }
-       UNLOCK(&adb->namescntlock);
 
        return (name);
 }
@@ -1760,7 +1358,7 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
        REQUIRE(!NAME_FETCH(n));
        REQUIRE(ISC_LIST_EMPTY(n->finds));
        REQUIRE(!ISC_LINK_LINKED(n, plink));
-       REQUIRE(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
+       REQUIRE(n->bucket == NULL);
        REQUIRE(n->adb == adb);
 
        n->magic = 0;
@@ -1768,10 +1366,24 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
 
        isc_mem_put(adb->mctx, n, sizeof(*n));
 
-       LOCK(&adb->namescntlock);
-       adb->namescnt--;
+       dec_adb_irefcnt(adb);
        dec_adbstats(adb, dns_adbstats_namescnt);
-       UNLOCK(&adb->namescntlock);
+}
+
+static dns_adbnamebucket_t *
+new_adbnamebucket(dns_adb_t *adb) {
+       dns_adbnamebucket_t *bucket = NULL;
+
+       bucket = isc_mem_get(adb->mctx, sizeof(*bucket));
+       *bucket = (dns_adbnamebucket_t){ .shuttingdown = false };
+
+       ISC_LIST_INIT(bucket->names);
+       ISC_LIST_INIT(bucket->deadnames);
+
+       isc_mutex_init(&bucket->lock);
+       isc_refcount_init(&bucket->references, 0);
+
+       return (bucket);
 }
 
 static dns_adbnamehook_t *
@@ -1844,60 +1456,43 @@ new_adbentry(dns_adb_t *adb) {
        dns_adbentry_t *e = NULL;
 
        e = isc_mem_get(adb->mctx, sizeof(*e));
+       *e = (dns_adbentry_t){
+               .adb = adb,
+               .srtt = isc_random_uniform(0x1f) + 1,
+       };
 
-       e->magic = DNS_ADBENTRY_MAGIC;
-       e->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       e->refcnt = 0;
-       e->nh = 0;
-       e->flags = 0;
-       e->udpsize = 0;
-       e->edns = 0;
-       e->ednsto = 0;
-       e->completed = 0;
-       e->timeouts = 0;
-       e->plain = 0;
-       e->plainto = 0;
-       e->cookie = NULL;
-       e->cookielen = 0;
-       e->srtt = (isc_random_uniform(0x1f)) + 1;
-       e->lastage = 0;
-       e->expires = 0;
+       isc_refcount_init(&e->references, 1);
        atomic_init(&e->active, 0);
-       e->mode = 0;
        atomic_init(&e->quota, adb->quota);
-       e->atr = 0.0;
+
        ISC_LIST_INIT(e->lameinfo);
        ISC_LINK_INIT(e, plink);
-       LOCK(&adb->entriescntlock);
-       adb->entriescnt++;
+
+       e->magic = DNS_ADBENTRY_MAGIC;
+
+       inc_adb_irefcnt(adb);
+
        inc_adbstats(adb, dns_adbstats_entriescnt);
-       if (!adb->growentries_sent && adb->excl != NULL &&
-           adb->entriescnt > (adb->nentries * 8))
-       {
-               isc_event_t *event = &adb->growentries;
-               inc_adb_irefcnt(adb);
-               isc_task_send(adb->excl, &event);
-               adb->growentries_sent = true;
-       }
-       UNLOCK(&adb->entriescntlock);
 
        return (e);
 }
 
 static void
-free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
+free_adbentry(dns_adbentry_t **entry) {
        dns_adbentry_t *e = NULL;
        dns_adblameinfo_t *li = NULL;
+       dns_adb_t *adb = NULL;
 
        REQUIRE(entry != NULL && DNS_ADBENTRY_VALID(*entry));
 
        e = *entry;
        *entry = NULL;
 
-       REQUIRE(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
-       REQUIRE(e->refcnt == 0);
+       REQUIRE(e->bucket == NULL);
        REQUIRE(!ISC_LINK_LINKED(e, plink));
 
+       adb = e->adb;
+
        e->magic = 0;
 
        if (e->cookie != NULL) {
@@ -1912,10 +1507,25 @@ free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
        }
 
        isc_mem_put(adb->mctx, e, sizeof(*e));
-       LOCK(&adb->entriescntlock);
-       adb->entriescnt--;
+
+       dec_adb_irefcnt(adb);
        dec_adbstats(adb, dns_adbstats_entriescnt);
-       UNLOCK(&adb->entriescntlock);
+}
+
+static dns_adbentrybucket_t *
+new_adbentrybucket(dns_adb_t *adb) {
+       dns_adbentrybucket_t *bucket = NULL;
+
+       bucket = isc_mem_get(adb->mctx, sizeof(*bucket));
+       *bucket = (dns_adbentrybucket_t){ .shuttingdown = false };
+
+       ISC_LIST_INIT(bucket->entries);
+       ISC_LIST_INIT(bucket->deadentries);
+
+       isc_mutex_init(&bucket->lock);
+       isc_refcount_init(&bucket->references, 0);
+
+       return (bucket);
 }
 
 static dns_adbfind_t *
@@ -1923,34 +1533,22 @@ new_adbfind(dns_adb_t *adb) {
        dns_adbfind_t *h = NULL;
 
        h = isc_mem_get(adb->mctx, sizeof(*h));
+       *h = (dns_adbfind_t){
+               .adb = adb,
+               .result_v4 = ISC_R_UNEXPECTED,
+               .result_v6 = ISC_R_UNEXPECTED,
+       };
        isc_refcount_increment0(&adb->ahrefcnt);
-
-       /*
-        * Public members.
-        */
-       h->magic = 0;
-       h->adb = adb;
-       h->partial_result = 0;
-       h->options = 0;
-       h->flags = 0;
-       h->result_v4 = ISC_R_UNEXPECTED;
-       h->result_v6 = ISC_R_UNEXPECTED;
        ISC_LINK_INIT(h, publink);
        ISC_LINK_INIT(h, plink);
        ISC_LIST_INIT(h->list);
-       h->adbname = NULL;
-       h->name_bucket = DNS_ADB_INVALIDBUCKET;
-
-       /*
-        * private members
-        */
        isc_mutex_init(&h->lock);
-
        ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
                       NULL, NULL, h);
-
        inc_adb_irefcnt(adb);
+
        h->magic = DNS_ADBFIND_MAGIC;
+
        return (h);
 }
 
@@ -1959,10 +1557,7 @@ new_adbfetch(dns_adb_t *adb) {
        dns_adbfetch_t *f = NULL;
 
        f = isc_mem_get(adb->mctx, sizeof(*f));
-
-       f->magic = 0;
-       f->fetch = NULL;
-
+       *f = (dns_adbfetch_t){ 0 };
        dns_rdataset_init(&f->rdataset);
 
        f->magic = DNS_ADBFETCH_MAGIC;
@@ -2000,7 +1595,7 @@ free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
        REQUIRE(!FIND_HAS_ADDRS(find));
        REQUIRE(!ISC_LINK_LINKED(find, publink));
        REQUIRE(!ISC_LINK_LINKED(find, plink));
-       REQUIRE(find->name_bucket == DNS_ADB_INVALIDBUCKET);
+       REQUIRE(find->bucket == NULL);
        REQUIRE(find->adbname == NULL);
 
        find->magic = 0;
@@ -2022,15 +1617,16 @@ new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
        dns_adbaddrinfo_t *ai = NULL;
 
        ai = isc_mem_get(adb->mctx, sizeof(*ai));
+       *ai = (dns_adbaddrinfo_t){ .srtt = entry->srtt,
+                                  .flags = entry->flags,
+                                  .entry = entry,
+                                  .dscp = -1 };
 
-       ai->magic = DNS_ADBADDRINFO_MAGIC;
+       ISC_LINK_INIT(ai, publink);
        ai->sockaddr = entry->sockaddr;
        isc_sockaddr_setport(&ai->sockaddr, port);
-       ai->srtt = entry->srtt;
-       ai->flags = entry->flags;
-       ai->entry = entry;
-       ai->dscp = -1;
-       ISC_LINK_INIT(ai, publink);
+
+       ai->magic = DNS_ADBADDRINFO_MAGIC;
 
        return (ai);
 }
@@ -2053,30 +1649,51 @@ free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
 }
 
 /*
- * Search for the name.  NOTE:  The bucket is kept locked on both
+ * Search for the name.  NOTE: The bucket is kept locked on both
  * success and failure, so it must always be unlocked by the caller!
  *
- * On the first call to this function, *bucketp must be set to
- * DNS_ADB_INVALIDBUCKET.
+ * On the first call to this function, *bucketp must be set to NULL.
  */
 static dns_adbname_t *
 find_name_and_lock(dns_adb_t *adb, const dns_name_t *name, unsigned int options,
-                  int *bucketp) {
+                  dns_adbnamebucket_t **bucketp) {
+       isc_result_t result;
        dns_adbname_t *adbname = NULL;
-       int bucket;
+       dns_adbnamebucket_t *bucket = NULL;
+
+       result = isc_ht_find(adb->namebuckets, name->ndata, name->length,
+                            (void **)&bucket);
+       if (result == ISC_R_NOTFOUND) {
+               /*
+                * Allocate a new bucket and add it to the hash table.
+                */
+               bucket = new_adbnamebucket(adb);
+               result = isc_ht_add(adb->namebuckets, name->ndata, name->length,
+                                   bucket);
+               if (result == ISC_R_EXISTS) {
+                       /*
+                        * Some other thread got in ahead of us;
+                        * redo the lookup.
+                        */
+                       isc_mem_put(adb->mctx, bucket, sizeof(*bucket));
+                       result = isc_ht_find(adb->namebuckets, name->ndata,
+                                            name->length, (void **)&bucket);
+                       INSIST(result == ISC_R_SUCCESS);
+               }
+       }
 
-       bucket = dns_name_fullhash(name, false) % adb->nnames;
+       INSIST(result == ISC_R_SUCCESS);
 
-       if (*bucketp == DNS_ADB_INVALIDBUCKET) {
-               LOCK(&adb->namelocks[bucket]);
+       if (*bucketp == NULL) {
+               LOCK(&bucket->lock);
                *bucketp = bucket;
        } else if (*bucketp != bucket) {
-               UNLOCK(&adb->namelocks[*bucketp]);
-               LOCK(&adb->namelocks[bucket]);
+               UNLOCK(&(*bucketp)->lock);
+               LOCK(&bucket->lock);
                *bucketp = bucket;
        }
 
-       adbname = ISC_LIST_HEAD(adb->names[bucket]);
+       adbname = ISC_LIST_HEAD(bucket->names);
        while (adbname != NULL) {
                if (!NAME_DEAD(adbname)) {
                        if (dns_name_equal(name, &adbname->name) &&
@@ -2097,40 +1714,60 @@ find_name_and_lock(dns_adb_t *adb, const dns_name_t *name, unsigned int options,
  * success and failure, so it must always be unlocked by the caller.
  *
  * On the first call to this function, *bucketp must be set to
- * DNS_ADB_INVALIDBUCKET.  This will cause a lock to occur.  On
- * later calls (within the same "lock path") it can be left alone, so
- * if this function is called multiple times locking is only done if
- * the bucket changes.
+ * NULL.  This will cause a lock to occur.  On later calls (within the
+ * same "lock path") it can be left alone, so if this function is
+ * called multiple times locking is only done if the bucket changes.
  */
 static dns_adbentry_t *
-find_entry_and_lock(dns_adb_t *adb, const isc_sockaddr_t *addr, int *bucketp,
-                   isc_stdtime_t now) {
+find_entry_and_lock(dns_adb_t *adb, const isc_sockaddr_t *addr,
+                   isc_stdtime_t now, dns_adbentrybucket_t **bucketp) {
+       isc_result_t result;
        dns_adbentry_t *entry = NULL, *entry_next = NULL;
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
-       bucket = isc_sockaddr_hash(addr, true) % adb->nentries;
+       result = isc_ht_find(adb->entrybuckets, (const unsigned char *)addr,
+                            sizeof(*addr), (void **)&bucket);
+       if (result == ISC_R_NOTFOUND) {
+               /*
+                * Allocate a new bucket and add it to the hash table.
+                */
+               bucket = new_adbentrybucket(adb);
+               result = isc_ht_add(adb->entrybuckets,
+                                   (const unsigned char *)addr, sizeof(*addr),
+                                   bucket);
+               if (result == ISC_R_EXISTS) {
+                       /*
+                        * Some other thread got in ahead of us;
+                        * redo the lookup.
+                        */
+                       isc_mem_put(adb->mctx, bucket, sizeof(*bucket));
+                       result = isc_ht_find(adb->entrybuckets,
+                                            (const unsigned char *)addr,
+                                            sizeof(*addr), (void **)&bucket);
+                       INSIST(result == ISC_R_SUCCESS);
+               }
+       }
 
-       if (*bucketp == DNS_ADB_INVALIDBUCKET) {
-               LOCK(&adb->entrylocks[bucket]);
+       if (*bucketp == NULL) {
+               LOCK(&bucket->lock);
                *bucketp = bucket;
        } else if (*bucketp != bucket) {
-               UNLOCK(&adb->entrylocks[*bucketp]);
-               LOCK(&adb->entrylocks[bucket]);
+               UNLOCK(&(*bucketp)->lock);
+               LOCK(&bucket->lock);
                *bucketp = bucket;
        }
 
        /* Search the list, while cleaning up expired entries. */
-       for (entry = ISC_LIST_HEAD(adb->entries[bucket]); entry != NULL;
-            entry = entry_next)
-       {
+       for (entry = ISC_LIST_HEAD(bucket->entries); entry != NULL;
+            entry = entry_next) {
                entry_next = ISC_LIST_NEXT(entry, plink);
-               (void)check_expire_entry(adb, &entry, now);
+               (void)check_expire_entry(&entry, now);
                if (entry != NULL &&
                    (entry->expires == 0 || entry->expires > now) &&
                    isc_sockaddr_equal(addr, &entry->sockaddr))
                {
-                       ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
-                       ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
+                       ISC_LIST_UNLINK(bucket->entries, entry, plink);
+                       ISC_LIST_PREPEND(bucket->entries, entry, plink);
                        return (entry);
                }
        }
@@ -2208,17 +1845,15 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
        dns_adbnamehook_t *namehook = NULL;
        dns_adbaddrinfo_t *addrinfo = NULL;
        dns_adbentry_t *entry = NULL;
-       int bucket;
-
-       bucket = DNS_ADB_INVALIDBUCKET;
+       dns_adbentrybucket_t *bucket = NULL;
 
        if ((find->options & DNS_ADBFIND_INET) != 0) {
                namehook = ISC_LIST_HEAD(name->v4);
                while (namehook != NULL) {
                        entry = namehook->entry;
-                       bucket = entry->lock_bucket;
-                       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
-                       LOCK(&adb->entrylocks[bucket]);
+                       bucket = entry->bucket;
+                       INSIST(bucket != NULL);
+                       LOCK(&bucket->lock);
 
                        if (dns_adbentry_overquota(entry)) {
                                find->options |= (DNS_ADBFIND_LAMEPRUNED |
@@ -2237,12 +1872,12 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
                        /*
                         * Found a valid entry.  Add it to the find's list.
                         */
-                       inc_entry_refcnt(adb, entry, false);
+                       inc_entry_refcnt(entry, false);
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
                        addrinfo = NULL;
                nextv4:
-                       UNLOCK(&adb->entrylocks[bucket]);
-                       bucket = DNS_ADB_INVALIDBUCKET;
+                       UNLOCK(&bucket->lock);
+                       bucket = NULL;
                        namehook = ISC_LIST_NEXT(namehook, plink);
                }
        }
@@ -2251,9 +1886,9 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
                namehook = ISC_LIST_HEAD(name->v6);
                while (namehook != NULL) {
                        entry = namehook->entry;
-                       bucket = entry->lock_bucket;
-                       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
-                       LOCK(&adb->entrylocks[bucket]);
+                       bucket = entry->bucket;
+                       INSIST(bucket != NULL);
+                       LOCK(&bucket->lock);
 
                        if (dns_adbentry_overquota(entry)) {
                                find->options |= (DNS_ADBFIND_LAMEPRUNED |
@@ -2271,18 +1906,18 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
                        /*
                         * Found a valid entry.  Add it to the find's list.
                         */
-                       inc_entry_refcnt(adb, entry, false);
+                       inc_entry_refcnt(entry, false);
                        ISC_LIST_APPEND(find->list, addrinfo, publink);
                        addrinfo = NULL;
                nextv6:
-                       UNLOCK(&adb->entrylocks[bucket]);
-                       bucket = DNS_ADB_INVALIDBUCKET;
+                       UNLOCK(&bucket->lock);
+                       bucket = NULL;
                        namehook = ISC_LIST_NEXT(namehook, plink);
                }
        }
 
-       if (bucket != DNS_ADB_INVALIDBUCKET) {
-               UNLOCK(&adb->entrylocks[bucket]);
+       if (bucket != NULL) {
+               UNLOCK(&bucket->lock);
        }
 }
 
@@ -2309,39 +1944,35 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) {
 static bool
 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
        dns_adbname_t *name = NULL;
-       bool ret = false;
 
        REQUIRE(namep != NULL && DNS_ADBNAME_VALID(*namep));
 
        name = *namep;
 
        if (NAME_HAS_V4(name) || NAME_HAS_V6(name)) {
-               return (ret);
+               return (false);
        }
        if (NAME_FETCH(name)) {
-               return (ret);
+               return (false);
        }
        if (!EXPIRE_OK(name->expire_v4, now)) {
-               return (ret);
+               return (false);
        }
        if (!EXPIRE_OK(name->expire_v6, now)) {
-               return (ret);
+               return (false);
        }
        if (!EXPIRE_OK(name->expire_target, now)) {
-               return (ret);
+               return (false);
        }
 
        /*
         * The name is empty.  Delete it.
-        */
-       *namep = NULL;
-       ret = kill_name(&name, DNS_EVENT_ADBEXPIRED);
-
-       /*
+        *
         * Our caller, or one of its callers, will be calling check_exit() at
         * some point, so we don't need to do it here.
         */
-       return (ret);
+       *namep = NULL;
+       return (kill_name(&name, DNS_EVENT_ADBEXPIRED));
 }
 
 /*%
@@ -2356,13 +1987,14 @@ check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
  * Name bucket must be locked; adb may be locked; no other locks held.
  */
 static void
-check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
+check_stale_name(dns_adb_t *adb, dns_adbnamebucket_t *bucket,
+                isc_stdtime_t now) {
        int victims, max_victims;
        dns_adbname_t *victim = NULL, *next_victim = NULL;
        bool overmem = isc_mem_isovermem(adb->mctx);
        int scans = 0;
 
-       REQUIRE(bucket != DNS_ADB_INVALIDBUCKET);
+       REQUIRE(bucket != NULL);
 
        max_victims = overmem ? 2 : 1;
 
@@ -2372,7 +2004,7 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
         * tail entries that have fetches (this should be rare, but could
         * happen).
         */
-       victim = ISC_LIST_TAIL(adb->names[bucket]);
+       victim = ISC_LIST_TAIL(bucket->names);
        for (victims = 0; victim != NULL && victims < max_victims && scans < 10;
             victim = next_victim)
        {
@@ -2404,14 +2036,15 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
  * Entry bucket must be locked; adb may be locked; no other locks held.
  */
 static bool
-check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) {
+check_expire_entry(dns_adbentry_t **entryp, isc_stdtime_t now) {
        dns_adbentry_t *entry = NULL;
        bool ret = false;
 
        REQUIRE(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
+
        entry = *entryp;
 
-       if (entry->refcnt != 0) {
+       if (isc_refcount_current(&entry->references) != 0) {
                return (ret);
        }
 
@@ -2425,11 +2058,9 @@ check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) {
        *entryp = NULL;
        DP(DEF_LEVEL, "killing entry %p", entry);
        INSIST(ISC_LINK_LINKED(entry, plink));
-       ret = unlink_entry(adb, entry);
-       free_adbentry(adb, &entry);
-       if (ret) {
-               dec_adb_irefcnt(adb);
-       }
+       ret = unlink_entry(entry);
+       dec_entry_refcnt(entry, false);
+
        return (ret);
 }
 
@@ -2437,22 +2068,21 @@ check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now) {
  * ADB must be locked, and no other locks held.
  */
 static bool
-cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
+cleanup_names(dns_adbnamebucket_t *bucket, isc_stdtime_t now) {
        dns_adbname_t *name = NULL;
-       dns_adbname_t *next_name;
        bool ret = false;
 
-       DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
+       DP(CLEAN_LEVEL, "cleaning name bucket %p", bucket);
 
-       LOCK(&adb->namelocks[bucket]);
-       if (adb->name_sd[bucket]) {
-               UNLOCK(&adb->namelocks[bucket]);
+       LOCK(&bucket->lock);
+       if (bucket->shuttingdown) {
+               UNLOCK(&bucket->lock);
                return (ret);
        }
 
-       name = ISC_LIST_HEAD(adb->names[bucket]);
+       name = ISC_LIST_HEAD(bucket->names);
        while (name != NULL) {
-               next_name = ISC_LIST_NEXT(name, plink);
+               dns_adbname_t *next_name = ISC_LIST_NEXT(name, plink);
                INSIST(!ret);
                ret = check_expire_namehooks(name, now);
                if (!ret) {
@@ -2460,7 +2090,8 @@ cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
                }
                name = next_name;
        }
-       UNLOCK(&adb->namelocks[bucket]);
+       UNLOCK(&bucket->lock);
+
        return (ret);
 }
 
@@ -2468,26 +2099,56 @@ cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
  * ADB must be locked, and no other locks held.
  */
 static bool
-cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
-       dns_adbentry_t *entry, *next_entry;
+cleanup_entries(dns_adbentrybucket_t *bucket, isc_stdtime_t now) {
+       dns_adbentry_t *entry = NULL, *next_entry = NULL;
        bool ret = false;
 
-       DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
+       DP(CLEAN_LEVEL, "cleaning entry bucket %p", bucket);
 
-       LOCK(&adb->entrylocks[bucket]);
-       entry = ISC_LIST_HEAD(adb->entries[bucket]);
+       LOCK(&bucket->lock);
+       entry = ISC_LIST_HEAD(bucket->entries);
        while (entry != NULL) {
                next_entry = ISC_LIST_NEXT(entry, plink);
                INSIST(!ret);
-               ret = check_expire_entry(adb, &entry, now);
+               ret = check_expire_entry(&entry, now);
                entry = next_entry;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
+
        return (ret);
 }
 
+static void
+clean_hashes(dns_adb_t *adb, isc_stdtime_t now) {
+       isc_result_t result;
+       isc_ht_iter_t *it = NULL;
+
+       isc_ht_iter_create(adb->namebuckets, &it);
+       for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(it))
+       {
+               dns_adbnamebucket_t *bucket = NULL;
+               isc_ht_iter_current(it, (void **)&bucket);
+               RUNTIME_CHECK(!cleanup_names(bucket, now));
+       }
+       isc_ht_iter_destroy(&it);
+
+       isc_ht_iter_create(adb->entrybuckets, &it);
+       for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(it))
+       {
+               dns_adbentrybucket_t *bucket = NULL;
+               isc_ht_iter_current(it, (void **)&bucket);
+               RUNTIME_CHECK(!cleanup_entries(bucket, now));
+       }
+       isc_ht_iter_destroy(&it);
+}
+
 static void
 destroy(dns_adb_t *adb) {
+       isc_result_t result;
+       isc_ht_iter_t *it = NULL;
+
        adb->magic = 0;
 
        isc_task_detach(&adb->task);
@@ -2495,34 +2156,35 @@ destroy(dns_adb_t *adb) {
                isc_task_detach(&adb->excl);
        }
 
-       isc_mutexblock_destroy(adb->entrylocks, adb->nentries);
-       isc_mem_put(adb->mctx, adb->entries,
-                   sizeof(*adb->entries) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->deadentries,
-                   sizeof(*adb->deadentries) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entrylocks,
-                   sizeof(*adb->entrylocks) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entry_sd,
-                   sizeof(*adb->entry_sd) * adb->nentries);
-       isc_mem_put(adb->mctx, adb->entry_refcnt,
-                   sizeof(*adb->entry_refcnt) * adb->nentries);
-
-       isc_mutexblock_destroy(adb->namelocks, adb->nnames);
-       isc_mem_put(adb->mctx, adb->names, sizeof(*adb->names) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->deadnames,
-                   sizeof(*adb->deadnames) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->namelocks,
-                   sizeof(*adb->namelocks) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->name_sd,
-                   sizeof(*adb->name_sd) * adb->nnames);
-       isc_mem_put(adb->mctx, adb->name_refcnt,
-                   sizeof(*adb->name_refcnt) * adb->nnames);
-
-       isc_mutex_destroy(&adb->reflock);
+       if (adb->namebuckets != NULL) {
+               isc_ht_iter_create(adb->namebuckets, &it);
+               for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+                    result = isc_ht_iter_delcurrent_next(it))
+               {
+                       dns_adbnamebucket_t *bucket = NULL;
+                       isc_ht_iter_current(it, (void **)&bucket);
+                       RUNTIME_CHECK(!cleanup_names(bucket, INT_MAX));
+                       isc_mem_put(adb->mctx, bucket, sizeof(*bucket));
+               }
+               isc_ht_iter_destroy(&it);
+               isc_ht_destroy(&adb->namebuckets);
+       }
+
+       if (adb->entrybuckets != NULL) {
+               isc_ht_iter_create(adb->entrybuckets, &it);
+               for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+                    result = isc_ht_iter_delcurrent_next(it))
+               {
+                       dns_adbentrybucket_t *bucket = NULL;
+                       isc_ht_iter_current(it, (void **)&bucket);
+                       RUNTIME_CHECK(!cleanup_entries(bucket, INT_MAX));
+                       isc_mem_put(adb->mctx, bucket, sizeof(*bucket));
+               }
+               isc_ht_iter_destroy(&it);
+               isc_ht_destroy(&adb->entrybuckets);
+       }
+
        isc_mutex_destroy(&adb->lock);
-       isc_mutex_destroy(&adb->overmemlock);
-       isc_mutex_destroy(&adb->entriescntlock);
-       isc_mutex_destroy(&adb->namescntlock);
 
        isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
 }
@@ -2536,7 +2198,6 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
               isc_taskmgr_t *taskmgr, dns_adb_t **newadb) {
        dns_adb_t *adb = NULL;
        isc_result_t result;
-       unsigned int i;
 
        REQUIRE(mem != NULL);
        REQUIRE(view != NULL);
@@ -2547,119 +2208,30 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
        UNUSED(timermgr);
 
        adb = isc_mem_get(mem, sizeof(dns_adb_t));
+       *adb = (dns_adb_t){
+               .erefcnt = 1,
+               .view = view,
+               .taskmgr = taskmgr,
+       };
 
        /*
         * Initialize things here that cannot fail, and especially things
         * that must be NULL for the error return to work properly.
         */
-       adb->magic = 0;
-       adb->erefcnt = 1;
-       adb->irefcnt = 0;
-       adb->task = NULL;
-       adb->excl = NULL;
-       adb->mctx = NULL;
-       adb->view = view;
-       adb->taskmgr = taskmgr;
-       adb->next_cleanbucket = 0;
        ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, 0, NULL,
                       NULL, NULL, NULL, NULL);
-       adb->cevent_out = false;
-       atomic_init(&adb->shutting_down, false);
        ISC_LIST_INIT(adb->whenshutdown);
-
-       adb->nentries = nbuckets[0];
-       adb->entriescnt = 0;
-       adb->entries = NULL;
-       adb->deadentries = NULL;
-       adb->entry_sd = NULL;
-       adb->entry_refcnt = NULL;
-       adb->entrylocks = NULL;
-       ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
-                      DNS_EVENT_ADBGROWENTRIES, grow_entries, adb, adb, NULL,
-                      NULL);
-       adb->growentries_sent = false;
-
-       adb->quota = 0;
-       adb->atr_freq = 0;
-       adb->atr_low = 0.0;
-       adb->atr_high = 0.0;
-       adb->atr_discount = 0.0;
-
-       adb->nnames = nbuckets[0];
-       adb->namescnt = 0;
-       adb->names = NULL;
-       adb->deadnames = NULL;
-       adb->name_sd = NULL;
-       adb->name_refcnt = NULL;
-       adb->namelocks = NULL;
-       ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
-                      DNS_EVENT_ADBGROWNAMES, grow_names, adb, adb, NULL,
-                      NULL);
-       adb->grownames_sent = false;
-
-       result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
-       if (result != ISC_R_SUCCESS) {
-               DP(DEF_LEVEL,
-                  "adb: task-exclusive mode unavailable, "
-                  "initializing table sizes to %u\n",
-                  nbuckets[11]);
-               adb->nentries = nbuckets[11];
-               adb->nnames = nbuckets[11];
-       }
+       atomic_init(&adb->shutting_down, false);
 
        isc_mem_attach(mem, &adb->mctx);
 
-       isc_mutex_init(&adb->lock);
-       isc_mutex_init(&adb->reflock);
-       isc_mutex_init(&adb->overmemlock);
-       isc_mutex_init(&adb->entriescntlock);
-       isc_mutex_init(&adb->namescntlock);
-
-#define ALLOCENTRY(adb, el)                                                    \
-       do {                                                                   \
-               (adb)->el = isc_mem_get((adb)->mctx,                           \
-                                       sizeof(*(adb)->el) * (adb)->nentries); \
-       } while (0)
-       ALLOCENTRY(adb, entries);
-       ALLOCENTRY(adb, deadentries);
-       ALLOCENTRY(adb, entrylocks);
-       ALLOCENTRY(adb, entry_sd);
-       ALLOCENTRY(adb, entry_refcnt);
-#undef ALLOCENTRY
-
-#define ALLOCNAME(adb, el)                                                   \
-       do {                                                                 \
-               (adb)->el = isc_mem_get((adb)->mctx,                         \
-                                       sizeof(*(adb)->el) * (adb)->nnames); \
-       } while (0)
-       ALLOCNAME(adb, names);
-       ALLOCNAME(adb, deadnames);
-       ALLOCNAME(adb, namelocks);
-       ALLOCNAME(adb, name_sd);
-       ALLOCNAME(adb, name_refcnt);
-#undef ALLOCNAME
+       isc_ht_init(&adb->namebuckets, adb->mctx, 1, ISC_HT_CASE_INSENSITIVE);
+       isc_ht_init(&adb->entrybuckets, adb->mctx, 1, ISC_HT_CASE_INSENSITIVE);
 
-       /*
-        * Initialize the bucket locks for names and elements.
-        * May as well initialize the list heads, too.
-        */
-       isc_mutexblock_init(adb->namelocks, adb->nnames);
+       result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl);
+       INSIST(result == ISC_R_SUCCESS);
 
-       for (i = 0; i < adb->nnames; i++) {
-               ISC_LIST_INIT(adb->names[i]);
-               ISC_LIST_INIT(adb->deadnames[i]);
-               adb->name_sd[i] = false;
-               adb->name_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-       for (i = 0; i < adb->nentries; i++) {
-               ISC_LIST_INIT(adb->entries[i]);
-               ISC_LIST_INIT(adb->deadentries[i]);
-               adb->entry_sd[i] = false;
-               adb->entry_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-       isc_mutexblock_init(adb->entrylocks, adb->nentries);
+       isc_mutex_init(&adb->lock);
 
        isc_refcount_init(&adb->ahrefcnt, 0);
        isc_refcount_init(&adb->nhrefcnt, 0);
@@ -2679,8 +2251,9 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
                goto fail2;
        }
 
-       set_adbstat(adb, adb->nentries, dns_adbstats_nentries);
-       set_adbstat(adb, adb->nnames, dns_adbstats_nnames);
+       set_adbstat(adb, isc_ht_count(adb->namebuckets), dns_adbstats_nnames);
+       set_adbstat(adb, isc_ht_count(adb->entrybuckets),
+                   dns_adbstats_nentries);
 
        /*
         * Normal return.
@@ -2694,55 +2267,10 @@ fail2:
                isc_task_detach(&adb->task);
        }
 
-       /* clean up entrylocks */
-       isc_mutexblock_destroy(adb->entrylocks, adb->nentries);
-       isc_mutexblock_destroy(adb->namelocks, adb->nnames);
-
-       if (adb->entries != NULL) {
-               isc_mem_put(adb->mctx, adb->entries,
-                           sizeof(*adb->entries) * adb->nentries);
-       }
-       if (adb->deadentries != NULL) {
-               isc_mem_put(adb->mctx, adb->deadentries,
-                           sizeof(*adb->deadentries) * adb->nentries);
-       }
-       if (adb->entrylocks != NULL) {
-               isc_mem_put(adb->mctx, adb->entrylocks,
-                           sizeof(*adb->entrylocks) * adb->nentries);
-       }
-       if (adb->entry_sd != NULL) {
-               isc_mem_put(adb->mctx, adb->entry_sd,
-                           sizeof(*adb->entry_sd) * adb->nentries);
-       }
-       if (adb->entry_refcnt != NULL) {
-               isc_mem_put(adb->mctx, adb->entry_refcnt,
-                           sizeof(*adb->entry_refcnt) * adb->nentries);
-       }
-       if (adb->names != NULL) {
-               isc_mem_put(adb->mctx, adb->names,
-                           sizeof(*adb->names) * adb->nnames);
-       }
-       if (adb->deadnames != NULL) {
-               isc_mem_put(adb->mctx, adb->deadnames,
-                           sizeof(*adb->deadnames) * adb->nnames);
-       }
-       if (adb->namelocks != NULL) {
-               isc_mem_put(adb->mctx, adb->namelocks,
-                           sizeof(*adb->namelocks) * adb->nnames);
-       }
-       if (adb->name_sd != NULL) {
-               isc_mem_put(adb->mctx, adb->name_sd,
-                           sizeof(*adb->name_sd) * adb->nnames);
-       }
-       if (adb->name_refcnt != NULL) {
-               isc_mem_put(adb->mctx, adb->name_refcnt,
-                           sizeof(*adb->name_refcnt) * adb->nnames);
+       if (adb->namebuckets != NULL) {
+               isc_ht_destroy(&adb->namebuckets);
        }
 
-       isc_mutex_destroy(&adb->namescntlock);
-       isc_mutex_destroy(&adb->entriescntlock);
-       isc_mutex_destroy(&adb->overmemlock);
-       isc_mutex_destroy(&adb->reflock);
        isc_mutex_destroy(&adb->lock);
        if (adb->excl != NULL) {
                isc_task_detach(&adb->excl);
@@ -2764,32 +2292,25 @@ dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
 void
 dns_adb_detach(dns_adb_t **adbx) {
        dns_adb_t *adb = NULL;
-       bool need_exit_check;
 
        REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
 
        adb = *adbx;
        *adbx = NULL;
 
-       LOCK(&adb->reflock);
-       INSIST(adb->erefcnt > 0);
-       adb->erefcnt--;
-       need_exit_check = (adb->erefcnt == 0 && adb->irefcnt == 0);
-       UNLOCK(&adb->reflock);
-
-       if (need_exit_check) {
-               LOCK(&adb->lock);
-               INSIST(atomic_load(&adb->shutting_down));
-               check_exit(adb);
-               UNLOCK(&adb->lock);
+       if (isc_refcount_decrement(&adb->erefcnt) == 1) {
+               if (isc_refcount_current(&adb->irefcnt) == 0) {
+                       LOCK(&adb->lock);
+                       INSIST(atomic_load(&adb->shutting_down));
+                       check_exit(adb);
+                       UNLOCK(&adb->lock);
+               }
        }
 }
 
 void
 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
-       isc_task_t *tclone = NULL;
        isc_event_t *event = NULL;
-       bool zeroirefcnt;
 
        /*
         * Send '*eventp' to 'task' when 'adb' has shutdown.
@@ -2802,11 +2323,9 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
        *eventp = NULL;
 
        LOCK(&adb->lock);
-       LOCK(&adb->reflock);
-
-       zeroirefcnt = (adb->irefcnt == 0);
 
-       if (atomic_load(&adb->shutting_down) && zeroirefcnt &&
+       if (atomic_load(&adb->shutting_down) &&
+           isc_refcount_current(&adb->irefcnt) == 0 &&
            isc_refcount_current(&adb->ahrefcnt) == 0)
        {
                /*
@@ -2815,13 +2334,11 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
                event->ev_sender = adb;
                isc_task_send(task, &event);
        } else {
-               tclone = NULL;
-               isc_task_attach(task, &tclone);
-               event->ev_sender = tclone;
+               isc_task_attach(task, &(isc_task_t *){ NULL });
+               event->ev_sender = task;
                ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
        }
 
-       UNLOCK(&adb->reflock);
        UNLOCK(&adb->lock);
 }
 
@@ -2836,8 +2353,8 @@ shutdown_stage2(isc_task_t *task, isc_event_t *event) {
        LOCK(&adb->lock);
        INSIST(atomic_load(&adb->shutting_down));
        adb->cevent_out = false;
-       (void)shutdown_names(adb);
-       (void)shutdown_entries(adb);
+       shutdown_names(adb);
+       shutdown_entries(adb);
        if (dec_adb_irefcnt(adb)) {
                check_exit(adb);
        }
@@ -2881,7 +2398,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
                   dns_adbfind_t **findp) {
        dns_adbfind_t *find = NULL;
        dns_adbname_t *adbname = NULL;
-       int bucket;
+       dns_adbnamebucket_t *bucket = NULL;
        bool want_event = true;
        bool start_at_zone = false;
        bool alias = false;
@@ -2959,10 +2476,9 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
        /*
         * Try to see if we know anything about this name at all.
         */
-       bucket = DNS_ADB_INVALIDBUCKET;
        adbname = find_name_and_lock(adb, name, find->options, &bucket);
-       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
-       if (adb->name_sd[bucket]) {
+       INSIST(bucket != NULL);
+       if (bucket->shuttingdown) {
                DP(DEF_LEVEL, "dns_adb_createfind: returning "
                              "ISC_R_SHUTTINGDOWN");
                RUNTIME_CHECK(!free_adbfind(adb, &find));
@@ -2981,7 +2497,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
                check_stale_name(adb, bucket, now);
 
                adbname = new_adbname(adb, name);
-               link_name(adb, bucket, adbname);
+               link_name(bucket, adbname);
                if (FIND_HINTOK(find)) {
                        adbname->flags |= NAME_HINT_OK;
                }
@@ -2993,8 +2509,8 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
                }
        } else {
                /* Move this name forward in the LRU list */
-               ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
-               ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
+               ISC_LIST_UNLINK(bucket->names, adbname, plink);
+               ISC_LIST_PREPEND(bucket->names, adbname, plink);
        }
        adbname->last_used = now;
 
@@ -3182,7 +2698,7 @@ post_copy:
        if (want_event) {
                bool empty;
                find->adbname = adbname;
-               find->name_bucket = bucket;
+               find->bucket = bucket;
                empty = ISC_LIST_EMPTY(adbname->finds);
                ISC_LIST_APPEND(adbname->finds, find, plink);
                find->query_pending = (query_pending & wanted_addresses);
@@ -3232,7 +2748,7 @@ out:
                *findp = find;
        }
 
-       UNLOCK(&adb->namelocks[bucket]);
+       UNLOCK(&bucket->lock);
        return (result);
 }
 
@@ -3241,9 +2757,7 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
        dns_adbfind_t *find = NULL;
        dns_adbentry_t *entry = NULL;
        dns_adbaddrinfo_t *ai = NULL;
-       int bucket;
        dns_adb_t *adb = NULL;
-       bool overmem;
 
        REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
 
@@ -3255,12 +2769,10 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
        DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
 
        adb = find->adb;
-       REQUIRE(DNS_ADB_VALID(adb));
 
+       REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(FIND_EVENTFREED(find));
-
-       bucket = find->name_bucket;
-       INSIST(bucket == DNS_ADB_INVALIDBUCKET);
+       REQUIRE(find->bucket == NULL);
 
        UNLOCK(&find->lock);
 
@@ -3269,14 +2781,14 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
         * Return the find to the memory pool, and decrement the adb's
         * reference count.
         */
-       overmem = isc_mem_isovermem(adb->mctx);
        ai = ISC_LIST_HEAD(find->list);
        while (ai != NULL) {
                ISC_LIST_UNLINK(find->list, ai, publink);
                entry = ai->entry;
                ai->entry = NULL;
+
                INSIST(DNS_ADBENTRY_VALID(entry));
-               RUNTIME_CHECK(!dec_entry_refcnt(adb, overmem, entry, true));
+               RUNTIME_CHECK(!dec_entry_refcnt(entry, true));
                free_adbaddrinfo(adb, &ai);
                ai = ISC_LIST_HEAD(find->list);
        }
@@ -3300,8 +2812,8 @@ dns_adb_cancelfind(dns_adbfind_t *find) {
        isc_event_t *ev = NULL;
        isc_task_t *task = NULL;
        dns_adb_t *adb = NULL;
-       int bucket;
-       int unlock_bucket;
+       dns_adbnamebucket_t *bucket = NULL;
+       dns_adbnamebucket_t *unlock_bucket = NULL;
 
        LOCK(&find->lock);
 
@@ -3313,8 +2825,8 @@ dns_adb_cancelfind(dns_adbfind_t *find) {
        REQUIRE(!FIND_EVENTFREED(find));
        REQUIRE(FIND_WANTEVENT(find));
 
-       bucket = find->name_bucket;
-       if (bucket == DNS_ADB_INVALIDBUCKET) {
+       bucket = find->bucket;
+       if (bucket == NULL) {
                goto cleanup;
        }
 
@@ -3322,15 +2834,15 @@ dns_adb_cancelfind(dns_adbfind_t *find) {
         * We need to get the adbname's lock to unlink the find.
         */
        unlock_bucket = bucket;
-       violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
-       bucket = find->name_bucket;
-       if (bucket != DNS_ADB_INVALIDBUCKET) {
+       violate_locking_hierarchy(&find->lock, &unlock_bucket->lock);
+       bucket = find->bucket;
+       if (bucket != NULL) {
                ISC_LIST_UNLINK(find->adbname->finds, find, plink);
                find->adbname = NULL;
-               find->name_bucket = DNS_ADB_INVALIDBUCKET;
+               find->bucket = NULL;
        }
-       UNLOCK(&adb->namelocks[unlock_bucket]);
-       bucket = DNS_ADB_INVALIDBUCKET;
+       UNLOCK(&unlock_bucket->lock);
+       bucket = NULL;
        POST(bucket);
 
 cleanup:
@@ -3356,7 +2868,6 @@ cleanup:
 
 void
 dns_adb_dump(dns_adb_t *adb, FILE *f) {
-       unsigned int i;
        isc_stdtime_t now;
 
        REQUIRE(DNS_ADB_VALID(adb));
@@ -3371,14 +2882,7 @@ dns_adb_dump(dns_adb_t *adb, FILE *f) {
 
        LOCK(&adb->lock);
        isc_stdtime_get(&now);
-
-       for (i = 0; i < adb->nnames; i++) {
-               RUNTIME_CHECK(!cleanup_names(adb, i, now));
-       }
-       for (i = 0; i < adb->nentries; i++) {
-               RUNTIME_CHECK(!cleanup_entries(adb, i, now));
-       }
-
+       clean_hashes(adb, now);
        dump_adb(adb, f, false, now);
        UNLOCK(&adb->lock);
 }
@@ -3393,55 +2897,43 @@ dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
 
 static void
 dump_adb(dns_adb_t *adb, FILE *f, bool debug, isc_stdtime_t now) {
-       dns_adbname_t *name = NULL;
-       dns_adbentry_t *entry = NULL;
+       isc_result_t result;
+       isc_ht_iter_t *it = NULL;
 
        fprintf(f, ";\n; Address database dump\n;\n");
        fprintf(f, "; [edns success/timeout]\n");
        fprintf(f, "; [plain success/timeout]\n;\n");
        if (debug) {
-               LOCK(&adb->reflock);
                fprintf(f,
-                       "; addr %p, erefcnt %u, irefcnt %u, finds out "
+                       "; addr %p, erefcnt %" PRIuFAST32
+                       ", irefcnt %" PRIuFAST32 ", finds out "
                        "%" PRIuFAST32 "\n",
-                       adb, adb->erefcnt, adb->irefcnt,
+                       adb, isc_refcount_current(&adb->erefcnt),
+                       isc_refcount_current(&adb->irefcnt),
                        isc_refcount_current(&adb->nhrefcnt));
-               UNLOCK(&adb->reflock);
        }
 
-/*
- * In TSAN mode we need to lock the locks individually, as TSAN
- * can't handle more than 64 locks locked by one thread.
- * In regular mode we want a consistent dump so we need to
- * lock everything.
- */
-#ifndef __SANITIZE_THREAD__
-       for (size_t i = 0; i < adb->nnames; i++) {
-               LOCK(&adb->namelocks[i]);
-       }
-       for (size_t i = 0; i < adb->nentries; i++) {
-               LOCK(&adb->entrylocks[i]);
-       }
-#endif /* ifndef __SANITIZE_THREAD__ */
+       isc_ht_iter_create(adb->namebuckets, &it);
+       for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(it))
+       {
+               dns_adbnamebucket_t *bucket = NULL;
+               dns_adbname_t *name = NULL;
 
-       /*
-        * Dump the names
-        */
-       for (size_t i = 0; i < adb->nnames; i++) {
-#ifdef __SANITIZE_THREAD__
-               LOCK(&adb->namelocks[i]);
-#endif /* ifdef __SANITIZE_THREAD__ */
-               name = ISC_LIST_HEAD(adb->names[i]);
-               if (name == NULL) {
-#ifdef __SANITIZE_THREAD__
-                       UNLOCK(&adb->namelocks[i]);
-#endif /* ifdef __SANITIZE_THREAD__ */
-                       continue;
-               }
+               isc_ht_iter_current(it, (void **)&bucket);
+               LOCK(&bucket->lock);
                if (debug) {
-                       fprintf(f, "; bucket %zu\n", i);
+                       static int n = 0;
+                       fprintf(f, "; bucket %d\n", n);
+                       n++;
                }
-               for (; name != NULL; name = ISC_LIST_NEXT(name, plink)) {
+
+               /*
+                * Dump the names
+                */
+               for (name = ISC_LIST_HEAD(bucket->names); name != NULL;
+                    name = ISC_LIST_NEXT(name, plink))
+               {
                        if (debug) {
                                fprintf(f, "; name %p (flags %08x)\n", name,
                                        name->flags);
@@ -3473,40 +2965,32 @@ dump_adb(dns_adb_t *adb, FILE *f, bool debug, isc_stdtime_t now) {
                                print_find_list(f, name);
                        }
                }
-#ifdef __SANITIZE_THREAD__
-               UNLOCK(&adb->namelocks[i]);
-#endif /* ifdef __SANITIZE_THREAD__ */
+               UNLOCK(&bucket->lock);
        }
+       isc_ht_iter_destroy(&it);
 
        fprintf(f, ";\n; Unassociated entries\n;\n");
 
-       for (size_t i = 0; i < adb->nentries; i++) {
-#ifdef __SANITIZE_THREAD__
-               LOCK(&adb->entrylocks[i]);
-#endif /* ifdef __SANITIZE_THREAD__ */
-               entry = ISC_LIST_HEAD(adb->entries[i]);
-               while (entry != NULL) {
+       isc_ht_iter_create(adb->entrybuckets, &it);
+       for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(it))
+       {
+               dns_adbentrybucket_t *bucket = NULL;
+               dns_adbentry_t *entry = NULL;
+
+               isc_ht_iter_current(it, (void **)&bucket);
+               LOCK(&bucket->lock);
+
+               for (entry = ISC_LIST_HEAD(bucket->entries); entry != NULL;
+                    entry = ISC_LIST_NEXT(entry, plink))
+               {
                        if (entry->nh == 0) {
                                dump_entry(f, adb, entry, debug, now);
                        }
-                       entry = ISC_LIST_NEXT(entry, plink);
                }
-#ifdef __SANITIZE_THREAD__
-               UNLOCK(&adb->entrylocks[i]);
-#endif /* ifdef __SANITIZE_THREAD__ */
-       }
-
-#ifndef __SANITIZE_THREAD__
-       /*
-        * Unlock everything
-        */
-       for (ssize_t i = adb->nentries - 1; i >= 0; i--) {
-               UNLOCK(&adb->entrylocks[i]);
+               UNLOCK(&bucket->lock);
        }
-       for (ssize_t i = adb->nnames - 1; i >= 0; i--) {
-               UNLOCK(&adb->namelocks[i]);
-       }
-#endif /* ifndef __SANITIZE_THREAD__ */
+       isc_ht_iter_destroy(&it);
 }
 
 static void
@@ -3521,7 +3005,8 @@ dump_entry(FILE *f, dns_adb_t *adb, dns_adbentry_t *entry, bool debug,
        isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
 
        if (debug) {
-               fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
+               fprintf(f, ";\t%p: refcnt %" PRIuFAST32 "\n", entry,
+                       isc_refcount_current(&entry->references));
        }
 
        fprintf(f,
@@ -3580,8 +3065,8 @@ dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
        fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
                find->query_pending, find->partial_result, find->options,
                find->flags);
-       fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
-               find->name_bucket, find->adbname, find->event.ev_sender);
+       fprintf(f, ";\tname bucket %p, name %p, event sender %p\n",
+               find->bucket, find->adbname, find->event.ev_sender);
 
        ai = ISC_LIST_HEAD(find->list);
        if (ai != NULL) {
@@ -3813,11 +3298,11 @@ dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype) {
 
 static void
 fetch_callback(isc_task_t *task, isc_event_t *ev) {
-       dns_fetchevent_t *dev = NULL;
+       dns_fetchevent_t *dev = (dns_fetchevent_t *)ev;
        dns_adbname_t *name = NULL;
        dns_adb_t *adb = NULL;
        dns_adbfetch_t *fetch = NULL;
-       int bucket;
+       dns_adbnamebucket_t *bucket = NULL;
        isc_eventtype_t ev_status;
        isc_stdtime_t now;
        isc_result_t result;
@@ -3834,8 +3319,8 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
 
        REQUIRE(DNS_ADB_VALID(adb));
 
-       bucket = name->lock_bucket;
-       LOCK(&adb->namelocks[bucket]);
+       bucket = name->bucket;
+       LOCK(&bucket->lock);
 
        INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
        address_type = 0;
@@ -3879,7 +3364,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
 
                want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
 
-               UNLOCK(&adb->namelocks[bucket]);
+               UNLOCK(&bucket->lock);
 
                if (want_check_exit) {
                        LOCK(&adb->lock);
@@ -3996,7 +3481,7 @@ out:
 
        clean_finds_at_name(name, ev_status, address_type);
 
-       UNLOCK(&adb->namelocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 static isc_result_t
@@ -4083,16 +3568,16 @@ isc_result_t
 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
                 const dns_name_t *qname, dns_rdatatype_t qtype,
                 isc_stdtime_t expire_time) {
-       dns_adblameinfo_t *li = NULL;
-       int bucket;
        isc_result_t result = ISC_R_SUCCESS;
+       dns_adblameinfo_t *li = NULL;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
        REQUIRE(qname != NULL);
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
        li = ISC_LIST_HEAD(addr->entry->lameinfo);
        while (li != NULL &&
               (li->qtype != qtype || !dns_name_equal(qname, &li->qname))) {
@@ -4108,46 +3593,46 @@ dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
        li->lame_timer = expire_time;
 
        ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
-unlock:
-       UNLOCK(&adb->entrylocks[bucket]);
 
+unlock:
+       UNLOCK(&bucket->lock);
        return (result);
 }
 
 void
 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int rtt,
                   unsigned int factor) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
        isc_stdtime_t now = 0;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
        REQUIRE(factor <= 10);
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        if (addr->entry->expires == 0 || factor == DNS_ADB_RTTADJAGE) {
                isc_stdtime_get(&now);
        }
        adjustsrtt(addr, rtt, factor, now);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 void
 dns_adb_agesrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr, isc_stdtime_t now) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        adjustsrtt(addr, 0, DNS_ADB_RTTADJAGE, now);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 static void
@@ -4181,7 +3666,7 @@ adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt, unsigned int factor,
 void
 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int bits,
                    unsigned int mask) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
        isc_stdtime_t now;
 
        REQUIRE(DNS_ADB_VALID(adb));
@@ -4190,8 +3675,8 @@ dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int bits,
        REQUIRE((bits & ENTRY_IS_DEAD) == 0);
        REQUIRE((mask & ENTRY_IS_DEAD) == 0);
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
        if (addr->entry->expires == 0) {
@@ -4205,7 +3690,7 @@ dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int bits,
         */
        addr->flags = (addr->flags & ~mask) | (bits & mask);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 /*
@@ -4289,13 +3774,13 @@ maybe_adjust_quota(dns_adb_t *adb, dns_adbaddrinfo_t *addr, bool timeout) {
 
 void
 dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        maybe_adjust_quota(adb, addr, false);
 
@@ -4306,18 +3791,18 @@ dns_adb_plainresponse(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
                addr->entry->plain >>= 1;
                addr->entry->plainto >>= 1;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 void
 dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        maybe_adjust_quota(adb, addr, true);
 
@@ -4328,18 +3813,18 @@ dns_adb_timeout(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
                addr->entry->plain >>= 1;
                addr->entry->plainto >>= 1;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 void
 dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        maybe_adjust_quota(adb, addr, true);
 
@@ -4350,18 +3835,18 @@ dns_adb_ednsto(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
                addr->entry->plain >>= 1;
                addr->entry->plainto >>= 1;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 void
 dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
        if (size < 512U) {
                size = 512U;
        }
@@ -4378,21 +3863,21 @@ dns_adb_setudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr, unsigned int size) {
                addr->entry->plain >>= 1;
                addr->entry->plainto >>= 1;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 unsigned int
 dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
        unsigned int size;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
        size = addr->entry->udpsize;
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 
        return (size);
 }
@@ -4400,13 +3885,13 @@ dns_adb_getudpsize(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
 void
 dns_adb_setcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
                  const unsigned char *cookie, size_t len) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        if (addr->entry->cookie != NULL &&
            (cookie == NULL || len != addr->entry->cookielen))
@@ -4425,19 +3910,19 @@ dns_adb_setcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
        if (addr->entry->cookie != NULL) {
                memmove(addr->entry->cookie, cookie, len);
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 }
 
 size_t
 dns_adb_getcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
                  unsigned char *cookie, size_t len) {
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
        if (cookie != NULL && addr->entry->cookie != NULL &&
            len >= addr->entry->cookielen)
        {
@@ -4446,7 +3931,7 @@ dns_adb_getcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
        } else {
                len = 0;
        }
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 
        return (len);
 }
@@ -4454,32 +3939,30 @@ dns_adb_getcookie(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
 isc_result_t
 dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *sa,
                     dns_adbaddrinfo_t **addrp, isc_stdtime_t now) {
-       int bucket;
+       isc_result_t result = ISC_R_SUCCESS;
+       dns_adbentrybucket_t *bucket = NULL;
        dns_adbentry_t *entry = NULL;
        dns_adbaddrinfo_t *addr = NULL;
-       isc_result_t result;
        in_port_t port;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(addrp != NULL && *addrp == NULL);
 
-       UNUSED(now);
+       entry = find_entry_and_lock(adb, sa, now, &bucket);
+       INSIST(bucket != NULL);
 
-       result = ISC_R_SUCCESS;
-       bucket = DNS_ADB_INVALIDBUCKET;
-       entry = find_entry_and_lock(adb, sa, &bucket, now);
-       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
-       if (adb->entry_sd[bucket]) {
+       if (bucket->shuttingdown) {
                result = ISC_R_SHUTTINGDOWN;
                goto unlock;
        }
+
        if (entry == NULL) {
                /*
                 * We don't know anything about this address.
                 */
                entry = new_adbentry(adb);
                entry->sockaddr = *sa;
-               link_entry(adb, bucket, entry);
+               link_entry(bucket, entry);
                DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
        } else {
                DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
@@ -4487,12 +3970,10 @@ dns_adb_findaddrinfo(dns_adb_t *adb, const isc_sockaddr_t *sa,
 
        port = isc_sockaddr_getport(sa);
        addr = new_adbaddrinfo(adb, entry, port);
-       inc_entry_refcnt(adb, entry, false);
        *addrp = addr;
 
 unlock:
-       UNLOCK(&adb->entrylocks[bucket]);
-
+       UNLOCK(&bucket->lock);
        return (result);
 }
 
@@ -4500,32 +3981,31 @@ void
 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
        dns_adbaddrinfo_t *addr = NULL;
        dns_adbentry_t *entry = NULL;
-       int bucket;
+       dns_adbentrybucket_t *bucket = NULL;
        isc_stdtime_t now;
        bool want_check_exit = false;
-       bool overmem;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(addrp != NULL);
+
        addr = *addrp;
        *addrp = NULL;
+
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
        entry = addr->entry;
        REQUIRE(DNS_ADBENTRY_VALID(entry));
 
-       overmem = isc_mem_isovermem(adb->mctx);
-
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+       bucket = addr->entry->bucket;
+       LOCK(&bucket->lock);
 
        if (entry->expires == 0) {
                isc_stdtime_get(&now);
                entry->expires = now + ADB_ENTRY_WINDOW;
        }
 
-       want_check_exit = dec_entry_refcnt(adb, overmem, entry, false);
+       want_check_exit = dec_entry_refcnt(entry, false);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+       UNLOCK(&bucket->lock);
 
        addr->entry = NULL;
        free_adbaddrinfo(adb, &addr);
@@ -4539,21 +4019,11 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
 
 void
 dns_adb_flush(dns_adb_t *adb) {
-       unsigned int i;
-
        REQUIRE(DNS_ADB_VALID(adb));
 
        LOCK(&adb->lock);
 
-       /*
-        * Call our cleanup routines.
-        */
-       for (i = 0; i < adb->nnames; i++) {
-               RUNTIME_CHECK(!cleanup_names(adb, i, INT_MAX));
-       }
-       for (i = 0; i < adb->nentries; i++) {
-               RUNTIME_CHECK(!cleanup_entries(adb, i, INT_MAX));
-       }
+       clean_hashes(adb, INT_MAX);
 
 #ifdef DUMP_ADB_AFTER_CLEANING
        dump_adb(adb, stdout, true, INT_MAX);
@@ -4566,15 +4036,23 @@ void
 dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) {
        dns_adbname_t *adbname = NULL;
        dns_adbname_t *nextname = NULL;
-       unsigned int bucket;
+       dns_adbnamebucket_t *bucket = NULL;
+       isc_result_t result;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(name != NULL);
 
        LOCK(&adb->lock);
-       bucket = dns_name_hash(name, false) % adb->nnames;
-       LOCK(&adb->namelocks[bucket]);
-       adbname = ISC_LIST_HEAD(adb->names[bucket]);
+
+       result = isc_ht_find(adb->namebuckets, name->ndata, name->length,
+                            (void **)&bucket);
+       if (result != ISC_R_SUCCESS) {
+               UNLOCK(&adb->lock);
+               return;
+       }
+
+       LOCK(&bucket->lock);
+       adbname = ISC_LIST_HEAD(bucket->names);
        while (adbname != NULL) {
                nextname = ISC_LIST_NEXT(adbname, plink);
                if (!NAME_DEAD(adbname) && dns_name_equal(name, &adbname->name))
@@ -4584,40 +4062,52 @@ dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) {
                }
                adbname = nextname;
        }
-       UNLOCK(&adb->namelocks[bucket]);
+       UNLOCK(&bucket->lock);
        UNLOCK(&adb->lock);
 }
 
 void
 dns_adb_flushnames(dns_adb_t *adb, const dns_name_t *name) {
-       dns_adbname_t *adbname = NULL, *nextname = NULL;
-       unsigned int i;
+       isc_result_t result;
+       isc_ht_iter_t *iter = NULL;
 
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(name != NULL);
 
+       isc_ht_iter_create(adb->namebuckets, &iter);
+
        LOCK(&adb->lock);
-       for (i = 0; i < adb->nnames; i++) {
-               LOCK(&adb->namelocks[i]);
-               adbname = ISC_LIST_HEAD(adb->names[i]);
+       for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
+            result = isc_ht_iter_next(iter))
+       {
+               dns_adbnamebucket_t *bucket = NULL;
+               dns_adbname_t *adbname = NULL, *nextname = NULL;
+
+               isc_ht_iter_current(iter, (void **)&bucket);
+               LOCK(&bucket->lock);
+               adbname = ISC_LIST_HEAD(bucket->names);
                while (adbname != NULL) {
-                       bool ret;
                        nextname = ISC_LIST_NEXT(adbname, plink);
                        if (!NAME_DEAD(adbname) &&
                            dns_name_issubdomain(&adbname->name, name)) {
-                               ret = kill_name(&adbname,
-                                               DNS_EVENT_ADBCANCELED);
+                               bool ret = kill_name(&adbname,
+                                                    DNS_EVENT_ADBCANCELED);
                                RUNTIME_CHECK(!ret);
                        }
                        adbname = nextname;
                }
-               UNLOCK(&adb->namelocks[i]);
+               UNLOCK(&bucket->lock);
        }
        UNLOCK(&adb->lock);
+
+       isc_ht_iter_destroy(&iter);
 }
 
 static void
 water(void *arg, int mark) {
+       dns_adb_t *adb = arg;
+       bool overmem = (mark == ISC_MEM_HIWATER);
+
        /*
         * We're going to change the way to handle overmem condition: use
         * isc_mem_isovermem() instead of storing the state via this callback,
@@ -4626,9 +4116,6 @@ water(void *arg, int mark) {
         * approach, however, keep this function at the moment.
         */
 
-       dns_adb_t *adb = arg;
-       bool overmem = (mark == ISC_MEM_HIWATER);
-
        REQUIRE(DNS_ADB_VALID(adb));
 
        DP(ISC_LOG_DEBUG(1), "adb reached %s water mark",
index cd5092d34251766a1687a1f784fd1df6c8c8e4aa..34636adfdadf1ff9d8fddb4569c09a7077d7a65a 100644 (file)
@@ -92,7 +92,9 @@ ISC_LANG_BEGINDECLS
  *** TYPES
  ***/
 
-typedef struct dns_adbname dns_adbname_t;
+typedef struct dns_adbname       dns_adbname_t;
+typedef struct dns_adbnamebucket  dns_adbnamebucket_t;
+typedef struct dns_adbentrybucket dns_adbentrybucket_t;
 
 /*!
  *\brief
@@ -114,13 +116,13 @@ struct dns_adbfind {
        ISC_LINK(dns_adbfind_t) publink;      /*%< RW: client use */
 
        /* Private */
-       isc_mutex_t    lock; /* locks all below */
-       in_port_t      port;
-       int            name_bucket;
-       unsigned int   flags;
-       dns_adbname_t *adbname;
-       dns_adb_t         *adb;
-       isc_event_t    event;
+       isc_mutex_t          lock; /* locks all below */
+       in_port_t            port;
+       dns_adbnamebucket_t *bucket;
+       unsigned int         flags;
+       dns_adbname_t         *adbname;
+       dns_adb_t                 *adb;
+       isc_event_t          event;
        ISC_LINK(dns_adbfind_t) plink;
 };