mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 23:25:38 +00:00
Replace glue_cache hashtable with direct link in rdatasetheader
Instead of having a global hashtable with a global rwlock for the GLUE cache, move the glue_list directly into rdatasetheader and use Userspace-RCU to update the pointer when the glue_list is empty. Additionally, the cached glue_lists needs to be stored in the RBTDB version for early cleaning, otherwise the circular dependencies between nodes and glue_lists will prevent nodes to be ever cleaned up.
This commit is contained in:
@@ -231,7 +231,13 @@ AS_CASE([$with_liburcu],
|
|||||||
|
|
||||||
AC_MSG_RESULT([$RCU_FLAVOR])
|
AC_MSG_RESULT([$RCU_FLAVOR])
|
||||||
|
|
||||||
PKG_CHECK_MODULES([LIBURCU], [$RCU_FLAVOR liburcu-cds])
|
#
|
||||||
|
# liburcu << v0.13.0 didn't add -lurcu-common and some toolchains would
|
||||||
|
# not add it automatically - we need to add it explicitly in such case.
|
||||||
|
#
|
||||||
|
PKG_CHECK_MODULES([LIBURCU], [$RCU_FLAVOR >= 0.13.0 liburcu-cds >= 0.13.0], [],
|
||||||
|
[PKG_CHECK_MODULES([LIBURCU], [$RCU_FLAVOR liburcu-cds],
|
||||||
|
[LIBURCU_LIBS="$LIBURCU_LIBS -lurcu-common"])])
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED([RCU_FLAVOR], ["$RCU_FLAVOR"], [Chosen Userspace-RCU flavor])
|
AC_DEFINE_UNQUOTED([RCU_FLAVOR], ["$RCU_FLAVOR"], [Chosen Userspace-RCU flavor])
|
||||||
|
|
||||||
|
@@ -263,6 +263,7 @@ libdns_la_CPPFLAGS = \
|
|||||||
$(AM_CPPFLAGS) \
|
$(AM_CPPFLAGS) \
|
||||||
$(LIBDNS_CFLAGS) \
|
$(LIBDNS_CFLAGS) \
|
||||||
$(LIBISC_CFLAGS) \
|
$(LIBISC_CFLAGS) \
|
||||||
|
$(LIBURCU_CFLAGS) \
|
||||||
$(LIBUV_CFLAGS) \
|
$(LIBUV_CFLAGS) \
|
||||||
$(OPENSSL_CFLAGS)
|
$(OPENSSL_CFLAGS)
|
||||||
|
|
||||||
@@ -272,6 +273,7 @@ libdns_la_LDFLAGS = \
|
|||||||
|
|
||||||
libdns_la_LIBADD = \
|
libdns_la_LIBADD = \
|
||||||
$(LIBISC_LIBS) \
|
$(LIBISC_LIBS) \
|
||||||
|
$(LIBURCU_LIBS) \
|
||||||
$(LIBUV_LIBS) \
|
$(LIBUV_LIBS) \
|
||||||
$(OPENSSL_LIBS)
|
$(OPENSSL_LIBS)
|
||||||
|
|
||||||
|
484
lib/dns/rbtdb.c
484
lib/dns/rbtdb.c
@@ -24,6 +24,7 @@
|
|||||||
#include <isc/crc64.h>
|
#include <isc/crc64.h>
|
||||||
#include <isc/file.h>
|
#include <isc/file.h>
|
||||||
#include <isc/hash.h>
|
#include <isc/hash.h>
|
||||||
|
#include <isc/hashmap.h>
|
||||||
#include <isc/heap.h>
|
#include <isc/heap.h>
|
||||||
#include <isc/hex.h>
|
#include <isc/hex.h>
|
||||||
#include <isc/loop.h>
|
#include <isc/loop.h>
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
#include <isc/stdio.h>
|
#include <isc/stdio.h>
|
||||||
#include <isc/string.h>
|
#include <isc/string.h>
|
||||||
#include <isc/time.h>
|
#include <isc/time.h>
|
||||||
|
#include <isc/urcu.h>
|
||||||
#include <isc/util.h>
|
#include <isc/util.h>
|
||||||
|
|
||||||
#include <dns/callbacks.h>
|
#include <dns/callbacks.h>
|
||||||
@@ -222,6 +224,8 @@ typedef isc_rwlock_t treelock_t;
|
|||||||
*/
|
*/
|
||||||
#define RBTDB_VIRTUAL 300
|
#define RBTDB_VIRTUAL 300
|
||||||
|
|
||||||
|
typedef struct rbtdb_glue rbtdb_glue_t;
|
||||||
|
|
||||||
struct noqname {
|
struct noqname {
|
||||||
dns_name_t name;
|
dns_name_t name;
|
||||||
void *neg;
|
void *neg;
|
||||||
@@ -287,6 +291,10 @@ typedef struct rdatasetheader {
|
|||||||
* rendering that character upper case.
|
* rendering that character upper case.
|
||||||
*/
|
*/
|
||||||
unsigned char upper[32];
|
unsigned char upper[32];
|
||||||
|
|
||||||
|
rbtdb_glue_t *glue_list;
|
||||||
|
|
||||||
|
struct cds_wfs_node wfs_node;
|
||||||
} rdatasetheader_t;
|
} rdatasetheader_t;
|
||||||
|
|
||||||
typedef ISC_LIST(rdatasetheader_t) rdatasetheaderlist_t;
|
typedef ISC_LIST(rdatasetheader_t) rdatasetheaderlist_t;
|
||||||
@@ -430,14 +438,6 @@ typedef struct dns_rbtdb dns_rbtdb_t;
|
|||||||
/* Reason for expiring a record from cache */
|
/* Reason for expiring a record from cache */
|
||||||
typedef enum { expire_lru, expire_ttl, expire_flush } expire_t;
|
typedef enum { expire_lru, expire_ttl, expire_flush } expire_t;
|
||||||
|
|
||||||
typedef struct rbtdb_glue rbtdb_glue_t;
|
|
||||||
|
|
||||||
typedef struct rbtdb_glue_table_node {
|
|
||||||
struct rbtdb_glue_table_node *next;
|
|
||||||
dns_rbtnode_t *node;
|
|
||||||
rbtdb_glue_t *glue_list;
|
|
||||||
} rbtdb_glue_table_node_t;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
rdataset_ttl_fresh,
|
rdataset_ttl_fresh,
|
||||||
rdataset_ttl_stale,
|
rdataset_ttl_stale,
|
||||||
@@ -476,10 +476,7 @@ typedef struct rbtdb_version {
|
|||||||
uint64_t records;
|
uint64_t records;
|
||||||
uint64_t xfrsize;
|
uint64_t xfrsize;
|
||||||
|
|
||||||
isc_rwlock_t glue_rwlock;
|
struct cds_wfs_stack glue_stack;
|
||||||
size_t glue_table_bits;
|
|
||||||
size_t glue_table_nodecount;
|
|
||||||
rbtdb_glue_table_node_t **glue_table;
|
|
||||||
} rbtdb_version_t;
|
} rbtdb_version_t;
|
||||||
|
|
||||||
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
|
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
|
||||||
@@ -1040,12 +1037,13 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log) {
|
|||||||
|
|
||||||
if (rbtdb->current_version != NULL) {
|
if (rbtdb->current_version != NULL) {
|
||||||
isc_refcount_decrementz(&rbtdb->current_version->references);
|
isc_refcount_decrementz(&rbtdb->current_version->references);
|
||||||
UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
|
|
||||||
isc_rwlock_destroy(&rbtdb->current_version->glue_rwlock);
|
|
||||||
isc_refcount_destroy(&rbtdb->current_version->references);
|
isc_refcount_destroy(&rbtdb->current_version->references);
|
||||||
|
UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
|
||||||
|
cds_wfs_destroy(&rbtdb->current_version->glue_stack);
|
||||||
isc_rwlock_destroy(&rbtdb->current_version->rwlock);
|
isc_rwlock_destroy(&rbtdb->current_version->rwlock);
|
||||||
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
|
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
|
||||||
sizeof(rbtdb_version_t));
|
sizeof(*rbtdb->current_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1260,27 +1258,18 @@ currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
|
|||||||
static rbtdb_version_t *
|
static rbtdb_version_t *
|
||||||
allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
|
allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
|
||||||
unsigned int references, bool writer) {
|
unsigned int references, bool writer) {
|
||||||
rbtdb_version_t *version;
|
rbtdb_version_t *version = isc_mem_get(mctx, sizeof(*version));
|
||||||
size_t size;
|
*version = (rbtdb_version_t){
|
||||||
|
.serial = serial,
|
||||||
|
.writer = writer,
|
||||||
|
.changed_list = ISC_LIST_INITIALIZER,
|
||||||
|
.resigned_list = ISC_LIST_INITIALIZER,
|
||||||
|
.link = ISC_LINK_INITIALIZER,
|
||||||
|
};
|
||||||
|
|
||||||
version = isc_mem_get(mctx, sizeof(*version));
|
cds_wfs_init(&version->glue_stack);
|
||||||
version->serial = serial;
|
|
||||||
|
|
||||||
isc_refcount_init(&version->references, references);
|
isc_refcount_init(&version->references, references);
|
||||||
isc_rwlock_init(&version->glue_rwlock);
|
|
||||||
|
|
||||||
version->glue_table_bits = ISC_HASH_MIN_BITS;
|
|
||||||
version->glue_table_nodecount = 0U;
|
|
||||||
|
|
||||||
size = ISC_HASHSIZE(version->glue_table_bits) *
|
|
||||||
sizeof(version->glue_table[0]);
|
|
||||||
version->glue_table = isc_mem_getx(mctx, size, ISC_MEM_ZERO);
|
|
||||||
|
|
||||||
version->writer = writer;
|
|
||||||
version->commit_ok = false;
|
|
||||||
ISC_LIST_INIT(version->changed_list);
|
|
||||||
ISC_LIST_INIT(version->resigned_list);
|
|
||||||
ISC_LINK_INIT(version, link);
|
|
||||||
|
|
||||||
return (version);
|
return (version);
|
||||||
}
|
}
|
||||||
@@ -1402,9 +1391,12 @@ static void
|
|||||||
init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h) {
|
init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h) {
|
||||||
ISC_LINK_INIT(h, link);
|
ISC_LINK_INIT(h, link);
|
||||||
h->heap_index = 0;
|
h->heap_index = 0;
|
||||||
|
h->glue_list = NULL;
|
||||||
atomic_init(&h->attributes, 0);
|
atomic_init(&h->attributes, 0);
|
||||||
atomic_init(&h->last_refresh_fail_ts, 0);
|
atomic_init(&h->last_refresh_fail_ts, 0);
|
||||||
|
|
||||||
|
cds_wfs_node_init(&h->wfs_node);
|
||||||
|
|
||||||
STATIC_ASSERT((sizeof(h->attributes) == 2),
|
STATIC_ASSERT((sizeof(h->attributes) == 2),
|
||||||
"The .attributes field of rdatasetheader_t needs to be "
|
"The .attributes field of rdatasetheader_t needs to be "
|
||||||
"16-bit int type exactly.");
|
"16-bit int type exactly.");
|
||||||
@@ -1429,12 +1421,14 @@ update_newheader(rdatasetheader_t *newh, rdatasetheader_t *old) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_gluelist(rbtdb_glue_t *glue_list);
|
||||||
|
|
||||||
static rdatasetheader_t *
|
static rdatasetheader_t *
|
||||||
new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) {
|
new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) {
|
||||||
rdatasetheader_t *h;
|
rdatasetheader_t *h;
|
||||||
|
|
||||||
h = isc_mem_get(mctx, sizeof(*h));
|
h = isc_mem_get(mctx, sizeof(*h));
|
||||||
|
|
||||||
#if TRACE_HEADER
|
#if TRACE_HEADER
|
||||||
if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) {
|
if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) {
|
||||||
fprintf(stderr, "allocated header: %p\n", h);
|
fprintf(stderr, "allocated header: %p\n", h);
|
||||||
@@ -1447,39 +1441,42 @@ new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset) {
|
free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *header) {
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
update_rrsetstats(rbtdb, rdataset->type,
|
update_rrsetstats(rbtdb, header->type,
|
||||||
atomic_load_acquire(&rdataset->attributes), false);
|
atomic_load_acquire(&header->attributes), false);
|
||||||
|
|
||||||
idx = rdataset->node->locknum;
|
idx = header->node->locknum;
|
||||||
if (ISC_LINK_LINKED(rdataset, link)) {
|
if (ISC_LINK_LINKED(header, link)) {
|
||||||
INSIST(IS_CACHE(rbtdb));
|
INSIST(IS_CACHE(rbtdb));
|
||||||
ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, link);
|
ISC_LIST_UNLINK(rbtdb->rdatasets[idx], header, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rdataset->heap_index != 0) {
|
if (header->heap_index != 0) {
|
||||||
isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index);
|
isc_heap_delete(rbtdb->heaps[idx], header->heap_index);
|
||||||
}
|
}
|
||||||
rdataset->heap_index = 0;
|
header->heap_index = 0;
|
||||||
|
|
||||||
if (rdataset->noqname != NULL) {
|
if (header->noqname != NULL) {
|
||||||
free_noqname(mctx, &rdataset->noqname);
|
free_noqname(mctx, &header->noqname);
|
||||||
}
|
}
|
||||||
if (rdataset->closest != NULL) {
|
if (header->closest != NULL) {
|
||||||
free_noqname(mctx, &rdataset->closest);
|
free_noqname(mctx, &header->closest);
|
||||||
|
}
|
||||||
|
if (header->glue_list) {
|
||||||
|
free_gluelist(header->glue_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NONEXISTENT(rdataset)) {
|
if (NONEXISTENT(header)) {
|
||||||
size = sizeof(*rdataset);
|
size = sizeof(*header);
|
||||||
} else {
|
} else {
|
||||||
size = dns_rdataslab_size((unsigned char *)rdataset,
|
size = dns_rdataslab_size((unsigned char *)header,
|
||||||
sizeof(*rdataset));
|
sizeof(*header));
|
||||||
}
|
}
|
||||||
|
|
||||||
isc_mem_put(mctx, rdataset, size);
|
isc_mem_put(mctx, header, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2638,9 +2635,10 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
|
|||||||
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
|
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
|
||||||
|
|
||||||
if (cleanup_version != NULL) {
|
if (cleanup_version != NULL) {
|
||||||
|
isc_refcount_destroy(&cleanup_version->references);
|
||||||
INSIST(EMPTY(cleanup_version->changed_list));
|
INSIST(EMPTY(cleanup_version->changed_list));
|
||||||
free_gluetable(cleanup_version);
|
free_gluetable(cleanup_version);
|
||||||
isc_rwlock_destroy(&cleanup_version->glue_rwlock);
|
cds_wfs_destroy(&cleanup_version->glue_stack);
|
||||||
isc_rwlock_destroy(&cleanup_version->rwlock);
|
isc_rwlock_destroy(&cleanup_version->rwlock);
|
||||||
isc_mem_put(rbtdb->common.mctx, cleanup_version,
|
isc_mem_put(rbtdb->common.mctx, cleanup_version,
|
||||||
sizeof(*cleanup_version));
|
sizeof(*cleanup_version));
|
||||||
@@ -9525,6 +9523,9 @@ struct rbtdb_glue {
|
|||||||
dns_rdataset_t sigrdataset_a;
|
dns_rdataset_t sigrdataset_a;
|
||||||
dns_rdataset_t rdataset_aaaa;
|
dns_rdataset_t rdataset_aaaa;
|
||||||
dns_rdataset_t sigrdataset_aaaa;
|
dns_rdataset_t sigrdataset_aaaa;
|
||||||
|
|
||||||
|
isc_mem_t *mctx;
|
||||||
|
struct rcu_head rcu_head;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -9535,142 +9536,74 @@ typedef struct {
|
|||||||
} rbtdb_glue_additionaldata_ctx_t;
|
} rbtdb_glue_additionaldata_ctx_t;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_gluelist(rbtdb_glue_t *glue_list, dns_rbtdb_t *rbtdb) {
|
free_gluelist(rbtdb_glue_t *glue_list) {
|
||||||
rbtdb_glue_t *cur, *cur_next;
|
|
||||||
|
|
||||||
if (glue_list == (void *)-1) {
|
if (glue_list == (void *)-1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = glue_list;
|
rbtdb_glue_t *glue = glue_list;
|
||||||
while (cur != NULL) {
|
while (glue != NULL) {
|
||||||
cur_next = cur->next;
|
rbtdb_glue_t *next = glue->next;
|
||||||
|
|
||||||
if (dns_rdataset_isassociated(&cur->rdataset_a)) {
|
if (dns_rdataset_isassociated(&glue->rdataset_a)) {
|
||||||
dns_rdataset_disassociate(&cur->rdataset_a);
|
dns_rdataset_disassociate(&glue->rdataset_a);
|
||||||
}
|
}
|
||||||
if (dns_rdataset_isassociated(&cur->sigrdataset_a)) {
|
if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
|
||||||
dns_rdataset_disassociate(&cur->sigrdataset_a);
|
dns_rdataset_disassociate(&glue->sigrdataset_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dns_rdataset_isassociated(&cur->rdataset_aaaa)) {
|
if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
|
||||||
dns_rdataset_disassociate(&cur->rdataset_aaaa);
|
dns_rdataset_disassociate(&glue->rdataset_aaaa);
|
||||||
}
|
}
|
||||||
if (dns_rdataset_isassociated(&cur->sigrdataset_aaaa)) {
|
if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
|
||||||
dns_rdataset_disassociate(&cur->sigrdataset_aaaa);
|
dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_rdataset_invalidate(&cur->rdataset_a);
|
dns_rdataset_invalidate(&glue->rdataset_a);
|
||||||
dns_rdataset_invalidate(&cur->sigrdataset_a);
|
dns_rdataset_invalidate(&glue->sigrdataset_a);
|
||||||
dns_rdataset_invalidate(&cur->rdataset_aaaa);
|
dns_rdataset_invalidate(&glue->rdataset_aaaa);
|
||||||
dns_rdataset_invalidate(&cur->sigrdataset_aaaa);
|
dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
|
||||||
|
|
||||||
isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
|
isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue));
|
||||||
cur = cur_next;
|
|
||||||
|
glue = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rbtdb_glue_t *
|
||||||
|
new_gluelist(isc_mem_t *mctx, dns_name_t *name) {
|
||||||
|
rbtdb_glue_t *glue = isc_mem_getx(mctx, sizeof(*glue), ISC_MEM_ZERO);
|
||||||
|
dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
|
||||||
|
|
||||||
|
isc_mem_attach(mctx, &glue->mctx);
|
||||||
|
dns_name_copy(name, gluename);
|
||||||
|
|
||||||
|
return (glue);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_gluetable(rbtdb_version_t *version) {
|
free_gluelist_rcu(struct rcu_head *rcu_head) {
|
||||||
dns_rbtdb_t *rbtdb;
|
rbtdb_glue_t *glue = caa_container_of(rcu_head, rbtdb_glue_t, rcu_head);
|
||||||
size_t size, i;
|
__tsan_acquire(glue);
|
||||||
|
|
||||||
RWLOCK(&version->glue_rwlock, isc_rwlocktype_write);
|
free_gluelist(glue);
|
||||||
|
|
||||||
rbtdb = version->rbtdb;
|
|
||||||
|
|
||||||
for (i = 0; i < ISC_HASHSIZE(version->glue_table_bits); i++) {
|
|
||||||
rbtdb_glue_table_node_t *cur, *cur_next;
|
|
||||||
|
|
||||||
cur = version->glue_table[i];
|
|
||||||
while (cur != NULL) {
|
|
||||||
cur_next = cur->next;
|
|
||||||
/* isc_refcount_decrement(&cur->node->references); */
|
|
||||||
cur->node = NULL;
|
|
||||||
free_gluelist(cur->glue_list, rbtdb);
|
|
||||||
cur->glue_list = NULL;
|
|
||||||
isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
|
|
||||||
cur = cur_next;
|
|
||||||
}
|
|
||||||
version->glue_table[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = ISC_HASHSIZE(version->glue_table_bits) *
|
|
||||||
sizeof(*version->glue_table);
|
|
||||||
isc_mem_put(rbtdb->common.mctx, version->glue_table, size);
|
|
||||||
|
|
||||||
RWUNLOCK(&version->glue_rwlock, isc_rwlocktype_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
|
||||||
rehash_bits(rbtdb_version_t *version, size_t newcount) {
|
|
||||||
uint32_t oldbits = version->glue_table_bits;
|
|
||||||
uint32_t newbits = oldbits;
|
|
||||||
|
|
||||||
while (newcount >= ISC_HASHSIZE(newbits) &&
|
|
||||||
newbits <= ISC_HASH_MAX_BITS)
|
|
||||||
{
|
|
||||||
newbits += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (newbits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*%
|
|
||||||
* Write lock (version->glue_rwlock) must be held.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
rehash_gluetable(rbtdb_version_t *version) {
|
|
||||||
uint32_t oldbits, newbits;
|
|
||||||
size_t newsize, oldcount, i;
|
|
||||||
rbtdb_glue_table_node_t **oldtable;
|
|
||||||
|
|
||||||
oldbits = version->glue_table_bits;
|
|
||||||
oldcount = ISC_HASHSIZE(oldbits);
|
|
||||||
oldtable = version->glue_table;
|
|
||||||
|
|
||||||
newbits = rehash_bits(version, version->glue_table_nodecount);
|
|
||||||
newsize = ISC_HASHSIZE(newbits) * sizeof(version->glue_table[0]);
|
|
||||||
|
|
||||||
version->glue_table = isc_mem_getx(version->rbtdb->common.mctx, newsize,
|
|
||||||
ISC_MEM_ZERO);
|
|
||||||
version->glue_table_bits = newbits;
|
|
||||||
|
|
||||||
for (i = 0; i < oldcount; i++) {
|
|
||||||
rbtdb_glue_table_node_t *gluenode;
|
|
||||||
rbtdb_glue_table_node_t *nextgluenode;
|
|
||||||
for (gluenode = oldtable[i]; gluenode != NULL;
|
|
||||||
gluenode = nextgluenode)
|
|
||||||
{
|
|
||||||
uint32_t hash = isc_hash32(
|
|
||||||
&gluenode->node, sizeof(gluenode->node), true);
|
|
||||||
uint32_t idx = isc_hash_bits32(hash, newbits);
|
|
||||||
nextgluenode = gluenode->next;
|
|
||||||
gluenode->next = version->glue_table[idx];
|
|
||||||
version->glue_table[idx] = gluenode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isc_mem_put(version->rbtdb->common.mctx, oldtable,
|
|
||||||
oldcount * sizeof(*version->glue_table));
|
|
||||||
|
|
||||||
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ZONE,
|
|
||||||
ISC_LOG_DEBUG(3),
|
|
||||||
"rehash_gluetable(): "
|
|
||||||
"resized glue table from %zu to "
|
|
||||||
"%zu",
|
|
||||||
oldcount, newsize / sizeof(version->glue_table[0]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
maybe_rehash_gluetable(rbtdb_version_t *version) {
|
free_gluetable(rbtdb_version_t *rbtversion) {
|
||||||
size_t overcommit = ISC_HASHSIZE(version->glue_table_bits) *
|
struct cds_wfs_head *head = __cds_wfs_pop_all(&rbtversion->glue_stack);
|
||||||
ISC_HASH_OVERCOMMIT;
|
struct cds_wfs_node *node, *next;
|
||||||
if (version->glue_table_nodecount < overcommit) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rehash_gluetable(version);
|
rcu_read_lock();
|
||||||
|
cds_wfs_for_each_blocking_safe(head, node, next) {
|
||||||
|
rdatasetheader_t *header =
|
||||||
|
caa_container_of(node, rdatasetheader_t, wfs_node);
|
||||||
|
rbtdb_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL);
|
||||||
|
|
||||||
|
__tsan_release(glue);
|
||||||
|
call_rcu(&glue->rcu_head, free_gluelist_rcu);
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static isc_result_t
|
static isc_result_t
|
||||||
@@ -9687,7 +9620,6 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||||||
dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
|
dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
|
||||||
dns_rbtnode_t *node_aaaa = NULL;
|
dns_rbtnode_t *node_aaaa = NULL;
|
||||||
rbtdb_glue_t *glue = NULL;
|
rbtdb_glue_t *glue = NULL;
|
||||||
dns_name_t *gluename = NULL;
|
|
||||||
|
|
||||||
UNUSED(unused);
|
UNUSED(unused);
|
||||||
|
|
||||||
@@ -9711,10 +9643,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||||||
(dns_dbnode_t **)&node_a, name_a, &rdataset_a,
|
(dns_dbnode_t **)&node_a, name_a, &rdataset_a,
|
||||||
&sigrdataset_a DNS__DB_FLARG_PASS);
|
&sigrdataset_a DNS__DB_FLARG_PASS);
|
||||||
if (result == DNS_R_GLUE) {
|
if (result == DNS_R_GLUE) {
|
||||||
glue = isc_mem_get(ctx->rbtdb->common.mctx, sizeof(*glue));
|
glue = new_gluelist(ctx->rbtdb->common.mctx, name_a);
|
||||||
|
|
||||||
gluename = dns_fixedname_initname(&glue->fixedname);
|
|
||||||
dns_name_copy(name_a, gluename);
|
|
||||||
|
|
||||||
dns_rdataset_init(&glue->rdataset_a);
|
dns_rdataset_init(&glue->rdataset_a);
|
||||||
dns_rdataset_init(&glue->sigrdataset_a);
|
dns_rdataset_init(&glue->sigrdataset_a);
|
||||||
@@ -9735,11 +9664,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||||||
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
|
&sigrdataset_aaaa DNS__DB_FLARG_PASS);
|
||||||
if (result == DNS_R_GLUE) {
|
if (result == DNS_R_GLUE) {
|
||||||
if (glue == NULL) {
|
if (glue == NULL) {
|
||||||
glue = isc_mem_get(ctx->rbtdb->common.mctx,
|
glue = new_gluelist(ctx->rbtdb->common.mctx, name_aaaa);
|
||||||
sizeof(*glue));
|
|
||||||
|
|
||||||
gluename = dns_fixedname_initname(&glue->fixedname);
|
|
||||||
dns_name_copy(name_aaaa, gluename);
|
|
||||||
|
|
||||||
dns_rdataset_init(&glue->rdataset_a);
|
dns_rdataset_init(&glue->rdataset_a);
|
||||||
dns_rdataset_init(&glue->sigrdataset_a);
|
dns_rdataset_init(&glue->sigrdataset_a);
|
||||||
@@ -9811,83 +9736,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
|
|||||||
|
|
||||||
#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
|
#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
|
||||||
|
|
||||||
static isc_result_t
|
static void
|
||||||
rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
|
addglue_to_message(rbtdb_glue_t *ge, dns_message_t *msg) {
|
||||||
dns_message_t *msg) {
|
|
||||||
dns_rbtdb_t *rbtdb = rdataset->private1;
|
|
||||||
dns_rbtnode_t *node = rdataset->private2;
|
|
||||||
rbtdb_version_t *rbtversion = version;
|
|
||||||
dns_fixedname_t nodename;
|
|
||||||
uint32_t idx;
|
|
||||||
rbtdb_glue_table_node_t *cur;
|
|
||||||
bool found = false;
|
|
||||||
bool restarted = false;
|
|
||||||
rbtdb_glue_t *ge;
|
|
||||||
rbtdb_glue_additionaldata_ctx_t ctx;
|
|
||||||
uint64_t hash;
|
|
||||||
|
|
||||||
REQUIRE(rdataset->type == dns_rdatatype_ns);
|
|
||||||
REQUIRE(rbtdb == rbtversion->rbtdb);
|
|
||||||
REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The glue table cache that forms a part of the DB version
|
|
||||||
* structure is not explicitly bounded and there's no cache
|
|
||||||
* cleaning. The zone data size itself is an implicit bound.
|
|
||||||
*
|
|
||||||
* The key into the glue hashtable is the node pointer. This is
|
|
||||||
* because the glue hashtable is a property of the DB version,
|
|
||||||
* and the glue is keyed for the ownername/NS tuple. We don't
|
|
||||||
* bother with using an expensive dns_name_t comparison here as
|
|
||||||
* the node pointer is a fixed value that won't change for a DB
|
|
||||||
* version and can be compared directly.
|
|
||||||
*/
|
|
||||||
hash = isc_hash_function(&node, sizeof(node), true);
|
|
||||||
|
|
||||||
restart:
|
|
||||||
/*
|
|
||||||
* First, check if we have the additional entries already cached
|
|
||||||
* in the glue table.
|
|
||||||
*/
|
|
||||||
RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
|
|
||||||
|
|
||||||
idx = isc_hash_bits32(hash, rbtversion->glue_table_bits);
|
|
||||||
|
|
||||||
for (cur = rbtversion->glue_table[idx]; cur != NULL; cur = cur->next) {
|
|
||||||
if (cur->node == node) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cur == NULL) {
|
|
||||||
goto no_glue;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* We found a cached result. Add it to the message and
|
|
||||||
* return.
|
|
||||||
*/
|
|
||||||
found = true;
|
|
||||||
ge = cur->glue_list;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (void *) -1 is a special value that means no glue is
|
|
||||||
* present in the zone.
|
|
||||||
*/
|
|
||||||
if (ge == (void *)-1) {
|
|
||||||
if (!restarted && (rbtdb->gluecachestats != NULL)) {
|
|
||||||
isc_stats_increment(
|
|
||||||
rbtdb->gluecachestats,
|
|
||||||
dns_gluecachestatscounter_hits_absent);
|
|
||||||
}
|
|
||||||
goto no_glue;
|
|
||||||
} else {
|
|
||||||
if (!restarted && (rbtdb->gluecachestats != NULL)) {
|
|
||||||
isc_stats_increment(
|
|
||||||
rbtdb->gluecachestats,
|
|
||||||
dns_gluecachestatscounter_hits_present);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; ge != NULL; ge = ge->next) {
|
for (; ge != NULL; ge = ge->next) {
|
||||||
dns_name_t *name = NULL;
|
dns_name_t *name = NULL;
|
||||||
dns_rdataset_t *rdataset_a = NULL;
|
dns_rdataset_t *rdataset_a = NULL;
|
||||||
@@ -9962,86 +9812,90 @@ restart:
|
|||||||
name, link);
|
name, link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
no_glue:
|
|
||||||
RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
return (ISC_R_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restarted) {
|
static rbtdb_glue_t *
|
||||||
return (ISC_R_FAILURE);
|
rdataset_newglue(dns_rbtdb_t *rbtdb, rbtdb_version_t *rbtversion,
|
||||||
}
|
dns_rbtnode_t *node, dns_rdataset_t *rdataset) {
|
||||||
|
dns_fixedname_t nodename;
|
||||||
/*
|
rbtdb_glue_additionaldata_ctx_t ctx = {
|
||||||
* No cached glue was found in the table. Cache it and restart
|
.rbtdb = rbtdb,
|
||||||
* this function.
|
.rbtversion = rbtversion,
|
||||||
*
|
.nodename = dns_fixedname_initname(&nodename),
|
||||||
* Due to the gap between the read lock and the write lock, it's
|
};
|
||||||
* possible that we may cache a duplicate glue table entry, but
|
|
||||||
* we don't care.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ctx.glue_list = NULL;
|
|
||||||
ctx.rbtdb = rbtdb;
|
|
||||||
ctx.rbtversion = rbtversion;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the owner name of the NS RRset - it will be necessary for
|
* Get the owner name of the NS RRset - it will be necessary for
|
||||||
* identifying required glue in glue_nsdname_cb() (by determining which
|
* identifying required glue in glue_nsdname_cb() (by
|
||||||
* NS records in the delegation are in-bailiwick).
|
* determining which NS records in the delegation are
|
||||||
|
* in-bailiwick).
|
||||||
*/
|
*/
|
||||||
ctx.nodename = dns_fixedname_initname(&nodename);
|
|
||||||
nodefullname((dns_db_t *)rbtdb, node, ctx.nodename);
|
nodefullname((dns_db_t *)rbtdb, node, ctx.nodename);
|
||||||
|
|
||||||
RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
|
|
||||||
|
|
||||||
maybe_rehash_gluetable(rbtversion);
|
|
||||||
idx = isc_hash_bits32(hash, rbtversion->glue_table_bits);
|
|
||||||
|
|
||||||
(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
|
(void)dns_rdataset_additionaldata(rdataset, dns_rootname,
|
||||||
glue_nsdname_cb, &ctx);
|
glue_nsdname_cb, &ctx);
|
||||||
|
|
||||||
cur = isc_mem_get(rbtdb->common.mctx, sizeof(*cur));
|
return (ctx.glue_list);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
static isc_result_t
|
||||||
* XXXMUKS: it looks like the dns_dbversion is not destroyed
|
rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
|
||||||
* when named is terminated by a keyboard break. This doesn't
|
dns_message_t *msg) {
|
||||||
* cleanup the node reference and keeps the process dangling.
|
dns_rbtdb_t *rbtdb = rdataset->private1;
|
||||||
*/
|
dns_rbtnode_t *node = rdataset->private2;
|
||||||
/* isc_refcount_increment0(&node->references); */
|
unsigned char *raw = rdataset->private3; /* RDATASLAB */
|
||||||
cur->node = node;
|
rbtdb_version_t *rbtversion = version;
|
||||||
|
|
||||||
|
REQUIRE(rdataset->type == dns_rdatatype_ns);
|
||||||
|
REQUIRE(rbtdb == rbtversion->rbtdb);
|
||||||
|
REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
|
||||||
|
|
||||||
|
rdatasetheader_t *header =
|
||||||
|
(struct rdatasetheader *)(raw - sizeof(*header));
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
rbtdb_glue_t *glue = rcu_dereference(header->glue_list);
|
||||||
|
if (glue == NULL) {
|
||||||
|
/* No cached glue was found in the table. Get new glue. */
|
||||||
|
glue = rdataset_newglue(rbtdb, rbtversion, node, rdataset);
|
||||||
|
|
||||||
|
/* Cache the glue or (void *)-1 if no glue was found. */
|
||||||
|
rbtdb_glue_t *old_glue = rcu_cmpxchg_pointer(
|
||||||
|
&header->glue_list, NULL, (glue) ? glue : (void *)-1);
|
||||||
|
if (old_glue != NULL) {
|
||||||
|
/* Somebody else was faster */
|
||||||
|
free_gluelist(glue);
|
||||||
|
glue = old_glue;
|
||||||
|
} else if (glue != NULL) {
|
||||||
|
__tsan_release(glue);
|
||||||
|
cds_wfs_push(&rbtversion->glue_stack,
|
||||||
|
&header->wfs_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have a cached result. Add it to the message and return. */
|
||||||
|
|
||||||
if (ctx.glue_list == NULL) {
|
|
||||||
/*
|
|
||||||
* No glue was found. Cache it so.
|
|
||||||
*/
|
|
||||||
cur->glue_list = (void *)-1;
|
|
||||||
if (rbtdb->gluecachestats != NULL) {
|
if (rbtdb->gluecachestats != NULL) {
|
||||||
isc_stats_increment(
|
isc_stats_increment(
|
||||||
rbtdb->gluecachestats,
|
rbtdb->gluecachestats,
|
||||||
dns_gluecachestatscounter_inserts_absent);
|
(glue == (void *)-1)
|
||||||
}
|
? dns_gluecachestatscounter_hits_absent
|
||||||
} else {
|
: dns_gluecachestatscounter_hits_present);
|
||||||
cur->glue_list = ctx.glue_list;
|
|
||||||
if (rbtdb->gluecachestats != NULL) {
|
|
||||||
isc_stats_increment(
|
|
||||||
rbtdb->gluecachestats,
|
|
||||||
dns_gluecachestatscounter_inserts_present);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cur->next = rbtversion->glue_table[idx];
|
/*
|
||||||
rbtversion->glue_table[idx] = cur;
|
* (void *)-1 is a special value that means no glue is present in the
|
||||||
rbtversion->glue_table_nodecount++;
|
* zone.
|
||||||
|
*/
|
||||||
|
if (glue != (void *)-1) {
|
||||||
|
__tsan_acquire(glue);
|
||||||
|
addglue_to_message(glue, msg);
|
||||||
|
}
|
||||||
|
|
||||||
RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
|
rcu_read_unlock();
|
||||||
|
|
||||||
restarted = true;
|
return (ISC_R_SUCCESS);
|
||||||
goto restart;
|
|
||||||
|
|
||||||
/* UNREACHABLE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*%
|
/*%
|
||||||
|
@@ -30,9 +30,12 @@
|
|||||||
#include <urcu-bp.h>
|
#include <urcu-bp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <urcu-pointer.h>
|
||||||
|
|
||||||
#include <urcu/compiler.h>
|
#include <urcu/compiler.h>
|
||||||
#include <urcu/rculfhash.h>
|
#include <urcu/rculfhash.h>
|
||||||
#include <urcu/rculist.h>
|
#include <urcu/rculist.h>
|
||||||
|
#include <urcu/wfstack.h>
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
@@ -3,8 +3,8 @@ include $(top_srcdir)/Makefile.top
|
|||||||
AM_CPPFLAGS += \
|
AM_CPPFLAGS += \
|
||||||
$(LIBISC_CFLAGS) \
|
$(LIBISC_CFLAGS) \
|
||||||
$(LIBDNS_CFLAGS) \
|
$(LIBDNS_CFLAGS) \
|
||||||
$(LIBUV_CFLAGS) \
|
|
||||||
$(LIBURCU_CFLAGS) \
|
$(LIBURCU_CFLAGS) \
|
||||||
|
$(LIBUV_CFLAGS) \
|
||||||
$(KRB5_CFLAGS) \
|
$(KRB5_CFLAGS) \
|
||||||
-DSRCDIR=\"$(abs_srcdir)\" \
|
-DSRCDIR=\"$(abs_srcdir)\" \
|
||||||
-DBUILDDIR=\"$(abs_builddir)\" \
|
-DBUILDDIR=\"$(abs_builddir)\" \
|
||||||
@@ -13,8 +13,8 @@ AM_CPPFLAGS += \
|
|||||||
|
|
||||||
LDADD += \
|
LDADD += \
|
||||||
$(LIBISC_LIBS) \
|
$(LIBISC_LIBS) \
|
||||||
$(LIBUV_LIBS) \
|
|
||||||
$(LIBURCU_LIBS) \
|
$(LIBURCU_LIBS) \
|
||||||
|
$(LIBUV_LIBS) \
|
||||||
$(LIBDNS_LIBS)
|
$(LIBDNS_LIBS)
|
||||||
|
|
||||||
check_PROGRAMS = \
|
check_PROGRAMS = \
|
||||||
|
Reference in New Issue
Block a user