2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 23:25:38 +00:00

Use automatically-resizing hash table for fetches-per-zone

Replace the statically-sized hash table used for fcount_incr()
and fcount_decr() with an isc_ht_t.
This commit is contained in:
Evan Hunt
2022-05-04 15:26:39 -07:00
committed by Ondřej Surý
parent 5731a3d7f0
commit 1595304312

View File

@@ -296,6 +296,22 @@ typedef enum {
badns_forwarder, badns_forwarder,
} badnstype_t; } badnstype_t;
typedef struct fctxcount fctxcount_t;
struct fctxcount {
dns_fixedname_t dfname;
dns_name_t *domain;
uint32_t count;
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;
} zonebucket_t;
struct fetchctx { struct fetchctx {
/*% Not locked. */ /*% Not locked. */
unsigned int magic; unsigned int magic;
@@ -305,7 +321,7 @@ struct fetchctx {
dns_rdatatype_t type; dns_rdatatype_t type;
unsigned int options; unsigned int options;
unsigned int bucketnum; unsigned int bucketnum;
unsigned int dbucketnum; zonebucket_t *zbucket;
char *info; char *info;
isc_mem_t *mctx; isc_mem_t *mctx;
isc_stdtime_t now; isc_stdtime_t now;
@@ -492,22 +508,6 @@ typedef struct fctxbucket {
atomic_bool exiting; atomic_bool exiting;
} fctxbucket_t; } fctxbucket_t;
typedef struct fctxcount fctxcount_t;
struct fctxcount {
dns_fixedname_t dfname;
dns_name_t *domain;
uint32_t count;
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;
} zonebucket_t;
typedef struct alternate { typedef struct alternate {
bool isaddress; bool isaddress;
union { union {
@@ -540,8 +540,8 @@ struct dns_resolver {
isc_dscp_t querydscp6; isc_dscp_t querydscp6;
unsigned int nbuckets; unsigned int nbuckets;
fctxbucket_t *buckets; fctxbucket_t *buckets;
uint8_t dhashbits; isc_ht_t *zonebuckets;
zonebucket_t *dbuckets; isc_rwlock_t zonehash_lock;
uint32_t lame_ttl; uint32_t lame_ttl;
ISC_LIST(alternate_t) alternates; ISC_LIST(alternate_t) alternates;
uint16_t udpsize; uint16_t udpsize;
@@ -1594,22 +1594,44 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter) {
static isc_result_t static isc_result_t
fcount_incr(fetchctx_t *fctx, bool force) { fcount_incr(fetchctx_t *fctx, bool force) {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
zonebucket_t *dbucket = NULL; dns_resolver_t *res = NULL;
zonebucket_t *zbucket = NULL;
fctxcount_t *counter = NULL; fctxcount_t *counter = NULL;
uint32_t hashval; isc_rwlocktype_t ltype = isc_rwlocktype_read;
uint32_t dbucketnum;
REQUIRE(fctx != NULL); REQUIRE(fctx != NULL);
REQUIRE(fctx->res != NULL); res = fctx->res;
REQUIRE(res != NULL);
INSIST(fctx->zbucket == NULL);
INSIST(fctx->dbucketnum == RES_NOBUCKET); RWLOCK(&res->zonehash_lock, ltype);
hashval = dns_name_fullhash(fctx->domain, false); result = isc_ht_find(res->zonebuckets, fctx->domain->ndata,
dbucketnum = isc_hash_bits32(hashval, fctx->res->dhashbits); fctx->domain->length, (void **)&zbucket);
if (result != ISC_R_SUCCESS) {
RWUNLOCK(&res->zonehash_lock, ltype);
zbucket = isc_mem_get(res->mctx, sizeof(*zbucket));
*zbucket = (zonebucket_t){ .list = { 0 } };
ISC_LIST_INIT(zbucket->list);
isc_mutex_init(&zbucket->lock);
dbucket = &fctx->res->dbuckets[dbucketnum]; ltype = isc_rwlocktype_write;
RWLOCK(&res->zonehash_lock, ltype);
result = isc_ht_add(res->zonebuckets, fctx->domain->ndata,
fctx->domain->length, zbucket);
if (result != ISC_R_SUCCESS) {
/* Another thread must have created it */
isc_mutex_destroy(&zbucket->lock);
isc_mem_put(res->mctx, zbucket, sizeof(*zbucket));
result = isc_ht_find(
res->zonebuckets, fctx->domain->ndata,
fctx->domain->length, (void **)&zbucket);
}
}
RUNTIME_CHECK(result == ISC_R_SUCCESS);
RWUNLOCK(&res->zonehash_lock, ltype);
LOCK(&dbucket->lock); LOCK(&zbucket->lock);
for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL; for (counter = ISC_LIST_HEAD(zbucket->list); counter != NULL;
counter = ISC_LIST_NEXT(counter, link)) counter = ISC_LIST_NEXT(counter, link))
{ {
if (dns_name_equal(counter->domain, fctx->domain)) { if (dns_name_equal(counter->domain, fctx->domain)) {
@@ -1618,7 +1640,7 @@ fcount_incr(fetchctx_t *fctx, bool force) {
} }
if (counter == NULL) { if (counter == NULL) {
counter = isc_mem_get(fctx->res->mctx, sizeof(*counter)); counter = isc_mem_get(res->mctx, sizeof(*counter));
*counter = (fctxcount_t){ *counter = (fctxcount_t){
.count = 1, .count = 1,
.allowed = 1, .allowed = 1,
@@ -1627,9 +1649,9 @@ fcount_incr(fetchctx_t *fctx, bool force) {
counter->domain = dns_fixedname_initname(&counter->dfname); counter->domain = dns_fixedname_initname(&counter->dfname);
ISC_LINK_INIT(counter, link); ISC_LINK_INIT(counter, link);
dns_name_copy(fctx->domain, counter->domain); dns_name_copy(fctx->domain, counter->domain);
ISC_LIST_APPEND(dbucket->list, counter, link); ISC_LIST_APPEND(zbucket->list, counter, link);
} else { } else {
uint_fast32_t spill = atomic_load_acquire(&fctx->res->zspill); uint_fast32_t spill = atomic_load_acquire(&res->zspill);
if (!force && spill != 0 && counter->count >= spill) { if (!force && spill != 0 && counter->count >= spill) {
counter->dropped++; counter->dropped++;
fcount_logspill(fctx, counter); fcount_logspill(fctx, counter);
@@ -1639,10 +1661,10 @@ fcount_incr(fetchctx_t *fctx, bool force) {
counter->allowed++; counter->allowed++;
} }
} }
UNLOCK(&dbucket->lock); UNLOCK(&zbucket->lock);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
fctx->dbucketnum = dbucketnum; fctx->zbucket = zbucket;
} }
return (result); return (result);
@@ -1650,19 +1672,18 @@ fcount_incr(fetchctx_t *fctx, bool force) {
static void static void
fcount_decr(fetchctx_t *fctx) { fcount_decr(fetchctx_t *fctx) {
zonebucket_t *dbucket = NULL; zonebucket_t *zbucket = NULL;
fctxcount_t *counter = NULL; fctxcount_t *counter = NULL;
REQUIRE(fctx != NULL); REQUIRE(fctx != NULL);
if (fctx->dbucketnum == RES_NOBUCKET) { zbucket = fctx->zbucket;
if (zbucket == NULL) {
return; return;
} }
dbucket = &fctx->res->dbuckets[fctx->dbucketnum]; LOCK(&zbucket->lock);
for (counter = ISC_LIST_HEAD(zbucket->list); counter != NULL;
LOCK(&dbucket->lock);
for (counter = ISC_LIST_HEAD(dbucket->list); counter != NULL;
counter = ISC_LIST_NEXT(counter, link)) counter = ISC_LIST_NEXT(counter, link))
{ {
if (dns_name_equal(counter->domain, fctx->domain)) { if (dns_name_equal(counter->domain, fctx->domain)) {
@@ -1673,15 +1694,14 @@ fcount_decr(fetchctx_t *fctx) {
if (counter != NULL) { if (counter != NULL) {
INSIST(counter->count != 0); INSIST(counter->count != 0);
counter->count--; counter->count--;
fctx->dbucketnum = RES_NOBUCKET; fctx->zbucket = NULL;
if (counter->count == 0) { if (counter->count == 0) {
ISC_LIST_UNLINK(dbucket->list, counter, link); ISC_LIST_UNLINK(zbucket->list, counter, link);
isc_mem_put(fctx->res->mctx, counter, sizeof(*counter)); isc_mem_put(fctx->res->mctx, counter, sizeof(*counter));
} }
} }
UNLOCK(&zbucket->lock);
UNLOCK(&dbucket->lock);
} }
static void static void
@@ -4696,7 +4716,6 @@ fctx_create(dns_resolver_t *res, isc_task_t *task, const dns_name_t *name,
.options = options, .options = options,
.task = task, .task = task,
.bucketnum = bucketnum, .bucketnum = bucketnum,
.dbucketnum = RES_NOBUCKET,
.state = fetchstate_init, .state = fetchstate_init,
.depth = depth, .depth = depth,
.qmin_labels = 1, .qmin_labels = 1,
@@ -6868,7 +6887,7 @@ name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
{ {
/* /*
* If 'name' is covered by a 'forward only' clause then we * If 'name' is covered by a 'forward only' clause then we
* can't cache this repsonse. * can't cache this response.
*/ */
return (true); return (true);
} }
@@ -10062,8 +10081,10 @@ rctx_delonly_zone(respctx_t *rctx) {
***/ ***/
static void static void
destroy(dns_resolver_t *res) { destroy(dns_resolver_t *res) {
isc_result_t result;
unsigned int i; unsigned int i;
alternate_t *a; alternate_t *a = NULL;
isc_ht_iter_t *it = NULL;
isc_refcount_destroy(&res->references); isc_refcount_destroy(&res->references);
REQUIRE(!atomic_load_acquire(&res->priming)); REQUIRE(!atomic_load_acquire(&res->priming));
@@ -10096,12 +10117,26 @@ destroy(dns_resolver_t *res) {
} }
isc_mem_put(res->mctx, res->buckets, isc_mem_put(res->mctx, res->buckets,
res->nbuckets * sizeof(fctxbucket_t)); res->nbuckets * sizeof(fctxbucket_t));
for (i = 0; i < ISC_HASHSIZE(res->dhashbits); i++) {
INSIST(ISC_LIST_EMPTY(res->dbuckets[i].list)); isc_ht_iter_create(res->zonebuckets, &it);
isc_mutex_destroy(&res->dbuckets[i].lock); for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
result = isc_ht_iter_delcurrent_next(it))
{
zonebucket_t *bucket = NULL;
fctxcount_t *fc = NULL, *next = NULL;
isc_ht_iter_current(it, (void **)&bucket);
for (fc = ISC_LIST_HEAD(bucket->list); fc != NULL; fc = next) {
next = ISC_LIST_NEXT(fc, link);
ISC_LIST_UNLINK(bucket->list, fc, link);
isc_mem_put(res->mctx, fc, sizeof(*fc));
} }
isc_mem_put(res->mctx, res->dbuckets, isc_mem_put(res->mctx, bucket, sizeof(*bucket));
ISC_HASHSIZE(res->dhashbits) * sizeof(zonebucket_t)); }
isc_ht_iter_destroy(&it);
isc_ht_destroy(&res->zonebuckets);
if (res->dispatches4 != NULL) { if (res->dispatches4 != NULL) {
dns_dispatchset_destroy(&res->dispatches4); dns_dispatchset_destroy(&res->dispatches4);
} }
@@ -10194,7 +10229,6 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
.maxdepth = DEFAULT_RECURSION_DEPTH, .maxdepth = DEFAULT_RECURSION_DEPTH,
.maxqueries = DEFAULT_MAX_QUERIES, .maxqueries = DEFAULT_MAX_QUERIES,
.nbuckets = ntasks, .nbuckets = ntasks,
.dhashbits = RES_DOMAIN_HASH_BITS,
.querydscp4 = -1, .querydscp4 = -1,
.querydscp6 = -1 }; .querydscp6 = -1 };
@@ -10239,14 +10273,9 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr,
atomic_init(&res->buckets[i].exiting, false); atomic_init(&res->buckets[i].exiting, false);
} }
res->dbuckets = isc_mem_get(view->mctx, isc_ht_init(&res->zonebuckets, view->mctx, RES_DOMAIN_HASH_BITS,
ISC_HASHSIZE(res->dhashbits) * ISC_HT_CASE_INSENSITIVE);
sizeof(res->dbuckets[0])); isc_rwlock_init(&res->zonehash_lock, 0, 0);
for (size_t i = 0; i < ISC_HASHSIZE(res->dhashbits); i++) {
res->dbuckets[i] = (zonebucket_t){ .list = { 0 } };
ISC_LIST_INIT(res->dbuckets[i].list);
isc_mutex_init(&res->dbuckets[i].lock);
}
if (dispatchv4 != NULL) { if (dispatchv4 != NULL) {
dns_dispatchset_create(view->mctx, dispatchv4, dns_dispatchset_create(view->mctx, dispatchv4,
@@ -10288,11 +10317,8 @@ cleanup_primelock:
dns_dispatchset_destroy(&res->dispatches4); dns_dispatchset_destroy(&res->dispatches4);
} }
for (size_t i = 0; i < ISC_HASHSIZE(res->dhashbits); i++) { isc_rwlock_destroy(&res->zonehash_lock);
isc_mutex_destroy(&res->dbuckets[i].lock); isc_ht_destroy(&res->zonebuckets);
}
isc_mem_put(view->mctx, res->dbuckets,
ISC_HASHSIZE(res->dhashbits) * sizeof(zonebucket_t));
cleanup_buckets: cleanup_buckets:
for (size_t i = 0; i < ntasks; i++) { for (size_t i = 0; i < ntasks; i++) {
@@ -11427,16 +11453,26 @@ dns_resolver_getmaxqueries(dns_resolver_t *resolver) {
} }
void void
dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format, dns_resolver_dumpfetches(dns_resolver_t *res, isc_statsformat_t format,
FILE *fp) { FILE *fp) {
REQUIRE(VALID_RESOLVER(resolver)); isc_result_t result;
isc_ht_iter_t *it = NULL;
REQUIRE(VALID_RESOLVER(res));
REQUIRE(fp != NULL); REQUIRE(fp != NULL);
REQUIRE(format == isc_statsformat_file); REQUIRE(format == isc_statsformat_file);
for (size_t i = 0; i < ISC_HASHSIZE(resolver->dhashbits); i++) { RWLOCK(&res->zonehash_lock, isc_rwlocktype_read);
fctxcount_t *fc; isc_ht_iter_create(res->zonebuckets, &it);
LOCK(&resolver->dbuckets[i].lock); for (result = isc_ht_iter_first(it); result == ISC_R_SUCCESS;
for (fc = ISC_LIST_HEAD(resolver->dbuckets[i].list); fc != NULL; result = isc_ht_iter_next(it))
{
zonebucket_t *zbucket = NULL;
fctxcount_t *fc = NULL;
isc_ht_iter_current(it, (void **)&zbucket);
LOCK(&zbucket->lock);
for (fc = ISC_LIST_HEAD(zbucket->list); fc != NULL;
fc = ISC_LIST_NEXT(fc, link)) fc = ISC_LIST_NEXT(fc, link))
{ {
dns_name_print(fc->domain, fp); dns_name_print(fc->domain, fp);
@@ -11445,8 +11481,10 @@ dns_resolver_dumpfetches(dns_resolver_t *resolver, isc_statsformat_t format,
"allowed)\n", "allowed)\n",
fc->count, fc->dropped, fc->allowed); fc->count, fc->dropped, fc->allowed);
} }
UNLOCK(&resolver->dbuckets[i].lock); UNLOCK(&zbucket->lock);
} }
RWUNLOCK(&res->zonehash_lock, isc_rwlocktype_read);
isc_ht_iter_destroy(&it);
} }
void void