badns_forwarder,
} badnstype_t;
+typedef struct fctxbucket {
+ isc_mutex_t lock;
+ ISC_LIST(fetchctx_t) fctxs;
+} fctxbucket_t;
+
typedef struct fctxcount fctxcount_t;
struct fctxcount {
dns_fixedname_t dfname;
dns_name_t *name;
dns_rdatatype_t type;
unsigned int options;
- unsigned int bucketnum;
+ fctxbucket_t *bucket;
zonebucket_t *zbucket;
char *info;
isc_mem_t *mctx;
/* Atomic */
isc_refcount_t references;
- /*% Locked by appropriate bucket lock. */
+ /*% Locked by bucket lock. */
fetchstate_t state;
atomic_bool want_shutdown;
bool cloned;
#define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h')
#define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
-typedef struct fctxbucket {
- isc_task_t *task;
- isc_mutex_t lock;
- ISC_LIST(fetchctx_t) fctxs;
- atomic_bool exiting;
-} fctxbucket_t;
-
typedef struct alternate {
bool isaddress;
union {
dns_dispatchset_t *dispatches6;
isc_dscp_t querydscp4;
isc_dscp_t querydscp6;
- unsigned int nbuckets;
- fctxbucket_t *buckets;
+ isc_ht_t *buckets;
+ isc_rwlock_t hash_lock;
isc_ht_t *zonebuckets;
isc_rwlock_t zonehash_lock;
+ unsigned int ntasks;
+ isc_task_t **tasks;
uint32_t lame_ttl;
ISC_LIST(alternate_t) alternates;
uint16_t udpsize;
atomic_bool priming;
/* Locked by lock. */
- isc_refcount_t activebuckets;
unsigned int spillat; /* clients-per-query */
dns_badcache_t *badcache; /* Bad cache. */
static isc_result_t
fctx_minimize_qname(fetchctx_t *fctx);
static void
-fctx_destroy(fetchctx_t *fctx, bool exiting);
+fctx_destroy(fetchctx_t *fctx);
static isc_result_t
ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
static void
resquery_destroy(resquery_t *query) {
fetchctx_t *fctx = query->fctx;
- dns_resolver_t *res = fctx->res;
- unsigned int bucket = fctx->bucketnum;
if (ISC_LINK_LINKED(query, link)) {
ISC_LIST_UNLINK(fctx->queries, query, link);
isc_refcount_destroy(&query->references);
- LOCK(&res->buckets[bucket].lock);
+ LOCK(&fctx->bucket->lock);
atomic_fetch_sub_release(&fctx->nqueries, 1);
- UNLOCK(&res->buckets[bucket].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(&query->fctx);
if (query->rmessage != NULL) {
dns_dispatch_cancel(&query->dispentry);
}
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
if (ISC_LINK_LINKED(query, link)) {
ISC_LIST_UNLINK(fctx->queries, query, link);
}
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
resquery_detach(queryp);
}
* Move the queries to a local list so we can cancel
* them without holding the lock.
*/
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
ISC_LIST_MOVE(queries, fctx->queries);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
for (query = ISC_LIST_HEAD(queries); query != NULL; query = next_query)
{
fctx__done_detach(fetchctx_t **fctxp, isc_result_t result, const char *file,
unsigned int line, const char *func) {
fetchctx_t *fctx = NULL;
- dns_resolver_t *res = NULL;
bool no_response = false;
bool age_untried = false;
REQUIRE(fctxp != NULL && VALID_FCTX(*fctxp));
fctx = *fctxp;
- res = fctx->res;
FCTXTRACE("done");
UNUSED(func);
#endif
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
INSIST(fctx->state != fetchstate_done);
fctx->state = fetchstate_done;
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
if (result == ISC_R_SUCCESS) {
if (fctx->qmin_warning != ISC_R_SUCCESS) {
fctx_cancelqueries(fctx, no_response, age_untried);
fctx_stoptimer(fctx);
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
FCTX_ATTR_CLR(fctx, FCTX_ATTR_ADDRWAIT);
fctx_sendevents(fctx, result, line);
fctx_shutdown(fctx);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(fctxp);
}
/*
* Send the TRYSTALE events.
*/
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next) {
isc_task_t *sender = NULL;
event->result = ISC_R_TIMEDOUT;
isc_task_sendanddetach(&sender, ISC_EVENT_PTR(&event));
}
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/*
* If the next timeout is more than 1ms in the future,
dns_adb_beginudpfetch(fctx->adb, addrinfo);
}
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
ISC_LIST_APPEND(fctx->queries, query, link);
atomic_fetch_add_relaxed(&fctx->nqueries, 1);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/* Set up the dispatch and set the query ID */
result = dns_dispatch_add(
fctx_finddone(isc_task_t *task, isc_event_t *event) {
fetchctx_t *fctx = event->ev_arg;
dns_adbfind_t *find = event->ev_sender;
- dns_resolver_t *res;
bool want_try = false;
bool want_done = false;
- unsigned int bucketnum;
REQUIRE(VALID_FCTX(fctx));
- res = fctx->res;
UNUSED(task);
FCTXTRACE("finddone");
- bucketnum = fctx->bucketnum;
- LOCK(&res->buckets[bucketnum].lock);
-
+ LOCK(&fctx->bucket->lock);
INSIST(atomic_fetch_sub_release(&fctx->pending, 1) > 0);
if (ADDRWAIT(fctx)) {
}
isc_event_free(&event);
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
dns_adb_destroyfind(&find);
* See what we know about this address.
*/
fctx_addref(fctx);
- result = dns_adb_createfind(
- fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone,
- fctx, name, fctx->name, fctx->type, options, now, NULL,
- res->view->dstport, fctx->depth + 1, fctx->qc, &find);
+ result = dns_adb_createfind(fctx->adb, fctx->task, fctx_finddone, fctx,
+ name, fctx->name, fctx->type, options, now,
+ NULL, res->view->dstport, fctx->depth + 1,
+ fctx->qc, &find);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
isc_result_t result;
dns_adbaddrinfo_t *addrinfo = NULL;
- dns_resolver_t *res;
- isc_task_t *task;
- unsigned int bucketnum;
+ dns_resolver_t *res = NULL;
FCTXTRACE5("try", "fctx->qc=", isc_counter_used(fctx->qc));
REQUIRE(!ADDRWAIT(fctx));
res = fctx->res;
- bucketnum = fctx->bucketnum;
/* We've already exceeded maximum query count */
if (isc_counter_used(fctx->qc) > res->maxqueries) {
options |= DNS_FETCHOPT_NOFOLLOW;
}
fctx_addref(fctx);
- task = res->buckets[bucketnum].task;
result = dns_resolver_createfetch(
fctx->res, fctx->qminname, fctx->qmintype, fctx->domain,
&fctx->nameservers, NULL, NULL, 0, options, 0, fctx->qc,
- task, resume_qmin, fctx, &fctx->qminrrset, NULL,
+ fctx->task, resume_qmin, fctx, &fctx->qminrrset, NULL,
&fctx->qminfetch);
if (result != ISC_R_SUCCESS) {
fctx_unref(fctx);
dns_resolver_t *res = NULL;
fetchctx_t *fctx = NULL;
isc_result_t result;
- unsigned int bucketnum;
unsigned int findoptions = 0;
dns_name_t *fname = NULL, *dcname = NULL;
dns_fixedname_t ffixed, dcfixed;
dns_db_detach(&fevent->db);
}
- bucketnum = fctx->bucketnum;
-
if (dns_rdataset_isassociated(fevent->rdataset)) {
dns_rdataset_disassociate(fevent->rdataset);
}
dns_resolver_destroyfetch(&fctx->qminfetch);
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
if (SHUTTINGDOWN(fctx)) {
maybe_cancel_validators(fctx);
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(&fctx);
return;
}
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
if (result == ISC_R_CANCELED) {
goto cleanup;
}
static void
-fctx_destroy(fetchctx_t *fctx, bool exiting) {
+fctx_destroy(fetchctx_t *fctx) {
dns_resolver_t *res = NULL;
isc_sockaddr_t *sa = NULL, *next_sa = NULL;
struct tried *tried = NULL;
- unsigned int bucketnum;
+ fctxbucket_t *bucket = NULL;
REQUIRE(VALID_FCTX(fctx));
REQUIRE(ISC_LIST_EMPTY(fctx->events));
FCTXTRACE("destroy");
res = fctx->res;
- bucketnum = fctx->bucketnum;
-
- LOCK(&res->buckets[bucketnum].lock);
- REQUIRE(fctx->state != fetchstate_active);
- ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
-
- INSIST(atomic_fetch_sub_release(&res->nfctx, 1) > 0);
+ bucket = fctx->bucket;
dec_stats(res, dns_resstatscounter_nfetch);
- if (exiting && atomic_load_acquire(&res->buckets[bucketnum].exiting) &&
- ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
- {
- isc_refcount_decrement(&res->activebuckets);
- }
- UNLOCK(&res->buckets[bucketnum].lock);
+ LOCK(&bucket->lock);
+ REQUIRE(fctx->state != fetchstate_active);
+ ISC_LIST_UNLINK(bucket->fctxs, fctx, link);
+ INSIST(atomic_fetch_sub_release(&res->nfctx, 1) > 0);
+ UNLOCK(&bucket->lock);
isc_refcount_destroy(&fctx->references);
if (fctx->state != fetchstate_init) {
FCTXTRACE("posting control event");
cevent = &fctx->control_event;
- isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
- &cevent);
+ isc_task_send(fctx->task, &cevent);
}
}
static void
fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
fetchctx_t *fctx = event->ev_arg;
- dns_resolver_t *res = NULL;
- unsigned int bucketnum;
dns_validator_t *validator = NULL;
REQUIRE(VALID_FCTX(fctx));
UNUSED(task);
- res = fctx->res;
- bucketnum = fctx->bucketnum;
-
FCTXTRACE("doshutdown");
/*
fctx_cancelqueries(fctx, false, false);
fctx_cleanup(fctx);
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN);
fctx_unref(fctx);
}
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(&fctx);
}
static void
fctx_start(isc_task_t *task, isc_event_t *event) {
fetchctx_t *fctx = event->ev_arg;
- dns_resolver_t *res = NULL;
- unsigned int bucketnum;
isc_result_t result;
REQUIRE(VALID_FCTX(fctx));
UNUSED(task);
- res = fctx->res;
- bucketnum = fctx->bucketnum;
-
FCTXTRACE("start");
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
INSIST(fctx->state == fetchstate_init);
if (atomic_load_acquire(&fctx->want_shutdown)) {
INSIST(atomic_load_acquire(&fctx->pending) == 0);
INSIST(atomic_load_acquire(&fctx->nqueries) == 0);
INSIST(ISC_LIST_EMPTY(fctx->validators));
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
FCTX_ATTR_SET(fctx, FCTX_ATTR_SHUTTINGDOWN);
ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL,
fctx_doshutdown, fctx, NULL, NULL, NULL);
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/*
* As a backstop, we also set a timer to stop the fetch
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"shut down hung fetch while resolving '%s'", fctx->info);
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
fctx_shutdown(fctx);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
isc_event_free(&event);
}
static isc_result_t
-fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
- dns_rdatatype_t type, const dns_name_t *domain,
- dns_rdataset_t *nameservers, const isc_sockaddr_t *client,
- unsigned int options, unsigned int bucketnum, unsigned int depth,
- isc_counter_t *qc, fetchctx_t **fctxp) {
+fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
+ const dns_name_t *domain, dns_rdataset_t *nameservers,
+ const isc_sockaddr_t *client, unsigned int options,
+ fctxbucket_t *bucket, unsigned int depth, isc_counter_t *qc,
+ fetchctx_t **fctxp) {
fetchctx_t *fctx = NULL;
isc_result_t result;
isc_result_t iresult;
isc_interval_t interval;
unsigned int findoptions = 0;
char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1];
+ unsigned int tid;
size_t p;
/*
- * Caller must be holding the lock for bucket number
- * 'bucketnum'.
+ * Caller must be holding the lock for 'bucket'
*/
REQUIRE(fctxp != NULL && *fctxp == NULL);
+ tid = isc_random_uniform(res->ntasks);
fctx = isc_mem_get(res->mctx, sizeof(*fctx));
*fctx = (fetchctx_t){
.type = type,
.qmintype = type,
.options = options,
- .task = task,
- .bucketnum = bucketnum,
+ .bucket = bucket,
+ .task = res->tasks[tid],
.state = fetchstate_init,
.depth = depth,
.qmin_labels = 1,
* lifetime. It will be made active when the fetch is
* started.
*/
- isc_timer_create(res->timermgr, res->buckets[bucketnum].task,
- fctx_expired, fctx, &fctx->timer);
+ isc_timer_create(res->timermgr, fctx->task, fctx_expired, fctx,
+ &fctx->timer);
/*
* Default retry interval initialization. We set the interval
}
}
- ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
+ ISC_LIST_APPEND(bucket->fctxs, fctx, link);
INSIST(atomic_fetch_add_relaxed(&res->nfctx, 1) < UINT32_MAX);
isc_stdtime_t now;
uint32_t ttl;
unsigned options;
- uint32_t bucketnum;
dns_fixedname_t fwild;
dns_name_t *wild = NULL;
dns_message_t *message = NULL;
vevent = (dns_validatorevent_t *)event;
fctx->vresult = vevent->result;
- bucketnum = fctx->bucketnum;
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
fctx->validator = NULL;
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/*
* Destroy the validator early so that we can
negative = (vevent->rdataset == NULL);
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
sentresponse = ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
/*
* events; if so, destroy the fctx.
*/
if (SHUTTINGDOWN(fctx) && !sentresponse) {
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(&fctx);
goto cleanup_event;
}
dns_message_detach(&message);
isc_event_free(&event);
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
INSIST(fctx->validator == NULL);
fctx->validator = ISC_LIST_HEAD(fctx->validators);
if (SHUTTINGDOWN(fctx)) {
maybe_cancel_validators(fctx);
}
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
fctx_detach(&fctx);
goto cleanup_event;
}
* be validated.
*/
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
dns_validator_send(ISC_LIST_HEAD(fctx->validators));
fctx_detach(&fctx);
goto cleanup_event;
dns_db_detachnode(fctx->cache, &node);
}
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/* Detach the extra reference that was set in valcreate() */
fctx_unref(fctx);
fctx_done_detach(&fctx, result); /* Locks bucket. */
isc_result_t result, eresult = ISC_R_SUCCESS;
dns_fetchevent_t *event = NULL;
unsigned int options;
- isc_task_t *task;
bool fail;
unsigned int valoptions = 0;
bool checknta = true;
/*
* The appropriate bucket lock must be held.
*/
- task = res->buckets[fctx->bucketnum].task;
/*
* Is DNSSEC validation required for this name?
result = valcreate(
fctx, message, addrinfo, name,
rdataset->type, rdataset,
- sigrdataset, valoptions, task);
+ sigrdataset, valoptions,
+ fctx->task);
}
} else if (CHAINING(rdataset)) {
if (rdataset->type == dns_rdatatype_cname) {
result = valcreate(fctx, message, addrinfo, name, vtype,
valrdataset, valsigrdataset, valoptions,
- task);
+ fctx->task);
}
if (result == ISC_R_SUCCESS && have_answer) {
FCTX_ATTR_CLR(fctx, FCTX_ATTR_WANTCACHE);
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL;
section++) {
result = ISC_R_SUCCESS;
}
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
return (result);
}
* Do negative response validation.
*/
result = valcreate(fctx, message, addrinfo, name, fctx->type,
- NULL, NULL, valoptions,
- res->buckets[fctx->bucketnum].task);
+ NULL, NULL, valoptions, fctx->task);
/*
* If validation is necessary, return now. Otherwise
* continue to process the message, letting the
return (result);
}
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
if (!HAVE_ANSWER(fctx)) {
event = ISC_LIST_HEAD(fctx->events);
}
unlock:
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
if (node != NULL) {
dns_db_detachnode(fctx->cache, &node);
#endif
if (refs == 1) {
- fctx_destroy(fctx, true);
+ fctx_destroy(fctx);
}
}
result = fevent->result;
isc_event_free(&event);
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
if (SHUTTINGDOWN(fctx)) {
maybe_cancel_validators(fctx);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
if (dns_rdataset_isassociated(frdataset)) {
dns_rdataset_disassociate(frdataset);
fctx_detach(&fctx);
return;
}
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
/*
* Detach the extra reference that was set in rctx_chaseds()
rctx_chaseds(respctx_t *rctx, dns_message_t *message,
dns_adbaddrinfo_t *addrinfo, isc_result_t result) {
fetchctx_t *fctx = rctx->fctx;
- isc_task_t *task = NULL;
unsigned int n;
add_bad(fctx, message, addrinfo, result, rctx->broken_type);
FCTXTRACE("suspending DS lookup to find parent's NS records");
fctx_addref(fctx);
- task = fctx->res->buckets[fctx->bucketnum].task;
result = dns_resolver_createfetch(
fctx->res, fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL,
- NULL, 0, fctx->options, 0, NULL, task, resume_dslookup, fctx,
- &fctx->nsrrset, NULL, &fctx->nsfetch);
+ NULL, 0, fctx->options, 0, NULL, fctx->task, resume_dslookup,
+ fctx, &fctx->nsrrset, NULL, &fctx->nsfetch);
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_DUPLICATE) {
result = DNS_R_SERVFAIL;
/*
* If nobody's waiting for results, don't resend.
*/
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
if (ISC_LIST_EMPTY(fctx->events)) {
rctx->resend = false;
}
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
if (rctx->next_server) {
rctx_nextserver(rctx, message, addrinfo, result);
static void
destroy(dns_resolver_t *res) {
isc_result_t result;
- unsigned int i;
alternate_t *a = NULL;
isc_ht_iter_t *it = NULL;
isc_mutex_destroy(&res->primelock);
isc_mutex_destroy(&res->lock);
- for (i = 0; i < res->nbuckets; i++) {
- INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
- isc_task_detach(&res->buckets[i].task);
- isc_mutex_destroy(&res->buckets[i].lock);
+
+ for (size_t i = 0; i < res->ntasks; i++) {
+ isc_task_detach(&res->tasks[i]);
+ }
+ isc_mem_put(res->mctx, res->tasks, res->ntasks * sizeof(res->tasks[0]));
+
+ isc_ht_iter_create(res->buckets, &it);
+ for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+ result = isc_ht_iter_delcurrent_next(it))
+ {
+ fctxbucket_t *bucket = NULL;
+ isc_ht_iter_current(it, (void **)&bucket);
+
+ INSIST(ISC_LIST_EMPTY(bucket->fctxs));
+ isc_mutex_destroy(&bucket->lock);
+ isc_mem_put(res->mctx, bucket, sizeof(*bucket));
}
- isc_mem_put(res->mctx, res->buckets,
- res->nbuckets * sizeof(fctxbucket_t));
+ isc_ht_iter_destroy(&it);
+ isc_ht_destroy(&res->buckets);
isc_ht_iter_create(res->zonebuckets, &it);
for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
.taskmgr = taskmgr,
.dispatchmgr = dispatchmgr,
.options = options,
+ .ntasks = ntasks,
.udpsize = DEFAULT_EDNS_BUFSIZE,
.spillatmin = 10,
.spillat = 10,
.query_timeout = DEFAULT_QUERY_TIMEOUT,
.maxdepth = DEFAULT_RECURSION_DEPTH,
.maxqueries = DEFAULT_MAX_QUERIES,
- .nbuckets = ntasks,
.querydscp4 = -1,
.querydscp6 = -1 };
- atomic_init(&res->activebuckets, ntasks);
-
dns_view_weakattach(view, &res->view);
isc_mem_attach(view->mctx, &res->mctx);
goto cleanup_res;
}
- res->buckets = isc_mem_get(view->mctx,
- ntasks * sizeof(res->buckets[0]));
+ res->tasks = isc_mem_get(view->mctx, ntasks * sizeof(res->tasks[0]));
for (uint32_t i = 0; i < ntasks; i++) {
- res->buckets[i] = (fctxbucket_t){ 0 };
-
- isc_mutex_init(&res->buckets[i].lock);
-
/*
* Since we have a pool of tasks we bind them to task
* queues to spread the load evenly
*/
- result = isc_task_create_bound(taskmgr, 0,
- &res->buckets[i].task, i);
+ res->tasks[i] = NULL;
+ result = isc_task_create_bound(taskmgr, 0, &res->tasks[i], i);
if (result != ISC_R_SUCCESS) {
- isc_mutex_destroy(&res->buckets[i].lock);
- goto cleanup_buckets;
+ goto cleanup_tasks;
}
snprintf(name, sizeof(name), "res%" PRIu32, i);
- isc_task_setname(res->buckets[i].task, name, res);
-
- ISC_LIST_INIT(res->buckets[i].fctxs);
- atomic_init(&res->buckets[i].exiting, false);
+ isc_task_setname(res->tasks[i], name, res);
}
+ isc_ht_init(&res->buckets, view->mctx, RES_DOMAIN_HASH_BITS,
+ ISC_HT_CASE_INSENSITIVE);
+ isc_rwlock_init(&res->hash_lock, 0, 0);
+
isc_ht_init(&res->zonebuckets, view->mctx, RES_DOMAIN_HASH_BITS,
ISC_HT_CASE_INSENSITIVE);
isc_rwlock_init(&res->zonehash_lock, 0, 0);
isc_rwlock_destroy(&res->zonehash_lock);
isc_ht_destroy(&res->zonebuckets);
-cleanup_buckets:
+ isc_rwlock_destroy(&res->hash_lock);
+ isc_ht_destroy(&res->buckets);
+
+cleanup_tasks:
for (size_t i = 0; i < ntasks; i++) {
- isc_mutex_destroy(&res->buckets[i].lock);
- isc_task_detach(&res->buckets[i].task);
+ isc_task_detach(&res->tasks[i]);
}
- isc_mem_put(view->mctx, res->buckets,
- res->nbuckets * sizeof(fctxbucket_t));
+ isc_mem_put(view->mctx, res->tasks,
+ res->ntasks * sizeof(res->tasks[0]));
dns_badcache_destroy(&res->badcache);
INSIST(res->primefetch == NULL);
result = dns_resolver_createfetch(
res, dns_rootname, dns_rdatatype_ns, NULL, NULL, NULL,
- NULL, 0, DNS_FETCHOPT_NOFORWARD, 0, NULL,
- res->buckets[0].task, prime_done, res, rdataset, NULL,
- &res->primefetch);
+ NULL, 0, DNS_FETCHOPT_NOFORWARD, 0, NULL, res->tasks[0],
+ prime_done, res, rdataset, NULL, &res->primefetch);
UNLOCK(&res->primelock);
if (result != ISC_R_SUCCESS) {
void
dns_resolver_shutdown(dns_resolver_t *res) {
- unsigned int i;
- fetchctx_t *fctx;
isc_result_t result;
bool is_false = false;
RTRACE("shutdown");
- LOCK(&res->lock);
if (atomic_compare_exchange_strong(&res->exiting, &is_false, true)) {
+ isc_ht_iter_t *it = NULL;
+
RTRACE("exiting");
- for (i = 0; i < res->nbuckets; i++) {
- LOCK(&res->buckets[i].lock);
- for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
- fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link))
+ RWLOCK(&res->hash_lock, isc_rwlocktype_read);
+ isc_ht_iter_create(res->buckets, &it);
+ for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
+ result = isc_ht_iter_next(it))
+ {
+ fctxbucket_t *bucket = NULL;
+ fetchctx_t *fctx = NULL;
+
+ isc_ht_iter_current(it, (void **)&bucket);
+ LOCK(&bucket->lock);
+ for (fctx = ISC_LIST_HEAD(bucket->fctxs); fctx != NULL;
+ fctx = ISC_LIST_NEXT(fctx, link))
{
fctx_shutdown(fctx);
}
- atomic_store(&res->buckets[i].exiting, true);
- if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
- isc_refcount_decrement(&res->activebuckets);
- }
- UNLOCK(&res->buckets[i].lock);
+ UNLOCK(&bucket->lock);
}
+ isc_ht_iter_destroy(&it);
+ RWUNLOCK(&res->hash_lock, isc_rwlocktype_read);
+
result = isc_timer_reset(res->spillattimer,
isc_timertype_inactive, NULL, true);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
- UNLOCK(&res->lock);
}
void
RTRACE("detach");
if (isc_refcount_decrement(&res->references) == 1) {
- isc_refcount_destroy(&res->activebuckets);
INSIST(atomic_load_acquire(&res->exiting));
destroy(res);
}
return (result);
}
+static fctxbucket_t *
+get_fctxbucket(dns_resolver_t *res, const dns_name_t *domain) {
+ isc_result_t result;
+ isc_rwlocktype_t ltype = isc_rwlocktype_read;
+ fctxbucket_t *bucket = NULL;
+
+ RWLOCK(&res->hash_lock, ltype);
+ result = isc_ht_find(res->buckets, domain->ndata, domain->length,
+ (void **)&bucket);
+ if (result != ISC_R_SUCCESS) {
+ bucket = isc_mem_get(res->mctx, sizeof(*bucket));
+ *bucket = (fctxbucket_t){ .fctxs = { 0 } };
+ ISC_LIST_INIT(bucket->fctxs);
+ isc_mutex_init(&bucket->lock);
+ RWUNLOCK(&res->hash_lock, ltype);
+
+ ltype = isc_rwlocktype_write;
+ RWLOCK(&res->hash_lock, ltype);
+ result = isc_ht_add(res->buckets, domain->ndata, domain->length,
+ bucket);
+ if (result == ISC_R_SUCCESS) {
+ inc_stats(res, dns_resstatscounter_buckets);
+ } else {
+ /* Another thread must have created it */
+ isc_mutex_destroy(&bucket->lock);
+ isc_mem_put(res->mctx, bucket, sizeof(*bucket));
+ result = isc_ht_find(res->buckets, domain->ndata,
+ domain->length, (void **)&bucket);
+ }
+ }
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ RWUNLOCK(&res->hash_lock, ltype);
+
+ return (bucket);
+}
+
isc_result_t
dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name,
dns_rdatatype_t type, const dns_name_t *domain,
isc_taskaction_t action, void *arg,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_fetch_t **fetchp) {
- dns_fetch_t *fetch;
+ dns_fetch_t *fetch = NULL;
fetchctx_t *fctx = NULL;
isc_result_t result = ISC_R_SUCCESS;
- unsigned int bucketnum;
bool new_fctx = false;
- isc_event_t *event;
+ isc_event_t *event = NULL;
unsigned int count = 0;
unsigned int spillat;
unsigned int spillatmin;
bool dodestroy = false;
+ fctxbucket_t *bucket = NULL;
UNUSED(forwarders);
dns_resolver_attach(res, &fetch->res);
isc_mem_attach(res->mctx, &fetch->mctx);
- bucketnum = dns_name_fullhash(name, false) % res->nbuckets;
-
LOCK(&res->lock);
spillat = res->spillat;
spillatmin = res->spillatmin;
UNLOCK(&res->lock);
- LOCK(&res->buckets[bucketnum].lock);
- if (atomic_load(&res->buckets[bucketnum].exiting)) {
- result = ISC_R_SHUTTINGDOWN;
- goto unlock;
- }
+ bucket = get_fctxbucket(res, name);
+ LOCK(&bucket->lock);
if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
- for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
- fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link))
+ for (fctx = ISC_LIST_HEAD(bucket->fctxs); fctx != NULL;
+ fctx = ISC_LIST_NEXT(fctx, link))
{
if (fctx_match(fctx, name, type, options)) {
break;
}
if (fctx == NULL) {
- result = fctx_create(res, task, name, type, domain, nameservers,
- client, options, bucketnum, depth, qc,
- &fctx);
+ result = fctx_create(res, name, type, domain, nameservers,
+ client, options, bucket, depth, qc, &fctx);
if (result != ISC_R_SUCCESS) {
goto unlock;
}
ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
DNS_EVENT_FETCHCONTROL, fctx_start, fctx,
NULL, NULL, NULL);
- isc_task_send(res->buckets[bucketnum].task, &event);
+ isc_task_send(fctx->task, &event);
} else {
dodestroy = true;
}
}
unlock:
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&bucket->lock);
if (dodestroy) {
- fctx_destroy(fctx, false);
+ fctx_destroy(fctx);
}
if (result == ISC_R_SUCCESS) {
void
dns_resolver_cancelfetch(dns_fetch_t *fetch) {
fetchctx_t *fctx = NULL;
- dns_resolver_t *res = NULL;
dns_fetchevent_t *event = NULL;
REQUIRE(DNS_FETCH_VALID(fetch));
fctx = fetch->private;
REQUIRE(VALID_FCTX(fctx));
- res = fctx->res;
FTRACE("cancelfetch");
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
/*
* Find the completion event for this fetch (as opposed
* The fctx continues running even if no fetches remain;
* the answer is still cached.
*/
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
}
void
dns_fetch_t *fetch = NULL;
dns_resolver_t *res = NULL;
fetchctx_t *fctx = NULL;
- unsigned int bucketnum;
REQUIRE(fetchp != NULL);
fetch = *fetchp;
FTRACE("destroyfetch");
- bucketnum = fctx->bucketnum;
- LOCK(&res->buckets[bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
/*
* Sanity check: the caller should have gotten its event before
RUNTIME_CHECK(event->fetch != fetch);
}
}
- UNLOCK(&res->buckets[bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx,
isc_logcategory_t *category, isc_logmodule_t *module,
int level, bool duplicateok) {
- fetchctx_t *fctx;
- dns_resolver_t *res;
+ fetchctx_t *fctx = NULL;
char domainbuf[DNS_NAME_FORMATSIZE];
REQUIRE(DNS_FETCH_VALID(fetch));
fctx = fetch->private;
REQUIRE(VALID_FCTX(fctx));
- res = fctx->res;
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ LOCK(&fctx->bucket->lock);
INSIST(fctx->exitline >= 0);
if (!fctx->logged || duplicateok) {
fctx->logged = true;
}
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&fctx->bucket->lock);
}
dns_dispatchmgr_t *
isc_stats_attach(stats, &res->stats);
/* initialize the bucket "counter"; it's a static value */
- set_stats(res, dns_resstatscounter_buckets, res->nbuckets);
+ set_stats(res, dns_resstatscounter_buckets, res->ntasks);
}
void