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:
@@ -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
|
||||||
|
Reference in New Issue
Block a user