mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch '2732-zone-dumping-is-blocking-the-networking-io' into 'main'
Improve the zone dumping impact on the networking Closes #2732 See merge request isc-projects/bind9!5107
This commit is contained in:
commit
5a8a21a88d
20 changed files with 278 additions and 181 deletions
3
CHANGES
3
CHANGES
|
|
@ -1,3 +1,6 @@
|
|||
5651. [func] Refactor zone dumping to be processed asynchronously
|
||||
via the uv_work_t thread pool API. [GL #2732]
|
||||
|
||||
5650. [bug] Prevent a crash that could occur if serve-stale
|
||||
was enabled and a prefetch was triggered during a
|
||||
query restart. [GL #2733]
|
||||
|
|
|
|||
|
|
@ -11487,7 +11487,7 @@ resume:
|
|||
";\n; Cache dump of view '%s' (cache %s)\n;\n",
|
||||
dctx->view->view->name,
|
||||
dns_cache_getname(dctx->view->view->cache));
|
||||
result = dns_master_dumptostreaminc(
|
||||
result = dns_master_dumptostreamasync(
|
||||
dctx->mctx, dctx->cache, NULL, style, dctx->fp,
|
||||
dctx->task, dumpdone, dctx, &dctx->mdctx);
|
||||
if (result == DNS_R_CONTINUE) {
|
||||
|
|
@ -11547,7 +11547,7 @@ resume:
|
|||
goto nextzone;
|
||||
}
|
||||
dns_db_currentversion(dctx->db, &dctx->version);
|
||||
result = dns_master_dumptostreaminc(
|
||||
result = dns_master_dumptostreamasync(
|
||||
dctx->mctx, dctx->db, dctx->version, style,
|
||||
dctx->fp, dctx->task, dumpdone, dctx,
|
||||
&dctx->mdctx);
|
||||
|
|
|
|||
|
|
@ -378,15 +378,6 @@ typedef __int64 off_t;
|
|||
/* Define to 1 if you have the `SSL_CTX_up_ref' function. */
|
||||
#define SSL_CTX_UP_REF 1
|
||||
|
||||
/* Define to 1 if you have the `uv_handle_get_data' function. */
|
||||
@HAVE_UV_HANDLE_GET_DATA@
|
||||
|
||||
/* Define to 1 if you have the `uv_handle_set_data' function. */
|
||||
@HAVE_UV_HANDLE_SET_DATA@
|
||||
|
||||
/* Define to 1 if you have the `uv_import' function. */
|
||||
@HAVE_UV_IMPORT@
|
||||
|
||||
/* GSSAPI Related defines */
|
||||
@HAVE_GSSAPI@
|
||||
@HAVE_GSSAPI_H@
|
||||
|
|
|
|||
|
|
@ -600,7 +600,10 @@ LIBS="$LIBS $LIBUV_LIBS"
|
|||
|
||||
# Those functions are only provided in newer versions of libuv, we'll be emulating them
|
||||
# for now
|
||||
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import uv_udp_connect uv_translate_sys_error uv_sleep])
|
||||
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data])
|
||||
AC_CHECK_FUNCS([uv_req_get_data uv_req_set_data])
|
||||
AC_CHECK_FUNCS([uv_udp_connect uv_translate_sys_error uv_sleep])
|
||||
AC_CHECK_FUNCS([uv_os_getenv uv_os_setenv])
|
||||
AX_RESTORE_FLAGS([libuv])
|
||||
|
||||
# libnghttp2
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ New Features
|
|||
became clogged up with queries that are too old and have already timeouted
|
||||
on the receiving side. :gl:`#2313`
|
||||
|
||||
- Run zone dumping tasks on separate asynchronous thread pools. This change
|
||||
makes zone dumping no longer block networking I/O. :gl:`#2732`
|
||||
|
||||
Removed Features
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -243,11 +243,11 @@ dns_dumpctx_db(dns_dumpctx_t *dctx);
|
|||
|
||||
/*@{*/
|
||||
isc_result_t
|
||||
dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
|
||||
dns_dbversion_t * version,
|
||||
const dns_master_style_t *style, FILE *f,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done,
|
||||
void *done_arg, dns_dumpctx_t **dctxp);
|
||||
dns_master_dumptostreamasync(isc_mem_t *mctx, dns_db_t *db,
|
||||
dns_dbversion_t * version,
|
||||
const dns_master_style_t *style, FILE *f,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done,
|
||||
void *done_arg, dns_dumpctx_t **dctxp);
|
||||
|
||||
isc_result_t
|
||||
dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
|
|
@ -259,11 +259,6 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
* 'format'. If the format is dns_masterformat_text (the RFC1035 format),
|
||||
* 'style' specifies the file style (e.g., &dns_master_style_default).
|
||||
*
|
||||
* dns_master_dumptostream() is an old form of dns_master_dumptostream3(),
|
||||
* which always specifies the dns_masterformat_text format.
|
||||
* dns_master_dumptostream2() is an old form which always specifies
|
||||
* a NULL header.
|
||||
*
|
||||
* If 'format' is dns_masterformat_raw, then 'header' can contain
|
||||
* information to be written to the file header.
|
||||
*
|
||||
|
|
@ -276,7 +271,6 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
*
|
||||
* Returns:
|
||||
*\li ISC_R_SUCCESS
|
||||
*\li ISC_R_CONTINUE dns_master_dumptostreaminc() only.
|
||||
*\li ISC_R_NOMEMORY
|
||||
*\li Any database or rrset iterator error.
|
||||
*\li Any dns_rdata_totext() error code.
|
||||
|
|
@ -286,11 +280,11 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
/*@{*/
|
||||
|
||||
isc_result_t
|
||||
dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, const char *filename,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
|
||||
dns_dumpctx_t **dctxp, dns_masterformat_t format,
|
||||
dns_masterrawheader_t *header);
|
||||
dns_master_dumpasync(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, const char *filename,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
|
||||
dns_dumpctx_t **dctxp, dns_masterformat_t format,
|
||||
dns_masterrawheader_t *header);
|
||||
|
||||
isc_result_t
|
||||
dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
|
|
@ -302,11 +296,6 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
* 'format'. If the format is dns_masterformat_text (the RFC1035 format),
|
||||
* 'style' specifies the file style (e.g., &dns_master_style_default).
|
||||
*
|
||||
* dns_master_dumpinc() and dns_master_dump() are old forms of _dumpinc3()
|
||||
* and _dump3(), respectively, which always specify the dns_masterformat_text
|
||||
* format. dns_master_dumpinc2() and dns_master_dump2() are old forms which
|
||||
* always specify a NULL header.
|
||||
*
|
||||
* If 'format' is dns_masterformat_raw, then 'header' can contain
|
||||
* information to be written to the file header.
|
||||
*
|
||||
|
|
@ -314,7 +303,6 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
*
|
||||
* Returns:
|
||||
*\li ISC_R_SUCCESS
|
||||
*\li ISC_R_CONTINUE dns_master_dumpinc() only.
|
||||
*\li ISC_R_NOMEMORY
|
||||
*\li Any database or rrset iterator error.
|
||||
*\li Any dns_rdata_totext() error code.
|
||||
|
|
|
|||
|
|
@ -265,8 +265,8 @@ struct dns_dumpctx {
|
|||
isc_task_t *task;
|
||||
dns_dumpdonefunc_t done;
|
||||
void *done_arg;
|
||||
unsigned int nodes;
|
||||
/* dns_master_dumpinc() */
|
||||
/* dns_master_dumpasync() */
|
||||
isc_result_t result;
|
||||
char *file;
|
||||
char *tmpfile;
|
||||
dns_masterformat_t format;
|
||||
|
|
@ -1343,7 +1343,7 @@ dump_rdatasets_map(isc_mem_t *mctx, const dns_name_t *name,
|
|||
static const int initial_buffer_length = 1200;
|
||||
|
||||
static isc_result_t
|
||||
dumptostreaminc(dns_dumpctx_t *dctx);
|
||||
dumptostream(dns_dumpctx_t *dctx);
|
||||
|
||||
static void
|
||||
dumpctx_destroy(dns_dumpctx_t *dctx) {
|
||||
|
|
@ -1486,27 +1486,23 @@ closeandrename(FILE *f, isc_result_t result, const char *temp,
|
|||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will run in a libuv threadpool thread.
|
||||
*/
|
||||
static void
|
||||
dump_quantum(isc_task_t *task, isc_event_t *event) {
|
||||
isc_result_t result;
|
||||
isc_result_t tresult;
|
||||
dns_dumpctx_t *dctx;
|
||||
|
||||
REQUIRE(event != NULL);
|
||||
dctx = event->ev_arg;
|
||||
master_dump_cb(void *data) {
|
||||
isc_result_t result = ISC_R_UNSET;
|
||||
dns_dumpctx_t *dctx = data;
|
||||
REQUIRE(DNS_DCTX_VALID(dctx));
|
||||
|
||||
if (atomic_load_acquire(&dctx->canceled)) {
|
||||
result = ISC_R_CANCELED;
|
||||
} else {
|
||||
result = dumptostreaminc(dctx);
|
||||
}
|
||||
if (result == DNS_R_CONTINUE) {
|
||||
event->ev_arg = dctx;
|
||||
isc_task_send(task, &event);
|
||||
return;
|
||||
result = dumptostream(dctx);
|
||||
}
|
||||
|
||||
if (dctx->file != NULL) {
|
||||
isc_result_t tresult = ISC_R_UNSET;
|
||||
tresult = closeandrename(dctx->f, result, dctx->tmpfile,
|
||||
dctx->file);
|
||||
if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS) {
|
||||
|
|
@ -1515,17 +1511,51 @@ dump_quantum(isc_task_t *task, isc_event_t *event) {
|
|||
} else {
|
||||
result = flushandsync(dctx->f, result, NULL);
|
||||
}
|
||||
|
||||
dctx->result = result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will run in a network/task manager thread when the dump is complete.
|
||||
*/
|
||||
static void
|
||||
master_dump_done_cb(void *data, isc_result_t result) {
|
||||
dns_dumpctx_t *dctx = data;
|
||||
|
||||
if (result == ISC_R_SUCCESS && dctx->result != ISC_R_SUCCESS) {
|
||||
result = dctx->result;
|
||||
}
|
||||
|
||||
(dctx->done)(dctx->done_arg, result);
|
||||
isc_event_free(&event);
|
||||
dns_dumpctx_detach(&dctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be run from a network/task manager thread.
|
||||
*/
|
||||
static void
|
||||
setup_dump(isc_task_t *task, isc_event_t *event) {
|
||||
dns_dumpctx_t *dctx = NULL;
|
||||
|
||||
REQUIRE(isc_nm_tid() >= 0);
|
||||
REQUIRE(event != NULL);
|
||||
|
||||
dctx = event->ev_arg;
|
||||
|
||||
REQUIRE(DNS_DCTX_VALID(dctx));
|
||||
|
||||
isc_nm_work_offload(isc_task_getnetmgr(task), master_dump_cb,
|
||||
master_dump_done_cb, dctx);
|
||||
|
||||
isc_event_free(&event);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
task_send(dns_dumpctx_t *dctx) {
|
||||
isc_event_t *event;
|
||||
|
||||
event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
|
||||
dump_quantum, dctx, sizeof(*event));
|
||||
setup_dump, dctx, sizeof(*event));
|
||||
isc_task_send(dctx->task, &event);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
|
@ -1548,7 +1578,6 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
dctx->done = NULL;
|
||||
dctx->done_arg = NULL;
|
||||
dctx->task = NULL;
|
||||
dctx->nodes = 0;
|
||||
dctx->first = true;
|
||||
atomic_init(&dctx->canceled, false);
|
||||
dctx->file = NULL;
|
||||
|
|
@ -1702,13 +1731,12 @@ writeheader(dns_dumpctx_t *dctx) {
|
|||
}
|
||||
|
||||
static isc_result_t
|
||||
dumptostreaminc(dns_dumpctx_t *dctx) {
|
||||
dumptostream(dns_dumpctx_t *dctx) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc_buffer_t buffer;
|
||||
char *bufmem;
|
||||
dns_name_t *name;
|
||||
dns_fixedname_t fixname;
|
||||
unsigned int nodes;
|
||||
isc_time_t start;
|
||||
|
||||
bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
|
||||
|
|
@ -1742,9 +1770,8 @@ dumptostreaminc(dns_dumpctx_t *dctx) {
|
|||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
nodes = dctx->nodes;
|
||||
isc_time_now(&start);
|
||||
while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
|
||||
while (result == ISC_R_SUCCESS) {
|
||||
dns_rdatasetiter_t *rdsiter = NULL;
|
||||
dns_dbnode_t *node = NULL;
|
||||
|
||||
|
|
@ -1780,52 +1807,7 @@ dumptostreaminc(dns_dumpctx_t *dctx) {
|
|||
result = dns_dbiterator_next(dctx->dbiter);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out how many nodes can be written in the time between
|
||||
* two requests to the nameserver. Smooth the resulting number and
|
||||
* use it as a estimate for the number of nodes to be written in the
|
||||
* next iteration.
|
||||
*/
|
||||
if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
|
||||
unsigned int pps = dns_pps; /* packets per second */
|
||||
unsigned int interval;
|
||||
uint64_t usecs;
|
||||
isc_time_t end;
|
||||
|
||||
isc_time_now(&end);
|
||||
if (pps < 100) {
|
||||
pps = 100;
|
||||
}
|
||||
interval = 1000000 / pps; /* interval in usecs */
|
||||
if (interval == 0) {
|
||||
interval = 1;
|
||||
}
|
||||
usecs = isc_time_microdiff(&end, &start);
|
||||
if (usecs == 0) {
|
||||
dctx->nodes = dctx->nodes * 2;
|
||||
if (dctx->nodes > 1000) {
|
||||
dctx->nodes = 1000;
|
||||
}
|
||||
} else {
|
||||
nodes = dctx->nodes * interval;
|
||||
nodes /= (unsigned int)usecs;
|
||||
if (nodes == 0) {
|
||||
nodes = 1;
|
||||
} else if (nodes > 1000) {
|
||||
nodes = 1000;
|
||||
}
|
||||
|
||||
/* Smooth and assign. */
|
||||
dctx->nodes = (nodes + dctx->nodes * 7) / 8;
|
||||
|
||||
isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
|
||||
DNS_LOGMODULE_MASTERDUMP,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"dumptostreaminc(%p) new nodes -> %d",
|
||||
dctx, dctx->nodes);
|
||||
}
|
||||
result = DNS_R_CONTINUE;
|
||||
} else if (result == ISC_R_NOMORE) {
|
||||
if (result == ISC_R_NOMORE) {
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
cleanup:
|
||||
|
|
@ -1835,11 +1817,11 @@ cleanup:
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
|
||||
dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, FILE *f,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done,
|
||||
void *done_arg, dns_dumpctx_t **dctxp) {
|
||||
dns_master_dumptostreamasync(isc_mem_t *mctx, dns_db_t *db,
|
||||
dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, FILE *f,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done,
|
||||
void *done_arg, dns_dumpctx_t **dctxp) {
|
||||
dns_dumpctx_t *dctx = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
|
|
@ -1855,7 +1837,6 @@ dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
|
|||
isc_task_attach(task, &dctx->task);
|
||||
dctx->done = done;
|
||||
dctx->done_arg = done_arg;
|
||||
dctx->nodes = 100;
|
||||
|
||||
result = task_send(dctx);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
|
|
@ -1881,7 +1862,7 @@ dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
return (result);
|
||||
}
|
||||
|
||||
result = dumptostreaminc(dctx);
|
||||
result = dumptostream(dctx);
|
||||
INSIST(result != DNS_R_CONTINUE);
|
||||
dns_dumpctx_detach(&dctx);
|
||||
|
||||
|
|
@ -1917,6 +1898,11 @@ opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
|
|||
isc_result_totext(result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if defined(POSIX_FADV_DONTNEED)
|
||||
posix_fadvise(fileno(f), 0, 0, POSIX_FADV_DONTNEED);
|
||||
#endif
|
||||
|
||||
*tempp = tempname;
|
||||
*fp = f;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
|
@ -1927,11 +1913,11 @@ cleanup:
|
|||
}
|
||||
|
||||
isc_result_t
|
||||
dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, const char *filename,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
|
||||
dns_dumpctx_t **dctxp, dns_masterformat_t format,
|
||||
dns_masterrawheader_t *header) {
|
||||
dns_master_dumpasync(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
||||
const dns_master_style_t *style, const char *filename,
|
||||
isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
|
||||
dns_dumpctx_t **dctxp, dns_masterformat_t format,
|
||||
dns_masterrawheader_t *header) {
|
||||
FILE *f = NULL;
|
||||
isc_result_t result;
|
||||
char *tempname = NULL;
|
||||
|
|
@ -1956,7 +1942,6 @@ dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
isc_task_attach(task, &dctx->task);
|
||||
dctx->done = done;
|
||||
dctx->done_arg = done_arg;
|
||||
dctx->nodes = 100;
|
||||
dctx->file = file;
|
||||
file = NULL;
|
||||
dctx->tmpfile = tempname;
|
||||
|
|
@ -2001,7 +1986,7 @@ dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
result = dumptostreaminc(dctx);
|
||||
result = dumptostream(dctx);
|
||||
INSIST(result != DNS_R_CONTINUE);
|
||||
dns_dumpctx_detach(&dctx);
|
||||
|
||||
|
|
|
|||
|
|
@ -493,11 +493,11 @@ dns_lookup_cancel
|
|||
dns_lookup_create
|
||||
dns_lookup_destroy
|
||||
dns_master_dump
|
||||
dns_master_dumpinc
|
||||
dns_master_dumpasync
|
||||
dns_master_dumpnode
|
||||
dns_master_dumpnodetostream
|
||||
dns_master_dumptostream
|
||||
dns_master_dumptostreaminc
|
||||
dns_master_dumptostreamasync
|
||||
dns_master_initrawheader
|
||||
dns_master_loadbuffer
|
||||
dns_master_loadbufferinc
|
||||
|
|
|
|||
|
|
@ -2549,7 +2549,7 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) {
|
|||
} else {
|
||||
output_style = &dns_master_style_default;
|
||||
}
|
||||
result = dns_master_dumpinc(
|
||||
result = dns_master_dumpasync(
|
||||
zone->mctx, db, version, output_style, zone->masterfile,
|
||||
zone->task, dump_done, zone, &zone->dctx,
|
||||
zone->masterformat, &rawdata);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ typedef void (*isc_nm_opaquecb_t)(void *arg);
|
|||
* callbacks.
|
||||
*/
|
||||
|
||||
typedef void (*isc_nm_workcb_t)(void *arg);
|
||||
typedef void (*isc_nm_after_workcb_t)(void *arg, isc_result_t result);
|
||||
/*%<
|
||||
* Callback functions for libuv threadpool work (see uv_work_t)
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_attach(isc_nm_t *mgr, isc_nm_t **dst);
|
||||
void
|
||||
|
|
@ -529,6 +535,19 @@ isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid);
|
|||
* maximum number of 'workers' as specifed in isc_nm_start()
|
||||
*/
|
||||
|
||||
void
|
||||
isc_nm_work_offload(isc_nm_t *mgr, isc_nm_workcb_t work_cb,
|
||||
isc_nm_after_workcb_t after_work_cb, void *data);
|
||||
/*%<
|
||||
* Schedules a job to be handled by the libuv thread pool (see uv_work_t).
|
||||
* The function specified in `work_cb` will be run by a thread in the
|
||||
* thread pool; when complete, the `after_work_cb` function will run.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'mgr' is a valid netmgr object.
|
||||
* \li We are currently running in a network manager thread.
|
||||
*/
|
||||
|
||||
void
|
||||
isc__nm_force_tid(int tid);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -511,6 +511,9 @@ isc_task_getname(isc_task_t *task);
|
|||
*
|
||||
*/
|
||||
|
||||
isc_nm_t *
|
||||
isc_task_getnetmgr(isc_task_t *task);
|
||||
|
||||
void *
|
||||
isc_task_gettag(isc_task_t *task);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -646,6 +646,17 @@ typedef union {
|
|||
isc__netievent_tlsconnect_t nitc;
|
||||
} isc__netievent_storage_t;
|
||||
|
||||
/*
|
||||
* Work item for a uv_work threadpool.
|
||||
*/
|
||||
typedef struct isc__nm_work {
|
||||
isc_nm_t *netmgr;
|
||||
uv_work_t req;
|
||||
isc_nm_workcb_t cb;
|
||||
isc_nm_after_workcb_t after_cb;
|
||||
void *data;
|
||||
} isc__nm_work_t;
|
||||
|
||||
/*
|
||||
* Network manager
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "netmgr-int.h"
|
||||
#include "netmgr_p.h"
|
||||
#include "openssl_shim.h"
|
||||
#include "trampoline_p.h"
|
||||
#include "uv-compat.h"
|
||||
|
||||
/*%
|
||||
|
|
@ -199,6 +200,14 @@ static void
|
|||
isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
static void
|
||||
isc__nm_async_close(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
|
||||
static void
|
||||
isc__nm_threadpool_initialize(uint32_t workers);
|
||||
static void
|
||||
isc__nm_work_cb(uv_work_t *req);
|
||||
static void
|
||||
isc__nm_after_work_cb(uv_work_t *req, int status);
|
||||
|
||||
/*%<
|
||||
* Issue a 'handle closed' callback on the socket.
|
||||
*/
|
||||
|
|
@ -256,6 +265,17 @@ isc__nm_winsock_destroy(void) {
|
|||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
static void
|
||||
isc__nm_threadpool_initialize(uint32_t workers) {
|
||||
char buf[11];
|
||||
int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf,
|
||||
&(size_t){ sizeof(buf) });
|
||||
if (r == UV_ENOENT) {
|
||||
snprintf(buf, sizeof(buf), "%" PRIu32, workers);
|
||||
uv_os_setenv("UV_THREADPOOL_SIZE", buf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
|
||||
isc_nm_t *mgr = NULL;
|
||||
|
|
@ -267,6 +287,8 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
|
|||
isc__nm_winsock_initialize();
|
||||
#endif /* WIN32 */
|
||||
|
||||
isc__nm_threadpool_initialize(workers);
|
||||
|
||||
mgr = isc_mem_get(mctx, sizeof(*mgr));
|
||||
*mgr = (isc_nm_t){ .nworkers = workers };
|
||||
|
||||
|
|
@ -280,8 +302,6 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
|
|||
atomic_init(&mgr->workers_paused, 0);
|
||||
atomic_init(&mgr->paused, false);
|
||||
atomic_init(&mgr->closing, false);
|
||||
atomic_init(&mgr->idle, false);
|
||||
atomic_init(&mgr->keepalive, false);
|
||||
atomic_init(&mgr->recv_tcp_buffer_size, 0);
|
||||
atomic_init(&mgr->send_tcp_buffer_size, 0);
|
||||
atomic_init(&mgr->recv_udp_buffer_size, 0);
|
||||
|
|
@ -818,7 +838,8 @@ async_cb(uv_async_t *handle) {
|
|||
isc__networker_t *worker = (isc__networker_t *)handle->loop->data;
|
||||
|
||||
if (process_all_queues(worker)) {
|
||||
/* If we didn't process all the events, we need to enqueue
|
||||
/*
|
||||
* If we didn't process all the events, we need to enqueue
|
||||
* async_cb to be run in the next iteration of the uv_loop
|
||||
*/
|
||||
uv_async_send(handle);
|
||||
|
|
@ -3242,6 +3263,73 @@ isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle) {
|
|||
}
|
||||
}
|
||||
|
||||
static isc_threadresult_t
|
||||
isc__nm_work_run(isc_threadarg_t arg) {
|
||||
isc__nm_work_t *work = (isc__nm_work_t *)arg;
|
||||
|
||||
work->cb(work->data);
|
||||
|
||||
return ((isc_threadresult_t)0);
|
||||
}
|
||||
|
||||
static void
|
||||
isc__nm_work_cb(uv_work_t *req) {
|
||||
isc__nm_work_t *work = uv_req_get_data((uv_req_t *)req);
|
||||
|
||||
if (isc_tid_v == SIZE_MAX) {
|
||||
isc__trampoline_t *trampoline_arg =
|
||||
isc__trampoline_get(isc__nm_work_run, work);
|
||||
(void)isc__trampoline_run(trampoline_arg);
|
||||
} else {
|
||||
(void)isc__nm_work_run((isc_threadarg_t)work);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isc__nm_after_work_cb(uv_work_t *req, int status) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
isc__nm_work_t *work = uv_req_get_data((uv_req_t *)req);
|
||||
isc_nm_t *netmgr = work->netmgr;
|
||||
|
||||
if (status != 0) {
|
||||
result = isc__nm_uverr2result(status);
|
||||
}
|
||||
|
||||
work->after_cb(work->data, result);
|
||||
|
||||
isc_mem_put(netmgr->mctx, work, sizeof(*work));
|
||||
|
||||
isc_nm_detach(&netmgr);
|
||||
}
|
||||
|
||||
void
|
||||
isc_nm_work_offload(isc_nm_t *netmgr, isc_nm_workcb_t work_cb,
|
||||
isc_nm_after_workcb_t after_work_cb, void *data) {
|
||||
isc__networker_t *worker = NULL;
|
||||
isc__nm_work_t *work = NULL;
|
||||
int r;
|
||||
|
||||
REQUIRE(isc__nm_in_netthread());
|
||||
REQUIRE(VALID_NM(netmgr));
|
||||
|
||||
worker = &netmgr->workers[isc_nm_tid()];
|
||||
|
||||
work = isc_mem_get(netmgr->mctx, sizeof(*work));
|
||||
*work = (isc__nm_work_t){
|
||||
.cb = work_cb,
|
||||
.after_cb = after_work_cb,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
isc_nm_attach(netmgr, &work->netmgr);
|
||||
|
||||
uv_req_set_data((uv_req_t *)&work->req, work);
|
||||
|
||||
r = uv_queue_work(&worker->loop, &work->req, isc__nm_work_cb,
|
||||
isc__nm_after_work_cb);
|
||||
RUNTIME_CHECK(r == 0);
|
||||
}
|
||||
|
||||
#ifdef NETMGR_TRACE
|
||||
/*
|
||||
* Dump all active sockets in netmgr. We output to stderr
|
||||
|
|
@ -3302,7 +3390,8 @@ nmsocket_dump(isc_nmsocket_t *sock) {
|
|||
nmsocket_type_totext(sock->type),
|
||||
isc_refcount_current(&sock->references));
|
||||
fprintf(stderr,
|
||||
"Parent %p, listener %p, server %p, statichandle = %p\n",
|
||||
"Parent %p, listener %p, server %p, statichandle = "
|
||||
"%p\n",
|
||||
sock->parent, sock->listener, sock->server, sock->statichandle);
|
||||
fprintf(stderr, "Flags:%s%s%s%s%s\n",
|
||||
atomic_load(&sock->active) ? " active" : "",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "netmgr-int.h"
|
||||
|
||||
#ifndef HAVE_UV_UDP_CONNECT
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 27, 0)
|
||||
int
|
||||
isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
|
||||
int err = 0;
|
||||
|
|
@ -46,7 +46,7 @@ isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
|
|||
|
||||
return (0);
|
||||
}
|
||||
#endif /* ifndef HAVE_UV_UDP_CONNECT */
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
|
||||
|
||||
int
|
||||
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
|
|
|
|||
|
|
@ -19,28 +19,35 @@
|
|||
* library version.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UV_HANDLE_GET_DATA
|
||||
#define UV_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 19, 0)
|
||||
static inline void *
|
||||
uv_handle_get_data(const uv_handle_t *handle) {
|
||||
return (handle->data);
|
||||
}
|
||||
#endif /* ifndef HAVE_UV_HANDLE_GET_DATA */
|
||||
|
||||
#ifndef HAVE_UV_HANDLE_SET_DATA
|
||||
static inline void
|
||||
uv_handle_set_data(uv_handle_t *handle, void *data) {
|
||||
handle->data = data;
|
||||
}
|
||||
#endif /* ifndef HAVE_UV_HANDLE_SET_DATA */
|
||||
|
||||
#ifndef HAVE_UV_SLEEP
|
||||
static inline void *
|
||||
uv_req_get_data(const uv_req_t *req) {
|
||||
return (req->data);
|
||||
}
|
||||
|
||||
static inline void
|
||||
uv_req_set_data(uv_req_t *req, void *data) {
|
||||
req->data = data;
|
||||
}
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 19, 0) */
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 34, 0)
|
||||
#define uv_sleep(msec) usleep(msec * 1000)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UV_UDP_CONNECT
|
||||
#define isc_uv_udp_connect uv_udp_connect
|
||||
#else
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 34, 0) */
|
||||
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 27, 0)
|
||||
int
|
||||
isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
|
||||
/*%<
|
||||
|
|
@ -50,8 +57,37 @@ isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
|
|||
* NOTE: This is just a limited shim for uv_udp_connect() as it requires the
|
||||
* handle to be bound.
|
||||
*/
|
||||
#else /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
|
||||
#define isc_uv_udp_connect uv_udp_connect
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 27, 0) */
|
||||
|
||||
#endif
|
||||
#if UV_VERSION_HEX < UV_VERSION(1, 12, 0)
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline int
|
||||
uv_os_getenv(const char *name, char *buffer, size_t *size) {
|
||||
size_t len;
|
||||
char *buf = getenv(name);
|
||||
|
||||
if (buf == NULL) {
|
||||
return (UV_ENOENT);
|
||||
}
|
||||
|
||||
len = strlen(buf) + 1;
|
||||
if (len > *size) {
|
||||
*size = len;
|
||||
return (UV_ENOBUFS);
|
||||
}
|
||||
|
||||
*size = len;
|
||||
memmove(buffer, buf, len);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define uv_os_setenv(name, value) setenv(name, value, 0)
|
||||
#endif /* UV_VERSION_HEX < UV_VERSION(1, 12, 0) */
|
||||
|
||||
int
|
||||
isc_uv_udp_freebind(uv_udp_t *handle, const struct sockaddr *addr,
|
||||
|
|
|
|||
|
|
@ -774,6 +774,13 @@ isc_task_gettag(isc_task_t *task) {
|
|||
return (task->tag);
|
||||
}
|
||||
|
||||
isc_nm_t *
|
||||
isc_task_getnetmgr(isc_task_t *task) {
|
||||
REQUIRE(VALID_TASK(task));
|
||||
|
||||
return (task->manager->netmgr);
|
||||
}
|
||||
|
||||
/***
|
||||
*** Task Manager.
|
||||
***/
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ isc_socketmgr_getmaxsockets
|
|||
isc_socketmgr_setreserved
|
||||
isc_socketmgr_setstats
|
||||
isc_task_getname
|
||||
isc_task_getnetmgr
|
||||
isc_task_gettag
|
||||
isc_task_ready
|
||||
isc_task_run
|
||||
|
|
@ -474,11 +475,13 @@ isc_nm_tcpdnsconnect
|
|||
isc_nm_gettimeouts
|
||||
isc_nm_setnetbuffers
|
||||
isc_nm_settimeouts
|
||||
isc_nm_task_enqueue
|
||||
isc_nm_tcpdns_keepalive
|
||||
isc_nm_tcpdns_sequential
|
||||
isc_nm_tid
|
||||
isc_nm_tlsdnsconnect
|
||||
isc_nm_udpconnect
|
||||
isc_nm_work_offload
|
||||
isc_nmsocket_close
|
||||
isc__nm_acquire_interlocked
|
||||
isc__nm_drop_interlocked
|
||||
|
|
|
|||
|
|
@ -2260,4 +2260,3 @@
|
|||
./win32utils/Configure PERL 2013,2014,2015,2016,2017,2018,2019,2020,2021
|
||||
./win32utils/GeoIP.diff X 2013,2018,2019,2020,2021
|
||||
./win32utils/bind9.sln.in X 2013,2014,2015,2016,2017,2018,2019,2020
|
||||
./win32utils/libuv.diff X 2020,2021
|
||||
|
|
|
|||
|
|
@ -172,9 +172,6 @@ my @substdefh = ("PACKAGE_VERSION_MAJOR",
|
|||
"WITH_IDN",
|
||||
"CPU_RELAX",
|
||||
"VALIDATION_DEFAULT",
|
||||
"HAVE_UV_HANDLE_GET_DATA",
|
||||
"HAVE_UV_HANDLE_SET_DATA",
|
||||
"HAVE_UV_IMPORT",
|
||||
);
|
||||
|
||||
# for platform.h
|
||||
|
|
@ -1276,13 +1273,6 @@ if ($use_libuv eq "auto") {
|
|||
if ($use_libuv eq "auto") {
|
||||
die "can't find an libuv built directory at sibling root\n";
|
||||
}
|
||||
|
||||
# When a libuv version exposing uv_import() and uv_export() is released, the
|
||||
# following three config.h macros will need to be conditionally defined for
|
||||
# that libuv version and all later ones.
|
||||
# $configdefh{"HAVE_UV_HANDLE_SET_DATA"} = 1;
|
||||
# $configdefh{"HAVE_UV_HANDLE_GET_DATA"} = 1;
|
||||
# $configdefh{"HAVE_UV_IMPORT"} = 1;
|
||||
}
|
||||
# falls into (so no else)
|
||||
if ($use_libuv eq "yes") {
|
||||
|
|
@ -1309,12 +1299,6 @@ if ($use_libuv eq "yes") {
|
|||
$configinc{"LIBUV_INC"} = "$libuv_inc";
|
||||
$configlib{"LIBUV_LIB"} = "$libuv_lib";
|
||||
$configdll{"LIBUV_DLL"} = "$libuv_dll";
|
||||
# When a libuv version exposing uv_import() and uv_export() is released, the
|
||||
# following three config.h macros will need to be conditionally defined for
|
||||
# that libuv version and all later ones.
|
||||
# $configdefh{"HAVE_UV_HANDLE_SET_DATA"} = 1;
|
||||
# $configdefh{"HAVE_UV_HANDLE_GET_DATA"} = 1;
|
||||
# $configdefh{"HAVE_UV_IMPORT"} = 1;
|
||||
}
|
||||
|
||||
# with-nghttp2
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
To make TCP listening properly multithreaded, we need to have the
|
||||
uv_export() and uv_import() functions that were removed from libuv.
|
||||
The alternative is passing sockets over IPC, which is complicated and
|
||||
error prone.
|
||||
|
||||
To make it simple, we export two internal functions from libuv; they will
|
||||
be used in lib/isc/netmgr/uv-compat.c by our versions of the uv_export()
|
||||
and uv_import() functions.
|
||||
|
||||
diff --git a/src/win/internal.h b/src/win/internal.h
|
||||
index 058ddb8e..a9dc4168 100644
|
||||
--- a/src/win/internal.h
|
||||
+++ b/src/win/internal.h
|
||||
@@ -92,11 +92,11 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
|
||||
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
|
||||
|
||||
-int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
+UV_EXTERN int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
int pid,
|
||||
uv__ipc_socket_xfer_type_t* xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
-int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
+UV_EXTERN int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
|
||||
Loading…
Reference in a new issue