From 4cc1160e4d81e7b835fae57b52172b8453e40113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 15 Jan 2025 13:02:20 +0100 Subject: [PATCH] Replace linked lists with the hashtables to hold fetch contexts When the recursive-clients value is too large, the linked lists holding the fetch contexts can also grow large and since the algorithm to merge outgoing queries is quadratic, named can get slow. Replace the linked list with hashtable for faster lookups. This also allows us to reduce the number of tasks (buckets) in the resolver. --- bin/named/server.c | 109 ++++++++++++++++- lib/dns/client.c | 7 +- lib/dns/resolver.c | 285 ++++++++++++++++++++++++++++++--------------- 3 files changed, 299 insertions(+), 102 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 8ce865f2c7..bd3f5a8dca 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -155,8 +155,6 @@ #define SIZE_AS_PERCENT ((size_t)-2) #endif /* ifndef SIZE_AS_PERCENT */ -#define RESOLVER_NTASKS 523 - /* RFC7828 defines timeout as 16-bit value specified in units of 100 * milliseconds, so the maximum and minimum advertised and keepalive * timeouts are capped by the data type (it's ~109 minutes) @@ -503,6 +501,104 @@ static isc_result_t nzf_append(dns_view_t *view, const cfg_obj_t *zconfig); #endif /* ifdef HAVE_LMDB */ +static const uint32_t primes[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, + 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, + 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, + 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, + 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, + 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, + 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, + 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, + 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, + 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, + 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, + 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, + 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, + 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, + 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, + 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, + 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, + 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, + 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, + 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, + 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, + 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, + 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, + 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, + 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, + 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, + 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, + 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, + 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, + 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, + 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, + 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, + 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, + 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, + 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, + 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, + 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, + 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, + 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, + 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, + 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, + 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, + 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, + 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, + 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, + 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, + 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, + 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, + 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, + 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, + 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, + 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, + 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, + 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, + 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, + 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, + 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, + 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, + 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, + 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, + 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, + 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, + 7883, 7901, 7907, 7919, +}; + +static uint32_t +closest_prime(uint32_t n) { + for (size_t i = 0; i < ARRAY_SIZE(primes); i++) { + if (primes[i] >= n) { + return primes[i]; + } + } + + return primes[ARRAY_SIZE(primes) - 1]; +} + /*% * Configure a single view ACL at '*aclp'. Get its configuration from * 'vconfig' (for per-view configuration) and maybe from 'config' @@ -4221,7 +4317,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, named_cache_t *nsc; bool zero_no_soattl; dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL; - unsigned int query_timeout, ndisp; + unsigned int query_timeout, ndisp, ntasks; bool old_rpz_ok = false; dns_dyndbctx_t *dctx = NULL; unsigned int resolver_param; @@ -4880,10 +4976,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, } dns_view_setresquerystats(view, resquerystats); + ntasks = closest_prime(2 * named_g_cpus); ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH); - CHECK(dns_view_createresolver(view, named_g_taskmgr, RESOLVER_NTASKS, - ndisp, named_g_netmgr, named_g_timermgr, - resopts, named_g_dispatchmgr, dispatch4, + CHECK(dns_view_createresolver(view, named_g_taskmgr, ntasks, ndisp, + named_g_netmgr, named_g_timermgr, resopts, + named_g_dispatchmgr, dispatch4, dispatch6)); /* diff --git a/lib/dns/client.c b/lib/dns/client.c index ed6bf0e0cb..bde6ec61a3 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -60,8 +60,6 @@ #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) -#define RESOLVER_NTASKS 523 - #define CHECK(r) \ do { \ result = (r); \ @@ -328,9 +326,8 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, isc_refcount_init(&client->references, 1); /* Create the default view for class IN */ - result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS, - nm, timermgr, client->dispatchmgr, dispatchv4, - dispatchv6, &view); + result = createview(mctx, dns_rdataclass_in, taskmgr, 1, nm, timermgr, + client->dispatchmgr, dispatchv4, dispatchv6, &view); if (result != ISC_R_SUCCESS) { goto cleanup_references; } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index e612eb7bb3..2178a17b5e 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -327,6 +329,7 @@ struct fetchctx { unsigned int options; unsigned int bucketnum; unsigned int dbucketnum; + bool hashed; char *info; isc_mem_t *mctx; isc_stdtime_t now; @@ -341,7 +344,6 @@ struct fetchctx { bool cloned; bool spilled; isc_event_t control_event; - ISC_LINK(struct fetchctx) link; ISC_LIST(dns_fetchevent_t) events; /*% Locked by task event serialization. */ @@ -514,10 +516,14 @@ struct dns_fetch { #define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h') #define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC) +#define DNS_FCTX_KEYSIZE \ + (DNS_NAME_MAXWIRE + sizeof(dns_rdatatype_t) + sizeof(unsigned int)) + typedef struct fctxbucket { isc_task_t *task; isc_mutex_t lock; - ISC_LIST(fetchctx_t) fctxs; + isc_refcount_t nfctxs; + isc_ht_t *fctxs; atomic_bool exiting; } fctxbucket_t; @@ -529,12 +535,11 @@ struct fctxcount { uint32_t allowed; uint32_t dropped; isc_stdtime_t logged; - ISC_LINK(fctxcount_t) link; }; typedef struct zonebucket { isc_mutex_t lock; - ISC_LIST(fctxcount_t) list; + isc_ht_t *counters; } zonebucket_t; typedef struct alternate { @@ -603,9 +608,6 @@ struct dns_resolver { /* Locked by primelock. */ dns_fetch_t *primefetch; - - /* Atomic. */ - atomic_uint_fast32_t nfctx; }; #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!') @@ -1623,6 +1625,25 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter, bool final) { counter->logged = now; } +static void +fcount_makekey(const dns_name_t *name, uint8_t *key, size_t *keysizep) { + REQUIRE(*keysizep >= name->length); + + size_t keysize = 0; + isc_buffer_t buffer; + dns_name_t downname; + isc_result_t result; + + DNS_NAME_INIT(&downname, NULL); + isc_buffer_init(&buffer, key, *keysizep); + + result = dns_name_downcase(name, &downname, &buffer); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + keysize += isc_buffer_usedlength(&buffer); + + *keysizep = keysize; +} + static isc_result_t fcount_incr(fetchctx_t *fctx, bool force) { isc_result_t result = ISC_R_SUCCESS; @@ -1630,6 +1651,9 @@ fcount_incr(fetchctx_t *fctx, bool force) { fctxcount_t *counter = NULL; uint32_t hashval; uint32_t dbucketnum; + uint8_t key[DNS_NAME_MAXWIRE]; + size_t keysize = sizeof(key); + uint_fast32_t spill; REQUIRE(fctx != NULL); REQUIRE(fctx->res != NULL); @@ -1641,15 +1665,14 @@ fcount_incr(fetchctx_t *fctx, bool force) { dbucket = &fctx->res->dbuckets[dbucketnum]; LOCK(&dbucket->lock); - for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; - counter = ISC_LIST_NEXT(counter, link)) - { - if (dns_name_equal(counter->domain, fctx->domain)) { - break; - } - } - if (counter == NULL) { + fcount_makekey(fctx->domain, key, &keysize); + + result = isc_ht_find(dbucket->counters, key, keysize, + (void **)&counter); + + switch (result) { + case ISC_R_NOTFOUND: counter = isc_mem_get(fctx->res->mctx, sizeof(*counter)); *counter = (fctxcount_t){ .count = 1, @@ -1657,11 +1680,11 @@ fcount_incr(fetchctx_t *fctx, bool force) { }; counter->domain = dns_fixedname_initname(&counter->dfname); - ISC_LINK_INIT(counter, link); dns_name_copy(fctx->domain, counter->domain); - ISC_LIST_APPEND(dbucket->list, counter, link); - } else { - uint_fast32_t spill = atomic_load_acquire(&fctx->res->zspill); + result = isc_ht_add(dbucket->counters, key, keysize, counter); + break; + case ISC_R_SUCCESS: + spill = atomic_load_acquire(&fctx->res->zspill); if (!force && spill != 0 && counter->count >= spill) { counter->dropped++; fcount_logspill(fctx, counter, false); @@ -1670,6 +1693,9 @@ fcount_incr(fetchctx_t *fctx, bool force) { counter->count++; counter->allowed++; } + break; + default: + UNREACHABLE(); } UNLOCK(&dbucket->lock); @@ -1684,6 +1710,9 @@ static void fcount_decr(fetchctx_t *fctx) { zonebucket_t *dbucket = NULL; fctxcount_t *counter = NULL; + uint8_t key[DNS_NAME_MAXWIRE]; + size_t keysize = sizeof(key); + isc_result_t result; REQUIRE(fctx != NULL); @@ -1694,24 +1723,22 @@ fcount_decr(fetchctx_t *fctx) { dbucket = &fctx->res->dbuckets[fctx->dbucketnum]; LOCK(&dbucket->lock); - for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; - counter = ISC_LIST_NEXT(counter, link)) - { - if (dns_name_equal(counter->domain, fctx->domain)) { - break; - } - } - if (counter != NULL) { - INSIST(counter->count != 0); - counter->count--; - fctx->dbucketnum = RES_NOBUCKET; + fcount_makekey(fctx->domain, key, &keysize); - if (counter->count == 0) { - fcount_logspill(fctx, counter, true); - ISC_LIST_UNLINK(dbucket->list, counter, link); - isc_mem_put(fctx->res->mctx, counter, sizeof(*counter)); - } + result = isc_ht_find(dbucket->counters, key, keysize, + (void **)&counter); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + INSIST(counter->count != 0); + counter->count--; + fctx->dbucketnum = RES_NOBUCKET; + + if (counter->count == 0) { + fcount_logspill(fctx, counter, true); + result = isc_ht_delete(dbucket->counters, key, keysize); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + isc_mem_put(fctx->res->mctx, counter, sizeof(*counter)); } UNLOCK(&dbucket->lock); @@ -1830,6 +1857,73 @@ fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) { } } +static void +fctx_makekey(const dns_name_t *name, dns_rdatatype_t type, unsigned int options, + uint8_t *key, size_t *keysizep) { + REQUIRE(*keysizep >= name->length + sizeof(type) + sizeof(options)); + + size_t keysize = 0; + isc_buffer_t buffer; + dns_name_t downname; + isc_result_t result; + + DNS_NAME_INIT(&downname, NULL); + isc_buffer_init(&buffer, key, *keysizep); + + result = dns_name_downcase(name, &downname, &buffer); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + keysize += isc_buffer_usedlength(&buffer); + + memmove(&key[keysize], &type, sizeof(type)); + keysize += sizeof(type); + + memmove(&key[keysize], &options, sizeof(options)); + keysize += sizeof(options); + + *keysizep = keysize; +} + +static void +fctx_unhash(fetchctx_t *fctx) { + dns_resolver_t *res = fctx->res; + unsigned int bucketnum = fctx->bucketnum; + uint8_t key[DNS_FCTX_KEYSIZE] = { 0 }; + size_t keysize = sizeof(key); + isc_result_t result; + + if (!fctx->hashed) { + return; + } + + fctx_makekey(fctx->name, fctx->type, fctx->options, key, &keysize); + + result = isc_ht_delete(res->buckets[bucketnum].fctxs, key, keysize); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + fctx->hashed = false; +} + +static void +fctx_hash(fetchctx_t *fctx) { + dns_resolver_t *res = fctx->res; + unsigned int bucketnum = fctx->bucketnum; + uint8_t key[DNS_FCTX_KEYSIZE] = { 0 }; + size_t keysize = sizeof(key); + isc_result_t result; + bool unshared = ((fctx->options & DNS_FETCHOPT_UNSHARED) != 0); + + if (unshared) { + return; + } + + fctx_makekey(fctx->name, fctx->type, fctx->options, key, &keysize); + + result = isc_ht_add(res->buckets[bucketnum].fctxs, key, keysize, fctx); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + fctx->hashed = true; +} + static void fctx__done_detach(fetchctx_t **fctxp, isc_result_t result, const char *file, unsigned int line, const char *func) { @@ -1857,6 +1951,7 @@ fctx__done_detach(fetchctx_t **fctxp, isc_result_t result, const char *file, LOCK(&res->buckets[fctx->bucketnum].lock); INSIST(fctx->state != fetchstate_done); fctx->state = fetchstate_done; + fctx_unhash(fctx); UNLOCK(&res->buckets[fctx->bucketnum].lock); if (result == ISC_R_SUCCESS) { @@ -2089,6 +2184,10 @@ resquery_timeout(resquery_t *query) { event->result = ISC_R_TIMEDOUT; isc_task_sendanddetach(&sender, ISC_EVENT_PTR(&event)); } + + if (ISC_LIST_EMPTY(fctx->events)) { + fctx_unhash(fctx); + } UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); /* @@ -4481,7 +4580,6 @@ fctx_destroy(fetchctx_t *fctx, bool exiting) { struct tried *tried = NULL; unsigned int bucketnum; bool bucket_empty = false; - uint_fast32_t nfctx; REQUIRE(VALID_FCTX(fctx)); REQUIRE(ISC_LIST_EMPTY(fctx->events)); @@ -4501,18 +4599,19 @@ fctx_destroy(fetchctx_t *fctx, bool exiting) { LOCK(&res->buckets[bucketnum].lock); REQUIRE(fctx->state != fetchstate_active); - ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); + fctx_unhash(fctx); - nfctx = atomic_fetch_sub_release(&res->nfctx, 1); - INSIST(nfctx > 0); - - dec_stats(res, dns_resstatscounter_nfetch); + INSIST(res->buckets[bucketnum].nfctxs > 0); + res->buckets[bucketnum].nfctxs--; if (atomic_load_acquire(&res->buckets[bucketnum].exiting) && - ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) + res->buckets[bucketnum].nfctxs == 0) { bucket_empty = true; } + + dec_stats(res, dns_resstatscounter_nfetch); + UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty && exiting && @@ -4654,6 +4753,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { if (fctx->state == fetchstate_active) { fctx->state = fetchstate_done; + fctx_unhash(fctx); fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); @@ -4828,7 +4928,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, isc_interval_t interval; unsigned int findoptions = 0; char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 1]; - uint_fast32_t nfctx; size_t p; /* @@ -5110,7 +5209,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, isc_mem_attach(res->mctx, &fctx->mctx); ISC_LIST_INIT(fctx->events); - ISC_LINK_INIT(fctx, link); fctx->magic = FCTX_MAGIC; /* @@ -5124,10 +5222,9 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name, fctx_minimize_qname(fctx); } - ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link); + fctx_hash(fctx); - nfctx = atomic_fetch_add_relaxed(&res->nfctx, 1); - INSIST(nfctx < UINT32_MAX); + res->buckets[bucketnum].nfctxs++; inc_stats(res, dns_resstatscounter_nfetch); @@ -5334,6 +5431,7 @@ clone_results(fetchctx_t *fctx) { * Caller must be holding the appropriate lock. */ + fctx_unhash(fctx); fctx->cloned = true; for (event = ISC_LIST_HEAD(fctx->events); event != NULL; @@ -10356,12 +10454,12 @@ destroy(dns_resolver_t *res) { RTRACE("destroy"); - REQUIRE(atomic_load_acquire(&res->nfctx) == 0); - 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)); + INSIST(res->buckets[i].nfctxs == 0); + INSIST(isc_ht_count(res->buckets[i].fctxs) == 0); + isc_ht_destroy(&res->buckets[i].fctxs); isc_task_shutdown(res->buckets[i].task); isc_task_detach(&res->buckets[i].task); isc_mutex_destroy(&res->buckets[i].lock); @@ -10369,7 +10467,8 @@ destroy(dns_resolver_t *res) { isc_mem_put(res->mctx, res->buckets, res->nbuckets * sizeof(fctxbucket_t)); for (i = 0; i < HASHSIZE(res->dhashbits); i++) { - INSIST(ISC_LIST_EMPTY(res->dbuckets[i].list)); + INSIST(isc_ht_count(res->dbuckets[i].counters) == 0); + isc_ht_destroy(&res->dbuckets[i].counters); isc_mutex_destroy(&res->dbuckets[i].lock); } isc_mem_put(res->mctx, res->dbuckets, @@ -10500,7 +10599,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, atomic_init(&res->exiting, false); atomic_init(&res->priming, false); atomic_init(&res->zspill, 0); - atomic_init(&res->nfctx, 0); ISC_LIST_INIT(res->whenshutdown); ISC_LIST_INIT(res->alternates); @@ -10537,7 +10635,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, snprintf(name, sizeof(name), "res%" PRIu32, i); isc_task_setname(res->buckets[i].task, name, res); - ISC_LIST_INIT(res->buckets[i].fctxs); + isc_ht_init(&res->buckets[i].fctxs, res->mctx, 8, + ISC_HT_CASE_SENSITIVE); atomic_init(&res->buckets[i].exiting, false); } @@ -10545,8 +10644,10 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, HASHSIZE(res->dhashbits) * sizeof(res->dbuckets[0])); for (size_t i = 0; i < HASHSIZE(res->dhashbits); i++) { - res->dbuckets[i] = (zonebucket_t){ .list = { 0 } }; - ISC_LIST_INIT(res->dbuckets[i].list); + res->dbuckets[i] = (zonebucket_t){ 0 }; + isc_ht_init(&res->dbuckets[i].counters, res->mctx, 8, + ISC_HT_CASE_SENSITIVE); + isc_mutex_init(&res->dbuckets[i].lock); } @@ -10774,33 +10875,45 @@ dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, void dns_resolver_shutdown(dns_resolver_t *res) { unsigned int i; - fetchctx_t *fctx; isc_result_t result; - bool is_false = false; bool is_done = false; REQUIRE(VALID_RESOLVER(res)); RTRACE("shutdown"); - if (atomic_compare_exchange_strong(&res->exiting, &is_false, true)) { + if (atomic_compare_exchange_strong(&res->exiting, &(bool){ false }, + true)) + { 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)) + isc_ht_iter_t *it = NULL; + + isc_ht_iter_create(res->buckets[i].fctxs, &it); + + for (result = isc_ht_iter_first(it); + result == ISC_R_SUCCESS; + result = isc_ht_iter_next(it)) { + fetchctx_t *fctx = NULL; + isc_ht_iter_current(it, (void **)&fctx); fctx_shutdown(fctx); } + + isc_ht_iter_destroy(&it); + atomic_store(&res->buckets[i].exiting, true); - if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { + + if (res->buckets[i].nfctxs == 0) { if (isc_refcount_decrement( &res->activebuckets) == 1) { is_done = true; } } + UNLOCK(&res->buckets[i].lock); } if (is_done) { @@ -10831,24 +10944,6 @@ dns_resolver_detach(dns_resolver_t **resp) { } } -static bool -fctx_match(fetchctx_t *fctx, const dns_name_t *name, dns_rdatatype_t type, - unsigned int options) { - /* - * Don't match fetch contexts that are shutting down. - */ - if (fctx->cloned || fctx->state == fetchstate_done || - ISC_LIST_EMPTY(fctx->events)) - { - return false; - } - - if (fctx->type != type || fctx->options != options) { - return false; - } - return dns_name_equal(fctx->name, name); -} - static void log_fetch(const dns_name_t *name, dns_rdatatype_t type) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -11039,13 +11134,13 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, } if ((options & DNS_FETCHOPT_UNSHARED) == 0) { - for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs); - fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link)) - { - if (fctx_match(fctx, name, type, options)) { - break; - } - } + uint8_t key[DNS_FCTX_KEYSIZE]; + size_t keysize = sizeof(key); + + fctx_makekey(name, type, options, key, &keysize); + + (void)isc_ht_find(res->buckets[bucketnum].fctxs, key, keysize, + (void **)&fctx); } /* @@ -11192,6 +11287,7 @@ dns_resolver_cancelfetch(dns_fetch_t *fetch) { } } } + /* * The "trystale" event must be sent before the "fetchdone" event, * because the latter clears the "recursing" query attribute, which is @@ -11810,17 +11906,24 @@ dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format, REQUIRE(format == isc_statsformat_file); for (size_t i = 0; i < HASHSIZE(resolver->dhashbits); i++) { - fctxcount_t *fc; LOCK(&resolver->dbuckets[i].lock); - for (fc = ISC_LIST_HEAD(resolver->dbuckets[i].list); fc != NULL; - fc = ISC_LIST_NEXT(fc, link)) + isc_ht_iter_t *it = NULL; + isc_result_t result; + + isc_ht_iter_create(resolver->dbuckets[i].counters, &it); + for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS; + result = isc_ht_iter_next(it)) { - dns_name_print(fc->domain, fp); + fctxcount_t *counter = NULL; + isc_ht_iter_current(it, (void **)&counter); + dns_name_print(counter->domain, fp); fprintf(fp, ": %u active (%u spilled, %u " "allowed)\n", - fc->count, fc->dropped, fc->allowed); + counter->count, counter->dropped, + counter->allowed); } + isc_ht_iter_destroy(&it); UNLOCK(&resolver->dbuckets[i].lock); } }