Merge branch 'fanf-qp-zt' into 'main'

Use a qp-trie for the zone table

See merge request isc-projects/bind9!7582
This commit is contained in:
Tony Finch 2023-04-05 12:02:38 +00:00
commit edb497ce4f
33 changed files with 1102 additions and 820 deletions

View file

@ -1,3 +1,6 @@
6146. [performance] Replace the zone table red-black tree and associated
locking with a lock-free qp-trie. [GL !7582]
6145. [bug] Fix a possible use-after-free bug in the
dns__catz_done_cb() function. [GL #3997]

View file

@ -2134,7 +2134,8 @@ run_server(void *arg) {
CHECK(ns_interfacemgr_create(mctx, sctx, loopmgr, netmgr, dispatchmgr,
NULL, false, &interfacemgr));
CHECK(dns_view_create(mctx, dns_rdataclass_in, "_default", &view));
CHECK(dns_view_create(mctx, loopmgr, dns_rdataclass_in, "_default",
&view));
CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", &cache));
dns_view_setcache(view, cache, false);
dns_cache_detach(&cache);

View file

@ -2708,7 +2708,7 @@ catz_addmodzone_cb(void *arg) {
goto cleanup;
}
result = dns_zt_find(cz->view->zonetable, name, 0, NULL, &zone);
result = dns_view_findzone(cz->view, name, &zone);
if (cz->mod) {
dns_catz_zone_t *parentcatz;
@ -2780,19 +2780,8 @@ catz_addmodzone_cb(void *arg) {
nameb);
}
goto cleanup;
} else if (result != ISC_R_NOTFOUND &&
result != DNS_R_PARTIALMATCH)
{
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
"catz: error \"%s\" while trying to "
"add zone '%s'",
isc_result_totext(result), nameb);
goto cleanup;
} else { /* this can happen in case of DNS_R_PARTIALMATCH */
if (zone != NULL) {
dns_zone_detach(&zone);
}
} else {
RUNTIME_CHECK(result == ISC_R_NOTFOUND);
}
}
RUNTIME_CHECK(zone == NULL);
@ -2845,7 +2834,7 @@ catz_addmodzone_cb(void *arg) {
}
/* Is it there yet? */
CHECK(dns_zt_find(cz->view->zonetable, name, 0, NULL, &zone));
CHECK(dns_view_findzone(cz->view, name, &zone));
/*
* Load the zone from the master file. If this fails, we'll
@ -2901,8 +2890,8 @@ catz_delzone_cb(void *arg) {
dns_name_format(dns_catz_entry_getname(cz->entry), cname,
DNS_NAME_FORMATSIZE);
result = dns_zt_find(cz->view->zonetable,
dns_catz_entry_getname(cz->entry), 0, NULL, &zone);
result = dns_view_findzone(cz->view, dns_catz_entry_getname(cz->entry),
&zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
@ -6448,7 +6437,8 @@ create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
}
INSIST(view == NULL);
result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
result = dns_view_create(named_g_mctx, named_g_loopmgr, viewclass,
viewname, &view);
if (result != ISC_R_SUCCESS) {
return (result);
}
@ -9734,8 +9724,8 @@ cleanup_viewlist:
if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
{
dns_view_setviewrevert(view);
(void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
false, NULL, removed, view);
(void)dns_zt_apply(view->zonetable, false, NULL,
removed, view);
}
dns_view_detach(&view);
}
@ -10564,8 +10554,7 @@ zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
result = ISC_R_NOTFOUND;
}
} else {
result = dns_zt_find(view->zonetable, name, 0, NULL,
zonep);
result = dns_view_findzone(view, name, zonep);
}
if (result != ISC_R_SUCCESS) {
snprintf(problem, sizeof(problem),
@ -11304,8 +11293,8 @@ add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
ISC_LIST_INIT(vle->zonelist);
ISC_LIST_APPEND(dctx->viewlist, vle, link);
if (dctx->dumpzones) {
result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
true, NULL, add_zone_tolist, dctx);
result = dns_zt_apply(view->zonetable, true, NULL,
add_zone_tolist, dctx);
}
return (result);
}
@ -12402,8 +12391,7 @@ named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
view = ISC_LIST_NEXT(view, link))
{
result = dns_zt_apply(view->zonetable,
isc_rwlocktype_none, false, NULL,
result = dns_zt_apply(view->zonetable, false, NULL,
synczone, &cleanup);
if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
{
@ -13430,19 +13418,15 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
/* Zone shouldn't already exist */
if (redirect) {
result = (view->redirect != NULL) ? ISC_R_SUCCESS
: ISC_R_NOTFOUND;
result = (view->redirect == NULL) ? ISC_R_NOTFOUND
: ISC_R_EXISTS;
} else {
result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
result = dns_view_findzone(view, name, &zone);
if (result == ISC_R_SUCCESS) {
result = ISC_R_EXISTS;
}
}
if (result == ISC_R_SUCCESS) {
result = ISC_R_EXISTS;
goto cleanup;
} else if (result == DNS_R_PARTIALMATCH) {
/* Create our sub-zone anyway */
dns_zone_detach(&zone);
zone = NULL;
} else if (result != ISC_R_NOTFOUND) {
if (result != ISC_R_NOTFOUND) {
goto cleanup;
}
@ -13501,7 +13485,7 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
}
dns_zone_attach(view->redirect, &zone);
} else {
result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
result = dns_view_findzone(view, name, &zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
@ -13617,7 +13601,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
result = ISC_R_NOTFOUND;
}
} else {
result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
result = dns_view_findzone(view, name, &zone);
}
if (result != ISC_R_SUCCESS) {
goto cleanup;
@ -13686,7 +13670,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
}
dns_zone_attach(view->redirect, &zone);
} else {
CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
CHECK(dns_view_findzone(view, name, &zone));
}
#ifndef HAVE_LMDB

View file

@ -1776,8 +1776,8 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
if ((flags & STATS_XML_ZONES) != 0) {
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR "zones"));
CHECK(dns_zt_apply(view->zonetable, isc_rwlocktype_read,
true, NULL, zone_xmlrender, writer));
CHECK(dns_zt_apply(view->zonetable, true, NULL,
zone_xmlrender, writer));
TRY0(xmlTextWriterEndElement(writer)); /* /zones */
}
@ -2490,9 +2490,8 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
CHECKMEM(za);
if ((flags & STATS_JSON_ZONES) != 0) {
CHECK(dns_zt_apply(view->zonetable,
isc_rwlocktype_read, true,
NULL, zone_jsonrender, za));
CHECK(dns_zt_apply(view->zonetable, true, NULL,
zone_jsonrender, za));
}
if (json_object_array_length(za) != 0) {

View file

@ -294,7 +294,7 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone dom1.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom1.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -929,7 +929,7 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone dom5.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom5.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -987,7 +987,7 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone dom6.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom6.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -1483,7 +1483,7 @@ END
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone ${special}/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone '${special}' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -1621,7 +1621,7 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone dom11.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom11.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -1653,7 +1653,7 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "zone_shutdown: zone subdomain.of.dom11.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'subdomain.of.dom11.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -2424,10 +2424,8 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "catz: deleting zone 'dom17.example' from catalog 'catalog1.example' - success" &&
wait_for_message ns2/named.run "catz: deleting zone 'dom18.example' from catalog 'catalog1.example' - success" &&
wait_for_message ns2/named.run "zone_shutdown: zone dom17.example/IN/default: shutting down" &&
wait_for_message ns2/named.run "zone_shutdown: zone dom18.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom17.example' deleted" &&
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom18.example' deleted" &&
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
@ -2515,10 +2513,8 @@ status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
wait_for_message ns2/named.run "catz: deleting zone 'dom17.example' from catalog 'catalog2.example' - success" &&
wait_for_message ns2/named.run "catz: deleting zone 'dom18.example' from catalog 'catalog2.example' - success" &&
wait_for_message ns2/named.run "zone_shutdown: zone dom17.example/IN/default: shutting down" &&
wait_for_message ns2/named.run "zone_shutdown: zone dom18.example/IN/default: shutting down" || ret=1
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom17.example' deleted" &&
wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom18.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))

View file

@ -166,7 +166,7 @@ syncptr_find_zone(sample_instance_t *inst, dns_rdata_t *rdata, dns_name_t *name,
}
/* Find a zone containing owner name of the PTR record. */
result = dns_zt_find(inst->view->zonetable, name, 0, NULL, zone);
result = dns_zt_find(inst->view->zonetable, name, 0, zone);
if (result == DNS_R_PARTIALMATCH) {
result = ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {

View file

@ -256,7 +256,7 @@ main(int argc, char *argv[]) {
RUNCHECK(dns_requestmgr_create(mctx, dispatchmgr, dispatchv4, NULL,
&requestmgr));
RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
RUNCHECK(dns_view_create(mctx, loopmgr, 0, "_test", &view));
isc_loopmgr_setup(loopmgr, sendqueries, NULL);
isc_loopmgr_run(loopmgr);

View file

@ -2141,7 +2141,7 @@ main(int argc, char *argv[]) {
mctx, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
have_ipv6 ? dispatchvx : NULL, &requestmgr));
RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
RUNCHECK(dns_view_create(mctx, loopmgr, 0, "_mdig", &view));
query = ISC_LIST_HEAD(queries);
isc_loopmgr_setup(loopmgr, sendqueries, query);

View file

@ -22,6 +22,7 @@
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/tid.h>
#include <isc/util.h>
#include <dns/fixedname.h>
@ -85,6 +86,7 @@ static isc_mem_t *mctx = NULL;
#define HMACSHA256 "\x0bhmac-sha256"
static isc_stdtime_t fuzztime = 0x622acce1;
static isc_loopmgr_t *loopmgr = NULL;
static dns_view_t *view = NULL;
static dns_tsigkey_t *tsigkey = NULL;
static dns_tsig_keyring_t *ring = NULL;
@ -232,7 +234,10 @@ LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) {
}
destroy_dst = true;
result = dns_view_create(mctx, dns_rdataclass_in, "view", &view);
isc_loopmgr_create(mctx, 1, &loopmgr);
result = dns_view_create(mctx, loopmgr, dns_rdataclass_in, "view",
&view);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "dns_view_create failed: %s\n",
isc_result_totext(result));
@ -322,6 +327,7 @@ LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) {
return (1);
}
dns_zone_setview(zone, view);
dns_view_freeze(view);
dns_zone_detach(&zone);

View file

@ -57,19 +57,18 @@ static struct {
dns_qpkey_t ascii;
} item[256 * 256 / 4];
static uint32_t
static void
fuzz_attach(void *ctx, void *pval, uint32_t ival) {
assert(ctx == NULL);
assert(pval == &item[ival]);
return (item[ival].refcount++);
item[ival].refcount++;
}
static uint32_t
static void
fuzz_detach(void *ctx, void *pval, uint32_t ival) {
assert(ctx == NULL);
assert(pval == &item[ival]);
assert(item[ival].refcount > 0);
return (item[ival].refcount--);
item[ival].refcount--;
}
static size_t
@ -86,7 +85,7 @@ fuzz_triename(void *ctx, char *buf, size_t size) {
strlcpy(buf, "fuzz", size);
}
const struct dns_qpmethods fuzz_methods = {
const dns_qpmethods_t fuzz_methods = {
fuzz_attach,
fuzz_detach,
fuzz_makekey,

View file

@ -526,7 +526,7 @@ dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
result = delcur ? isc_ht_iter_delcurrent_next(iter1)
: isc_ht_iter_next(iter1))
{
isc_result_t zt_find_result;
isc_result_t find_result;
dns_catz_zone_t *parentcatz = NULL;
dns_catz_entry_t *nentry = NULL;
dns_catz_entry_t *oentry = NULL;
@ -559,10 +559,10 @@ dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
&catz->zoneoptions, &nentry->opts);
/* Try to find the zone in the view */
zt_find_result = dns_zt_find(catz->catzs->view->zonetable,
dns_catz_entry_getname(nentry), 0,
NULL, &zone);
if (zt_find_result == ISC_R_SUCCESS) {
find_result = dns_view_findzone(catz->catzs->view,
dns_catz_entry_getname(nentry),
&zone);
if (find_result == ISC_R_SUCCESS) {
dns_catz_coo_t *coo = NULL;
char pczname[DNS_NAME_FORMATSIZE];
bool parentcatz_locked = false;
@ -606,10 +606,6 @@ dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
UNLOCK(&parentcatz->lock);
LOCK(&catz->lock);
}
}
if (zt_find_result == ISC_R_SUCCESS ||
zt_find_result == DNS_R_PARTIALMATCH)
{
dns_zone_detach(&zone);
}
@ -617,8 +613,7 @@ dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
result = isc_ht_find(catz->entries, key, (uint32_t)keysize,
(void **)&oentry);
if (result != ISC_R_SUCCESS) {
if (zt_find_result == ISC_R_SUCCESS &&
parentcatz == catz)
if (find_result == ISC_R_SUCCESS && parentcatz == catz)
{
/*
* This means that the zone's unique label
@ -645,7 +640,7 @@ dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
continue;
}
if (zt_find_result != ISC_R_SUCCESS) {
if (find_result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
"catz: zone '%s' was expected to exist "

View file

@ -206,7 +206,8 @@ createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_loopmgr_t *loopmgr,
isc_result_t result;
dns_view_t *view = NULL;
result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
result = dns_view_create(mctx, loopmgr, rdclass, DNS_CLIENTVIEW_NAME,
&view);
if (result != ISC_R_SUCCESS) {
return (result);
}

View file

@ -19,7 +19,11 @@
*
* Keys are `dns_qpkey_t`, which is a string-like thing, usually created
* from a DNS name. You can use both relative and absolute DNS names as
* keys.
* keys, even in the same trie, except for one caveat: if a trie contains
* names relative to the zone apex, the natural way to represent the apex
* itself (spelled `@` in zone files) is a zero-length name; but a
* zero-length name has the same qpkey representation as the root zone
* (apart from its length), so they collide.
*
* Leaf values are a pair of a `void *` pointer and a `uint32_t`
* (because that is what fits inside an internal qp-trie leaf node).
@ -49,6 +53,12 @@
* lifetime of a `dns_qpread_t`, instead of using locks. Readers are
* not blocked by any write activity, and vice versa.
*
* For read-only access outside the scope of a loop, such as from an
* isc_work callback, `dns_qpmulti_lockedread()`. This looks like a
* query transaction; the difference is that a locked read transaction
* takes the `dns_qpmulti_t` mutex. When you have finished with a
* `dns_qpread_t`, call `dns_qpread_destroy()` to release the mutex.
*
* For reads that need a stable view of the trie for multiple cycles
* of an isc_loop, or which can be used from any thread, call
* `dns_qpmulti_snapshot()` to get a `dns_qpsnap_t`. A snapshot is for
@ -99,7 +109,9 @@ typedef struct dns_qpmulti dns_qpmulti_t;
* Read-only parts of a qp-trie.
*
* A `dns_qpreader_t` is the common prefix of the `dns_qpreadable`
* types, containing just the fields neded for the hot path.
* types, containing just the fields neded for the hot path. The
* internals of a `dns_qpreader_t` are private; they are only exposed
* so that callers can allocate a `dns_qpread_t` on the stack.
*
* Ranty aside: annoyingly, C doesn't allow us to use a predeclared
* structure type as an anonymous struct member, so we have to use a
@ -125,6 +137,9 @@ typedef struct dns_qpreader {
* The caller provides space for it on the stack; it can be
* used by only one thread. As well as the `DNS_QPREADER_FIELDS`,
* it contains a thread ID to check for incorrect usage.
*
* The internals of a `dns_qpread_t` are private; they are only
* exposed so that callers can allocate an instance on the stack.
*/
typedef struct dns_qpread {
DNS_QPREADER_FIELDS;
@ -154,10 +169,7 @@ typedef union dns_qpreadable {
#define dns_qpreader(qpr) ((qpr).qp)
/*%
* A trie lookup key is a small array, allocated on the stack during trie
* searches. Keys are usually created on demand from DNS names using
* `dns_qpkey_fromname()`, but in principle you can define your own
* functions to convert other types to trie lookup keys.
* The maximum size of a key is also the maximum depth of a trie.
*
* A domain name can be up to 255 bytes. When converted to a key, each
* character in the name corresponds to one byte in the key if it is a
@ -165,7 +177,29 @@ typedef union dns_qpreadable {
* using two bytes in the key. So we allow keys to be up to 512 bytes.
* (The actual max is (255 - 5) * 2 + 6 == 506)
*/
typedef uint8_t dns_qpkey_t[512];
#define DNS_QP_MAXKEY 512
/*%
* A trie lookup key is a small array, allocated on the stack during trie
* searches. Keys are usually created on demand from DNS names using
* `dns_qpkey_fromname()`, but in principle you can define your own
* functions to convert other types to trie lookup keys.
*/
typedef uint8_t dns_qpkey_t[DNS_QP_MAXKEY];
/*%
* A trie iterator describes a path through the trie from the root to
* a leaf node, for use with `dns_qpiter_init()` and `dns_qpiter_next()`.
*/
typedef struct dns_qpiter {
unsigned int magic;
dns_qpreader_t *qp;
uint16_t sp;
struct __attribute__((__packed__)) {
uint32_t ref;
uint8_t more;
} stack[DNS_QP_MAXKEY];
} dns_qpiter_t;
/*%
* These leaf methods allow the qp-trie code to call back to the code
@ -180,9 +214,7 @@ typedef uint8_t dns_qpkey_t[512];
* The `attach` and `detach` methods adjust reference counts on value
* objects. They support copy-on-write and safe memory reclamation
* needed for multi-version concurrency. The methods are only called
* when the `dns_qpmulti_t` mutex is held. For tracing purposes, they
* should return the same value as `isc_refcount_increment()` or
* `isc_refcount_decrement()`, respectively
* when the `dns_qpmulti_t` mutex is held.
*
* Note: When a value object reference count is greater than one, the
* object is in use by concurrent readers so it must not be modified. A
@ -201,8 +233,8 @@ typedef uint8_t dns_qpkey_t[512];
* readable identifier into `buf` which has max length `size`.
*/
typedef struct dns_qpmethods {
uint32_t (*attach)(void *uctx, void *pval, uint32_t ival);
uint32_t (*detach)(void *uctx, void *pval, uint32_t ival);
void (*attach)(void *uctx, void *pval, uint32_t ival);
void (*detach)(void *uctx, void *pval, uint32_t ival);
size_t (*makekey)(dns_qpkey_t key, void *uctx, void *pval,
uint32_t ival);
void (*triename)(void *uctx, char *buf, size_t size);
@ -240,6 +272,13 @@ typedef enum dns_qpgc {
DNS_QPGC_ALL,
} dns_qpgc_t;
/*%
* Options for fancy searches such as `dns_qp_findname_parent()`
*/
typedef enum dns_qpfind {
DNS_QPFIND_NOEXACT = 1 << 0,
} dns_qpfind_t;
/***********************************************************************
*
* functions - create, destory, enquire
@ -376,16 +415,13 @@ dns_qpmulti_memusage(dns_qpmulti_t *multi);
/*
* XXXFANF todo, based on what we discover BIND needs
*
* fancy searches: longest match, lexicographic predecessor,
* etc.
* more fancy searches: lexicographic predecessor (for NSEC),
* successor (for modification-safe iteration), etc.
*
* do we need specific lookup functions to find out if the
* returned value is readonly or mutable?
*
* richer modification such as dns_qp_replace{key,name}
*
* iteration - probably best to put an explicit stack in the iterator,
* cf. rbtnodechain
*/
size_t
@ -441,6 +477,30 @@ dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
* \li ISC_R_SUCCESS if the leaf was found
*/
isc_result_t
dns_qp_findname_parent(dns_qpreadable_t qpr, const dns_name_t *name,
dns_qpfind_t options, void **pval_r, uint32_t *ival_r);
/*%<
* Find a leaf in a qp-trie that is a parent domain of or equal to the
* given DNS name.
*
* If the DNS_QPFIND_NOEXACT option is set, find a strict parent
* domain not equal to the search name.
*
* The leaf values are assigned to `*pval_r` and `*ival_r`
*
* Requires:
* \li `qpr` is a pointer to a readable qp-trie
* \li `name` is a pointer to a valid `dns_name_t`
* \li `pval_r != NULL`
* \li `ival_r != NULL`
*
* Returns:
* \li ISC_R_SUCCESS if an exact match was found
* \li ISC_R_PARTIALMATCH if a parent domain was found
* \li ISC_R_NOTFOUND if no match was found
*/
isc_result_t
dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival);
/*%<
@ -484,6 +544,48 @@ dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name);
* \li ISC_R_SUCCESS if the leaf was deleted from the trie
*/
void
dns_qpiter_init(dns_qpreadable_t qpr, dns_qpiter_t *qpi);
/*%<
* Initialize an iterator
*
* SAFETY NOTE: If `qpr` is a `dns_qp_t`, it is not safe to modify the
* trie during iteration. If `qpr` is a `dns_qpread_t` or `dns_qpsnap_t`
* then (like any other read-only access) modifications will not affect
* iteration.
*
* Requires:
* \li `qp` is a pointer to a valid qp-trie
* \li `qpi` is a pointer to a qp iterator
*/
isc_result_t
dns_qpiter_next(dns_qpiter_t *qpi, void **pval_r, uint32_t *ival_r);
/*%<
* Get the next leaf object of a trie in lexicographic order of its keys.
*
* NOTE: see the safety note under `dns_qpiter_init()`.
*
* For example,
*
* dns_qpiter_t qpi;
* void *pval;
* uint32_t ival;
* dns_qpiter_init(qp, &qpi);
* while (dns_qpiter_next(&qpi, &pval, &ival)) {
* // do something with pval and ival
* }
*
* Requires:
* \li `qpi` is a pointer to a valid qp iterator
* \li `pval_r != NULL`
* \li `ival_r != NULL`
*
* Returns:
* \li ISC_R_SUCCESS if a leaf was found and pval_r and ival_r were set
* \li ISC_R_NOMORE otherwise
*/
/***********************************************************************
*
* functions - transactions
@ -505,10 +607,27 @@ dns_qpmulti_query(dns_qpmulti_t *multi, dns_qpread_t *qpr);
* \li `qpr` is a valid read-only qp-trie handle
*/
void
dns_qpmulti_lockedread(dns_qpmulti_t *multi, dns_qpread_t *qpr);
/*%<
* Start a read-only transaction that takes the `dns_qpmulti_t` mutex.
*
* The `dns_qpmulti_lockedread()` function must NOT be called from an
* isc_loop thread. We keep query and read transactions separate to
* avoid accidentally taking or failing to take the mutex.
*
* Requires:
* \li `multi` is a pointer to a valid multi-threaded qp-trie
* \li `qpr != NULL`
*
* Returns:
* \li `qpr` is a valid read-only qp-trie handle
*/
void
dns_qpread_destroy(dns_qpmulti_t *multi, dns_qpread_t *qpr);
/*%<
* End a lightweight read transaction.
* End a lightweight query or read transaction.
*
* Requires:
* \li `multi` is a pointer to a valid multi-threaded qp-trie

View file

@ -259,8 +259,8 @@ struct dns_view {
#endif /* HAVE_LMDB */
isc_result_t
dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name,
dns_view_t **viewp);
dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
dns_rdataclass_t rdclass, const char *name, dns_view_t **viewp);
/*%<
* Create a view.
*
@ -364,24 +364,6 @@ dns_view_weakdetach(dns_view_t **targetp);
*\li *viewp is NULL.
*/
isc_result_t
dns_view_createzonetable(dns_view_t *view);
/*%<
* Create a zonetable for the view.
*
* Requires:
*
*\li 'view' is a valid, unfrozen view.
*
*\li 'view' does not have a zonetable already.
*
* Returns:
*
*\li #ISC_R_SUCCESS
*
*\li Any error that dns_zt_create() can return.
*/
isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
unsigned int ndisp, isc_nm_t *netmgr,
@ -782,14 +764,13 @@ dns_view_findzone(dns_view_t *view, const dns_name_t *name, dns_zone_t **zonep);
* Returns:
*\li #ISC_R_SUCCESS A matching zone was found.
*\li #ISC_R_NOTFOUND No matching zone was found.
*\li others An error occurred.
*/
isc_result_t
dns_view_load(dns_view_t *view, bool stop, bool newonly);
isc_result_t
dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_allloaded_t callback,
dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_callback_t *callback,
void *arg);
/*%<
* Load zones attached to this view. dns_view_load() loads

View file

@ -424,15 +424,14 @@ dns_zone_loadandthaw(dns_zone_t *zone);
*/
isc_result_t
dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_zoneloaded_t done,
dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_callback_t done,
void *arg);
/*%<
* Cause the database to be loaded from its backing store asynchronously.
* Other zone maintenance functions are suspended until this is complete.
* When finished, 'done' is called to inform the caller, with 'arg' as
* its first argument and 'zone' as its second. (Normally, 'arg' is
* expected to point to the zone table but is left undefined for testing
* purposes.)
* its argument. (Normally, 'arg' is expected to point to the zone table
* but is left undefined for testing purposes.)
*
* Require:
*\li 'zone' to be a valid zone.

View file

@ -22,35 +22,37 @@
#include <dns/types.h>
#define DNS_ZTFIND_NOEXACT 0x01
#define DNS_ZTFIND_MIRROR 0x02
ISC_LANG_BEGINDECLS
typedef isc_result_t (*dns_zt_allloaded_t)(void *arg);
/*%<
* Method prototype: when all pending zone loads are complete,
* the zone table can inform the caller via a callback function with
* this signature.
*/
typedef enum dns_ztfind {
DNS_ZTFIND_EXACT = 1 << 0,
DNS_ZTFIND_NOEXACT = 1 << 1,
DNS_ZTFIND_MIRROR = 1 << 2,
} dns_ztfind_t;
typedef isc_result_t (*dns_zt_zoneloaded_t)(dns_zt_t *zt, dns_zone_t *zone);
/*%<
* Method prototype: when a zone finishes loading, the zt object
* can be informed via a callback function with this signature.
*/
typedef isc_result_t
dns_zt_callback_t(void *arg);
isc_result_t
dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **zt);
void
dns_zt_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, dns_view_t *view,
dns_zt_t **ztp);
/*%<
* Creates a new zone table.
* Creates a new zone table for a view.
*
* Requires:
* \li 'mctx' to be initialized.
* \li 'view' is non-NULL
* \li 'ztp' is non-NULL
* \li '*ztp' is NULL
*/
void
dns_zt_compact(dns_zt_t *zt);
/*%<
* Reclaim unused memory in the zone table
*
* Returns:
* \li #ISC_R_SUCCESS on success.
* \li #ISC_R_NOMEMORY
* Requires:
* \li 'zt' to be valid
*/
isc_result_t
@ -65,8 +67,6 @@ dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone);
* Returns:
* \li #ISC_R_SUCCESS
* \li #ISC_R_EXISTS
* \li #ISC_R_NOSPACE
* \li #ISC_R_NOMEMORY
*/
isc_result_t
@ -75,37 +75,38 @@ dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone);
* Unmount the given zone from the table.
*
* Requires:
* 'zt' to be valid
* 'zt' to be valid
* \li 'zone' to be valid
*
* Returns:
* \li #ISC_R_SUCCESS
* \li #ISC_R_NOTFOUND
* \li #ISC_R_NOMEMORY
*/
isc_result_t
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, dns_zone_t **zone);
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, dns_ztfind_t options,
dns_zone_t **zone);
/*%<
* Find the best match for 'name' in 'zt'. If foundname is non NULL
* then the name of the zone found is returned.
* Find the best match for 'name' in 'zt'.
*
* Notes:
* \li If the DNS_ZTFIND_NOEXACT is set, the best partial match (if any)
* to 'name' will be returned.
* \li If the DNS_ZTFIND_EXACT option is set, only an exact match is
* returned.
*
* \li If the DNS_ZTFIND_NOEXACT option is set, the closest matching
* parent domain is returned, even when there is an exact match
* in the tree.
*
* Requires:
* \li 'zt' to be valid
* \li 'name' to be valid
* \li 'foundname' to be initialized and associated with a fixedname or NULL
* \li 'zone' to be non NULL and '*zone' to be NULL
* \li DNS_ZTFIND_EXACT and DNS_ZTFIND_NOEXACT are not both set
*
* Returns:
* \li #ISC_R_SUCCESS
* \li #DNS_R_PARTIALMATCH
* \li #DNS_R_PARTIALMATCH (if DNS_ZTFIND_EXACT is not set)
* \li #ISC_R_NOTFOUND
* \li #ISC_R_NOSPACE
*/
void
@ -142,14 +143,14 @@ isc_result_t
dns_zt_load(dns_zt_t *zt, bool stop, bool newonly);
isc_result_t
dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_callback_t alldone,
void *arg);
/*%<
* Load all zones in the table. If 'stop' is true,
* stop on the first error and return it. If 'stop'
* is false, ignore errors.
* Load all zones in the table. If 'stop' is true, stop on the first
* error and return it. If 'stop' is false, ignore errors.
*
* If newonly is set only zones that were never loaded are loaded.
*
* if newonly is set only zones that were never loaded are loaded.
* dns_zt_asyncload() loads zones asynchronously; when all
* zones in the zone table have finished loaded (or failed due
* to errors), the caller is informed by calling 'alldone'
@ -168,7 +169,7 @@ dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze);
*/
isc_result_t
dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub,
dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub,
isc_result_t (*action)(dns_zone_t *, void *), void *uap);
/*%<
* Apply a given 'action' to all zone zones in the table.

View file

@ -278,6 +278,25 @@ qpkey_compare(const dns_qpkey_t key_a, const size_t keylen_a,
return (QPKEY_EQUAL);
}
/*
* Given a key constructed by dns_qpkey_fromname(), trim it down to the last
* label boundary before the `max` length.
*
* This is used when searching a trie for the best match for a name.
*/
static size_t
qpkey_trim_label(dns_qpkey_t key, size_t len, size_t max) {
size_t stop = 0;
for (size_t offset = 0; offset < max; offset++) {
if (qpkey_bit(key, len, offset) == SHIFT_NOBYTE &&
qpkey_bit(key, len, offset + 1) != SHIFT_NOBYTE)
{
stop = offset + 1;
}
}
return (stop);
}
/***********************************************************************
*
* allocator wrappers
@ -463,6 +482,7 @@ static inline qp_ref_t
alloc_twigs(dns_qp_t *qp, qp_weight_t size) {
qp_chunk_t chunk = qp->bump;
qp_cell_t cell = qp->usage[chunk].used;
if (cell + size <= QP_CHUNK_SIZE) {
qp->usage[chunk].used += size;
qp->used_count += size;
@ -824,6 +844,7 @@ compact_recursive(dns_qp_t *qp, qp_node_t *parent) {
qp_weight_t size = branch_twigs_size(parent);
qp_ref_t twigs_ref = branch_twigs_ref(parent);
qp_chunk_t chunk = ref_chunk(twigs_ref);
if (qp->compact_all ||
(chunk != qp->bump && chunk_usage(qp, chunk) < QP_MIN_USED))
{
@ -884,6 +905,7 @@ dns_qp_compact(dns_qp_t *qp, dns_qpgc_t mode) {
return;
}
if (mode == DNS_QPGC_ALL) {
alloc_reset(qp);
qp->compact_all = true;
}
compact(qp);
@ -1007,15 +1029,12 @@ dns_qp_gctime(isc_nanosecs_t *compact_p, isc_nanosecs_t *recycle_p,
static dns_qp_t *
transaction_open(dns_qpmulti_t *multi, dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(QPMULTI_VALID(multi));
REQUIRE(qptp != NULL && *qptp == NULL);
LOCK(&multi->mutex);
qp = &multi->writer;
dns_qp_t *qp = &multi->writer;
INSIST(QP_VALID(qp));
/*
@ -1263,12 +1282,31 @@ dns_qpmulti_query(dns_qpmulti_t *multi, dns_qpread_t *qp) {
REQUIRE(QPMULTI_VALID(multi));
REQUIRE(qp != NULL);
dns_qpmulti_t *whence = reader_open(multi, qp);
INSIST(whence == multi);
/* we must be in an isc_loop thread */
/* we MUST be in an isc_loop thread */
qp->tid = isc_tid();
REQUIRE(qp->tid != ISC_TID_UNKNOWN);
dns_qpmulti_t *whence = reader_open(multi, qp);
INSIST(whence == multi);
}
/*
* a locked read takes the mutex
*/
void
dns_qpmulti_lockedread(dns_qpmulti_t *multi, dns_qpread_t *qp) {
REQUIRE(QPMULTI_VALID(multi));
REQUIRE(qp != NULL);
/* we MUST NOT be in an isc_loop thread */
qp->tid = isc_tid();
REQUIRE(qp->tid == ISC_TID_UNKNOWN);
LOCK(&multi->mutex);
dns_qpmulti_t *whence = reader_open(multi, qp);
INSIST(whence == multi);
}
void
@ -1276,6 +1314,9 @@ dns_qpread_destroy(dns_qpmulti_t *multi, dns_qpread_t *qp) {
REQUIRE(QPMULTI_VALID(multi));
REQUIRE(QP_VALID(qp));
REQUIRE(qp->tid == isc_tid());
if (qp->tid == ISC_TID_UNKNOWN) {
UNLOCK(&multi->mutex);
}
*qp = (dns_qpread_t){};
}
@ -1354,11 +1395,9 @@ dns_qpsnap_destroy(dns_qpmulti_t *multi, dns_qpsnap_t **qpsp) {
void
dns_qp_create(isc_mem_t *mctx, const dns_qpmethods_t *methods, void *uctx,
dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(qptp != NULL && *qptp == NULL);
qp = isc_mem_get(mctx, sizeof(*qp));
dns_qp_t *qp = isc_mem_get(mctx, sizeof(*qp));
QP_INIT(qp, methods, uctx);
isc_mem_attach(mctx, &qp->mctx);
alloc_reset(qp);
@ -1370,12 +1409,9 @@ void
dns_qpmulti_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
const dns_qpmethods_t *methods, void *uctx,
dns_qpmulti_t **qpmp) {
dns_qpmulti_t *multi;
dns_qp_t *qp;
REQUIRE(qpmp != NULL && *qpmp == NULL);
multi = isc_mem_get(mctx, sizeof(*multi));
dns_qpmulti_t *multi = isc_mem_get(mctx, sizeof(*multi));
*multi = (dns_qpmulti_t){
.magic = QPMULTI_MAGIC,
.reader_ref = INVALID_REF,
@ -1390,7 +1426,7 @@ dns_qpmulti_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
* allocates; to ensure dns_qpmulti_write() does too, pretend the
* previous transaction was an update
*/
qp = &multi->writer;
dns_qp_t *qp = &multi->writer;
QP_INIT(qp, methods, uctx);
isc_mem_attach(mctx, &qp->mctx);
qp->transaction_mode = QP_UPDATE;
@ -1418,12 +1454,10 @@ destroy_guts(dns_qp_t *qp) {
void
dns_qp_destroy(dns_qp_t **qptp) {
dns_qp_t *qp;
REQUIRE(qptp != NULL);
REQUIRE(QP_VALID(*qptp));
qp = *qptp;
dns_qp_t *qp = *qptp;
*qptp = NULL;
/* do not try to destroy part of a dns_qpmulti_t */
@ -1436,14 +1470,11 @@ dns_qp_destroy(dns_qp_t **qptp) {
void
dns_qpmulti_destroy(dns_qpmulti_t **qpmp) {
dns_qp_t *qp = NULL;
dns_qpmulti_t *multi = NULL;
REQUIRE(qpmp != NULL);
REQUIRE(QPMULTI_VALID(*qpmp));
multi = *qpmp;
qp = &multi->writer;
dns_qpmulti_t *multi = *qpmp;
dns_qp_t *qp = &multi->writer;
*qpmp = NULL;
REQUIRE(QP_VALID(qp));
@ -1471,7 +1502,7 @@ isc_result_t
dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival) {
qp_ref_t new_ref, old_ref;
qp_node_t new_leaf, old_node;
qp_node_t *new_twigs, *old_twigs;
qp_node_t *new_twigs = NULL, *old_twigs = NULL;
qp_shift_t new_bit, old_bit;
qp_weight_t old_size, new_size;
dns_qpkey_t new_key, old_key;
@ -1480,7 +1511,7 @@ dns_qp_insert(dns_qp_t *qp, void *pval, uint32_t ival) {
uint64_t index;
qp_shift_t bit;
qp_weight_t pos;
qp_node_t *n;
qp_node_t *n = NULL;
REQUIRE(QP_VALID(qp));
@ -1597,15 +1628,6 @@ growbranch:
isc_result_t
dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
size_t search_keylen) {
dns_qpkey_t found_key;
size_t found_keylen;
qp_shift_t bit = 0; /* suppress warning */
qp_weight_t pos, size;
qp_ref_t ref;
qp_node_t *twigs;
qp_node_t *parent;
qp_node_t *n;
REQUIRE(QP_VALID(qp));
REQUIRE(search_keylen < sizeof(dns_qpkey_t));
@ -1613,8 +1635,9 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
return (ISC_R_NOTFOUND);
}
parent = NULL;
n = make_root_mutable(qp);
qp_shift_t bit = 0; /* suppress warning */
qp_node_t *parent = NULL;
qp_node_t *n = make_root_mutable(qp);
while (is_branch(n)) {
prefetch_twigs(qp, n);
bit = branch_keybit(n, search_key, search_keylen);
@ -1626,7 +1649,8 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
n = branch_twig_ptr(qp, n, bit);
}
found_keylen = leaf_qpkey(qp, n, found_key);
dns_qpkey_t found_key;
size_t found_keylen = leaf_qpkey(qp, n, found_key);
if (qpkey_compare(search_key, search_keylen, found_key, found_keylen) !=
QPKEY_EQUAL)
{
@ -1650,10 +1674,10 @@ dns_qp_deletekey(dns_qp_t *qp, const dns_qpkey_t search_key,
parent = NULL;
INSIST(bit != 0);
size = branch_twigs_size(n);
pos = branch_twig_pos(n, bit);
ref = branch_twigs_ref(n);
twigs = ref_ptr(qp, ref);
qp_weight_t size = branch_twigs_size(n);
qp_weight_t pos = branch_twig_pos(n, bit);
qp_ref_t ref = branch_twigs_ref(n);
qp_node_t *twigs = ref_ptr(qp, ref);
if (size == 2) {
/*
@ -1681,6 +1705,72 @@ dns_qp_deletename(dns_qp_t *qp, const dns_name_t *name) {
return (dns_qp_deletekey(qp, key, keylen));
}
/***********************************************************************
*
* iterate
*/
void
dns_qpiter_init(dns_qpreadable_t qpr, dns_qpiter_t *qpi) {
dns_qpreader_t *qp = dns_qpreader(qpr);
REQUIRE(QP_VALID(qp));
REQUIRE(qpi != NULL);
qpi->magic = QPITER_MAGIC;
qpi->qp = qp;
qpi->sp = 0;
qpi->stack[qpi->sp].ref = qp->root_ref;
qpi->stack[qpi->sp].more = 0;
}
/*
* note: this function can go wrong when the iterator refers to
* a mutable view of the trie which is altered while iterating
*/
isc_result_t
dns_qpiter_next(dns_qpiter_t *qpi, void **pval_r, uint32_t *ival_r) {
REQUIRE(QPITER_VALID(qpi));
REQUIRE(QP_VALID(qpi->qp));
REQUIRE(pval_r != NULL);
REQUIRE(ival_r != NULL);
dns_qpreader_t *qp = qpi->qp;
if (qpi->stack[qpi->sp].ref == INVALID_REF) {
INSIST(qpi->sp == 0);
qpi->magic = 0;
return (ISC_R_NOMORE);
}
/* push branch nodes onto the stack until we reach a leaf */
for (;;) {
qp_node_t *n = ref_ptr(qp, qpi->stack[qpi->sp].ref);
if (node_tag(n) == LEAF_TAG) {
*pval_r = leaf_pval(n);
*ival_r = leaf_ival(n);
break;
}
qpi->sp++;
INSIST(qpi->sp < DNS_QP_MAXKEY);
qpi->stack[qpi->sp].ref = branch_twigs_ref(n);
qpi->stack[qpi->sp].more = branch_twigs_size(n) - 1;
}
/* pop the stack until we find a twig with a successor */
while (qpi->sp > 0 && qpi->stack[qpi->sp].more == 0) {
qpi->sp--;
}
/* move across to the next twig */
if (qpi->stack[qpi->sp].more > 0) {
qpi->stack[qpi->sp].more--;
qpi->stack[qpi->sp].ref++;
} else {
INSIST(qpi->sp == 0);
qpi->stack[qpi->sp].ref = INVALID_REF;
}
return (ISC_R_SUCCESS);
}
/***********************************************************************
*
* search
@ -1693,7 +1783,7 @@ dns_qp_getkey(dns_qpreadable_t qpr, const dns_qpkey_t search_key,
dns_qpkey_t found_key;
size_t found_keylen;
qp_shift_t bit;
qp_node_t *n;
qp_node_t *n = NULL;
REQUIRE(QP_VALID(qp));
REQUIRE(pval_r != NULL);
@ -1734,4 +1824,101 @@ dns_qp_getname(dns_qpreadable_t qpr, const dns_name_t *name, void **pval_r,
return (dns_qp_getkey(qpr, key, keylen, pval_r, ival_r));
}
isc_result_t
dns_qp_findname_parent(dns_qpreadable_t qpr, const dns_name_t *name,
dns_qpfind_t options, void **pval_r, uint32_t *ival_r) {
dns_qpreader_t *qp = dns_qpreader(qpr);
dns_qpkey_t search, found;
size_t searchlen, foundlen;
size_t offset;
qp_shift_t bit;
qp_node_t *n = NULL, *twigs = NULL;
isc_result_t result;
unsigned int labels = 0;
struct offref {
uint32_t off;
qp_ref_t ref;
} label[DNS_NAME_MAXLABELS];
REQUIRE(QP_VALID(qp));
REQUIRE(pval_r != NULL);
REQUIRE(ival_r != NULL);
searchlen = dns_qpkey_fromname(search, name);
if ((options & DNS_QPFIND_NOEXACT) != 0) {
searchlen = qpkey_trim_label(search, searchlen, searchlen);
result = DNS_R_PARTIALMATCH;
} else {
result = ISC_R_SUCCESS;
}
n = get_root(qp);
if (n == NULL) {
return (ISC_R_NOTFOUND);
}
/*
* Like `dns_qp_insert()`, we must find a leaf. However, we don't make a
* second pass: instead, we keep track of any leaves with shorter keys
* that we discover along the way. (In general, qp-trie searches can be
* one-pass, by recording their traversal, or two-pass, for less stack
* memory usage.)
*
* A shorter key that can be a parent domain always has a leaf node at
* SHIFT_NOBYTE (indicating end of its key) where our search key has a
* normal character immediately after a label separator. Note 1: It is
* OK if `offset - 1` underflows: it will become SIZE_MAX, which is
* greater than `searchlen`, so `qpkey_bit()` will return SHIFT_NOBYTE,
* which is what we want when `offset == 0`. Note 2: Any SHIFT_NOBYTE
* twig is always `twigs[0]`.
*/
while (is_branch(n)) {
prefetch_twigs(qp, n);
twigs = branch_twigs_vector(qp, n);
offset = branch_key_offset(n);
bit = qpkey_bit(search, searchlen, offset);
if (bit != SHIFT_NOBYTE && branch_has_twig(n, SHIFT_NOBYTE) &&
qpkey_bit(search, searchlen, offset - 1) == SHIFT_NOBYTE &&
!is_branch(&twigs[0]))
{
label[labels].off = offset;
label[labels].ref = branch_twigs_ref(n);
labels++;
INSIST(labels <= DNS_NAME_MAXLABELS);
}
if (branch_has_twig(n, bit)) {
n = branch_twig_ptr(qp, n, bit);
} else if (labels == 0) {
/* any twig will do */
n = &twigs[0];
} else {
n = ref_ptr(qp, label[labels - 1].ref);
break;
}
}
/* do the keys differ, and if so, where? */
foundlen = leaf_qpkey(qp, n, found);
offset = qpkey_compare(search, searchlen, found, foundlen);
if (offset == QPKEY_EQUAL || offset == foundlen) {
*pval_r = leaf_pval(n);
*ival_r = leaf_ival(n);
if (offset == QPKEY_EQUAL) {
return (result);
} else {
return (DNS_R_PARTIALMATCH);
}
}
while (labels-- > 0) {
if (offset > label[labels].off) {
n = ref_ptr(qp, label[labels].ref);
*pval_r = leaf_pval(n);
*ival_r = leaf_ival(n);
return (DNS_R_PARTIALMATCH);
}
}
return (ISC_R_NOTFOUND);
}
/**********************************************************************/

View file

@ -379,11 +379,13 @@ ref_ptr(dns_qpreadable_t qpr, qp_ref_t ref) {
*/
#define QP_MAGIC ISC_MAGIC('t', 'r', 'i', 'e')
#define QPITER_MAGIC ISC_MAGIC('q', 'p', 'i', 't')
#define QPMULTI_MAGIC ISC_MAGIC('q', 'p', 'm', 'v')
#define QPREADER_MAGIC ISC_MAGIC('q', 'p', 'r', 'x')
#define QP_VALID(qp) ISC_MAGIC_VALID(qp, QP_MAGIC)
#define QPMULTI_VALID(qp) ISC_MAGIC_VALID(qp, QPMULTI_MAGIC)
#define QP_VALID(p) ISC_MAGIC_VALID(p, QP_MAGIC)
#define QPITER_VALID(p) ISC_MAGIC_VALID(p, QPITER_MAGIC)
#define QPMULTI_VALID(p) ISC_MAGIC_VALID(p, QPMULTI_MAGIC)
/*
* Polymorphic initialization of the `dns_qpreader_t` prefix.
@ -892,34 +894,6 @@ unpack_reader(dns_qpreader_t *qp, qp_node_t *reader) {
* method invocation helpers
*/
#if 0
#define attach_leaf(qp, n) \
do { \
uint32_t iv = leaf_ival(n); \
void *pv = leaf_pval(n); \
uint32_t r = qp->methods->attach(qp->uctx, pv, iv); \
fprintf(stderr, \
"%s:%u:%s():t%u qp %p node %p leaf %p %u " \
"(%u -> %u)\n", \
__FILE__, __LINE__, __func__, isc_tid(), qp, n, pv, \
iv, r, r + 1); \
} while (0)
#define detach_leaf(qp, n) \
do { \
uint32_t iv = leaf_ival(n); \
void *pv = leaf_pval(n); \
uint32_t r = qp->methods->detach(qp->uctx, pv, iv); \
fprintf(stderr, \
"%s:%u:%s():t%u qp %p node %p leaf %p %u " \
"(%u -> %u)\n", \
__FILE__, __LINE__, __func__, isc_tid(), qp, n, pv, \
iv, r, r - 1); \
} while (0)
#else
static inline void
attach_leaf(dns_qpreadable_t qpr, qp_node_t *n) {
dns_qpreader_t *qp = dns_qpreader(qpr);
@ -932,8 +906,6 @@ detach_leaf(dns_qpreadable_t qpr, qp_node_t *n) {
qp->methods->detach(qp->uctx, leaf_pval(n), leaf_ival(n));
}
#endif
static inline size_t
leaf_qpkey(dns_qpreadable_t qpr, qp_node_t *n, dns_qpkey_t key) {
dns_qpreader_t *qp = dns_qpreader(qpr);

View file

@ -6544,9 +6544,8 @@ static inline bool
name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
isc_result_t result;
dns_forwarders_t *forwarders = NULL;
dns_fixedname_t fixed, zfixed;
dns_fixedname_t fixed;
dns_name_t *fname = dns_fixedname_initname(&fixed);
dns_name_t *zfname = dns_fixedname_initname(&zfixed);
dns_name_t *apex = NULL;
dns_name_t suffix;
dns_zone_t *zone = NULL;
@ -6584,25 +6583,17 @@ name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
* If there is a locally served zone between 'apex' and 'name'
* then don't cache.
*/
LOCK(&fctx->res->view->lock);
if (fctx->res->view->zonetable != NULL) {
unsigned int options = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_MIRROR;
result = dns_zt_find(fctx->res->view->zonetable, name, options,
zfname, &zone);
if (zone != NULL) {
dns_zone_detach(&zone);
}
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
if (dns_name_fullcompare(zfname, apex, &(int){ 0 },
&(unsigned int){ 0U }) ==
dns_namereln_subdomain)
{
UNLOCK(&fctx->res->view->lock);
return (true);
}
dns_ztfind_t options = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_MIRROR;
result = dns_zt_find(fctx->res->view->zonetable, name, options, &zone);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
dns_name_t *zname = dns_zone_getorigin(zone);
dns_namereln_t reln = dns_name_fullcompare(
zname, apex, &(int){ 0 }, &(unsigned int){ 0U });
dns_zone_detach(&zone);
if (reln == dns_namereln_subdomain) {
return (true);
}
}
UNLOCK(&fctx->res->view->lock);
/*
* Look for a forward declaration below 'name'.

View file

@ -79,7 +79,8 @@
#define DEFAULT_EDNS_BUFSIZE 1232
isc_result_t
dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name,
dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
dns_rdataclass_t rdclass, const char *name,
dns_view_t **viewp) {
dns_view_t *view = NULL;
isc_result_t result;
@ -134,13 +135,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name,
isc_rwlock_init(&view->sfd_lock);
view->zonetable = NULL;
result = dns_zt_create(mctx, rdclass, &view->zonetable);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR("dns_zt_create() failed: %s",
isc_result_totext(result));
result = ISC_R_UNEXPECTED;
goto cleanup_mutex;
}
dns_zt_create(mctx, loopmgr, view, &view->zonetable);
result = dns_fwdtable_create(mctx, &view->fwdtable);
if (result != ISC_R_SUCCESS) {
@ -214,11 +209,8 @@ cleanup_weakrefs:
}
cleanup_zt:
if (view->zonetable != NULL) {
dns_zt_detach(&view->zonetable);
}
dns_zt_detach(&view->zonetable);
cleanup_mutex:
isc_rwlock_destroy(&view->sfd_lock);
isc_mutex_destroy(&view->lock);
@ -572,8 +564,7 @@ dns_view_dialup(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->zonetable != NULL);
(void)dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL,
dialup, NULL);
(void)dns_zt_apply(view->zonetable, false, NULL, dialup, NULL);
}
void
@ -602,15 +593,6 @@ dns_view_weakdetach(dns_view_t **viewp) {
}
}
isc_result_t
dns_view_createzonetable(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(!view->frozen);
REQUIRE(view->zonetable == NULL);
return (dns_zt_create(view->mctx, view->rdclass, &view->zonetable));
}
isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
unsigned int ndisp, isc_nm_t *netmgr,
@ -784,7 +766,6 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(!view->frozen);
REQUIRE(view->zonetable != NULL);
result = dns_zt_mount(view->zonetable, zone);
@ -794,23 +775,9 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone) {
isc_result_t
dns_view_findzone(dns_view_t *view, const dns_name_t *name,
dns_zone_t **zonep) {
isc_result_t result;
REQUIRE(DNS_VIEW_VALID(view));
LOCK(&view->lock);
if (view->zonetable != NULL) {
result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
if (result == DNS_R_PARTIALMATCH) {
dns_zone_detach(zonep);
result = ISC_R_NOTFOUND;
}
} else {
result = ISC_R_NOTFOUND;
}
UNLOCK(&view->lock);
return (result);
return (dns_zt_find(view->zonetable, name, DNS_ZTFIND_EXACT, zonep));
}
isc_result_t
@ -820,11 +787,11 @@ dns_view_find(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
dns_name_t *foundname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset) {
isc_result_t result;
dns_db_t *db, *zdb;
dns_dbnode_t *node, *znode;
dns_db_t *db = NULL, *zdb = NULL;
dns_dbnode_t *node = NULL, *znode = NULL;
bool is_cache, is_staticstub_zone;
dns_rdataset_t zrdataset, zsigrdataset;
dns_zone_t *zone;
dns_zone_t *zone = NULL;
/*
* Find an rdataset whose owner name is 'name', and whose type is
@ -842,24 +809,12 @@ dns_view_find(dns_view_t *view, const dns_name_t *name, dns_rdatatype_t type,
*/
dns_rdataset_init(&zrdataset);
dns_rdataset_init(&zsigrdataset);
zdb = NULL;
znode = NULL;
/*
* Find a database to answer the query.
*/
db = NULL;
node = NULL;
is_staticstub_zone = false;
zone = NULL;
LOCK(&view->lock);
if (view->zonetable != NULL) {
result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_MIRROR,
NULL, &zone);
} else {
result = ISC_R_NOTFOUND;
}
UNLOCK(&view->lock);
result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_MIRROR, &zone);
if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
!use_static_stub)
{
@ -1109,10 +1064,10 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
unsigned int options, bool use_hints, bool use_cache,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
isc_result_t result;
dns_db_t *db;
bool is_cache, use_zone, try_hints;
dns_zone_t *zone;
dns_name_t *zfname;
dns_db_t *db = NULL;
bool is_cache, use_zone = false, try_hints = false;
dns_zone_t *zone = NULL;
dns_name_t *zfname = NULL;
dns_rdataset_t zrdataset, zsigrdataset;
dns_fixedname_t zfixedname;
unsigned int ztoptions = DNS_ZTFIND_MIRROR;
@ -1120,11 +1075,6 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->frozen);
db = NULL;
use_zone = false;
try_hints = false;
zfname = NULL;
/*
* Initialize.
*/
@ -1135,18 +1085,10 @@ dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
/*
* Find the right database.
*/
zone = NULL;
LOCK(&view->lock);
if (view->zonetable != NULL) {
if ((options & DNS_DBFIND_NOEXACT) != 0) {
ztoptions |= DNS_ZTFIND_NOEXACT;
}
result = dns_zt_find(view->zonetable, name, ztoptions, NULL,
&zone);
} else {
result = ISC_R_NOTFOUND;
if ((options & DNS_DBFIND_NOEXACT) != 0) {
ztoptions |= DNS_ZTFIND_NOEXACT;
}
UNLOCK(&view->lock);
result = dns_zt_find(view->zonetable, name, ztoptions, &zone);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
result = dns_zone_getdb(zone, &db);
}
@ -1339,7 +1281,6 @@ dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name,
dns_view_t *view;
isc_result_t result;
dns_zone_t *zone1 = NULL, *zone2 = NULL;
dns_zone_t **zp = NULL;
REQUIRE(list != NULL);
REQUIRE(zonep != NULL && *zonep == NULL);
@ -1350,30 +1291,9 @@ dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name,
if (!allclasses && view->rdclass != rdclass) {
continue;
}
/*
* If the zone is defined in more than one view,
* treat it as not found.
*/
zp = (zone1 == NULL) ? &zone1 : &zone2;
LOCK(&view->lock);
if (view->zonetable != NULL) {
result = dns_zt_find(view->zonetable, name, 0, NULL,
zp);
} else {
result = ISC_R_NOTFOUND;
}
UNLOCK(&view->lock);
INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND ||
result == DNS_R_PARTIALMATCH);
/* Treat a partial match as no match */
if (result == DNS_R_PARTIALMATCH) {
dns_zone_detach(zp);
result = ISC_R_NOTFOUND;
POST(result);
}
result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_EXACT,
(zone1 == NULL) ? &zone1 : &zone2);
INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND);
if (zone2 != NULL) {
dns_zone_detach(&zone1);
dns_zone_detach(&zone2);
@ -1393,17 +1313,13 @@ dns_viewlist_findzone(dns_viewlist_t *list, const dns_name_t *name,
isc_result_t
dns_view_load(dns_view_t *view, bool stop, bool newonly) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->zonetable != NULL);
return (dns_zt_load(view->zonetable, stop, newonly));
}
isc_result_t
dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_allloaded_t callback,
dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_callback_t *callback,
void *arg) {
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->zonetable != NULL);
return (dns_zt_asyncload(view->zonetable, newonly, callback, arg));
}

View file

@ -781,7 +781,7 @@ struct dns_nsfetch {
struct dns_asyncload {
dns_zone_t *zone;
unsigned int flags;
dns_zt_zoneloaded_t loaded;
dns_zt_callback_t *loaded;
void *loaded_arg;
};
@ -2371,7 +2371,7 @@ zone_asyncload(void *arg) {
/* Inform the zone table we've finished loading */
if (asl->loaded != NULL) {
(asl->loaded)(asl->loaded_arg, zone);
asl->loaded(asl->loaded_arg);
}
isc_mem_put(zone->mctx, asl, sizeof(*asl));
@ -2379,7 +2379,7 @@ zone_asyncload(void *arg) {
}
isc_result_t
dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_zoneloaded_t done,
dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_callback_t *done,
void *arg) {
dns_asyncload_t *asl = NULL;
@ -5617,15 +5617,7 @@ zone_destroy(dns_zone_t *zone) {
* This zone is unmanaged; we're probably running in
* named-checkzone or a unit test. There's no loop, so we
* need to free it immediately.
*
* Unmanaged zones must not have null views; we have no way
* of detaching from the view here without causing deadlock
* because this code is called with the view already
* locked.
*/
INSIST(isc_tid() == ISC_TID_UNKNOWN);
INSIST(zone->view == NULL);
zone_shutdown(zone);
} else {
/*

View file

@ -22,38 +22,35 @@
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/tid.h>
#include <isc/util.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/rbt.h>
#include <dns/qp.h>
#include <dns/rdataclass.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>
struct zt_load_params {
dns_zt_zoneloaded_t dl;
bool newonly;
};
#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
struct dns_zt {
/* Unlocked. */
unsigned int magic;
isc_mem_t *mctx;
dns_rdataclass_t rdclass;
isc_rwlock_t rwlock;
dns_zt_allloaded_t loaddone;
void *loaddone_arg;
struct zt_load_params *loadparams;
dns_qpmulti_t *multi;
/* Atomic */
atomic_bool flush;
isc_refcount_t references;
isc_refcount_t loads_pending;
};
/* Locked by lock. */
dns_rbt_t *table;
struct zt_load_params {
dns_zt_t *zt;
dns_zt_callback_t *loaddone;
void *loaddone_arg;
bool newonly;
};
struct zt_freeze_params {
@ -61,77 +58,93 @@ struct zt_freeze_params {
bool freeze;
};
#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
static void
ztqpattach(void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_zone_t *zone = pval;
dns_zone_ref(zone);
}
static void
auto_detach(void *, void *);
ztqpdetach(void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_zone_t *zone = pval;
dns_zone_detach(&zone);
}
static isc_result_t
load(dns_zone_t *zone, void *uap);
static size_t
ztqpmakekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
uint32_t ival ISC_ATTR_UNUSED) {
dns_zone_t *zone = pval;
dns_name_t *name = dns_zone_getorigin(zone);
return (dns_qpkey_fromname(key, name));
}
static isc_result_t
asyncload(dns_zone_t *zone, void *callback);
static void
ztqptriename(void *uctx, char *buf, size_t size) {
dns_view_t *view = uctx;
snprintf(buf, size, "view %s zone table", view->name);
}
static isc_result_t
freezezones(dns_zone_t *zone, void *uap);
static dns_qpmethods_t ztqpmethods = {
ztqpattach,
ztqpdetach,
ztqpmakekey,
ztqptriename,
};
static isc_result_t
doneloading(dns_zt_t *zt, dns_zone_t *zone);
isc_result_t
dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
dns_zt_t *zt;
isc_result_t result;
void
dns_zt_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, dns_view_t *view,
dns_zt_t **ztp) {
dns_qpmulti_t *multi = NULL;
dns_zt_t *zt = NULL;
REQUIRE(ztp != NULL && *ztp == NULL);
REQUIRE(view != NULL);
dns_qpmulti_create(mctx, loopmgr, &ztqpmethods, view, &multi);
zt = isc_mem_get(mctx, sizeof(*zt));
*zt = (dns_zt_t){
.magic = ZTMAGIC,
.multi = multi,
.references = 1,
};
zt->table = NULL;
result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
if (result != ISC_R_SUCCESS) {
goto cleanup_zt;
}
isc_rwlock_init(&zt->rwlock);
zt->mctx = NULL;
isc_mem_attach(mctx, &zt->mctx);
isc_refcount_init(&zt->references, 1);
atomic_init(&zt->flush, false);
zt->rdclass = rdclass;
zt->magic = ZTMAGIC;
zt->loaddone = NULL;
zt->loaddone_arg = NULL;
zt->loadparams = NULL;
isc_refcount_init(&zt->loads_pending, 0);
*ztp = zt;
}
return (ISC_R_SUCCESS);
/*
* XXXFANF it isn't clear whether this function will be useful. There
* is only one zone table per view, so it is probably enough to let
* the qp-trie auto-GC do its thing. However it might be problematic
* if a very large zone is replaced, and its database memory is
* retained for a long time.
*/
void
dns_zt_compact(dns_zt_t *zt) {
dns_qp_t *qp = NULL;
cleanup_zt:
isc_mem_put(mctx, zt, sizeof(*zt));
REQUIRE(VALID_ZT(zt));
return (result);
dns_qpmulti_write(zt->multi, &qp);
dns_qp_compact(qp, DNS_QPGC_ALL);
dns_qpmulti_commit(zt->multi, &qp);
}
isc_result_t
dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
isc_result_t result;
dns_name_t *name = NULL;
dns_qp_t *qp = NULL;
REQUIRE(VALID_ZT(zt));
name = dns_zone_getorigin(zone);
RWLOCK(&zt->rwlock, isc_rwlocktype_write);
result = dns_rbt_addname(zt->table, name, zone);
if (result == ISC_R_SUCCESS) {
dns_zone_ref(zone);
}
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
dns_qpmulti_write(zt->multi, &qp);
result = dns_qp_insert(qp, zone, 0);
dns_qp_compact(qp, DNS_QPGC_MAYBE);
dns_qpmulti_commit(zt->multi, &qp);
return (result);
}
@ -139,39 +152,48 @@ dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
isc_result_t
dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
isc_result_t result;
dns_name_t *name;
dns_qp_t *qp = NULL;
REQUIRE(VALID_ZT(zt));
name = dns_zone_getorigin(zone);
RWLOCK(&zt->rwlock, isc_rwlocktype_write);
result = dns_rbt_deletename(zt->table, name, false);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
dns_qpmulti_write(zt->multi, &qp);
result = dns_qp_deletename(qp, dns_zone_getorigin(zone));
dns_qp_compact(qp, DNS_QPGC_MAYBE);
dns_qpmulti_commit(zt->multi, &qp);
return (result);
}
isc_result_t
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
dns_name_t *foundname, dns_zone_t **zonep) {
dns_zt_find(dns_zt_t *zt, const dns_name_t *name, dns_ztfind_t options,
dns_zone_t **zonep) {
isc_result_t result;
dns_zone_t *dummy = NULL;
unsigned int rbtoptions = 0;
dns_qpread_t qpr;
void *pval = NULL;
uint32_t ival;
dns_ztfind_t exactmask = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_EXACT;
dns_ztfind_t exactopts = options & exactmask;
REQUIRE(VALID_ZT(zt));
REQUIRE(exactopts != exactmask);
if ((options & DNS_ZTFIND_NOEXACT) != 0) {
rbtoptions |= DNS_RBTFIND_NOEXACT;
if (isc_tid() == ISC_TID_UNKNOWN) {
dns_qpmulti_lockedread(zt->multi, &qpr);
} else {
dns_qpmulti_query(zt->multi, &qpr);
}
if (exactopts == DNS_ZTFIND_EXACT) {
result = dns_qp_getname(&qpr, name, &pval, &ival);
} else if (exactopts == DNS_ZTFIND_NOEXACT) {
result = dns_qp_findname_parent(&qpr, name, DNS_QPFIND_NOEXACT,
&pval, &ival);
} else {
result = dns_qp_findname_parent(&qpr, name, 0, &pval, &ival);
}
dns_qpread_destroy(zt->multi, &qpr);
RWLOCK(&zt->rwlock, isc_rwlocktype_read);
result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
(void **)&dummy);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
dns_zone_t *zone = pval;
/*
* If DNS_ZTFIND_MIRROR is set and the zone which was
* determined to be the deepest match for the supplied name is
@ -190,17 +212,15 @@ dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
* arguably not worth the added complexity.
*/
if ((options & DNS_ZTFIND_MIRROR) != 0 &&
dns_zone_gettype(dummy) == dns_zone_mirror &&
!dns_zone_isloaded(dummy))
dns_zone_gettype(zone) == dns_zone_mirror &&
!dns_zone_isloaded(zone))
{
result = ISC_R_NOTFOUND;
} else {
dns_zone_attach(dummy, zonep);
dns_zone_attach(zone, zonep);
}
}
RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
return (result);
}
@ -226,12 +246,10 @@ zt_destroy(dns_zt_t *zt) {
isc_refcount_destroy(&zt->loads_pending);
if (atomic_load_acquire(&zt->flush)) {
(void)dns_zt_apply(zt, isc_rwlocktype_none, false, NULL, flush,
NULL);
(void)dns_zt_apply(zt, false, NULL, flush, NULL);
}
dns_rbt_destroy(&zt->table);
isc_rwlock_destroy(&zt->rwlock);
dns_qpmulti_destroy(&zt->multi);
zt->magic = 0;
isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
}
@ -256,22 +274,10 @@ dns_zt_flush(dns_zt_t *zt) {
atomic_store_release(&zt->flush, true);
}
isc_result_t
dns_zt_load(dns_zt_t *zt, bool stop, bool newonly) {
isc_result_t result;
struct zt_load_params params;
REQUIRE(VALID_ZT(zt));
params.newonly = newonly;
result = dns_zt_apply(zt, isc_rwlocktype_read, stop, NULL, load,
&params);
return (result);
}
static isc_result_t
load(dns_zone_t *zone, void *paramsv) {
load(dns_zone_t *zone, void *uap) {
isc_result_t result;
struct zt_load_params *params = (struct zt_load_params *)paramsv;
result = dns_zone_load(zone, params->newonly);
result = dns_zone_load(zone, uap != NULL);
if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
result == DNS_R_DYNAMIC)
{
@ -280,71 +286,41 @@ load(dns_zone_t *zone, void *paramsv) {
return (result);
}
static void
call_loaddone(dns_zt_t *zt) {
dns_zt_allloaded_t loaddone = zt->loaddone;
void *loaddone_arg = zt->loaddone_arg;
/*
* Set zt->loaddone, zt->loaddone_arg and zt->loadparams to NULL
* before calling loaddone.
*/
zt->loaddone = NULL;
zt->loaddone_arg = NULL;
isc_mem_put(zt->mctx, zt->loadparams, sizeof(struct zt_load_params));
zt->loadparams = NULL;
/*
* Call the callback last.
*/
if (loaddone != NULL) {
loaddone(loaddone_arg);
}
isc_result_t
dns_zt_load(dns_zt_t *zt, bool stop, bool newonly) {
REQUIRE(VALID_ZT(zt));
return (dns_zt_apply(zt, stop, NULL, load, newonly ? &newonly : NULL));
}
isc_result_t
dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
void *arg) {
isc_result_t result;
uint_fast32_t loads_pending;
static void
loaded_all(struct zt_load_params *params) {
if (params->loaddone != NULL) {
params->loaddone(params->loaddone_arg);
}
isc_mem_put(params->zt->mctx, params, sizeof(*params));
}
/*
* Decrement the loads_pending counter; when counter reaches
* zero, call the loaddone callback that was initially set by
* dns_zt_asyncload().
*/
static isc_result_t
loaded_one(void *uap) {
struct zt_load_params *params = uap;
dns_zt_t *zt = params->zt;
REQUIRE(VALID_ZT(zt));
/*
* Obtain a reference to zt->loads_pending so that asyncload can
* safely decrement both zt->references and zt->loads_pending
* without going to zero.
*/
loads_pending = isc_refcount_increment0(&zt->loads_pending);
INSIST(loads_pending == 0);
/*
* Only one dns_zt_asyncload call at a time should be active so
* these pointers should be NULL. They are set back to NULL
* before the zt->loaddone (alldone) is called in call_loaddone.
*/
INSIST(zt->loadparams == NULL);
INSIST(zt->loaddone == NULL);
INSIST(zt->loaddone_arg == NULL);
zt->loadparams = isc_mem_get(zt->mctx, sizeof(struct zt_load_params));
zt->loadparams->dl = doneloading;
zt->loadparams->newonly = newonly;
zt->loaddone = alldone;
zt->loaddone_arg = arg;
result = dns_zt_apply(zt, isc_rwlocktype_read, false, NULL, asyncload,
zt);
/*
* Have all the loads completed?
*/
if (isc_refcount_decrement(&zt->loads_pending) == 1) {
call_loaddone(zt);
loaded_all(params);
}
return (result);
if (isc_refcount_decrement(&zt->references) == 1) {
zt_destroy(zt);
}
return (ISC_R_SUCCESS);
}
/*
@ -353,16 +329,18 @@ dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
* the zone loading is complete.
*/
static isc_result_t
asyncload(dns_zone_t *zone, void *zt_) {
asyncload(dns_zone_t *zone, void *uap) {
struct zt_load_params *params = uap;
struct dns_zt *zt = params->zt;
isc_result_t result;
struct dns_zt *zt = (dns_zt_t *)zt_;
REQUIRE(VALID_ZT(zt));
REQUIRE(zone != NULL);
isc_refcount_increment(&zt->references);
isc_refcount_increment(&zt->loads_pending);
result = dns_zone_asyncload(zone, zt->loadparams->newonly,
*zt->loadparams->dl, zt);
result = dns_zone_asyncload(zone, params->newonly, loaded_one, params);
if (result != ISC_R_SUCCESS) {
/*
* Caller is holding a reference to zt->loads_pending
@ -375,18 +353,40 @@ asyncload(dns_zone_t *zone, void *zt_) {
}
isc_result_t
dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) {
isc_result_t result, tresult;
struct zt_freeze_params params = { view, freeze };
dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_callback_t *loaddone,
void *arg) {
isc_result_t result;
uint_fast32_t loads_pending;
struct zt_load_params *params = NULL;
REQUIRE(VALID_ZT(zt));
result = dns_zt_apply(zt, isc_rwlocktype_read, false, &tresult,
freezezones, &params);
if (tresult == ISC_R_NOTFOUND) {
tresult = ISC_R_SUCCESS;
/*
* Obtain a reference to zt->loads_pending so that asyncload can
* safely decrement both zt->references and zt->loads_pending
* without going to zero.
*/
loads_pending = isc_refcount_increment0(&zt->loads_pending);
INSIST(loads_pending == 0);
params = isc_mem_get(zt->mctx, sizeof(*params));
*params = (struct zt_load_params){
.zt = zt,
.newonly = newonly,
.loaddone = loaddone,
.loaddone_arg = arg,
};
result = dns_zt_apply(zt, false, NULL, asyncload, params);
/*
* Have all the loads completed?
*/
if (isc_refcount_decrement(&zt->loads_pending) == 1) {
loaded_all(params);
}
return ((result == ISC_R_SUCCESS) ? tresult : result);
return (result);
}
static isc_result_t
@ -447,8 +447,8 @@ freezezones(dns_zone_t *zone, void *uap) {
}
}
view = dns_zone_getview(zone);
if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_defaul"
"t") == 0)
if (strcmp(view->name, "_bind") == 0 ||
strcmp(view->name, "_default") == 0)
{
vname = "";
sep = "";
@ -470,143 +470,70 @@ freezezones(dns_zone_t *zone, void *uap) {
return (result);
}
void
dns_zt_setviewcommit(dns_zt_t *zt) {
dns_rbtnode_t *node;
dns_rbtnodechain_t chain;
isc_result_t result;
isc_result_t
dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) {
isc_result_t result, tresult;
struct zt_freeze_params params = { view, freeze };
REQUIRE(VALID_ZT(zt));
RWLOCK(&zt->rwlock, isc_rwlocktype_read);
dns_rbtnodechain_init(&chain);
result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
if (result == ISC_R_SUCCESS && node->data != NULL) {
dns_zone_setviewcommit(node->data);
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);
result = dns_zt_apply(zt, false, &tresult, freezezones, &params);
if (tresult == ISC_R_NOTFOUND) {
tresult = ISC_R_SUCCESS;
}
return ((result == ISC_R_SUCCESS) ? tresult : result);
}
dns_rbtnodechain_invalidate(&chain);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
typedef void
setview_cb(dns_zone_t *zone);
static isc_result_t
setview(dns_zone_t *zone, void *arg) {
setview_cb *cb = arg;
cb(zone);
return (ISC_R_SUCCESS);
}
void
dns_zt_setviewcommit(dns_zt_t *zt) {
dns_zt_apply(zt, false, NULL, setview, dns_zone_setviewcommit);
}
void
dns_zt_setviewrevert(dns_zt_t *zt) {
dns_rbtnode_t *node;
dns_rbtnodechain_t chain;
isc_result_t result;
REQUIRE(VALID_ZT(zt));
dns_rbtnodechain_init(&chain);
result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
if (result == ISC_R_SUCCESS && node->data != NULL) {
dns_zone_setviewrevert(node->data);
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);
}
dns_rbtnodechain_invalidate(&chain);
dns_zt_apply(zt, false, NULL, setview, dns_zone_setviewrevert);
}
isc_result_t
dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub,
dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub,
isc_result_t (*action)(dns_zone_t *, void *), void *uap) {
dns_rbtnode_t *node;
dns_rbtnodechain_t chain;
isc_result_t result, tresult = ISC_R_SUCCESS;
dns_zone_t *zone;
isc_result_t result = ISC_R_SUCCESS;
isc_result_t tresult = ISC_R_SUCCESS;
dns_qpiter_t qpi;
dns_qpread_t qpr;
void *zone = NULL;
uint32_t ival;
REQUIRE(VALID_ZT(zt));
REQUIRE(action != NULL);
if (lock != isc_rwlocktype_none) {
RWLOCK(&zt->rwlock, lock);
}
dns_qpmulti_query(zt->multi, &qpr);
dns_qpiter_init(&qpr, &qpi);
dns_rbtnodechain_init(&chain);
result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
if (result == ISC_R_NOTFOUND) {
/*
* The tree is empty.
*/
tresult = result;
result = ISC_R_NOMORE;
}
while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
if (result == ISC_R_SUCCESS) {
zone = node->data;
if (zone != NULL) {
result = (action)(zone, uap);
}
if (result != ISC_R_SUCCESS && stop) {
tresult = result;
goto cleanup; /* don't break */
} else if (result != ISC_R_SUCCESS &&
tresult == ISC_R_SUCCESS)
{
tresult = result;
}
while (dns_qpiter_next(&qpi, &zone, &ival) == ISC_R_SUCCESS) {
result = action(zone, uap);
if (tresult == ISC_R_SUCCESS) {
tresult = result;
}
if (result != ISC_R_SUCCESS && stop) {
break;
}
result = dns_rbtnodechain_next(&chain, NULL, NULL);
}
if (result == ISC_R_NOMORE) {
result = ISC_R_SUCCESS;
}
dns_qpread_destroy(zt->multi, &qpr);
cleanup:
dns_rbtnodechain_invalidate(&chain);
if (sub != NULL) {
*sub = tresult;
}
if (lock != isc_rwlocktype_none) {
RWUNLOCK(&zt->rwlock, lock);
}
return (result);
}
/*
* Decrement the loads_pending counter; when counter reaches
* zero, call the loaddone callback that was initially set by
* dns_zt_asyncload().
*/
static isc_result_t
doneloading(dns_zt_t *zt, dns_zone_t *zone) {
REQUIRE(VALID_ZT(zt));
UNUSED(zone);
if (isc_refcount_decrement(&zt->loads_pending) == 1) {
call_loaddone(zt);
}
if (isc_refcount_decrement(&zt->references) == 1) {
zt_destroy(zt);
}
return (ISC_R_SUCCESS);
}
/***
*** Private
***/
static void
auto_detach(void *data, void *arg) {
dns_zone_t *zone = data;
UNUSED(arg);
dns_zone_detach(&zone);
}

View file

@ -146,7 +146,7 @@ ns_notify_start(ns_client_t *client, isc_nmhandle_t *handle) {
}
dns_name_format(zonename, namebuf, sizeof(namebuf));
result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone);
result = dns_view_findzone(client->view, zonename, &zone);
if (result == ISC_R_SUCCESS) {
dns_zonetype_t zonetype = dns_zone_gettype(zone);
@ -166,10 +166,10 @@ ns_notify_start(ns_client_t *client, isc_nmhandle_t *handle) {
}
}
notify_log(client, ISC_LOG_NOTICE,
"received notify for zone '%s'%s: not authoritative",
namebuf, tsigbuf);
result = DNS_R_NOTAUTH;
notify_log(client, ISC_LOG_NOTICE,
"received notify for zone '%s'%s: %s", namebuf, tsigbuf,
isc_result_totext(result));
done:
if (zone != NULL) {

View file

@ -1116,8 +1116,7 @@ query_getzonedb(ns_client_t *client, const dns_name_t *name,
ztoptions |= DNS_ZTFIND_NOEXACT;
}
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
&zone);
result = dns_zt_find(client->view->zonetable, name, ztoptions, &zone);
if (result == DNS_R_PARTIALMATCH) {
partial = true;

View file

@ -1988,15 +1988,8 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle,
"RRs");
}
result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone);
result = dns_view_findzone(client->view, zonename, &zone);
if (result != ISC_R_SUCCESS) {
/*
* If we found a zone that is a parent of the update zonename,
* detach it so it isn't mentioned in log - it is irrelevant.
*/
if (zone != NULL) {
dns_zone_detach(&zone);
}
FAILN(DNS_R_NOTAUTH, zonename,
"not authoritative for update zone");
}

View file

@ -797,9 +797,7 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
FAILC(DNS_R_FORMERR, "multiple questions");
}
result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
&zone);
result = dns_view_findzone(client->view, question_name, &zone);
if (result != ISC_R_SUCCESS || dns_zone_gettype(zone) == dns_zone_dlz) {
/*
* The normal zone table does not have a match, or this is

View file

@ -37,11 +37,10 @@ struct {
dns_fixedname_t fixed;
} item[1024 * 1024];
static uint32_t
static void
item_check(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
assert(pval == &item[ival]);
return (1);
}
static size_t
@ -57,7 +56,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods qpmethods = {
const dns_qpmethods_t qpmethods = {
item_check,
item_check,
item_makekey,
@ -164,7 +163,7 @@ add_qp(void *qp, size_t count) {
static void
sqz_qp(void *qp) {
dns_qp_compact(qp, true);
dns_qp_compact(qp, DNS_QPGC_ALL);
}
static isc_result_t
@ -201,7 +200,7 @@ static struct fun {
#define FILE_CHECK(check, msg) \
do { \
if (!(check)) { \
fprintf(stderr, "%s:%zu: %s\n", filename, count, msg); \
fprintf(stderr, "%s:%zu: %s\n", filename, lines, msg); \
exit(1); \
} \
} while (0)
@ -209,6 +208,12 @@ static struct fun {
int
main(int argc, char *argv[]) {
isc_result_t result;
const char *filename = NULL;
char *filetext = NULL;
off_t fileoff;
FILE *fp = NULL;
size_t filesize, lines = 0, wirebytes = 0, labels = 0;
char *pos = NULL, *file_end = NULL;
isc_mem_create(&mctx);
@ -217,18 +222,17 @@ main(int argc, char *argv[]) {
exit(1);
}
const char *filename = argv[1];
off_t fileoff;
filename = argv[1];
result = isc_file_getsize(filename, &fileoff);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "stat(%s): %s\n", filename,
isc_result_totext(result));
exit(1);
}
size_t filesize = (size_t)fileoff;
filesize = (size_t)fileoff;
char *filetext = isc_mem_get(mctx, filesize + 1);
FILE *fp = fopen(filename, "r");
filetext = isc_mem_get(mctx, filesize + 1);
fp = fopen(filename, "r");
if (fp == NULL || fread(filetext, 1, filesize, fp) < filesize) {
fprintf(stderr, "read(%s): %s\n", filename, strerror(errno));
exit(1);
@ -236,29 +240,28 @@ main(int argc, char *argv[]) {
fclose(fp);
filetext[filesize] = '\0';
size_t count = 0;
size_t wirebytes = 0;
size_t labels = 0;
char *pos = filetext;
char *file_end = pos + filesize;
pos = filetext;
file_end = pos + filesize;
while (pos < file_end) {
FILE_CHECK(count < ARRAY_SIZE(item), "too many lines");
char *domain = NULL, *newline = NULL;
size_t len;
FILE_CHECK(lines < ARRAY_SIZE(item), "too many lines");
pos += strspn(pos, "0123456789");
FILE_CHECK(*pos++ == ',', "missing comma");
char *domain = pos;
domain = pos;
pos += strcspn(pos, "\r\n");
FILE_CHECK(*pos != '\0', "missing newline");
char *newline = pos;
newline = pos;
pos += strspn(pos, "\r\n");
size_t len = newline - domain;
len = newline - domain;
item[count].text = domain;
item[lines].text = domain;
domain[len] = '\0';
dns_name_t *name = dns_fixedname_initname(&item[count].fixed);
dns_name_t *name = dns_fixedname_initname(&item[lines].fixed);
isc_buffer_t buffer;
isc_buffer_init(&buffer, domain, len);
isc_buffer_add(&buffer, len);
@ -268,41 +271,35 @@ main(int argc, char *argv[]) {
wirebytes += name->length;
labels += name->labels;
count++;
lines++;
}
printf("names %g MB labels %g MB\n", (double)wirebytes / 1048576.0,
(double)labels / 1048576.0);
size_t lines = count;
for (struct fun *fun = fun_list; fun->name != NULL; fun++) {
isc_time_t t0;
t0 = isc_time_now_hires();
isc_mem_t *mem = NULL;
isc_mem_create(&mem);
void *map = fun->new (mem);
void *map = NULL;
for (count = 0; count < lines; count++) {
result = fun->add(map, count);
isc_mem_create(&mem);
map = fun->new (mem);
isc_time_t t0 = isc_time_now_hires();
for (size_t n = 0; n < lines; n++) {
result = fun->add(map, n);
CHECK(result);
}
fun->sqz(map);
isc_time_t t1;
t1 = isc_time_now_hires();
for (count = 0; count < lines; count++) {
isc_time_t t1 = isc_time_now_hires();
for (size_t n = 0; n < lines; n++) {
void *pval = NULL;
result = fun->get(map, count, &pval);
result = fun->get(map, n, &pval);
CHECK(result);
assert(pval == &item[count]);
assert(pval == &item[n]);
}
isc_time_t t2;
t2 = isc_time_now_hires();
isc_time_t t2 = isc_time_now_hires();
printf("%f sec to load %s\n",
(double)isc_time_microdiff(&t1, &t0) / (1000.0 * 1000.0),
fun->name);

View file

@ -95,19 +95,17 @@ qpkey_from_smallname(dns_qpkey_t key, void *ctx, void *pval, uint32_t ival) {
return (dns_qpkey_fromname(key, &name));
}
static uint32_t
static void
smallname_attach(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
return (isc_refcount_increment0(smallname_refcount(pval, ival)));
isc_refcount_increment0(smallname_refcount(pval, ival));
}
static uint32_t
static void
smallname_detach(void *ctx, void *pval, uint32_t ival) {
uint32_t refs = isc_refcount_decrement(smallname_refcount(pval, ival));
if (refs == 1) {
if (isc_refcount_decrement(smallname_refcount(pval, ival)) == 1) {
isc_mem_free(ctx, pval);
}
return (refs);
}
static void
@ -116,7 +114,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods methods = {
const dns_qpmethods_t methods = {
smallname_attach,
smallname_detach,
qpkey_from_smallname,
@ -126,15 +124,23 @@ const struct dns_qpmethods methods = {
static void
usage(void) {
fprintf(stderr,
"usage: qp_dump [-drt] <filename>\n"
"usage: qp_dump [-dt] <filename>\n"
" -d output in graphviz dot format\n"
" -t output in ad-hoc indented text format\n");
}
int
main(int argc, char *argv[]) {
bool dumpdot = false;
bool dumptxt = false;
isc_result_t result;
dns_qp_t *qp = NULL;
const char *filename = NULL;
char *filetext = NULL;
size_t filesize;
off_t fileoff;
FILE *fp = NULL;
size_t wirebytes = 0, labels = 0, names = 0;
char *pos = NULL, *file_end = NULL;
bool dumpdot = false, dumptxt = false;
int opt;
while ((opt = isc_commandline_parse(argc, argv, "dt")) != -1) {
@ -162,18 +168,17 @@ main(int argc, char *argv[]) {
isc_mem_create(&mctx);
const char *filename = argv[0];
off_t fileoff;
isc_result_t result = isc_file_getsize(filename, &fileoff);
filename = argv[0];
result = isc_file_getsize(filename, &fileoff);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "stat(%s): %s\n", filename,
isc_result_totext(result));
exit(1);
}
size_t filesize = (size_t)fileoff;
char *filetext = isc_mem_get(mctx, filesize + 1);
FILE *fp = fopen(filename, "r");
filesize = (size_t)fileoff;
filetext = isc_mem_get(mctx, filesize + 1);
fp = fopen(filename, "r");
if (fp == NULL || fread(filetext, 1, filesize, fp) < filesize) {
fprintf(stderr, "read(%s): %s\n", filename, strerror(errno));
exit(1);
@ -181,31 +186,30 @@ main(int argc, char *argv[]) {
fclose(fp);
filetext[filesize] = '\0';
dns_qp_t *qp = NULL;
dns_qp_create(mctx, &methods, NULL, &qp);
size_t wirebytes = 0;
size_t labels = 0;
size_t names = 0;
char *pos = filetext;
char *file_end = pos + filesize;
pos = filetext;
file_end = pos + filesize;
while (pos < file_end) {
char *domain = pos;
pos += strcspn(pos, "\r\n");
char *newline = pos;
pos += strspn(pos, "\r\n");
size_t len = newline - domain;
domain[len] = '\0';
void *pval = NULL;
uint32_t ival = 0;
dns_fixedname_t fixed;
dns_name_t *name = dns_fixedname_initname(&fixed);
isc_buffer_t buffer;
char *newline = NULL, *domain = pos;
size_t len;
pos += strcspn(pos, "\r\n");
newline = pos;
pos += strspn(pos, "\r\n");
len = newline - domain;
domain[len] = '\0';
isc_buffer_init(&buffer, domain, len);
isc_buffer_add(&buffer, len);
result = dns_name_fromtext(name, &buffer, dns_rootname, 0,
NULL);
void *pval = NULL;
uint32_t ival = 0;
if (result == ISC_R_SUCCESS) {
smallname_from_name(name, &pval, &ival);
result = dns_qp_insert(qp, pval, ival);
@ -224,17 +228,18 @@ main(int argc, char *argv[]) {
labels += name->labels;
names += 1;
}
dns_qp_compact(qp, true);
size_t smallbytes = wirebytes + labels + names * sizeof(isc_refcount_t);
dns_qp_memusage_t memusage = dns_qp_memusage(qp);
uint64_t compaction_us, recovery_us, rollback_us;
dns_qp_gctime(&compaction_us, &recovery_us, &rollback_us);
dns_qp_compact(qp, DNS_QPGC_ALL);
#define print_megabytes(label, value) \
printf("%6.2f MiB - " label "\n", (double)(value) / 1048576.0)
if (!dumptxt && !dumpdot) {
size_t smallbytes = wirebytes + labels +
names * sizeof(isc_refcount_t);
dns_qp_memusage_t memusage = dns_qp_memusage(qp);
uint64_t compaction_us, recovery_us, rollback_us;
dns_qp_gctime(&compaction_us, &recovery_us, &rollback_us);
printf("leaves %zu\n"
" nodes %zu\n"
" used %zu\n"
@ -264,10 +269,12 @@ main(int argc, char *argv[]) {
printf("%6zu - max key len\n", qp_test_maxkeylen(qp));
}
if (dumptxt)
if (dumptxt) {
qp_test_dumptrie(qp);
if (dumpdot)
}
if (dumpdot) {
qp_test_dumpdot(qp);
}
return (0);
}

View file

@ -89,12 +89,11 @@ static struct {
dns_qpkey_t key;
} *item;
static uint32_t
static void
item_refcount(void *ctx, void *pval, uint32_t ival) {
UNUSED(ctx);
UNUSED(pval);
UNUSED(ival);
return (1);
}
static size_t
@ -111,7 +110,7 @@ benchname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "bench", size);
}
const struct dns_qpmethods item_methods = {
const dns_qpmethods_t item_methods = {
item_refcount,
item_refcount,
item_makekey,
@ -128,13 +127,12 @@ init_items(isc_mem_t *mctx) {
void *pval = NULL;
uint32_t ival = ~0U;
dns_qp_t *qp = NULL;
size_t bytes = ITEM_COUNT * sizeof(*item);
uint64_t start;
start = isc_time_monotonic();
item = isc_mem_allocatex(mctx, bytes, ISC_MEM_ZERO);
uint64_t start = isc_time_monotonic();
/* ensure there are no duplicate names */
dns_qp_create(mctx, &item_methods, NULL, &qp);
for (size_t i = 0; i < ITEM_COUNT; i++) {
@ -224,6 +222,7 @@ first_loop(void *varg) {
static void
next_loop(struct thread_args *args, isc_nanosecs_t start) {
isc_nanosecs_t stop = isc_time_monotonic();
args->worked += stop - start;
args->stop = stop;
if (args->stop - args->start < RUNTIME) {
@ -238,6 +237,9 @@ next_loop(struct thread_args *args, isc_nanosecs_t start) {
static void
read_zipf(uv_idle_t *idle) {
struct thread_args *args = idle->data;
isc_nanosecs_t start;
void *pval = NULL;
uint32_t ival;
/* outside time because it is v slow */
uint32_t r[args->tx_per_loop][args->ops_per_tx];
@ -247,10 +249,7 @@ read_zipf(uv_idle_t *idle) {
}
}
isc_nanosecs_t start = isc_time_monotonic();
void *pval;
uint32_t ival;
start = isc_time_monotonic();
for (uint32_t tx = 0; tx < args->tx_per_loop; tx++) {
args->transactions++;
dns_qpread_t qp;
@ -277,7 +276,7 @@ static void
read_transactions(uv_idle_t *idle) {
struct thread_args *args = idle->data;
isc_nanosecs_t start = isc_time_monotonic();
void *pval;
void *pval = NULL;
uint32_t ival;
for (uint32_t tx = 0; tx < args->tx_per_loop; tx++) {
@ -323,8 +322,12 @@ mutate_transactions(uv_idle_t *idle) {
args->absent++;
}
}
/*
* We would normally use DNS_QPGC_MAYBE, but here we do the
* fragmented check ourself so we can count compactions
*/
if (dns_qp_memusage(qp).fragmented) {
dns_qp_compact(qp, false);
dns_qp_compact(qp, DNS_QPGC_NOW);
args->compactions++;
}
dns_qpmulti_commit(args->multi, &qp);
@ -375,13 +378,13 @@ static void
load_multi(struct bench_state *bctx) {
dns_qp_t *qp = NULL;
size_t count = 0;
uint64_t start = isc_time_monotonic();
uint64_t start;
dns_qpmulti_create(bctx->mctx, bctx->loopmgr, &item_methods, NULL,
&bctx->multi);
/* initial contents of the trie */
start = isc_time_monotonic();
dns_qpmulti_update(bctx->multi, &qp);
for (size_t i = 0; i < bctx->max_item; i++) {
if (isc_random_uniform(2) == 0) {
@ -392,7 +395,7 @@ load_multi(struct bench_state *bctx) {
item[i].present = true;
count++;
}
dns_qp_compact(qp, true);
dns_qp_compact(qp, DNS_QPGC_ALL);
dns_qpmulti_commit(bctx->multi, &qp);
bctx->load_time = isc_time_monotonic() - start;
@ -741,11 +744,18 @@ dispatch(struct bench_state *bctx) {
static void
collect(void *varg) {
TRACE("");
struct thread_args *args = varg;
struct bench_state *bctx = args->bctx;
struct thread_args *thread = bctx->thread;
struct {
uint64_t worked, txns, ops, compactions;
} stats[2] = {};
double load_time = bctx->load_time;
double elapsed = 0, mut_work, readers, read_work, elapsed_ms;
uint32_t nloops;
bool zipf;
TRACE("collect");
bctx->waiting--;
if (bctx->waiting > 0) {
@ -753,20 +763,15 @@ collect(void *varg) {
}
isc_barrier_destroy(&bctx->barrier);
struct {
uint64_t worked, txns, ops, compactions;
} stats[2] = {};
double load_time = bctx->load_time;
load_time = load_time > 0 ? load_time / (double)NS_PER_SEC : NAN;
double elapsed = 0;
bool zipf = bctx->mutate == 0 && bctx->readers == 0;
uint32_t nloops = zipf ? bctx->nloops : bctx->readers + bctx->mutate;
zipf = bctx->mutate == 0 && bctx->readers == 0;
nloops = zipf ? bctx->nloops : bctx->readers + bctx->mutate;
for (uint32_t t = 0; t < nloops; t++) {
struct thread_args *tp = &thread[t];
elapsed = ISC_MAX(elapsed, (tp->stop - tp->start));
bool mut = t < bctx->mutate;
stats[mut].worked += tp->worked;
stats[mut].txns += tp->transactions;
stats[mut].ops += tp->transactions * tp->ops_per_tx;
@ -779,7 +784,7 @@ collect(void *varg) {
printf("%7.2f\t", (double)bctx->qp_bytes / bctx->qp_items);
printf("%7u\t", bctx->max_item);
double mut_work = stats[1].worked / (double)US_PER_MS;
mut_work = stats[1].worked / (double)US_PER_MS;
printf("%7u\t", bctx->mutate);
printf("%7u\t", bctx->mut_tx_per_loop);
printf("%7u\t", bctx->mut_ops_per_tx);
@ -790,9 +795,9 @@ collect(void *varg) {
printf("%7.2f\t", stats[1].txns / mut_work);
printf("%7.2f\t", stats[1].ops / mut_work);
double readers = zipf ? bctx->nloops - bctx->mutate : bctx->readers;
double read_work = stats[0].worked / (double)US_PER_MS;
double elapsed_ms = elapsed / (double)US_PER_MS;
readers = zipf ? bctx->nloops - bctx->mutate : bctx->readers;
read_work = stats[0].worked / (double)US_PER_MS;
elapsed_ms = elapsed / (double)US_PER_MS;
printf("%7u\t", bctx->readers);
printf("%7u\t", bctx->read_tx_per_loop);
printf("%7u\t", bctx->read_ops_per_tx);
@ -813,10 +818,8 @@ startup(void *arg) {
isc_loop_t *loop = isc_loop_current(loopmgr);
isc_mem_t *mctx = isc_loop_getmctx(loop);
uint32_t nloops = isc_loopmgr_nloops(loopmgr);
size_t bytes = sizeof(struct bench_state) +
sizeof(struct thread_args) * nloops;
struct bench_state *bctx = isc_mem_getx(mctx, bytes, ISC_MEM_ZERO);
*bctx = (struct bench_state){
@ -881,9 +884,9 @@ int
main(void) {
isc_loopmgr_t *loopmgr = NULL;
isc_mem_t *mctx = NULL;
uint32_t nloops;
const char *env_workers = getenv("ISC_TASK_WORKERS");
if (env_workers != NULL) {
nloops = atoi(env_workers);
} else {

View file

@ -22,6 +22,9 @@
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/qsbr.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>
@ -29,6 +32,8 @@
#include <dns/name.h>
#include <dns/qp.h>
#include "qp_p.h"
#include <tests/dns.h>
#include <tests/qp.h>
@ -129,9 +134,230 @@ ISC_RUN_TEST_IMPL(qpkey_sort) {
}
}
#define ITER_ITEMS 100
static void
check_leaf(void *uctx, void *pval, uint32_t ival) {
uint32_t *items = uctx;
assert_in_range(ival, 1, ITER_ITEMS - 1);
assert_ptr_equal(items + ival, pval);
}
static size_t
qpiter_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival) {
check_leaf(uctx, pval, ival);
char str[8];
snprintf(str, sizeof(str), "%03u", ival);
size_t i = 0;
while (str[i] != '\0') {
key[i] = str[i] - '0' + SHIFT_BITMAP;
i++;
}
key[i++] = SHIFT_NOBYTE;
return (i);
}
static void
getname(void *uctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
UNUSED(uctx);
UNUSED(size);
}
const dns_qpmethods_t qpiter_methods = {
check_leaf,
check_leaf,
qpiter_makekey,
getname,
};
ISC_RUN_TEST_IMPL(qpiter) {
dns_qp_t *qp = NULL;
uint32_t item[ITER_ITEMS] = { 0 };
dns_qp_create(mctx, &qpiter_methods, item, &qp);
for (size_t tests = 0; tests < 1234; tests++) {
uint32_t ival = isc_random_uniform(ITER_ITEMS - 1) + 1;
void *pval = &item[ival];
item[ival] = ival;
/* randomly insert or remove */
dns_qpkey_t key;
size_t len = qpiter_makekey(key, item, pval, ival);
if (dns_qp_insert(qp, pval, ival) == ISC_R_EXISTS) {
dns_qp_deletekey(qp, key, len);
item[ival] = 0;
}
/* check that we see only valid items in the correct order */
uint32_t prev = 0;
dns_qpiter_t qpi;
dns_qpiter_init(qp, &qpi);
while (dns_qpiter_next(&qpi, &pval, &ival) == ISC_R_SUCCESS) {
assert_in_range(ival, prev + 1, ITER_ITEMS - 1);
assert_int_equal(ival, item[ival]);
assert_ptr_equal(pval, &item[ival]);
item[ival] = ~ival;
prev = ival;
}
/* ensure we saw every item */
for (ival = 0; ival < ITER_ITEMS; ival++) {
if (item[ival] != 0) {
assert_int_equal(item[ival], ~ival);
item[ival] = ival;
}
}
}
dns_qp_destroy(&qp);
}
static void
no_op(void *uctx, void *pval, uint32_t ival) {
UNUSED(uctx);
UNUSED(pval);
UNUSED(ival);
}
static size_t
qpkey_fromstring(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival) {
dns_fixedname_t fixed;
UNUSED(uctx);
UNUSED(ival);
if (*(char *)pval == '\0') {
return (0);
}
dns_test_namefromstring(pval, &fixed);
return (dns_qpkey_fromname(key, dns_fixedname_name(&fixed)));
}
const dns_qpmethods_t string_methods = {
no_op,
no_op,
qpkey_fromstring,
getname,
};
struct check_partialmatch {
const char *query;
dns_qpfind_t options;
isc_result_t result;
const char *found;
};
static void
check_partialmatch(dns_qp_t *qp, struct check_partialmatch check[]) {
for (int i = 0; check[i].query != NULL; i++) {
isc_result_t result;
dns_fixedname_t fixed;
dns_name_t *name = dns_fixedname_name(&fixed);
void *pval = NULL;
uint32_t ival;
#if 0
fprintf(stderr, "%s %u %s %s\n", check[i].query,
check[i].options, isc_result_totext(check[i].result),
check[i].found);
#endif
dns_test_namefromstring(check[i].query, &fixed);
result = dns_qp_findname_parent(qp, name, check[i].options,
&pval, &ival);
assert_int_equal(result, check[i].result);
if (check[i].found == NULL) {
assert_null(pval);
} else {
assert_string_equal(pval, check[i].found);
}
}
}
static void
insert_str(dns_qp_t *qp, const char *str) {
isc_result_t result;
uintptr_t pval = (uintptr_t)str;
INSIST((pval & 3) == 0);
result = dns_qp_insert(qp, (void *)pval, 0);
assert_int_equal(result, ISC_R_SUCCESS);
}
ISC_RUN_TEST_IMPL(partialmatch) {
isc_result_t result;
dns_qp_t *qp = NULL;
dns_qp_create(mctx, &string_methods, NULL, &qp);
/*
* Fixed size strings [16] should ensure leaf-compatible alignment.
*/
const char insert[][16] = {
"a.b.", "b.", "fo.bar.", "foo.bar.",
"fooo.bar.", "web.foo.bar.", ".", "",
};
int i = 0;
while (insert[i][0] != '.') {
insert_str(qp, insert[i++]);
}
static struct check_partialmatch check1[] = {
{ "a.b.", 0, ISC_R_SUCCESS, "a.b." },
{ "a.b.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "b." },
{ "b.c.", DNS_QPFIND_NOEXACT, ISC_R_NOTFOUND, NULL },
{ "bar.", 0, ISC_R_NOTFOUND, NULL },
{ "f.bar.", 0, ISC_R_NOTFOUND, NULL },
{ "foo.bar.", 0, ISC_R_SUCCESS, "foo.bar." },
{ "foo.bar.", DNS_QPFIND_NOEXACT, ISC_R_NOTFOUND, NULL },
{ "foooo.bar.", 0, ISC_R_NOTFOUND, NULL },
{ "w.foo.bar.", 0, DNS_R_PARTIALMATCH, "foo.bar." },
{ "www.foo.bar.", 0, DNS_R_PARTIALMATCH, "foo.bar." },
{ "web.foo.bar.", 0, ISC_R_SUCCESS, "web.foo.bar." },
{ "webby.foo.bar.", 0, DNS_R_PARTIALMATCH, "foo.bar." },
{ "my.web.foo.bar.", 0, DNS_R_PARTIALMATCH, "web.foo.bar." },
{ "web.foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH,
"foo.bar." },
{ "my.web.foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH,
"web.foo.bar." },
{ NULL, 0, 0, NULL },
};
check_partialmatch(qp, check1);
/* what if the trie contains the root? */
INSIST(insert[i][0] == '.');
insert_str(qp, insert[i++]);
static struct check_partialmatch check2[] = {
{ "b.c.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "." },
{ "bar.", 0, DNS_R_PARTIALMATCH, "." },
{ "foo.bar.", 0, ISC_R_SUCCESS, "foo.bar." },
{ "foo.bar.", DNS_QPFIND_NOEXACT, DNS_R_PARTIALMATCH, "." },
{ NULL, 0, 0, NULL },
};
check_partialmatch(qp, check2);
/* what if entries in the trie are relative to the zone apex? */
dns_qpkey_t rootkey = { SHIFT_NOBYTE };
result = dns_qp_deletekey(qp, rootkey, 1);
assert_int_equal(result, ISC_R_SUCCESS);
INSIST(insert[i][0] == '\0');
insert_str(qp, insert[i++]);
check_partialmatch(qp, (struct check_partialmatch[]){
{ "bar", 0, DNS_R_PARTIALMATCH, "" },
{ "bar.", 0, DNS_R_PARTIALMATCH, "" },
{ NULL, 0, 0, NULL },
});
dns_qp_destroy(&qp);
}
ISC_TEST_LIST_START
ISC_TEST_ENTRY(qpkey_name)
ISC_TEST_ENTRY(qpkey_sort)
ISC_TEST_ENTRY(qpiter)
ISC_TEST_ENTRY(partialmatch)
ISC_TEST_LIST_END
ISC_TEST_MAIN

View file

@ -104,19 +104,19 @@ static struct {
dns_qpkey_t ascii;
} item[ITEM_COUNT];
static uint32_t
static void
item_attach(void *ctx, void *pval, uint32_t ival) {
assert_null(ctx);
assert_ptr_equal(pval, &item[ival]);
return (item[ival].refcount++);
INSIST(ctx == NULL);
INSIST(pval == &item[ival]);
item[ival].refcount++;
}
static uint32_t
static void
item_detach(void *ctx, void *pval, uint32_t ival) {
assert_null(ctx);
assert_ptr_equal(pval, &item[ival]);
assert_int_not_equal(item[ival].refcount, 0);
return (item[ival].refcount--);
item[ival].refcount--;
}
static size_t
@ -144,7 +144,7 @@ testname(void *ctx, char *buf, size_t size) {
strlcpy(buf, "test", size);
}
const struct dns_qpmethods test_methods = {
const dns_qpmethods_t test_methods = {
item_attach,
item_detach,
item_makekey,

View file

@ -64,8 +64,8 @@ ISC_LOOP_TEST_IMPL(apply) {
assert_non_null(view->zonetable);
assert_int_equal(nzones, 0);
result = dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL,
count_zone, &nzones);
result = dns_zt_apply(view->zonetable, false, NULL, count_zone,
&nzones);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(nzones, 1);
@ -83,12 +83,10 @@ ISC_LOOP_TEST_IMPL(apply) {
}
static isc_result_t
load_done_last(dns_zt_t *zt, dns_zone_t *zone) {
load_done_last(void *uap) {
dns_zone_t *zone = uap;
isc_result_t result;
UNUSED(zt);
UNUSED(zone);
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
@ -110,29 +108,25 @@ load_done_last(dns_zt_t *zt, dns_zone_t *zone) {
}
static isc_result_t
load_done_new_only(dns_zt_t *zt, dns_zone_t *zone) {
load_done_new_only(void *uap) {
dns_zone_t *zone = uap;
isc_result_t result;
UNUSED(zt);
UNUSED(zone);
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
dns_db_detach(&db);
dns_zone_asyncload(zone, true, load_done_last, NULL);
dns_zone_asyncload(zone, true, load_done_last, zone);
return (ISC_R_SUCCESS);
}
static isc_result_t
load_done_first(dns_zt_t *zt, dns_zone_t *zone) {
atomic_bool *done = (atomic_bool *)zt;
load_done_first(void *uap) {
dns_zone_t *zone = uap;
isc_result_t result;
UNUSED(zone);
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
@ -146,7 +140,7 @@ load_done_first(dns_zt_t *zt, dns_zone_t *zone) {
fflush(zonefile);
fclose(zonefile);
dns_zone_asyncload(zone, true, load_done_new_only, &done);
dns_zone_asyncload(zone, true, load_done_new_only, zone);
return (ISC_R_SUCCESS);
}
@ -157,9 +151,6 @@ ISC_LOOP_TEST_IMPL(asyncload_zone) {
int n;
dns_zone_t *zone = NULL;
char buf[4096];
atomic_bool done;
atomic_init(&done, false);
result = dns_test_makezone("foo", &zone, NULL, true);
assert_int_equal(result, ISC_R_SUCCESS);
@ -172,7 +163,6 @@ ISC_LOOP_TEST_IMPL(asyncload_zone) {
assert_non_null(view->zonetable);
assert_false(dns__zone_loadpending(zone));
assert_false(atomic_load(&done));
zonefile = fopen("./zone.data", "wb");
assert_non_null(zonefile);
origfile = fopen(TESTS_DIR "/testdata/zt/zone1.db", "r+b");
@ -185,7 +175,7 @@ ISC_LOOP_TEST_IMPL(asyncload_zone) {
dns_zone_setfile(zone, "./zone.data", dns_masterformat_text,
&dns_master_style_default);
dns_zone_asyncload(zone, false, load_done_first, &done);
dns_zone_asyncload(zone, false, load_done_first, zone);
}
dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;

View file

@ -64,7 +64,7 @@ dns_test_makeview(const char *name, bool with_cache, dns_view_t **viewp) {
dns_view_t *view = NULL;
dns_cache_t *cache = NULL;
result = dns_view_create(mctx, dns_rdataclass_in, name, &view);
result = dns_view_create(mctx, loopmgr, dns_rdataclass_in, name, &view);
if (result != ISC_R_SUCCESS) {
return (result);
}