#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;
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;
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;
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;
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;
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;
unsigned char plainto;
unsigned char edns;
unsigned char ednsto;
+ unsigned int nh;
uint8_t mode;
atomic_uint_fast32_t quota;
* 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 *
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
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
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
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
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
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.
*
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));
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);
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);
}
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 ||
*/
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);
}
* 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);
}
/*
clean_target(adb, &name->target);
name->expire_target = INT_MAX;
}
+
return (ret4 || ret6);
}
* 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
* 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);
}
/*
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));
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);
}
/*
namehook = ISC_LIST_HEAD(*namehooks);
}
- if (addr_bucket != DNS_ADB_INVALIDBUCKET) {
- UNLOCK(&adb->entrylocks[addr_bucket]);
+ if (bucket != NULL) {
+ UNLOCK(&bucket->lock);
}
+
return (ret);
}
*/
ISC_LIST_UNLINK(name->finds, find, plink);
find->adbname = NULL;
- find->name_bucket = DNS_ADB_INVALIDBUCKET;
+ find->bucket = NULL;
INSIST(!FIND_EVENTSENT(find));
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);
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);
}
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);
}
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;
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 *
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) {
}
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 *
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);
}
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;
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;
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);
}
}
/*
- * 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) &&
* 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);
}
}
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 |
/*
* 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);
}
}
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 |
/*
* 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);
}
}
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));
}
/*%
* 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;
* 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)
{
* 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);
}
*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);
}
* 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) {
}
name = next_name;
}
- UNLOCK(&adb->namelocks[bucket]);
+ UNLOCK(&bucket->lock);
+
return (ret);
}
* 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);
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));
}
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);
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);
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.
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);
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.
*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)
{
/*
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);
}
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);
}
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;
/*
* 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));
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;
}
}
} 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;
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);
*findp = find;
}
- UNLOCK(&adb->namelocks[bucket]);
+ UNLOCK(&bucket->lock);
return (result);
}
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));
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);
* 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);
}
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);
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;
}
* 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:
void
dns_adb_dump(dns_adb_t *adb, FILE *f) {
- unsigned int i;
isc_stdtime_t now;
REQUIRE(DNS_ADB_VALID(adb));
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);
}
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);
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
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,
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) {
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;
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;
want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
- UNLOCK(&adb->namelocks[bucket]);
+ UNLOCK(&bucket->lock);
if (want_check_exit) {
LOCK(&adb->lock);
clean_finds_at_name(name, ev_status, address_type);
- UNLOCK(&adb->namelocks[bucket]);
+ UNLOCK(&bucket->lock);
}
static 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))) {
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
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));
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) {
*/
addr->flags = (addr->flags & ~mask) | (bits & mask);
- UNLOCK(&adb->entrylocks[bucket]);
+ UNLOCK(&bucket->lock);
}
/*
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);
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);
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);
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;
}
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);
}
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))
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)
{
} else {
len = 0;
}
- UNLOCK(&adb->entrylocks[bucket]);
+ UNLOCK(&bucket->lock);
return (len);
}
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);
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);
}
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);
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);
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))
}
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,
* 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",