2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 21:17:54 +00:00

Split the top level slab header hierarchy and the headers

The code that combines the top-level hierarchy (per-typepair) and
individual slab headers (per-version) saves a little bit of memory, but
makes the code convoluted, hard to read and hard to modify.  Change the
top level hierarchy to be of different type with individual slabheaders
"hanging" from the per-typepair dns_slabtop_t structure.

This change makes the future enhancements (changing the top level data
structure for faster lookups; coupling type + sig(type) into single
slabtop) much easier.
This commit is contained in:
Ondřej Surý 2025-08-05 18:05:52 +02:00
parent 2f81952658
commit f4d8841f0d
No known key found for this signature in database
GPG Key ID: 2820F37E873DEA41
4 changed files with 513 additions and 550 deletions

View File

@ -64,6 +64,13 @@ 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;
};
struct dns_slabheader { struct dns_slabheader {
_Atomic(uint16_t) attributes; _Atomic(uint16_t) attributes;
@ -101,10 +108,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).
@ -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

@ -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
@ -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
@ -556,30 +557,38 @@ 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;
}
dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
} else {
top_prev = top;
} }
} }
node->dirty = 0; node->dirty = 0;
@ -1134,10 +1143,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 +1160,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 +1194,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 +1267,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 +1281,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 +1331,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 +1344,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 +1407,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 +1448,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 +1526,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 +1645,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 +1660,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 +1690,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 +1702,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 +1723,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 +1905,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 +1930,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 +2056,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 +2086,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 +2480,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 +2531,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 +2578,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 +2589,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 +2600,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 +2613,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 +2622,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 +2652,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 +2713,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 +2756,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 +2766,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))
@ -2824,14 +2807,10 @@ find_header:
qpcache_miss(qpdb, newheader, &nlocktype, qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS); &tlocktype DNS__DB_FLARG_PASS);
if (topheader_prev != NULL) { top->header = newheader;
topheader_prev->next = newheader; newheader->top = top;
} else { newheader->down = header;
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 +2825,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);
qpcache_miss(qpdb, newheader, &nlocktype, qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS); &tlocktype DNS__DB_FLARG_PASS);
if (prio_header(newheader)) {
newtop->header = newheader;
newheader->top = newtop;
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
@ -3105,7 +3090,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) {
@ -3170,7 +3155,7 @@ qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
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);
@ -3349,15 +3334,15 @@ 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 ((EXPIREDOK(iterator) && EXISTS(top->header)) ||
iterator_active(qpdb, iterator, header)) iterator_active(qpdb, iterator, top->header))
{ {
break; break;
} }
@ -3365,9 +3350,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 +3364,20 @@ 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 ((EXPIREDOK(iterator) && EXISTS(top->header)) ||
iterator_active(qpdb, iterator, header)) iterator_active(qpdb, iterator, top->header))
{ {
break; break;
} }
@ -3400,9 +3385,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 +3400,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);
@ -3770,13 +3755,15 @@ static void
qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { 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; 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);
@ -3866,24 +3853,25 @@ 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;
dns_db_t *db = (dns_db_t *)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); dns_slabtop_destroy(db->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,32 +34,19 @@
#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 peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); })
@ -240,8 +227,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) {
@ -397,8 +384,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
@ -943,23 +930,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 +956,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 +977,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 +996,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 +1045,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 +1103,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 +1240,21 @@ 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,
};
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));
}