From 77aeed6231946fd30e62812b9f5c68d343af8d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 26 Oct 2022 12:40:43 +0200 Subject: [PATCH] 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. --- lib/dns/include/dns/master.h | 19 ++-- lib/dns/master.c | 192 ++++++++++++----------------------- lib/dns/zone.c | 8 +- 3 files changed, 78 insertions(+), 141 deletions(-) diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h index 175ba5f23a..2e9966f8d0 100644 --- a/lib/dns/include/dns/master.h +++ b/lib/dns/include/dns/master.h @@ -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(). */ diff --git a/lib/dns/master.c b/lib/dns/master.c index 9f577a3293..b28ff98e82 100644 --- a/lib/dns/master.c +++ b/lib/dns/master.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -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)); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index fa6bdb0e7c..6880380d46 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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); }