2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 22:45:39 +00:00

Merge branch '3814-tighten-the-locking-around-fctxcount' into 'main'

Add magic to fctxcount and replace the atomics with integers

Closes #3814

See merge request isc-projects/bind9!7515
This commit is contained in:
Ondřej Surý
2023-02-11 20:22:01 +00:00

View File

@@ -319,14 +319,18 @@ struct fctxkey {
}; };
} __attribute__((__packed__)); } __attribute__((__packed__));
#define FCTXCOUNT_MAGIC ISC_MAGIC('F', 'C', 'n', 't')
#define VALID_FCTXCOUNT(counter) ISC_MAGIC_VALID(counter, FCTXCOUNT_MAGIC)
typedef struct fctxcount fctxcount_t; typedef struct fctxcount fctxcount_t;
struct fctxcount { struct fctxcount {
unsigned int magic;
dns_fixedname_t dfname; dns_fixedname_t dfname;
dns_name_t *domain; dns_name_t *domain;
atomic_uint_fast32_t count; uint_fast32_t count;
atomic_uint_fast32_t allowed; uint_fast32_t allowed;
atomic_uint_fast32_t dropped; uint_fast32_t dropped;
atomic_uint_fast32_t logged; isc_stdtime_t logged;
}; };
struct fetchctx { struct fetchctx {
@@ -1587,18 +1591,14 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter, bool final) {
return; return;
} }
uint_fast32_t allowed = atomic_load_relaxed(&counter->allowed);
uint_fast32_t dropped = atomic_load_relaxed(&counter->dropped);
isc_stdtime_t logged = atomic_load_relaxed(&counter->logged);
/* Do not log a message if there were no dropped fetches. */ /* Do not log a message if there were no dropped fetches. */
if (dropped == 0) { if (counter->dropped == 0) {
return; return;
} }
/* Do not log the cumulative message if the previous log is recent. */ /* Do not log the cumulative message if the previous log is recent. */
isc_stdtime_get(&now); isc_stdtime_get(&now);
if (!final && logged > now - 60) { if (!final && counter->logged > now - 60) {
return; return;
} }
@@ -1610,20 +1610,20 @@ fcount_logspill(fetchctx_t *fctx, fctxcount_t *counter, bool final) {
"too many simultaneous fetches for %s " "too many simultaneous fetches for %s "
"(allowed %" PRIuFAST32 " spilled %" PRIuFAST32 "(allowed %" PRIuFAST32 " spilled %" PRIuFAST32
"; %s)", "; %s)",
dbuf, allowed, dropped, dbuf, counter->allowed, counter->dropped,
dropped == 1 ? "initial trigger event" counter->dropped == 1 ? "initial trigger event"
: "cumulative since " : "cumulative since "
"initial trigger event"); "initial trigger event");
} else { } else {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_SPILL, isc_log_write(dns_lctx, DNS_LOGCATEGORY_SPILL,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"fetch counters for %s now being discarded " "fetch counters for %s now being discarded "
"(allowed %" PRIuFAST32 " spilled %" PRIuFAST32 "(allowed %" PRIuFAST32 " spilled %" PRIuFAST32
"; cumulative since initial trigger event)", "; cumulative since initial trigger event)",
dbuf, allowed, dropped); dbuf, counter->allowed, counter->dropped);
} }
atomic_store_release(&counter->logged, now); counter->logged = now;
} }
static isc_result_t static isc_result_t
@@ -1632,7 +1632,6 @@ fcount_incr(fetchctx_t *fctx, bool force) {
dns_resolver_t *res = NULL; dns_resolver_t *res = NULL;
fctxcount_t *counter = NULL; fctxcount_t *counter = NULL;
uint32_t hashval; uint32_t hashval;
uint_fast32_t count;
uint_fast32_t spill; uint_fast32_t spill;
REQUIRE(fctx != NULL); REQUIRE(fctx != NULL);
@@ -1640,6 +1639,11 @@ fcount_incr(fetchctx_t *fctx, bool force) {
REQUIRE(res != NULL); REQUIRE(res != NULL);
INSIST(fctx->counter == NULL); INSIST(fctx->counter == NULL);
spill = atomic_load_acquire(&res->zspill);
if (force || spill == 0) {
return (ISC_R_SUCCESS);
}
hashval = isc_hashmap_hash(res->counters, fctx->domain->ndata, hashval = isc_hashmap_hash(res->counters, fctx->domain->ndata,
fctx->domain->length); fctx->domain->length);
@@ -1652,6 +1656,7 @@ fcount_incr(fetchctx_t *fctx, bool force) {
case ISC_R_NOTFOUND: case ISC_R_NOTFOUND:
counter = isc_mem_get(fctx->mctx, sizeof(*counter)); counter = isc_mem_get(fctx->mctx, sizeof(*counter));
*counter = (fctxcount_t){ *counter = (fctxcount_t){
.magic = FCTXCOUNT_MAGIC,
.count = 0, .count = 0,
.allowed = 0, .allowed = 0,
}; };
@@ -1666,22 +1671,22 @@ fcount_incr(fetchctx_t *fctx, bool force) {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
count = atomic_fetch_add_relaxed(&counter->count, 1) + 1; INSIST(VALID_FCTXCOUNT(counter));
INSIST(spill > 0);
if (++counter->count > spill) {
counter->count--;
INSIST(counter->count > 0);
counter->dropped++;
fcount_logspill(fctx, counter, false);
result = ISC_R_QUOTA;
} else {
counter->allowed++;
fctx->counter = counter;
}
UNLOCK(&res->counters_lock); UNLOCK(&res->counters_lock);
spill = atomic_load_acquire(&res->zspill); return (result);
if (!force && spill != 0 && count > spill) {
atomic_fetch_sub_release(&counter->count, 1);
atomic_fetch_add_relaxed(&counter->dropped, 1);
fcount_logspill(fctx, counter, false);
return (ISC_R_QUOTA);
}
(void)atomic_fetch_add_relaxed(&counter->allowed, 1);
fctx->counter = counter;
return (ISC_R_SUCCESS);
} }
static void static void
@@ -1694,14 +1699,10 @@ fcount_decr(fetchctx_t *fctx) {
} }
fctx->counter = NULL; fctx->counter = NULL;
uint_fast32_t count = atomic_fetch_sub_release(&counter->count, 1) - 1; LOCK(&fctx->res->counters_lock);
if (count == 0) { INSIST(VALID_FCTXCOUNT(counter));
LOCK(&fctx->res->counters_lock); INSIST(counter->count > 0);
if (atomic_load_acquire(&counter->count) > 0) { if (--counter->count == 0) {
/* Other thread reacquired the counter */
goto unlock;
}
isc_result_t result = isc_hashmap_delete( isc_result_t result = isc_hashmap_delete(
fctx->res->counters, NULL, counter->domain->ndata, fctx->res->counters, NULL, counter->domain->ndata,
counter->domain->length); counter->domain->length);
@@ -1709,9 +1710,8 @@ fcount_decr(fetchctx_t *fctx) {
fcount_logspill(fctx, counter, true); fcount_logspill(fctx, counter, true);
isc_mem_put(fctx->mctx, counter, sizeof(*counter)); isc_mem_put(fctx->mctx, counter, sizeof(*counter));
unlock:
UNLOCK(&fctx->res->counters_lock);
} }
UNLOCK(&fctx->res->counters_lock);
} }
static void static void
@@ -4408,7 +4408,7 @@ resume_qmin(isc_task_t *task, isc_event_t *event) {
dns_name_copy(fname, fctx->domain); dns_name_copy(fname, fctx->domain);
result = fcount_incr(fctx, false); result = fcount_incr(fctx, true);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
goto cleanup; goto cleanup;
} }
@@ -11395,15 +11395,12 @@ dns_resolver_dumpfetches(dns_resolver_t *res, isc_statsformat_t format,
{ {
fctxcount_t *counter = NULL; fctxcount_t *counter = NULL;
isc_hashmap_iter_current(it, (void **)&counter); isc_hashmap_iter_current(it, (void **)&counter);
uint_fast32_t count = atomic_load_relaxed(&counter->count);
uint_fast32_t dropped = atomic_load_relaxed(&counter->dropped);
uint_fast32_t allowed = atomic_load_relaxed(&counter->allowed);
dns_name_print(counter->domain, fp); dns_name_print(counter->domain, fp);
fprintf(fp, fprintf(fp,
": %" PRIuFAST32 " active (%" PRIuFAST32 ": %" PRIuFAST32 " active (%" PRIuFAST32
" spilled, %" PRIuFAST32 " allowed)\n", " spilled, %" PRIuFAST32 " allowed)\n",
count, dropped, allowed); counter->count, counter->dropped, counter->allowed);
} }
UNLOCK(&res->counters_lock); UNLOCK(&res->counters_lock);
isc_hashmap_iter_destroy(&it); isc_hashmap_iter_destroy(&it);
@@ -11432,11 +11429,7 @@ dns_resolver_dumpquota(dns_resolver_t *res, isc_buffer_t **buf) {
char nb[DNS_NAME_FORMATSIZE], char nb[DNS_NAME_FORMATSIZE],
text[DNS_NAME_FORMATSIZE + BUFSIZ]; text[DNS_NAME_FORMATSIZE + BUFSIZ];
uint_fast32_t count = atomic_load_relaxed(&counter->count); if (counter->count < spill) {
uint_fast32_t allowed = atomic_load_relaxed(&counter->allowed);
uint_fast32_t dropped = atomic_load_relaxed(&counter->dropped);
if (count < spill) {
continue; continue;
} }
@@ -11444,7 +11437,8 @@ dns_resolver_dumpquota(dns_resolver_t *res, isc_buffer_t **buf) {
snprintf(text, sizeof(text), snprintf(text, sizeof(text),
"\n- %s: %" PRIuFAST32 " active (allowed %" PRIuFAST32 "\n- %s: %" PRIuFAST32 " active (allowed %" PRIuFAST32
" spilled %" PRIuFAST32 ")", " spilled %" PRIuFAST32 ")",
nb, count, allowed, dropped); nb, counter->count, counter->allowed,
counter->dropped);
result = isc_buffer_reserve(*buf, strlen(text)); result = isc_buffer_reserve(*buf, strlen(text));
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {