2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

Move the zone loading to the offloaded threads

Instead of doing incremental zone loading with fixed quantum - 100
loaded lines per event, move the zone loading process to the offloaded
libuv threads using isc_work_enqueue() API.

This has the advantage that the thread scheduling is given back to the
operating system that understands blocking operations, and the zone
loading operation doesn't block the networking threads directly.
This commit is contained in:
Ondřej Surý 2022-10-26 12:40:43 +02:00 committed by Evan Hunt
parent dcc4c3e3ec
commit 77aeed6231
3 changed files with 78 additions and 141 deletions

View File

@ -136,17 +136,17 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, dns_name_t *origin,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx);
isc_result_t
dns_master_loadfileinc(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
unsigned int options, uint32_t resign,
dns_rdatacallbacks_t *callbacks, isc_loop_t *loop,
dns_loaddonefunc_t done, void *done_arg,
dns_loadctx_t **ctxp, dns_masterincludecb_t include_cb,
void *include_arg, isc_mem_t *mctx,
dns_masterformat_t format, uint32_t maxttl);
dns_master_loadfileasync(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
unsigned int options, uint32_t resign,
dns_rdatacallbacks_t *callbacks, isc_loop_t *loop,
dns_loaddonefunc_t done, void *done_arg,
dns_loadctx_t **ctxp, dns_masterincludecb_t include_cb,
void *include_arg, isc_mem_t *mctx,
dns_masterformat_t format, uint32_t maxttl);
/*%<
* Loads a RFC1305 master file from a file, stream, or buffer
* Loads a RFC1035 master file from a file, stream, or buffer
* into rdatasets and then calls 'callbacks->commit' to commit the
* rdatasets. Rdata memory belongs to dns_master_load and will be
* reused / released when the callback completes. dns_load_master will
@ -188,7 +188,6 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top,
*\li DNS_R_NOOWNER failed to specify a ownername.
*\li DNS_R_NOTTL failed to specify a ttl.
*\li DNS_R_BADCLASS record class did not match zone class.
*\li DNS_R_CONTINUE load still in progress (dns_master_loadfileinc() only).
*\li Any dns_rdata_fromtext() error code.
*\li Any error code from callbacks->commit().
*/

View File

@ -31,6 +31,7 @@
#include <isc/stdtime.h>
#include <isc/string.h>
#include <isc/util.h>
#include <isc/work.h>
#include <dns/callbacks.h>
#include <dns/events.h>
@ -105,7 +106,6 @@ struct dns_loadctx {
dns_masterformat_t format;
dns_rdatacallbacks_t *callbacks;
isc_loop_t *loop;
dns_loaddonefunc_t done;
void *done_arg;
@ -138,8 +138,6 @@ struct dns_loadctx {
dns_masterrawheader_t header;
/* Which fixed buffers we are using? */
unsigned int loop_cnt; /*% records per quantum,
* 0 => all. */
isc_result_t result;
/* Atomic */
@ -206,9 +204,6 @@ static dns_rdata_t *
grow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
isc_mem_t *);
static void
load_quantum(void *arg);
static void
loadctx_destroy(dns_loadctx_t *lctx);
@ -293,11 +288,10 @@ loadctx_destroy(dns_loadctx_t *lctx);
((result != ISC_R_SUCCESS) && (result != ISC_R_IOERROR) && \
((lctx)->options & DNS_MASTER_MANYERRORS) != 0)
#define SETRESULT(lctx, r) \
do { \
if ((lctx)->result == ISC_R_SUCCESS) \
(lctx)->result = r; \
} while (0)
#define SETRESULT(lctx, r) \
if ((lctx)->result == ISC_R_SUCCESS) { \
(lctx)->result = r; \
}
#define LOGITFILE(result, filename) \
if (result == ISC_R_INVALIDFILE || result == ISC_R_FILENOTFOUND || \
@ -453,14 +447,10 @@ loadctx_destroy(dns_loadctx_t *lctx) {
isc_lex_destroy(&lctx->lex);
}
if (lctx->loop != NULL) {
isc_loop_detach(&lctx->loop);
}
isc_mem_putanddetach(&lctx->mctx, lctx, sizeof(*lctx));
}
static isc_result_t
static void
incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
dns_incctx_t *ictx;
isc_region_t r;
@ -490,20 +480,17 @@ incctx_create(isc_mem_t *mctx, dns_name_t *origin, dns_incctx_t **ictxp) {
ictx->origin_changed = true;
*ictxp = ictx;
return (ISC_R_SUCCESS);
}
static isc_result_t
static void
loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
uint32_t resign, dns_name_t *top, dns_rdataclass_t zclass,
dns_name_t *origin, dns_rdatacallbacks_t *callbacks,
isc_loop_t *loop, dns_loaddonefunc_t done, void *done_arg,
dns_loaddonefunc_t done, void *done_arg,
dns_masterincludecb_t include_cb, void *include_arg,
isc_lex_t *lex, dns_loadctx_t **lctxp) {
dns_loadctx_t *lctx = NULL;
isc_result_t result;
isc_region_t r;
isc_lexspecials_t specials;
REQUIRE(lctxp != NULL && *lctxp == NULL);
REQUIRE(callbacks != NULL);
@ -513,8 +500,6 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
REQUIRE(mctx != NULL);
REQUIRE(dns_name_isabsolute(top));
REQUIRE(dns_name_isabsolute(origin));
REQUIRE((loop == NULL && done == NULL) ||
(loop != NULL && done != NULL));
lctx = isc_mem_get(mctx, sizeof(*lctx));
*lctx = (dns_loadctx_t){
@ -533,14 +518,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
.done = done,
.callbacks = callbacks,
.done_arg = done_arg,
.loop_cnt = (done != NULL) ? 100 : 0,
};
result = incctx_create(mctx, origin, &lctx->inc);
if (result != ISC_R_SUCCESS) {
goto cleanup_ctx;
}
incctx_create(mctx, origin, &lctx->inc);
switch (format) {
case dns_masterformat_text:
@ -559,6 +539,7 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
lctx->lex = lex;
lctx->keep_lex = true;
} else {
isc_lexspecials_t specials;
lctx->lex = NULL;
isc_lex_create(mctx, TOKENSIZ, &lctx->lex);
lctx->keep_lex = false;
@ -583,20 +564,12 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, unsigned int options,
dns_master_initrawheader(&lctx->header);
if (loop != NULL) {
isc_loop_attach(loop, &lctx->loop);
}
isc_refcount_init(&lctx->references, 1); /* Implicit attach. */
isc_mem_attach(mctx, &lctx->mctx);
lctx->magic = DNS_LCTX_MAGIC;
*lctxp = lctx;
return (ISC_R_SUCCESS);
cleanup_ctx:
isc_mem_put(mctx, lctx, sizeof(*lctx));
return (result);
return;
}
static const char *hex = "0123456789abcdef0123456789ABCDEF";
@ -1037,7 +1010,6 @@ load_text(dns_loadctx_t *lctx) {
uint32_t ttl_offset = 0;
dns_name_t *new_name;
bool current_has_delegation = false;
bool done = false;
bool finish_origin = false;
bool finish_include = false;
bool read_till_eol = false;
@ -1065,7 +1037,6 @@ load_text(dns_loadctx_t *lctx) {
unsigned char *target_mem = NULL;
int target_size = TSIZ;
int new_in_use;
unsigned int loop_cnt = 0;
isc_mem_t *mctx;
dns_rdatacallbacks_t *callbacks;
dns_incctx_t *ictx;
@ -1109,7 +1080,12 @@ load_text(dns_loadctx_t *lctx) {
options |= DNS_RDATA_CHECKMXFAIL;
}
source = isc_lex_getsourcename(lctx->lex);
do {
while (true) {
if (atomic_load_acquire(&lctx->canceled)) {
result = ISC_R_CANCELED;
goto log_and_cleanup;
}
initialws = false;
line = isc_lex_getsourceline(lctx->lex);
GETTOKEN(lctx->lex, ISC_LEXOPT_INITIALWS | ISC_LEXOPT_QSTRING,
@ -1134,8 +1110,7 @@ load_text(dns_loadctx_t *lctx) {
ictx = lctx->inc;
continue;
}
done = true;
continue;
break;
}
if (token.type == isc_tokentype_eol) {
@ -1688,7 +1663,7 @@ load_text(dns_loadctx_t *lctx) {
SETRESULT(lctx, result);
read_till_eol = true;
continue;
} else if (result != ISC_R_SUCCESS) {
} else {
goto insist_and_cleanup;
}
}
@ -2097,7 +2072,7 @@ load_text(dns_loadctx_t *lctx) {
COMMITALL;
}
next_line:;
} while (!done && (lctx->loop_cnt == 0 || loop_cnt++ < lctx->loop_cnt));
}
/*
* Commit what has not yet been committed.
@ -2115,16 +2090,12 @@ load_text(dns_loadctx_t *lctx) {
SETRESULT(lctx, result);
} else if (result != ISC_R_SUCCESS) {
goto insist_and_cleanup;
}
if (!done) {
INSIST(lctx->done != NULL && lctx->loop != NULL);
result = DNS_R_CONTINUE;
} else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
} else if (lctx->result != ISC_R_SUCCESS) {
result = lctx->result;
} else if (result == ISC_R_SUCCESS && lctx->seen_include) {
} else if (lctx->seen_include) {
result = DNS_R_SEENINCLUDE;
}
goto cleanup;
log_and_cleanup:
@ -2165,6 +2136,7 @@ cleanup:
if (rhs != NULL) {
isc_mem_free(mctx, rhs);
}
return (result);
}
@ -2181,10 +2153,7 @@ pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t *lctx) {
ictx = lctx->inc;
lctx->seen_include = true;
result = incctx_create(lctx->mctx, origin, &newctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
incctx_create(lctx->mctx, origin, &newctx);
/*
* Push origin_changed.
@ -2341,8 +2310,6 @@ openfile_raw(dns_loadctx_t *lctx, const char *master_file) {
static isc_result_t
load_raw(dns_loadctx_t *lctx) {
isc_result_t result = ISC_R_SUCCESS;
bool done = false;
unsigned int loop_cnt = 0;
dns_rdatacallbacks_t *callbacks;
unsigned char namebuf[DNS_NAME_MAXWIRE];
dns_fixedname_t fixed;
@ -2387,9 +2354,7 @@ load_raw(dns_loadctx_t *lctx) {
* in this format, and so trying to continue parsing erroneous data
* does not really make sense.
*/
for (loop_cnt = 0; (lctx->loop_cnt == 0 || loop_cnt < lctx->loop_cnt);
loop_cnt++)
{
while (true) {
unsigned int i, rdcount;
uint16_t namelen;
uint32_t totallen;
@ -2403,7 +2368,6 @@ load_raw(dns_loadctx_t *lctx) {
lctx->f, NULL);
if (result == ISC_R_EOF) {
result = ISC_R_SUCCESS;
done = true;
break;
}
if (result != ISC_R_SUCCESS) {
@ -2612,10 +2576,7 @@ load_raw(dns_loadctx_t *lctx) {
}
}
if (!done) {
INSIST(lctx->done != NULL && lctx->loop != NULL);
result = DNS_R_CONTINUE;
} else if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS && lctx->result != ISC_R_SUCCESS) {
result = lctx->result;
}
@ -2630,7 +2591,7 @@ cleanup:
if (target_mem != NULL) {
isc_mem_put(mctx, target_mem, target_size);
}
if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE) {
if (result != ISC_R_SUCCESS) {
(*callbacks->error)(callbacks, "dns_master_load: %s",
isc_result_totext(result));
}
@ -2649,12 +2610,9 @@ dns_master_loadfile(const char *master_file, dns_name_t *top,
dns_loadctx_t *lctx = NULL;
isc_result_t result;
result = loadctx_create(format, mctx, options, resign, top, zclass,
origin, callbacks, NULL, NULL, NULL, include_cb,
include_arg, NULL, &lctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
loadctx_create(format, mctx, options, resign, top, zclass, origin,
callbacks, NULL, NULL, include_cb, include_arg, NULL,
&lctx);
lctx->maxttl = maxttl;
@ -2671,27 +2629,39 @@ cleanup:
return (result);
}
static void
load(void *arg) {
dns_loadctx_t *lctx = arg;
lctx->result = (lctx->load)(lctx);
}
static void
load_done(void *arg) {
dns_loadctx_t *lctx = arg;
(lctx->done)(lctx->done_arg, lctx->result);
dns_loadctx_detach(&lctx);
}
isc_result_t
dns_master_loadfileinc(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
unsigned int options, uint32_t resign,
dns_rdatacallbacks_t *callbacks, isc_loop_t *loop,
dns_loaddonefunc_t done, void *done_arg,
dns_loadctx_t **lctxp, dns_masterincludecb_t include_cb,
void *include_arg, isc_mem_t *mctx,
dns_masterformat_t format, uint32_t maxttl) {
dns_master_loadfileasync(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
unsigned int options, uint32_t resign,
dns_rdatacallbacks_t *callbacks, isc_loop_t *loop,
dns_loaddonefunc_t done, void *done_arg,
dns_loadctx_t **lctxp,
dns_masterincludecb_t include_cb, void *include_arg,
isc_mem_t *mctx, dns_masterformat_t format,
uint32_t maxttl) {
dns_loadctx_t *lctx = NULL;
isc_result_t result;
REQUIRE(loop != NULL);
REQUIRE(done != NULL);
result = loadctx_create(format, mctx, options, resign, top, zclass,
origin, callbacks, loop, done, done_arg,
include_cb, include_arg, NULL, &lctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
loadctx_create(format, mctx, options, resign, top, zclass, origin,
callbacks, done, done_arg, include_cb, include_arg, NULL,
&lctx);
lctx->maxttl = maxttl;
@ -2701,9 +2671,10 @@ dns_master_loadfileinc(const char *master_file, dns_name_t *top,
return (result);
}
isc_async_run(loop, load_quantum, lctx);
dns_loadctx_attach(lctx, lctxp);
return (DNS_R_CONTINUE);
isc_work_enqueue(loop, load, load_done, lctx);
return (ISC_R_SUCCESS);
}
isc_result_t
@ -2715,26 +2686,19 @@ dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
REQUIRE(stream != NULL);
result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
zclass, origin, callbacks, NULL, NULL, NULL,
NULL, NULL, NULL, &lctx);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass,
origin, callbacks, NULL, NULL, NULL, NULL, NULL, &lctx);
result = isc_lex_openstream(lctx->lex, stream);
if (result != ISC_R_SUCCESS) {
dns_loadctx_detach(&lctx);
return (result);
goto cleanup;
}
result = (lctx->load)(lctx);
INSIST(result != DNS_R_CONTINUE);
cleanup:
if (lctx != NULL) {
dns_loadctx_detach(&lctx);
}
dns_loadctx_detach(&lctx);
return (result);
}
@ -2747,12 +2711,8 @@ dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top, dns_name_t *origin,
REQUIRE(buffer != NULL);
result = loadctx_create(dns_masterformat_text, mctx, options, 0, top,
zclass, origin, callbacks, NULL, NULL, NULL,
NULL, NULL, NULL, &lctx);
if (result != ISC_R_SUCCESS) {
return (result);
}
loadctx_create(dns_masterformat_text, mctx, options, 0, top, zclass,
origin, callbacks, NULL, NULL, NULL, NULL, NULL, &lctx);
result = isc_lex_openbuffer(lctx->lex, buffer);
if (result != ISC_R_SUCCESS) {
@ -3011,26 +2971,6 @@ is_glue(rdatalist_head_t *head, dns_name_t *owner) {
return (false);
}
static void
load_quantum(void *arg) {
isc_result_t result;
dns_loadctx_t *lctx = (dns_loadctx_t *)arg;
REQUIRE(DNS_LCTX_VALID(lctx));
if (atomic_load_acquire(&lctx->canceled)) {
result = ISC_R_CANCELED;
} else {
result = (lctx->load)(lctx);
}
if (result == DNS_R_CONTINUE) {
isc_async_run(lctx->loop, load_quantum, lctx);
} else {
(lctx->done)(lctx->done_arg, result);
dns_loadctx_detach(&lctx);
}
}
void
dns_loadctx_cancel(dns_loadctx_t *lctx) {
REQUIRE(DNS_LCTX_VALID(lctx));

View File

@ -2616,19 +2616,17 @@ zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
options = get_primary_options(load->zone);
result = dns_master_loadfileinc(
result = dns_master_loadfileasync(
load->zone->masterfile, dns_db_origin(load->db),
dns_db_origin(load->db), load->zone->rdclass, options, 0,
&load->callbacks, load->zone->loop, zone_loaddone, load,
&load->zone->lctx, zone_registerinclude, load->zone,
load->zone->mctx, load->zone->masterformat, load->zone->maxttl);
if (result != ISC_R_SUCCESS && result != DNS_R_CONTINUE &&
result != DNS_R_SEENINCLUDE)
{
if (result != ISC_R_SUCCESS) {
goto fail;
}
return;
return;
fail:
zone_loaddone(load, result);
}