]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3318. [tuning] Reduce the amount of work performed while holding a v9.9.1
authorMark Andrews <marka@isc.org>
Wed, 9 May 2012 22:39:51 +0000 (08:39 +1000)
committerMark Andrews <marka@isc.org>
Wed, 9 May 2012 22:39:51 +0000 (08:39 +1000)
                        bucket lock when finshed with a fetch context.
                        [RT #29239]

CHANGES
lib/dns/resolver.c

diff --git a/CHANGES b/CHANGES
index aff48026ccc03bebc3309462068bf96fc108ddc4..11badf47b0380b634096a19e27496cbd5dcf000b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
        --- 9.9.1 released ---
 
+3318.  [tuning]        Reduce the amount of work performed while holding a
+                       bucket lock when finshed with a fetch context.
+                       [RT #29239]
+
 3314.  [bug]           The masters list could be updated while refesh_callback
                        and stub_callback were using it. [RT #26732]
 
index 69b88c1259d33e688845d42c1fdb2b8a06840828..fb50360df177d61abde6758c5c62491c1e0e9e5e 100644 (file)
@@ -180,7 +180,9 @@ struct fetchctx {
        dns_rdatatype_t                 type;
        unsigned int                    options;
        unsigned int                    bucketnum;
-       char *                  info;
+       char *                          info;
+       isc_mem_t *                     mctx;
+
        /*% Locked by appropriate bucket lock. */
        fetchstate                      state;
        isc_boolean_t                   want_shutdown;
@@ -446,7 +448,8 @@ static void resquery_response(isc_task_t *task, isc_event_t *event);
 static void resquery_connected(isc_task_t *task, isc_event_t *event);
 static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying,
                     isc_boolean_t badcache);
-static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
+static void fctx_destroy(fetchctx_t *fctx);
+static isc_boolean_t fctx_unlink(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,
@@ -478,8 +481,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
        dns_valarg_t *valarg;
        isc_result_t result;
 
-       valarg = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                            sizeof(*valarg));
+       valarg = isc_mem_get(fctx->mctx, sizeof(*valarg));
        if (valarg == NULL)
                return (ISC_R_NOMEMORY);
 
@@ -501,8 +503,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
                }
                ISC_LIST_APPEND(fctx->validators, validator, link);
        } else
-               isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
-                           valarg, sizeof(*valarg));
+               isc_mem_put(fctx->mctx, valarg, sizeof(*valarg));
        return (result);
 }
 
@@ -1386,13 +1387,12 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
 
        dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
 
-       query = isc_mem_get(res->buckets[fctx->bucketnum].mctx,
-                           sizeof(*query));
+       query = isc_mem_get(fctx->mctx, sizeof(*query));
        if (query == NULL) {
                result = ISC_R_NOMEMORY;
                goto stop_idle_timer;
        }
-       query->mctx = res->buckets[fctx->bucketnum].mctx;
+       query->mctx = fctx->mctx;
        query->options = options;
        query->attributes = 0;
        query->sends = 0;
@@ -1569,8 +1569,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
  cleanup_query:
        if (query->connects == 0) {
                query->magic = 0;
-               isc_mem_put(res->buckets[fctx->bucketnum].mctx,
-                           query, sizeof(*query));
+               isc_mem_put(fctx->mctx, query, sizeof(*query));
        }
 
  stop_idle_timer:
@@ -1600,8 +1599,7 @@ add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) {
        if (bad_edns(fctx, address))
                return;
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
+       sa = isc_mem_get(fctx->mctx, sizeof(*sa));
        if (sa == NULL)
                return;
 
@@ -1630,8 +1628,7 @@ add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
        if (triededns(fctx, address))
                return;
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
+       sa = isc_mem_get(fctx->mctx, sizeof(*sa));
        if (sa == NULL)
                return;
 
@@ -1660,8 +1657,7 @@ add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
        if (triededns512(fctx, address))
                return;
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
+       sa = isc_mem_get(fctx->mctx, sizeof(*sa));
        if (sa == NULL)
                return;
 
@@ -2167,6 +2163,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
        isc_boolean_t want_done = ISC_FALSE;
        isc_boolean_t bucket_empty = ISC_FALSE;
        unsigned int bucketnum;
+       isc_boolean_t destroy = ISC_FALSE;
 
        find = event->ev_sender;
        fctx = event->ev_arg;
@@ -2205,8 +2202,10 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
        } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
                   fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
 
-               if (fctx->references == 0)
-                       bucket_empty = fctx_destroy(fctx);
+               if (fctx->references == 0) {
+                       bucket_empty = fctx_unlink(fctx);
+                       destroy = ISC_TRUE;
+               }
        }
        UNLOCK(&res->buckets[bucketnum].lock);
 
@@ -2217,8 +2216,11 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
                fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        else if (want_done)
                fctx_done(fctx, ISC_R_FAILURE, __LINE__);
-       else if (bucket_empty)
-               empty_bucket(res);
+       else if (destroy) {
+                       fctx_destroy(fctx);
+               if (bucket_empty)
+                       empty_bucket(res);
+       }
 }
 
 
@@ -2341,8 +2343,7 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason,
 
        FCTXTRACE("add_bad");
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
+       sa = isc_mem_get(fctx->mctx, sizeof(*sa));
        if (sa == NULL)
                return;
        *sa = *address;
@@ -2625,12 +2626,9 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
                        fctx->fwdpolicy = forwarders->fwdpolicy;
                        if (fctx->fwdpolicy == dns_fwdpolicy_only &&
                            isstrictsubdomain(domain, &fctx->domain)) {
-                               isc_mem_t *mctx;
-
-                               mctx = res->buckets[fctx->bucketnum].mctx;
-                               dns_name_free(&fctx->domain, mctx);
+                               dns_name_free(&fctx->domain, fctx->mctx);
                                dns_name_init(&fctx->domain, NULL);
-                               result = dns_name_dup(domain, mctx,
+                               result = dns_name_dup(domain, fctx->mctx,
                                                      &fctx->domain);
                                if (result != ISC_R_SUCCESS)
                                        return (result);
@@ -3069,10 +3067,9 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) {
 }
 
 static isc_boolean_t
-fctx_destroy(fetchctx_t *fctx) {
+fctx_unlink(fetchctx_t *fctx) {
        dns_resolver_t *res;
        unsigned int bucketnum;
-       isc_sockaddr_t *sa, *next_sa;
 
        /*
         * Caller must be holding the bucket lock.
@@ -3089,13 +3086,42 @@ fctx_destroy(fetchctx_t *fctx) {
        REQUIRE(fctx->references == 0);
        REQUIRE(ISC_LIST_EMPTY(fctx->validators));
 
-       FCTXTRACE("destroy");
+       FCTXTRACE("unlink");
 
        res = fctx->res;
        bucketnum = fctx->bucketnum;
 
        ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
 
+       LOCK(&res->nlock);
+       res->nfctx--;
+       UNLOCK(&res->nlock);
+
+       if (res->buckets[bucketnum].exiting &&
+           ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
+               return (ISC_TRUE);
+
+       return (ISC_FALSE);
+}
+
+static void
+fctx_destroy(fetchctx_t *fctx) {
+       isc_sockaddr_t *sa, *next_sa;
+
+       REQUIRE(VALID_FCTX(fctx));
+       REQUIRE(fctx->state == fetchstate_done ||
+               fctx->state == fetchstate_init);
+       REQUIRE(ISC_LIST_EMPTY(fctx->events));
+       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+       REQUIRE(ISC_LIST_EMPTY(fctx->finds));
+       REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
+       REQUIRE(fctx->pending == 0);
+       REQUIRE(fctx->references == 0);
+       REQUIRE(ISC_LIST_EMPTY(fctx->validators));
+       REQUIRE(!ISC_LINK_LINKED(fctx, link));
+
+       FCTXTRACE("destroy");
+
        /*
         * Free bad.
         */
@@ -3104,7 +3130,7 @@ fctx_destroy(fetchctx_t *fctx) {
             sa = next_sa) {
                next_sa = ISC_LIST_NEXT(sa, link);
                ISC_LIST_UNLINK(fctx->bad, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+               isc_mem_put(fctx->mctx, sa, sizeof(*sa));
        }
 
        for (sa = ISC_LIST_HEAD(fctx->edns);
@@ -3112,7 +3138,7 @@ fctx_destroy(fetchctx_t *fctx) {
             sa = next_sa) {
                next_sa = ISC_LIST_NEXT(sa, link);
                ISC_LIST_UNLINK(fctx->edns, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+               isc_mem_put(fctx->mctx, sa, sizeof(*sa));
        }
 
        for (sa = ISC_LIST_HEAD(fctx->edns512);
@@ -3120,7 +3146,7 @@ fctx_destroy(fetchctx_t *fctx) {
             sa = next_sa) {
                next_sa = ISC_LIST_NEXT(sa, link);
                ISC_LIST_UNLINK(fctx->edns512, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+               isc_mem_put(fctx->mctx, sa, sizeof(*sa));
        }
 
        for (sa = ISC_LIST_HEAD(fctx->bad_edns);
@@ -3128,31 +3154,21 @@ fctx_destroy(fetchctx_t *fctx) {
             sa = next_sa) {
                next_sa = ISC_LIST_NEXT(sa, link);
                ISC_LIST_UNLINK(fctx->bad_edns, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+               isc_mem_put(fctx->mctx, sa, sizeof(*sa));
        }
 
        isc_timer_detach(&fctx->timer);
        dns_message_destroy(&fctx->rmessage);
        dns_message_destroy(&fctx->qmessage);
        if (dns_name_countlabels(&fctx->domain) > 0)
-               dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+               dns_name_free(&fctx->domain, fctx->mctx);
        if (dns_rdataset_isassociated(&fctx->nameservers))
                dns_rdataset_disassociate(&fctx->nameservers);
-       dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+       dns_name_free(&fctx->name, fctx->mctx);
        dns_db_detach(&fctx->cache);
        dns_adb_detach(&fctx->adb);
-       isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
-       isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
-
-       LOCK(&res->nlock);
-       res->nfctx--;
-       UNLOCK(&res->nlock);
-
-       if (res->buckets[bucketnum].exiting &&
-           ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
-               return (ISC_TRUE);
-
-       return (ISC_FALSE);
+       isc_mem_free(fctx->mctx, fctx->info);
+       isc_mem_putanddetach(&fctx->mctx, fctx, sizeof(*fctx));
 }
 
 /*
@@ -3252,6 +3268,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
        dns_resolver_t *res;
        unsigned int bucketnum;
        dns_validator_t *validator;
+       isc_boolean_t destroy = ISC_FALSE;
 
        REQUIRE(VALID_FCTX(fctx));
 
@@ -3301,13 +3318,18 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
        }
 
        if (fctx->references == 0 && fctx->pending == 0 &&
-           fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
-               bucket_empty = fctx_destroy(fctx);
+           fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+               bucket_empty = fctx_unlink(fctx);
+               destroy = ISC_TRUE;
+       }
 
        UNLOCK(&res->buckets[bucketnum].lock);
 
-       if (bucket_empty)
-               empty_bucket(res);
+       if (destroy) {
+               fctx_destroy(fctx);
+               if (bucket_empty)
+                       empty_bucket(res);
+       }
 }
 
 static void
@@ -3316,6 +3338,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
        isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
        dns_resolver_t *res;
        unsigned int bucketnum;
+       isc_boolean_t destroy = ISC_FALSE;
 
        REQUIRE(VALID_FCTX(fctx));
 
@@ -3348,7 +3371,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
                        /*
                         * It's now safe to destroy this fctx.
                         */
-                       bucket_empty = fctx_destroy(fctx);
+                       bucket_empty = fctx_unlink(fctx);
+                       destroy = ISC_TRUE;
                }
                done = ISC_TRUE;
        } else {
@@ -3370,6 +3394,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
        if (!done) {
                isc_result_t result;
 
+               INSIST(!destroy);
+
                /*
                 * All is well.  Start working on the fetch.
                 */
@@ -3378,8 +3404,11 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
                        fctx_done(fctx, result, __LINE__);
                else
                        fctx_try(fctx, ISC_FALSE, ISC_FALSE);
-       } else if (bucket_empty)
-               empty_bucket(res);
+       } else if (destroy) {
+                       fctx_destroy(fctx);
+               if (bucket_empty)
+                       empty_bucket(res);
+       }
 }
 
 /*
@@ -3467,27 +3496,29 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
        char typebuf[DNS_RDATATYPE_FORMATSIZE];
        dns_name_t suffix;
+       isc_mem_t *mctx;
 
        /*
         * Caller must be holding the lock for bucket number 'bucketnum'.
         */
        REQUIRE(fctxp != NULL && *fctxp == NULL);
 
-       fctx = isc_mem_get(res->buckets[bucketnum].mctx, sizeof(*fctx));
+       mctx = res->buckets[bucketnum].mctx;
+       fctx = isc_mem_get(mctx, sizeof(*fctx));
        if (fctx == NULL)
                return (ISC_R_NOMEMORY);
        dns_name_format(name, buf, sizeof(buf));
        dns_rdatatype_format(type, typebuf, sizeof(typebuf));
        strcat(buf, "/");       /* checked */
        strcat(buf, typebuf);   /* checked */
-       fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf);
+       fctx->info = isc_mem_strdup(mctx, buf);
        if (fctx->info == NULL) {
                result = ISC_R_NOMEMORY;
                goto cleanup_fetch;
        }
        FCTXTRACE("create");
        dns_name_init(&fctx->name, NULL);
-       result = dns_name_dup(name, res->buckets[bucketnum].mctx, &fctx->name);
+       result = dns_name_dup(name, mctx, &fctx->name);
        if (result != ISC_R_SUCCESS)
                goto cleanup_info;
        dns_name_init(&fctx->domain, NULL);
@@ -3590,9 +3621,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
                                                      NULL);
                        if (result != ISC_R_SUCCESS)
                                goto cleanup_name;
-                       result = dns_name_dup(domain,
-                                             res->buckets[bucketnum].mctx,
-                                             &fctx->domain);
+                       result = dns_name_dup(domain, mctx, &fctx->domain);
                        if (result != ISC_R_SUCCESS) {
                                dns_rdataset_disassociate(&fctx->nameservers);
                                goto cleanup_name;
@@ -3603,16 +3632,12 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
                        /*
                         * We're in forward-only mode.  Set the query domain.
                         */
-                       result = dns_name_dup(domain,
-                                             res->buckets[bucketnum].mctx,
-                                             &fctx->domain);
+                       result = dns_name_dup(domain, mctx, &fctx->domain);
                        if (result != ISC_R_SUCCESS)
                                goto cleanup_name;
                }
        } else {
-               result = dns_name_dup(domain,
-                                     res->buckets[bucketnum].mctx,
-                                     &fctx->domain);
+               result = dns_name_dup(domain, mctx, &fctx->domain);
                if (result != ISC_R_SUCCESS)
                        goto cleanup_name;
                dns_rdataset_clone(nameservers, &fctx->nameservers);
@@ -3625,16 +3650,14 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
 
        fctx->qmessage = NULL;
-       result = dns_message_create(res->buckets[bucketnum].mctx,
-                                   DNS_MESSAGE_INTENTRENDER,
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
                                    &fctx->qmessage);
 
        if (result != ISC_R_SUCCESS)
                goto cleanup_domain;
 
        fctx->rmessage = NULL;
-       result = dns_message_create(res->buckets[bucketnum].mctx,
-                                   DNS_MESSAGE_INTENTPARSE,
+       result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE,
                                    &fctx->rmessage);
 
        if (result != ISC_R_SUCCESS)
@@ -3684,6 +3707,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        dns_db_attach(res->view->cachedb, &fctx->cache);
        fctx->adb = NULL;
        dns_adb_attach(res->view->adb, &fctx->adb);
+       fctx->mctx = NULL;
+       isc_mem_attach(mctx, &fctx->mctx);
 
        ISC_LIST_INIT(fctx->events);
        ISC_LINK_INIT(fctx, link);
@@ -3707,18 +3732,18 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
 
  cleanup_domain:
        if (dns_name_countlabels(&fctx->domain) > 0)
-               dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+               dns_name_free(&fctx->domain, mctx);
        if (dns_rdataset_isassociated(&fctx->nameservers))
                dns_rdataset_disassociate(&fctx->nameservers);
 
  cleanup_name:
-       dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+       dns_name_free(&fctx->name, mctx);
 
  cleanup_info:
-       isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
+       isc_mem_free(mctx, fctx->info);
 
  cleanup_fetch:
-       isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
+       isc_mem_put(mctx, fctx, sizeof(*fctx));
 
        return (result);
 }
@@ -3928,6 +3953,7 @@ maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) {
        isc_boolean_t bucket_empty = ISC_FALSE;
        dns_resolver_t *res = fctx->res;
        dns_validator_t *validator, *next_validator;
+       isc_boolean_t destroy = ISC_FALSE;
 
        REQUIRE(SHUTTINGDOWN(fctx));
 
@@ -3943,11 +3969,15 @@ maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) {
                dns_validator_cancel(validator);
        }
 
-       if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators))
-               bucket_empty = fctx_destroy(fctx);
+       if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+               bucket_empty = fctx_unlink(fctx);
+               destroy = ISC_TRUE;
+       }
  unlock:
        if (!locked)
                UNLOCK(&res->buckets[bucketnum].lock);
+       if (destroy)
+               fctx_destroy(fctx);
        return (bucket_empty);
 }
 
@@ -4002,8 +4032,7 @@ validated(isc_task_t *task, isc_event_t *event) {
         * destroy the fctx if necessary.
         */
        dns_validator_destroy(&vevent->validator);
-       isc_mem_put(res->buckets[fctx->bucketnum].mctx,
-                   valarg, sizeof(*valarg));
+       isc_mem_put(fctx->mctx, valarg, sizeof(*valarg));
 
        negative = ISC_TF(vevent->rdataset == NULL);
 
@@ -5717,14 +5746,11 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
                 *              if so we should bail out.
                 */
                INSIST(dns_name_countlabels(&fctx->domain) > 0);
-               dns_name_free(&fctx->domain,
-                             fctx->res->buckets[fctx->bucketnum].mctx);
+               dns_name_free(&fctx->domain, fctx->mctx);
                if (dns_rdataset_isassociated(&fctx->nameservers))
                        dns_rdataset_disassociate(&fctx->nameservers);
                dns_name_init(&fctx->domain, NULL);
-               result = dns_name_dup(ns_name,
-                                     fctx->res->buckets[fctx->bucketnum].mctx,
-                                     &fctx->domain);
+               result = dns_name_dup(ns_name, fctx->mctx, &fctx->domain);
                if (result != ISC_R_SUCCESS)
                        return (result);
                fctx->attributes |= FCTX_ATTR_WANTCACHE;
@@ -6226,7 +6252,8 @@ fctx_decreference(fetchctx_t *fctx) {
                         * This fctx is already shutdown; we were just
                         * waiting for the last reference to go away.
                         */
-                       bucket_empty = fctx_destroy(fctx);
+                       bucket_empty = fctx_unlink(fctx);
+                       fctx_destroy(fctx);
                } else {
                        /*
                         * Initiate shutdown.
@@ -6281,12 +6308,9 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) {
                fctx->ns_ttl = fctx->nameservers.ttl;
                fctx->ns_ttl_ok = ISC_TRUE;
                log_ns_ttl(fctx, "resume_dslookup");
-               dns_name_free(&fctx->domain,
-                             fctx->res->buckets[bucketnum].mctx);
+               dns_name_free(&fctx->domain, fctx->mctx);
                dns_name_init(&fctx->domain, NULL);
-               result = dns_name_dup(&fctx->nsname,
-                                     fctx->res->buckets[bucketnum].mctx,
-                                     &fctx->domain);
+               result = dns_name_dup(&fctx->nsname, fctx->mctx, &fctx->domain);
                if (result != ISC_R_SUCCESS) {
                        fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
                        goto cleanup;
@@ -7204,12 +7228,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
                                fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
                                return;
                        }
-                       dns_name_free(&fctx->domain,
-                                     fctx->res->buckets[fctx->bucketnum].mctx);
+                       dns_name_free(&fctx->domain, fctx->mctx);
                        dns_name_init(&fctx->domain, NULL);
-                       result = dns_name_dup(fname,
-                                             fctx->res->buckets[fctx->bucketnum].mctx,
-                                             &fctx->domain);
+                       result = dns_name_dup(fname, fctx->mctx, &fctx->domain);
                        if (result != ISC_R_SUCCESS) {
                                fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
                                return;
@@ -7949,6 +7970,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
        unsigned int count = 0;
        unsigned int spillat;
        unsigned int spillatmin;
+       isc_boolean_t destroy = ISC_FALSE;
 
        UNUSED(forwarders);
 
@@ -8046,16 +8068,20 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
                        isc_task_send(res->buckets[bucketnum].task, &event);
                } else {
                        /*
-                        * We don't care about the result of fctx_destroy()
+                        * We don't care about the result of fctx_unlink()
                         * since we know we're not exiting.
                         */
-                       (void)fctx_destroy(fctx);
+                       (void)fctx_unlink(fctx);
+                       destroy = ISC_TRUE;
                }
        }
 
  unlock:
        UNLOCK(&res->buckets[bucketnum].lock);
 
+       if (destroy)
+               fctx_destroy(fctx);
+
        if (result == ISC_R_SUCCESS) {
                FTRACE("created");
                *fetchp = fetch;