2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

chg: dev: Split the top level slabheader hierarchy and the individual slabheaders

Merge branch 'ondrej/split-dns_slabheader' into 'main'

See merge request isc-projects/bind9!10826
This commit is contained in:
Ondřej Surý 2025-08-18 13:16:14 +02:00
commit 68153104fa
6 changed files with 622 additions and 647 deletions

View File

@ -64,6 +64,18 @@ struct dns_slabheader_proof {
dns_rdatatype_t type; dns_rdatatype_t type;
}; };
typedef struct dns_slabtop dns_slabtop_t;
struct dns_slabtop {
dns_slabtop_t *next;
dns_slabheader_t *header;
dns_typepair_t typepair;
/*% Used for SIEVE-LRU (cache) and changed_list (zone) */
ISC_LINK(struct dns_slabtop) link;
/*% Used for SIEVE-LRU */
bool visited;
};
struct dns_slabheader { struct dns_slabheader {
_Atomic(uint16_t) attributes; _Atomic(uint16_t) attributes;
@ -101,10 +113,8 @@ struct dns_slabheader {
* both head and tail pointers, and is doubly linked. * both head and tail pointers, and is doubly linked.
*/ */
union { dns_slabtop_t *top;
struct dns_slabheader *next;
struct dns_slabheader *up;
};
/*%< /*%<
* If this is the top header for an rdataset, 'next' points * If this is the top header for an rdataset, 'next' points
* to the top header for the next rdataset (i.e., the next type). * to the top header for the next rdataset (i.e., the next type).
@ -127,17 +137,18 @@ struct dns_slabheader {
dns_gluelist_t *gluelist; dns_gluelist_t *gluelist;
/*% Used for SIEVE-LRU (cache) and changed_list (zone) */
ISC_LINK(struct dns_slabheader) link;
/*% Used for SIEVE-LRU */
bool visited;
/*% /*%
* Case vector. If the bit is set then the corresponding * Case vector. If the bit is set then the corresponding
* character in the owner name needs to be AND'd with 0x20, * character in the owner name needs to be AND'd with 0x20,
* rendering that character upper case. * rendering that character upper case.
*/ */
unsigned char upper[32]; unsigned char upper[32];
/*%
* Flexible member indicates the address of the raw data
* following this header.
*/
unsigned char raw[];
}; };
enum { enum {
@ -273,12 +284,6 @@ dns_rdataslab_equalx(dns_slabheader_t *header1, dns_slabheader_t *header2,
*\li true if the slabs are equal, #false otherwise. *\li true if the slabs are equal, #false otherwise.
*/ */
void *
dns_slabheader_raw(dns_slabheader_t *header);
/*%
* Returns the address of the raw memory following a dns_slabheader.
*/
void void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name); dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name);
/*%< /*%<
@ -295,14 +300,14 @@ void
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node); dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node);
/*%< /*%<
* Reset an rdataslab header 'h' so it can be used to store data in * Reset an rdataslab header 'h' so it can be used to store data in
* database 'db' and node 'node'. * database node 'node'.
*/ */
dns_slabheader_t * dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node); dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node);
/*%< /*%<
* Allocate memory for an rdataslab header and initialize it for use * Allocate memory for an rdataslab header and initialize it for use
* in database 'db'/node 'node'. * in database node 'node'.
*/ */
void void
@ -317,8 +322,15 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proof);
* Free all memory associated with a nonexistence proof. * Free all memory associated with a nonexistence proof.
*/ */
dns_slabheader_t * dns_slabtop_t *
dns_slabheader_top(dns_slabheader_t *header); dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair);
/*%< /*%<
* Return the top header for the type or the negtype * Allocate memory for an rdataslab top and initialize it for use
* with 'typepair' type and covers pair.
*/
void
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp);
/*%<
* Free all memory associated with '*slabtopp'.
*/ */

View File

@ -154,7 +154,6 @@ typedef uint8_t dns_secproto_t;
typedef struct dns_signature dns_signature_t; typedef struct dns_signature dns_signature_t;
typedef struct dns_skr dns_skr_t; typedef struct dns_skr dns_skr_t;
typedef struct dns_slabheader dns_slabheader_t; typedef struct dns_slabheader dns_slabheader_t;
typedef ISC_LIST(dns_slabheader_t) dns_slabheaderlist_t;
typedef struct dns_ssurule dns_ssurule_t; typedef struct dns_ssurule dns_ssurule_t;
typedef struct dns_ssutable dns_ssutable_t; typedef struct dns_ssutable dns_ssutable_t;
typedef struct dns_stats dns_stats_t; typedef struct dns_stats dns_stats_t;

View File

@ -156,7 +156,8 @@ struct qpcnode {
*/ */
isc_refcount_t references; isc_refcount_t references;
isc_refcount_t erefs; isc_refcount_t erefs;
void *data;
dns_slabtop_t *data;
/*% /*%
* NOTE: The 'dirty' flag is protected by the node lock, so * NOTE: The 'dirty' flag is protected by the node lock, so
@ -200,13 +201,13 @@ typedef struct qpcache_bucket {
isc_heap_t *heap; isc_heap_t *heap;
/* SIEVE-LRU cache cleaning state. */ /* SIEVE-LRU cache cleaning state. */
ISC_SIEVE(dns_slabheader_t) sieve; ISC_SIEVE(dns_slabtop_t) sieve;
/* Padding to prevent false sharing between locks. */ /* Padding to prevent false sharing between locks. */
uint8_t __padding[ISC_OS_CACHELINE_SIZE - uint8_t __padding[ISC_OS_CACHELINE_SIZE -
(sizeof(isc_queue_t) + sizeof(isc_rwlock_t) + (sizeof(isc_queue_t) + sizeof(isc_rwlock_t) +
sizeof(isc_heap_t *) + sizeof(isc_heap_t *) +
sizeof(ISC_SIEVE(dns_slabheader_t))) % sizeof(ISC_SIEVE(dns_slabtop_t))) %
ISC_OS_CACHELINE_SIZE]; ISC_OS_CACHELINE_SIZE];
} qpcache_bucket_t; } qpcache_bucket_t;
@ -381,7 +382,7 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = {
typedef struct qpc_rditer { typedef struct qpc_rditer {
dns_rdatasetiter_t common; dns_rdatasetiter_t common;
dns_slabheader_t *current; dns_slabtop_t *current;
} qpc_rditer_t; } qpc_rditer_t;
static void static void
@ -485,13 +486,15 @@ expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested,
size_t expired = 0; size_t expired = 0;
do { do {
dns_slabheader_t *header = dns_slabtop_t *top = ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve,
ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve, visited, link); visited, link);
if (header == NULL) { if (top == NULL) {
return; return;
} }
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link); ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, top, link);
dns_slabheader_t *header = top->header;
expired += rdataset_size(header); expired += rdataset_size(header);
@ -528,7 +531,7 @@ qpcache_miss(qpcache_t *qpdb, dns_slabheader_t *newheader,
tlocktypep DNS__DB_FLARG_PASS); tlocktypep DNS__DB_FLARG_PASS);
} }
ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader, link); ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader->top, link);
} }
static void static void
@ -536,7 +539,7 @@ qpcache_hit(qpcache_t *qpdb ISC_ATTR_UNUSED, dns_slabheader_t *header) {
/* /*
* On cache hit, we only mark the header as seen. * On cache hit, we only mark the header as seen.
*/ */
ISC_SIEVE_MARK(header, visited); ISC_SIEVE_MARK(header->top, visited);
} }
/* /*
@ -556,30 +559,44 @@ clean_stale_headers(dns_slabheader_t *top) {
static void static void
clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
dns_slabheader_t *current = NULL, *top_prev = NULL, *top_next = NULL; dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL;
/* /*
* Caller must be holding the node lock. * Caller must be holding the node lock.
*/ */
for (current = node->data; current != NULL; current = top_next) { for (top = node->data; top != NULL; top = top_next) {
top_next = current->next; top_next = top->next;
clean_stale_headers(current); clean_stale_headers(top->header);
/* /*
* If current is nonexistent, ancient, or stale and * If current header is nonexistent, ancient, or stale and
* we are not keeping stale, we can clean it up. * we are not keeping stale, we can clean it up.
*/ */
if (!EXISTS(current) || ANCIENT(current) || if (!EXISTS(top->header) || ANCIENT(top->header) ||
(STALE(current) && !KEEPSTALE(qpdb))) (STALE(top->header) && !KEEPSTALE(qpdb)))
{ {
if (top_prev != NULL) { dns_slabheader_destroy(&top->header);
top_prev->next = current->next;
} else {
node->data = current->next;
} }
dns_slabheader_destroy(&current);
/*
* If current slabtype is empty, we can also clean it up.
*/
if (top->header == NULL) {
if (top_prev != NULL) {
top_prev->next = top->next;
} else { } else {
top_prev = current; node->data = top->next;
}
if (ISC_LINK_LINKED(top, link)) {
ISC_SIEVE_UNLINK(
qpdb->buckets[node->locknum].sieve, top,
link);
}
dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
} else {
top_prev = top;
} }
} }
node->dirty = 0; node->dirty = 0;
@ -1055,7 +1072,7 @@ bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header,
rdataset->slab.db = (dns_db_t *)qpdb; rdataset->slab.db = (dns_db_t *)qpdb;
rdataset->slab.node = (dns_dbnode_t *)node; rdataset->slab.node = (dns_dbnode_t *)node;
rdataset->slab.raw = dns_slabheader_raw(header); rdataset->slab.raw = header->raw;
rdataset->slab.iter_pos = NULL; rdataset->slab.iter_pos = NULL;
rdataset->slab.iter_count = 0; rdataset->slab.iter_count = 0;
@ -1134,10 +1151,8 @@ setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep,
} }
static bool static bool
check_stale_header(dns_slabheader_t *header, qpc_search_t *search, check_stale_header(dns_slabheader_t *header, qpc_search_t *search) {
dns_slabheader_t **header_prev) {
if (ACTIVE(header, search->now)) { if (ACTIVE(header, search->now)) {
*header_prev = header;
return false; return false;
} }
@ -1153,7 +1168,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) && stale > search->now) if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) && stale > search->now)
{ {
mark(header, DNS_SLABHEADERATTR_STALE); mark(header, DNS_SLABHEADERATTR_STALE);
*header_prev = header;
/* /*
* If DNS_DBFIND_STALESTART is set then it means we * If DNS_DBFIND_STALESTART is set then it means we
* failed to resolve the name during recursion, in * failed to resolve the name during recursion, in
@ -1188,7 +1202,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
return (search->options & DNS_DBFIND_STALEOK) == 0; return (search->options & DNS_DBFIND_STALEOK) == 0;
} }
*header_prev = header;
return true; return true;
} }
@ -1262,8 +1275,7 @@ both_headers(dns_slabheader_t *header, dns_rdatatype_t type,
static isc_result_t static isc_result_t
check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) { check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
qpc_search_t *search = arg; qpc_search_t *search = arg;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_result_t result; isc_result_t result;
isc_rwlock_t *nlock = NULL; isc_rwlock_t *nlock = NULL;
@ -1277,13 +1289,12 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
/* /*
* Look for a DNAME or RRSIG DNAME rdataset. * Look for a DNAME or RRSIG DNAME rdataset.
*/ */
for (header = node->data; header != NULL; header = header_next) { for (top = node->data; top != NULL; top = top->next) {
header_next = header->next; if (check_stale_header(top->header, search)) {
if (check_stale_header(header, search, &header_prev)) {
continue; continue;
} }
if (both_headers(header, dns_rdatatype_dname, &found, if (both_headers(top->header, dns_rdatatype_dname, &found,
&foundsig)) &foundsig))
{ {
break; break;
@ -1328,8 +1339,7 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
qpdb = search->qpdb; qpdb = search->qpdb;
for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) {
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_rwlock_t *nlock = NULL; isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
@ -1342,14 +1352,12 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
/* /*
* Look for NS and RRSIG NS rdatasets. * Look for NS and RRSIG NS rdatasets.
*/ */
for (header = node->data; header != NULL; header = header_next) for (top = node->data; top != NULL; top = top->next) {
{ if (check_stale_header(top->header, search)) {
header_next = header->next;
if (check_stale_header(header, search, &header_prev)) {
continue; continue;
} }
if (both_headers(header, dns_rdatatype_ns, &found, if (both_headers(top->header, dns_rdatatype_ns, &found,
&foundsig)) &foundsig))
{ {
break; break;
@ -1407,8 +1415,7 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL; isc_rwlock_t *nlock = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_next = NULL, *header_prev = NULL;
/* /*
* Look for the node in the auxilary tree. * Look for the node in the auxilary tree.
@ -1449,13 +1456,13 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
nlock = &search->qpdb->buckets[node->locknum].lock; nlock = &search->qpdb->buckets[node->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype); NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) { for (top = node->data; top != NULL; top = top->next) {
header_next = header->next; if (check_stale_header(top->header, search)) {
if (check_stale_header(header, search, &header_prev)) {
continue; continue;
} }
if (both_headers(header, dns_rdatatype_nsec, &found, &foundsig)) if (both_headers(top->header, dns_rdatatype_nsec, &found,
&foundsig))
{ {
break; break;
} }
@ -1527,8 +1534,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
isc_rwlock_t *nlock = NULL; isc_rwlock_t *nlock = NULL;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none; isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found = NULL, *nsheader = NULL; dns_slabheader_t *found = NULL, *nsheader = NULL;
dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL; dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL;
dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL; dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL;
@ -1647,14 +1653,12 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
nsecsig = NULL; nsecsig = NULL;
cnamesig = NULL; cnamesig = NULL;
empty_node = true; empty_node = true;
header_prev = NULL; for (top = node->data; top != NULL; top = top->next) {
for (header = node->data; header != NULL; header = header_next) { if (check_stale_header(top->header, &search)) {
header_next = header->next;
if (check_stale_header(header, &search, &header_prev)) {
continue; continue;
} }
if (!EXISTS(header) || ANCIENT(header)) { if (!EXISTS(top->header) || ANCIENT(top->header)) {
continue; continue;
} }
@ -1664,18 +1668,18 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
*/ */
empty_node = false; empty_node = false;
if (header->noqname != NULL && if (top->header->noqname != NULL &&
header->trust == dns_trust_secure) top->header->trust == dns_trust_secure)
{ {
found_noqname = true; found_noqname = true;
} }
if (!NEGATIVE(header)) { if (!NEGATIVE(top->header)) {
all_negative = false; all_negative = false;
} }
bool match = false; bool match = false;
if (related_headers(header, typepair, sigpair, &found, if (related_headers(top->header, typepair, sigpair, &found,
&foundsig, &match) && &foundsig, &match) &&
!MISSING_ANSWER(found, options)) !MISSING_ANSWER(found, options))
{ {
@ -1694,7 +1698,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
continue; continue;
} }
if (NEGATIVE(header)) { if (NEGATIVE(top->header)) {
/* /*
* FIXME: As of now, we are not interested in * FIXME: As of now, we are not interested in
* the negative headers. This could be * the negative headers. This could be
@ -1706,13 +1710,13 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
continue; continue;
} }
switch (header->typepair) { switch (top->typepair) {
case dns_rdatatype_cname: case dns_rdatatype_cname:
if (!cname_ok) { if (!cname_ok) {
break; break;
} }
found = header; found = top->header;
if (cnamesig != NULL) { if (cnamesig != NULL) {
/* We already have CNAME signature */ /* We already have CNAME signature */
foundsig = cnamesig; foundsig = cnamesig;
@ -1727,28 +1731,28 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
break; break;
} }
cnamesig = header; cnamesig = top->header;
break; break;
case dns_rdatatype_ns: case dns_rdatatype_ns:
/* Remember the NS rdataset */ /* Remember the NS rdataset */
nsheader = header; nsheader = top->header;
break; break;
case DNS_SIGTYPEPAIR(dns_rdatatype_ns): case DNS_SIGTYPEPAIR(dns_rdatatype_ns):
/* ...and its signature */ /* ...and its signature */
nssig = header; nssig = top->header;
break; break;
case dns_rdatatype_nsec: case dns_rdatatype_nsec:
nsecheader = header; nsecheader = top->header;
break; break;
case DNS_SIGTYPEPAIR(dns_rdatatype_nsec): case DNS_SIGTYPEPAIR(dns_rdatatype_nsec):
nsecsig = header; nsecsig = top->header;
break; break;
default: default:
if (typepair == dns_typepair_any) { if (typepair == dns_typepair_any) {
/* QTYPE==ANY, so any anwers will do */ /* QTYPE==ANY, so any anwers will do */
found = header; found = top->header;
break; break;
} }
} }
@ -1909,19 +1913,17 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_name_t *foundname, dns_name_t *dcname, dns_name_t *foundname, dns_name_t *dcname,
isc_rwlocktype_t *tlocktype) { isc_rwlocktype_t *tlocktype) {
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock; isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock;
dns_slabheader_t *found = NULL, *foundsig = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL;
NODE_RDLOCK(nlock, &nlocktype); NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) { for (top = node->data; top != NULL; top = top->next) {
header_next = header->next; bool ns = top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
bool ns = header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) || top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns);
header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns); if (check_stale_header(top->header, search)) {
if (check_stale_header(header, search, &header_prev)) {
if (ns) { if (ns) {
/* /*
* We found a cached NS, but was either * We found a cached NS, but was either
@ -1936,7 +1938,9 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
continue; continue;
} }
if (both_headers(header, dns_rdatatype_ns, &found, &foundsig)) { if (both_headers(top->header, dns_rdatatype_ns, &found,
&foundsig))
{
break; break;
} }
} }
@ -2060,8 +2064,7 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdataset_t *sigrdataset DNS__DB_FLARG) { dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
qpcache_t *qpdb = (qpcache_t *)db; qpcache_t *qpdb = (qpcache_t *)db;
qpcnode_t *qpnode = (qpcnode_t *)node; qpcnode_t *qpnode = (qpcnode_t *)node;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
dns_slabheader_t *header_prev = NULL, *header_next = NULL;
dns_slabheader_t *found = NULL, *foundsig = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL;
dns_typepair_t typepair, sigpair; dns_typepair_t typepair, sigpair;
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
@ -2091,14 +2094,12 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
sigpair = !dns_rdatatype_issig(type) ? DNS_SIGTYPEPAIR(type) sigpair = !dns_rdatatype_issig(type) ? DNS_SIGTYPEPAIR(type)
: dns_typepair_none; : dns_typepair_none;
for (header = qpnode->data; header != NULL; header = header_next) { for (top = qpnode->data; top != NULL; top = top->next) {
header_next = header->next; if (check_stale_header(top->header, &search)) {
if (check_stale_header(header, &search, &header_prev)) {
continue; continue;
} }
if (related_headers(header, typepair, sigpair, &found, if (related_headers(top->header, typepair, sigpair, &found,
&foundsig, NULL)) &foundsig, NULL))
{ {
break; break;
@ -2487,8 +2488,8 @@ overmaxtype(qpcache_t *qpdb, uint32_t ntypes) {
} }
static bool static bool
prio_header(dns_slabheader_t *header) { prio_header(dns_slabtop_t *top) {
return prio_type(header->typepair); return prio_type(top->typepair);
} }
static void static void
@ -2538,13 +2539,12 @@ qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
} }
static isc_result_t static isc_result_t
add(qpcache_t *qpdb, qpcnode_t *qpnode, add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader,
unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now, unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now,
isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) { isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; dns_slabtop_t *top = NULL;
dns_slabtop_t *priotop = NULL, *expiretop = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL; dns_slabheader_t *header = NULL, *sigheader = NULL;
dns_slabheader_t *prioheader = NULL, *expireheader = NULL;
dns_trust_t trust; dns_trust_t trust;
uint32_t ntypes = 0; uint32_t ntypes = 0;
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair); dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
@ -2586,11 +2586,10 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* only rdataset that can be found at this * only rdataset that can be found at this
* node is the negative cache entry. * node is the negative cache entry.
*/ */
for (topheader = qpnode->data; for (top = qpnode->data; top != NULL;
topheader != NULL; top = top->next)
topheader = topheader->next)
{ {
mark_ancient(topheader); mark_ancient(top->header);
} }
goto find_header; goto find_header;
} }
@ -2598,11 +2597,9 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* Otherwise look for any RRSIGs of the given * Otherwise look for any RRSIGs of the given
* type so they can be marked ancient later. * type so they can be marked ancient later.
*/ */
for (topheader = qpnode->data; topheader != NULL; for (top = qpnode->data; top != NULL; top = top->next) {
topheader = topheader->next) if (top->typepair == sigpair) {
{ sigheader = top->header;
if (topheader->typepair == sigpair) {
sigheader = topheader;
break; break;
} }
} }
@ -2611,14 +2608,12 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* We're adding something that isn't a * We're adding something that isn't a
* negative cache entry. * negative cache entry.
*/ */
for (topheader = qpnode->data; topheader != NULL; for (top = qpnode->data; top != NULL; top = top->next) {
topheader = topheader->next)
{
/* /*
* Look for any existing negative cache * Look for any existing negative cache
* entries. * entries.
*/ */
if (!NEGATIVE(topheader)) { if (!NEGATIVE(top->header)) {
continue; continue;
} }
@ -2626,7 +2621,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* If we find a cached NXDOMAIN, don't * If we find a cached NXDOMAIN, don't
* cache anything else. * cache anything else.
*/ */
if (topheader->typepair == dns_typepair_any) { if (top->typepair == dns_typepair_any) {
break; break;
} }
@ -2635,28 +2630,27 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* for which we have a cached NODATA record. * for which we have a cached NODATA record.
*/ */
if (newheader->typepair == sigpair && if (newheader->typepair == sigpair &&
DNS_TYPEPAIR_TYPE(topheader->typepair) == DNS_TYPEPAIR_TYPE(top->typepair) == covers)
covers)
{ {
break; break;
} }
} }
if (topheader != NULL && EXISTS(topheader) && if (top != NULL && EXISTS(top->header) &&
ACTIVE(topheader, now)) ACTIVE(top->header, now))
{ {
/* /*
* Found one. * Found one.
*/ */
if (trust < topheader->trust) { if (trust < top->header->trust) {
/* /*
* The NXDOMAIN/NODATA(QTYPE=ANY) * The NXDOMAIN/NODATA(QTYPE=ANY)
* is more trusted. * is more trusted.
*/ */
if (addedrdataset != NULL) { if (addedrdataset != NULL) {
bindrdataset( bindrdataset(
qpdb, qpnode, topheader, qpdb, qpnode,
now, nlocktype, top->header, now,
tlocktype, nlocktype, tlocktype,
addedrdataset addedrdataset
DNS__DB_FLARG_PASS); DNS__DB_FLARG_PASS);
} }
@ -2666,36 +2660,33 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode,
* The new rdataset is better. Expire the * The new rdataset is better. Expire the
* ncache entry. * ncache entry.
*/ */
mark_ancient(topheader); mark_ancient(top->header);
topheader = NULL; top = NULL;
goto find_header; goto find_header;
} }
} }
} }
for (topheader = qpnode->data; topheader != NULL; for (top = qpnode->data; top != NULL; top = top->next) {
topheader = topheader->next) if (ACTIVE(top->header, now)) {
{
if (ACTIVE(topheader, now)) {
++ntypes; ++ntypes;
expireheader = topheader; expiretop = top;
} }
if (prio_header(topheader)) { if (prio_header(top)) {
prioheader = topheader; priotop = top;
} }
if (topheader->typepair == newheader->typepair) { if (top->typepair == newheader->typepair) {
break; break;
} }
topheader_prev = topheader;
} }
find_header: find_header:
/* /*
* If header isn't NULL, we've found the right type. * If top isn't NULL, we've found the right type.
*/ */
header = topheader; if (top != NULL) {
if (header != NULL) { header = top->header;
/* /*
* Deleting an already non-existent rdataset has no effect. * Deleting an already non-existent rdataset has no effect.
*/ */
@ -2730,12 +2721,12 @@ find_header:
* normally further down. * normally further down.
*/ */
if (ACTIVE(header, now) && if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) && EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust && header->trust >= newheader->trust &&
dns_rdataslab_equalx(header, newheader, dns_rdataslab_equalx(header, newheader,
qpdb->common.rdclass, qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(header->typepair))) DNS_TYPEPAIR_TYPE(top->typepair)))
{ {
/* /*
* Honour the new ttl if it is less than the * Honour the new ttl if it is less than the
@ -2773,7 +2764,7 @@ find_header:
* ensures the delegations that are withdrawn are honoured. * ensures the delegations that are withdrawn are honoured.
*/ */
if (ACTIVE(header, now) && if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) && EXISTS(header) && EXISTS(newheader) &&
header->trust <= newheader->trust) header->trust <= newheader->trust)
{ {
@ -2783,10 +2774,10 @@ find_header:
} }
if (ACTIVE(header, now) && if (ACTIVE(header, now) &&
(options & DNS_DBADD_PREFETCH) == 0 && (options & DNS_DBADD_PREFETCH) == 0 &&
(header->typepair == DNS_TYPEPAIR(dns_rdatatype_a) || (top->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) || top->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) || top->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) && top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
EXISTS(header) && EXISTS(newheader) && EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust && header->trust >= newheader->trust &&
dns_rdataslab_equal(header, newheader)) dns_rdataslab_equal(header, newheader))
@ -2821,17 +2812,16 @@ find_header:
return DNS_R_UNCHANGED; return DNS_R_UNCHANGED;
} }
top->header = newheader;
newheader->top = top;
newheader->down = header;
ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve, top,
link);
qpcache_miss(qpdb, newheader, &nlocktype, qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS); &tlocktype DNS__DB_FLARG_PASS);
if (topheader_prev != NULL) {
topheader_prev->next = newheader;
} else {
qpnode->data = newheader;
}
newheader->next = topheader->next;
newheader->down = topheader;
topheader->next = newheader;
mark_ancient(header); mark_ancient(header);
if (sigheader != NULL) { if (sigheader != NULL) {
mark_ancient(sigheader); mark_ancient(sigheader);
@ -2846,36 +2836,42 @@ find_header:
/* No rdatasets of the given type exist at the node. */ /* No rdatasets of the given type exist at the node. */
INSIST(newheader->down == NULL); INSIST(newheader->down == NULL);
dns_slabtop_t *newtop = dns_slabtop_new(
((dns_db_t *)qpdb)->mctx, newheader->typepair);
newtop->header = newheader;
newheader->top = newtop;
qpcache_miss(qpdb, newheader, &nlocktype, qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS); &tlocktype DNS__DB_FLARG_PASS);
if (prio_header(newheader)) {
if (prio_header(newtop)) {
/* This is a priority type, prepend it */ /* This is a priority type, prepend it */
newheader->next = qpnode->data; newtop->next = qpnode->data;
qpnode->data = newheader; qpnode->data = newtop;
} else if (prioheader != NULL) { } else if (priotop != NULL) {
/* Append after the priority headers */ /* Append after the priority headers */
newheader->next = prioheader->next; newtop->next = priotop->next;
prioheader->next = newheader; priotop->next = newtop;
} else { } else {
/* There were no priority headers */ /* There were no priority headers */
newheader->next = qpnode->data; newtop->next = qpnode->data;
qpnode->data = newheader; qpnode->data = newtop;
} }
if (overmaxtype(qpdb, ntypes)) { if (overmaxtype(qpdb, ntypes)) {
if (expireheader == NULL) { if (expiretop == NULL) {
expireheader = newheader; expiretop = newtop;
} }
if (NEGATIVE(newheader) && !prio_header(newheader)) { if (NEGATIVE(newheader) && !prio_header(newtop)) {
/* /*
* Add the new non-priority negative * Add the new non-priority negative
* header to the database only * header to the database only
* temporarily. * temporarily.
*/ */
expireheader = newheader; expiretop = newtop;
} }
mark_ancient(expireheader); mark_ancient(expiretop->header);
/* /*
* FIXME: In theory, we should mark the RRSIG * FIXME: In theory, we should mark the RRSIG
* and the header at the same time, but there is * and the header at the same time, but there is
@ -2917,8 +2913,8 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
noqname = isc_mem_get(mctx, sizeof(*noqname)); noqname = isc_mem_get(mctx, sizeof(*noqname));
*noqname = (dns_slabheader_proof_t){ *noqname = (dns_slabheader_proof_t){
.neg = dns_slabheader_raw((dns_slabheader_t *)r1.base), .neg = ((dns_slabheader_t *)r1.base)->raw,
.negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base), .negsig = ((dns_slabheader_t *)r2.base)->raw,
.type = neg.type, .type = neg.type,
.name = DNS_NAME_INITEMPTY, .name = DNS_NAME_INITEMPTY,
}; };
@ -2956,8 +2952,8 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
closest = isc_mem_get(mctx, sizeof(*closest)); closest = isc_mem_get(mctx, sizeof(*closest));
*closest = (dns_slabheader_proof_t){ *closest = (dns_slabheader_proof_t){
.neg = dns_slabheader_raw((dns_slabheader_t *)r1.base), .neg = ((dns_slabheader_t *)r1.base)->raw,
.negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base), .negsig = ((dns_slabheader_t *)r2.base)->raw,
.name = DNS_NAME_INITEMPTY, .name = DNS_NAME_INITEMPTY,
.type = neg.type, .type = neg.type,
}; };
@ -3105,7 +3101,7 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
qpnode->havensec = true; qpnode->havensec = true;
} }
result = add(qpdb, qpnode, name, newheader, options, addedrdataset, now, result = add(qpdb, qpnode, newheader, options, addedrdataset, now,
nlocktype, tlocktype DNS__DB_FLARG_PASS); nlocktype, tlocktype DNS__DB_FLARG_PASS);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
@ -3163,14 +3159,14 @@ qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
return ISC_R_NOTIMPLEMENTED; return ISC_R_NOTIMPLEMENTED;
} }
newheader = dns_slabheader_new(db, node); newheader = dns_slabheader_new(db->mctx, node);
newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers); newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers);
setttl(newheader, 0); setttl(newheader, 0);
atomic_init(&newheader->attributes, attributes); atomic_init(&newheader->attributes, attributes);
nlock = &qpdb->buckets[qpnode->locknum].lock; nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_WRLOCK(nlock, &nlocktype); NODE_WRLOCK(nlock, &nlocktype);
result = add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, NULL, 0, result = add(qpdb, qpnode, newheader, DNS_DBADD_FORCE, NULL, 0,
nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS); nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
dns_slabheader_destroy(&newheader); dns_slabheader_destroy(&newheader);
@ -3320,13 +3316,6 @@ iterator_active(qpcache_t *qpdb, qpc_rditer_t *iterator,
dns_slabheader_t *header) { dns_slabheader_t *header) {
dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb); dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb);
/*
* Is this a "this rdataset doesn't exist" record?
*/
if (!EXISTS(header)) {
return false;
}
/* /*
* If this header is still active then return it. * If this header is still active then return it.
*/ */
@ -3349,15 +3338,16 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype); NODE_RDLOCK(nlock, &nlocktype);
for (header = qpnode->data; header != NULL; header = header->next) { for (top = qpnode->data; top != NULL; top = top->next) {
if ((EXPIREDOK(iterator) && EXISTS(header)) || if (EXISTS(top->header) &&
iterator_active(qpdb, iterator, header)) (EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
{ {
break; break;
} }
@ -3365,9 +3355,9 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_UNLOCK(nlock, &nlocktype); NODE_UNLOCK(nlock, &nlocktype);
iterator->current = header; iterator->current = top;
if (header == NULL) { if (top == NULL) {
return ISC_R_NOMORE; return ISC_R_NOMORE;
} }
@ -3379,20 +3369,21 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
header = iterator->current; top = iterator->current;
if (header == NULL) { if (top == NULL) {
return ISC_R_NOMORE; return ISC_R_NOMORE;
} }
NODE_RDLOCK(nlock, &nlocktype); NODE_RDLOCK(nlock, &nlocktype);
for (header = header->next; header != NULL; header = header->next) { for (top = top->next; top != NULL; top = top->next) {
if ((EXPIREDOK(iterator) && EXISTS(header)) || if (EXISTS(top->header) &&
iterator_active(qpdb, iterator, header)) (EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
{ {
break; break;
} }
@ -3400,9 +3391,9 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_UNLOCK(nlock, &nlocktype); NODE_UNLOCK(nlock, &nlocktype);
iterator->current = header; iterator->current = top;
if (header == NULL) { if (top == NULL) {
return ISC_R_NOMORE; return ISC_R_NOMORE;
} }
@ -3415,16 +3406,16 @@ rdatasetiter_current(dns_rdatasetiter_t *it,
qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpc_rditer_t *iterator = (qpc_rditer_t *)it;
qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcache_t *qpdb = (qpcache_t *)(iterator->common.db);
qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
dns_slabheader_t *header = NULL; dns_slabtop_t *top = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
header = iterator->current; top = iterator->current;
REQUIRE(header != NULL); REQUIRE(top != NULL);
NODE_RDLOCK(nlock, &nlocktype); NODE_RDLOCK(nlock, &nlocktype);
bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype, bindrdataset(qpdb, qpnode, top->header, iterator->common.now, nlocktype,
isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS); isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype); NODE_UNLOCK(nlock, &nlocktype);
@ -3771,19 +3762,16 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
dns_slabheader_t *header = data; dns_slabheader_t *header = data;
qpcache_t *qpdb = HEADERNODE(header)->qpdb; qpcache_t *qpdb = HEADERNODE(header)->qpdb;
int idx = HEADERNODE(header)->locknum;
if (header->heap != NULL && header->heap_index != 0) { if (header->heap != NULL && header->heap_index != 0) {
isc_heap_delete(header->heap, header->heap_index); isc_heap_delete(header->heap, header->heap_index);
} }
/*
* This place is the only place where we actually need header->typepair.
*/
update_rrsetstats(qpdb->rrsetstats, header->typepair, update_rrsetstats(qpdb->rrsetstats, header->typepair,
atomic_load_acquire(&header->attributes), false); atomic_load_acquire(&header->attributes), false);
if (ISC_LINK_LINKED(header, link)) {
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link);
}
if (header->noqname != NULL) { if (header->noqname != NULL) {
dns_slabheader_freeproof(qpdb->common.mctx, &header->noqname); dns_slabheader_freeproof(qpdb->common.mctx, &header->noqname);
} }
@ -3866,24 +3854,29 @@ static dns_dbmethods_t qpdb_cachemethods = {
}; };
static void static void
qpcnode_destroy(qpcnode_t *data) { qpcnode_destroy(qpcnode_t *qpnode) {
dns_slabheader_t *current = NULL, *next = NULL; dns_slabtop_t *top = NULL, *top_next = NULL;
qpcache_t *qpdb = qpnode->qpdb;
for (current = data->data; current != NULL; current = next) { for (top = qpnode->data; top != NULL; top = top_next) {
dns_slabheader_t *down = current->down, *down_next = NULL; top_next = top->next;
next = current->next; dns_slabheader_t *down = NULL, *down_next = NULL;
for (down = top->header; down != NULL; down = down_next) {
for (down = current->down; down != NULL; down = down_next) {
down_next = down->down; down_next = down->down;
dns_slabheader_destroy(&down); dns_slabheader_destroy(&down);
} }
top->header = NULL;
dns_slabheader_destroy(&current); if (ISC_LINK_LINKED(top, link)) {
ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
top, link);
}
dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
} }
dns_name_free(&data->name, data->mctx); dns_name_free(&qpnode->name, qpnode->mctx);
isc_mem_putanddetach(&data->mctx, data, sizeof(qpcnode_t)); isc_mem_putanddetach(&qpnode->mctx, qpnode, sizeof(qpcnode_t));
} }
#ifdef DNS_DB_NODETRACE #ifdef DNS_DB_NODETRACE

File diff suppressed because it is too large Load Diff

View File

@ -34,47 +34,21 @@
#include "rdataslab_p.h" #include "rdataslab_p.h"
/* /*
* The rdataslab structure allows iteration to occur in both load order * The memory structure of an rdataslab is as follows:
* and DNSSEC order. The structure is as follows:
* *
* header (dns_slabheader_t) * header (dns_slabheader_t)
* record count (2 bytes) * record count (2 bytes)
* offset table (4 x record count bytes in load order)
* data records * data records
* data length (2 bytes) * data length (2 bytes)
* order (2 bytes) * order (2 bytes)
* meta data (1 byte for RRSIG's) * meta data (1 byte for RRSIG, 0 for all other types)
* data (data length bytes) * data (data length bytes)
* *
* A "raw" rdataslab is the same but without the header. * A "bare" rdataslab is everything after "header".
* *
* DNSSEC order traversal is performed by walking the data records. * When a slab is created, data records are sorted into DNSSEC order.
*
* The order is stored with record to allow for efficient reconstruction
* of the offset table following a merge or subtraction.
*
* The iterator methods in rbtdb support both load order and DNSSEC order
* iteration.
*
* WARNING:
* rbtdb.c directly interacts with the slab's raw structures. If the
* structure changes then rbtdb.c also needs to be updated to reflect
* the changes. See the areas tagged with "RDATASLAB".
*/ */
#define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); })
#define get_uint16(buffer) \
({ \
uint16_t __ret = peek_uint16(buffer); \
buffer += sizeof(uint16_t); \
__ret; \
})
#define put_uint16(buffer, val) \
({ \
*buffer++ = (val & 0xff00) >> 8; \
*buffer++ = (val & 0x00ff); \
})
static void static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
static isc_result_t static isc_result_t
@ -240,8 +214,8 @@ makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
* If an rdata is not a duplicate, accumulate the storage size * If an rdata is not a duplicate, accumulate the storage size
* required for the rdata. We do not store the class, type, etc, * required for the rdata. We do not store the class, type, etc,
* just the rdata, so our overhead is 2 bytes for the number of * just the rdata, so our overhead is 2 bytes for the number of
* records, and 8 for each rdata, (length(2), offset(4) and order(2)) * records, and 2 bytes for the length of each rdata, plus the
* and then the rdata itself. * rdata itself.
*/ */
for (i = 1; i < nalloc; i++) { for (i = 1; i < nalloc; i++) {
if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) { if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
@ -359,7 +333,6 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
.typepair = typepair, .typepair = typepair,
.trust = rdataset->trust, .trust = rdataset->trust,
.ttl = rdataset->ttl, .ttl = rdataset->ttl,
.link = ISC_LINK_INITIALIZER,
}; };
} }
@ -397,8 +370,8 @@ dns_rdataslab_count(dns_slabheader_t *header) {
/* /*
* Make the dns_rdata_t 'rdata' refer to the slab item * Make the dns_rdata_t 'rdata' refer to the slab item
* beginning at '*current', which is part of a slab of type * beginning at '*current' (which is part of a slab of type
* 'type' and class 'rdclass', and advance '*current' to * 'type' and class 'rdclass') and advance '*current' to
* point to the next item in the slab. * point to the next item in the slab.
*/ */
static void static void
@ -827,11 +800,6 @@ dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
return true; return true;
} }
void *
dns_slabheader_raw(dns_slabheader_t *header) {
return header + 1;
}
void void
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) { dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
REQUIRE(!CASESET(header)); REQUIRE(!CASESET(header));
@ -871,11 +839,9 @@ dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
void void
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) { dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
ISC_LINK_INIT(h, link);
h->heap_index = 0; h->heap_index = 0;
h->heap = NULL; h->heap = NULL;
h->node = node; h->node = node;
h->visited = false;
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);
@ -886,14 +852,13 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
} }
dns_slabheader_t * dns_slabheader_t *
dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) { dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) {
dns_slabheader_t *h = NULL; dns_slabheader_t *h = NULL;
h = isc_mem_get(db->mctx, sizeof(*h)); h = isc_mem_get(mctx, sizeof(*h));
*h = (dns_slabheader_t){ *h = (dns_slabheader_t){
.link = ISC_LINK_INITIALIZER, .node = node,
}; };
dns_slabheader_reset(h, node);
return h; return h;
} }
@ -943,23 +908,8 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) {
isc_mem_put(mctx, proof, sizeof(*proof)); isc_mem_put(mctx, proof, sizeof(*proof));
} }
dns_slabheader_t *
dns_slabheader_top(dns_slabheader_t *header) {
/*
* Find the start of the header chain for the next type
* by walking back up the list.
*/
while (header->up != NULL && header->up->typepair == header->typepair) {
header = header->up;
}
return header;
}
/* Fixed RRSet helper macros */ /* Fixed RRSet helper macros */
#define DNS_RDATASET_LENGTH 2;
static void static void
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
dns_dbnode_t *node = rdataset->slab.node; dns_dbnode_t *node = rdataset->slab.node;
@ -984,7 +934,7 @@ rdataset_first(dns_rdataset_t *rdataset) {
* *
* 'raw' points to the first record. * 'raw' points to the first record.
*/ */
rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH; rdataset->slab.iter_pos = raw + sizeof(uint16_t);
rdataset->slab.iter_count = count - 1; rdataset->slab.iter_count = count - 1;
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
@ -1005,7 +955,7 @@ rdataset_next(dns_rdataset_t *rdataset) {
unsigned char *raw = rdataset->slab.iter_pos; unsigned char *raw = rdataset->slab.iter_pos;
uint16_t length = peek_uint16(raw); uint16_t length = peek_uint16(raw);
raw += length; raw += length;
rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH; rdataset->slab.iter_pos = raw + sizeof(uint16_t);
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
@ -1024,9 +974,7 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
* Find the start of the record if not already in iter_pos * Find the start of the record if not already in iter_pos
* then skip the length and order fields. * then skip the length and order fields.
*/ */
length = peek_uint16(raw); length = get_uint16(raw);
raw += DNS_RDATASET_LENGTH;
if (rdataset->type == dns_rdatatype_rrsig) { if (rdataset->type == dns_rdatatype_rrsig) {
if (*raw & DNS_RDATASLAB_OFFLINE) { if (*raw & DNS_RDATASLAB_OFFLINE) {
@ -1075,7 +1023,12 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
const dns_slabheader_proof_t *noqname = rdataset->slab.noqname; const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
/* /*
* The _KEEPCASE attribute is set to prevent setownercase and * Normally, rdataset->slab.raw points to the data immediately
* following a dns_slabheader in memory. Here, though, it will
* point to a bare rdataslab, a pointer to which is stored in
* the dns_slabheader's `noqname` field.
*
* The 'keepcase' attribute is set to prevent setownercase and
* getownercase methods from affecting the case of NSEC/NSEC3 * getownercase methods from affecting the case of NSEC/NSEC3
* owner names. * owner names.
*/ */
@ -1128,9 +1081,14 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
const dns_slabheader_proof_t *closest = rdataset->slab.closest; const dns_slabheader_proof_t *closest = rdataset->slab.closest;
/* /*
* As mentioned above, rdataset->slab.raw usually refers the data * Normally, rdataset->slab.raw points to the data immediately
* following an dns_slabheader, but in this case it points to a bare * following a dns_slabheader in memory. Here, though, it will
* rdataslab belonging to the dns_slabheader's `closest` field. * point to a bare rdataslab, a pointer to which is stored in
* the dns_slabheader's `closest` field.
*
* The 'keepcase' attribute is set to prevent setownercase and
* getownercase methods from affecting the case of NSEC/NSEC3
* owner names.
*/ */
dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
*nsec = (dns_rdataset_t){ *nsec = (dns_rdataset_t){
@ -1260,3 +1218,22 @@ rdataset_equals(const dns_rdataset_t *rdataset1,
return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass, return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass,
rdataset2->type); rdataset2->type);
} }
dns_slabtop_t *
dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) {
dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top));
*top = (dns_slabtop_t){
.typepair = typepair,
.link = ISC_LINK_INITIALIZER,
};
return top;
}
void
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp) {
REQUIRE(topp != NULL && *topp != NULL);
dns_slabtop_t *top = *topp;
*topp = NULL;
isc_mem_put(mctx, top, sizeof(*top));
}

View File

@ -13,6 +13,8 @@
#pragma once #pragma once
#include <isc/endian.h>
#include <dns/rdataslab.h> #include <dns/rdataslab.h>
#define ANCIENT(header) \ #define ANCIENT(header) \
@ -57,3 +59,16 @@
#define ZEROTTL(header) \ #define ZEROTTL(header) \
((atomic_load_acquire(&(header)->attributes) & \ ((atomic_load_acquire(&(header)->attributes) & \
DNS_SLABHEADERATTR_ZEROTTL) != 0) DNS_SLABHEADERATTR_ZEROTTL) != 0)
#define peek_uint16(buffer) ISC_U8TO16_BE(buffer)
#define get_uint16(buffer) \
({ \
uint16_t __ret = peek_uint16(buffer); \
buffer += sizeof(uint16_t); \
__ret; \
})
#define put_uint16(buffer, val) \
{ \
ISC_U16TO8_BE(buffer, val); \
(buffer) += sizeof(uint16_t); \
}