chg: nil: Reduce the code duplication around getting slabheaders from slabtop

There was a lot of duplicated code around getting the first header that
exists, is active, and matches the version header from the qpzonedb.
Move the duplicate code into a helper function and unify the same
approach for the qpcache too even though the code is much simpler there.
It should come handy when top->header is something more complicated than
a pointer to first slabheader.

Merge branch 'ondrej/refactor-getting-the-first-slabheader-from-slabtop' into 'main'

See merge request isc-projects/bind9!10953
This commit is contained in:
Ondřej Surý 2025-09-10 11:40:32 +02:00
commit f1568c1729
2 changed files with 283 additions and 288 deletions

View file

@ -472,6 +472,20 @@ rdataset_size(dns_slabheader_t *header) {
return sizeof(*header);
}
static dns_slabheader_t *
first_header(dns_slabtop_t *top) {
return top->header;
}
static dns_slabheader_t *
first_existing_header(dns_slabtop_t *top) {
dns_slabheader_t *header = first_header(top);
if (EXISTS(top->header)) {
return header;
}
return NULL;
}
static void
expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested,
isc_rwlocktype_t *nlocktypep,
@ -487,7 +501,7 @@ expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested,
ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, top, link);
dns_slabheader_t *header = top->header;
dns_slabheader_t *header = first_header(top);
expired += rdataset_size(header);
@ -540,14 +554,17 @@ qpcache_hit(qpcache_t *qpdb ISC_ATTR_UNUSED, dns_slabheader_t *header) {
*/
static void
clean_stale_headers(dns_slabheader_t *top) {
dns_slabheader_t *d = NULL, *down_next = NULL;
for (d = top->down; d != NULL; d = down_next) {
down_next = d->down;
dns_slabheader_destroy(&d);
clean_cache_headers(dns_slabtop_t *top) {
if (top->header == NULL) {
return;
}
top->down = NULL;
dns_slabheader_t *header = top->header, *header_down = NULL;
for (header = header->down; header != NULL; header = header_down) {
header_down = header->down;
dns_slabheader_destroy(&header);
}
top->header->down = NULL;
}
static void
@ -559,11 +576,11 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
*/
DNS_SLABTOP_FOREACH(top, node->data) {
clean_stale_headers(top->header);
clean_cache_headers(top);
/*
* If current header is nonexistent, ancient, or stale and
* we are not keeping stale, we can clean it up.
* If current top header is nonexistent, ancient, or stale
* and we are not keeping stale, we can clean it up too.
*/
if (!EXISTS(top->header) || ANCIENT(top->header) ||
(STALE(top->header) && !KEEPSTALE(qpdb)))
@ -572,7 +589,7 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
}
/*
* If current slabtype is empty, we can also clean it up.
* If current slabtop is empty, we can clean it up.
*/
if (top->header == NULL) {
if (top_prev != NULL) {
@ -1280,11 +1297,16 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
* Look for a DNAME or RRSIG DNAME rdataset.
*/
DNS_SLABTOP_FOREACH(top, node->data) {
if (check_stale_header(top->header, search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (both_headers(top->header, dns_rdatatype_dname, &found,
if (check_stale_header(header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_dname, &found,
&foundsig))
{
break;
@ -1342,11 +1364,16 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
* Look for NS and RRSIG NS rdatasets.
*/
DNS_SLABTOP_FOREACH(top, node->data) {
if (check_stale_header(top->header, search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (both_headers(top->header, dns_rdatatype_ns, &found,
if (check_stale_header(header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_ns, &found,
&foundsig))
{
break;
@ -1445,12 +1472,16 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
nlock = &search->qpdb->buckets[node->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype);
DNS_SLABTOP_FOREACH(top, node->data) {
if (check_stale_header(top->header, search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (both_headers(top->header, dns_rdatatype_nsec, &found,
&foundsig))
if (check_stale_header(header, search)) {
continue;
}
if (both_headers(header, dns_rdatatype_nsec, &found, &foundsig))
{
break;
}
@ -1645,11 +1676,16 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
cnamesig = NULL;
empty_node = true;
DNS_SLABTOP_FOREACH(top, node->data) {
if (check_stale_header(top->header, &search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (!EXISTS(top->header) || ANCIENT(top->header)) {
if (check_stale_header(header, &search)) {
continue;
}
if (!EXISTS(header) || ANCIENT(header)) {
continue;
}
@ -1659,18 +1695,18 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
*/
empty_node = false;
if (top->header->noqname != NULL &&
top->header->trust == dns_trust_secure)
if (header->noqname != NULL &&
header->trust == dns_trust_secure)
{
found_noqname = true;
}
if (!NEGATIVE(top->header)) {
if (!NEGATIVE(header)) {
all_negative = false;
}
bool match = false;
if (related_headers(top->header, typepair, sigpair, &found,
if (related_headers(header, typepair, sigpair, &found,
&foundsig, &match) &&
!MISSING_ANSWER(found, options))
{
@ -1689,7 +1725,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
continue;
}
if (NEGATIVE(top->header)) {
if (NEGATIVE(header)) {
/*
* FIXME: As of now, we are not interested in
* the negative headers. This could be
@ -1707,7 +1743,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
break;
}
found = top->header;
found = header;
if (cnamesig != NULL) {
/* We already have CNAME signature */
foundsig = cnamesig;
@ -1722,28 +1758,28 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
break;
}
cnamesig = top->header;
cnamesig = header;
break;
case dns_rdatatype_ns:
/* Remember the NS rdataset */
nsheader = top->header;
nsheader = header;
break;
case DNS_SIGTYPEPAIR(dns_rdatatype_ns):
/* ...and its signature */
nssig = top->header;
nssig = header;
break;
case dns_rdatatype_nsec:
nsecheader = top->header;
nsecheader = header;
break;
case DNS_SIGTYPEPAIR(dns_rdatatype_nsec):
nsecsig = top->header;
nsecsig = header;
break;
default:
if (typepair == dns_typepair_any) {
/* QTYPE==ANY, so any anwers will do */
found = top->header;
found = header;
break;
}
}
@ -1913,7 +1949,12 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
DNS_SLABTOP_FOREACH(top, node->data) {
bool ns = top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns);
if (check_stale_header(top->header, search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (check_stale_header(header, search)) {
if (ns) {
/*
* We found a cached NS, but was either
@ -1928,9 +1969,7 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep,
continue;
}
if (both_headers(top->header, dns_rdatatype_ns, &found,
&foundsig))
{
if (both_headers(header, dns_rdatatype_ns, &found, &foundsig)) {
break;
}
}
@ -2081,11 +2120,16 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
: dns_typepair_none;
DNS_SLABTOP_FOREACH(top, qpnode->data) {
if (check_stale_header(top->header, &search)) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (related_headers(top->header, typepair, sigpair, &found,
if (check_stale_header(header, &search)) {
continue;
}
if (related_headers(header, typepair, sigpair, &found,
&foundsig, NULL))
{
break;
@ -2546,12 +2590,17 @@ expire_ncache_entry(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabtop_t *top,
(sigpair != dns_rdatatype_none && newheader->typepair == sigpair &&
DNS_TYPEPAIR_TYPE(top->typepair) == covers))
{
if (trust < top->header->trust) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
return DNS_R_CONTINUE;
}
if (trust < header->trust) {
/*
* The NXDOMAIN/NODATA(QTYPE=ANY) is more trusted.
*/
qpcache_hit(qpdb, top->header);
bindrdataset(qpdb, qpnode, top->header, now, nlocktype,
qpcache_hit(qpdb, header);
bindrdataset(qpdb, qpnode, header, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
return DNS_R_UNCHANGED;
@ -2560,7 +2609,7 @@ expire_ncache_entry(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabtop_t *top,
/*
* The new rdataset is better. Expire the ncache entry.
*/
mark_ancient(top->header);
mark_ancient(header);
return DNS_R_CONTINUE;
}
@ -2572,7 +2621,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now,
isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_slabtop_t *priotop = NULL, *expiretop = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
dns_slabheader_t *oldheader = NULL, *oldsigheader = NULL;
dns_trust_t trust;
uint32_t ntypes = 0;
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
@ -2607,6 +2656,11 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
}
DNS_SLABTOP_FOREACH(top, qpnode->data) {
dns_slabheader_t *header = first_header(top);
if (header == NULL) {
continue;
}
if (EXISTS(newheader) && NEGATIVE(newheader) &&
rdtype == dns_rdatatype_any)
{
@ -2618,7 +2672,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
* rdataset that can be found at this node is the
* negative cache entry.
*/
mark_ancient(top->header);
mark_ancient(header);
}
if (EXISTS(newheader) && NEGATIVE(newheader) &&
@ -2632,13 +2686,12 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
if (DNS_TYPEPAIR_TYPE(top->typepair) ==
dns_rdatatype_rrsig)
{
mark_ancient(top->header);
mark_ancient(header);
}
}
if (EXISTS(newheader) && !NEGATIVE(newheader) &&
NEGATIVE(top->header) && EXISTS(top->header) &&
ACTIVE(top->header, now))
NEGATIVE(header) && EXISTS(header) && ACTIVE(header, now))
{
/*
* Look for existing active NXDOMAIN or negative
@ -2657,7 +2710,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
INSIST(result == DNS_R_CONTINUE);
}
if (ACTIVE(top->header, now)) {
if (ACTIVE(header, now)) {
++ntypes;
expiretop = top;
}
@ -2666,21 +2719,21 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
}
if (top->typepair == newheader->typepair) {
INSIST(header == NULL);
header = top->header;
INSIST(oldheader == NULL);
oldheader = top->header;
}
if (sigpair != dns_rdatatype_none && top->typepair == sigpair) {
INSIST(sigheader == NULL);
sigheader = top->header;
INSIST(oldsigheader == NULL);
oldsigheader = top->header;
}
}
if (header != NULL) {
if (oldheader != NULL) {
/*
* Deleting an already non-existent rdataset has no effect.
*/
if (!EXISTS(header) && !EXISTS(newheader)) {
if (!EXISTS(oldheader) && !EXISTS(newheader)) {
return DNS_R_UNCHANGED;
}
@ -2691,18 +2744,18 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
* data will supersede it below. Unclear what the best
* policy is here.
*/
if (trust < header->trust &&
(ACTIVE(header, now) || !EXISTS(header)))
if (trust < oldheader->trust &&
(ACTIVE(oldheader, now) || !EXISTS(oldheader)))
{
qpcache_hit(qpdb, header);
bindrdataset(qpdb, qpnode, header, now, nlocktype,
qpcache_hit(qpdb, oldheader);
bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
if (ACTIVE(header, now) &&
if (ACTIVE(oldheader, now) &&
(options & DNS_DBADD_EQUALOK) != 0 &&
dns_rdataslab_equalx(
header, newheader, qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(header->typepair)))
oldheader, newheader, qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(oldheader->typepair)))
{
/*
* Updated by caller to ISC_R_SUCCESS after
@ -2721,30 +2774,30 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
* to be done w.r.t stale data; it gets replaced normally
* further down.
*/
if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust &&
header->expire < newheader->expire &&
dns_rdataslab_equalx(header, newheader,
qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(header->typepair)))
if (ACTIVE(oldheader, now) &&
oldheader->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(oldheader) && EXISTS(newheader) &&
oldheader->trust >= newheader->trust &&
oldheader->expire < newheader->expire &&
dns_rdataslab_equalx(
oldheader, newheader, qpdb->common.rdclass,
DNS_TYPEPAIR_TYPE(oldheader->typepair)))
{
if (header->noqname == NULL &&
if (oldheader->noqname == NULL &&
newheader->noqname != NULL)
{
header->noqname = newheader->noqname;
oldheader->noqname = newheader->noqname;
newheader->noqname = NULL;
}
if (header->closest == NULL &&
if (oldheader->closest == NULL &&
newheader->closest != NULL)
{
header->closest = newheader->closest;
oldheader->closest = newheader->closest;
newheader->closest = NULL;
}
qpcache_hit(qpdb, header);
bindrdataset(qpdb, qpnode, header, now, nlocktype,
qpcache_hit(qpdb, oldheader);
bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
if ((options & DNS_DBADD_EQUALOK) != 0) {
@ -2762,46 +2815,47 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
* to be no more than the current NS RRset's TTL. This
* ensures the delegations that are withdrawn are honoured.
*/
if (ACTIVE(header, now) &&
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust <= newheader->trust)
if (ACTIVE(oldheader, now) &&
oldheader->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
EXISTS(oldheader) && EXISTS(newheader) &&
oldheader->trust <= newheader->trust)
{
if (newheader->expire > header->expire) {
if (ZEROTTL(header)) {
if (newheader->expire > oldheader->expire) {
if (ZEROTTL(oldheader)) {
DNS_SLABHEADER_SETATTR(
newheader,
DNS_SLABHEADERATTR_ZEROTTL);
}
newheader->expire = header->expire;
newheader->expire = oldheader->expire;
}
}
if (ACTIVE(header, now) &&
if (ACTIVE(oldheader, now) &&
(options & DNS_DBADD_PREFETCH) == 0 &&
(header->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
header->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
EXISTS(header) && EXISTS(newheader) &&
header->trust >= newheader->trust &&
header->expire < newheader->expire &&
dns_rdataslab_equal(header, newheader))
(oldheader->typepair == DNS_TYPEPAIR(dns_rdatatype_a) ||
oldheader->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) ||
oldheader->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) ||
oldheader->typepair ==
DNS_SIGTYPEPAIR(dns_rdatatype_ds)) &&
EXISTS(oldheader) && EXISTS(newheader) &&
oldheader->trust >= newheader->trust &&
oldheader->expire < newheader->expire &&
dns_rdataslab_equal(oldheader, newheader))
{
if (header->noqname == NULL &&
if (oldheader->noqname == NULL &&
newheader->noqname != NULL)
{
header->noqname = newheader->noqname;
oldheader->noqname = newheader->noqname;
newheader->noqname = NULL;
}
if (header->closest == NULL &&
if (oldheader->closest == NULL &&
newheader->closest != NULL)
{
header->closest = newheader->closest;
oldheader->closest = newheader->closest;
newheader->closest = NULL;
}
qpcache_hit(qpdb, header);
bindrdataset(qpdb, qpnode, header, now, nlocktype,
qpcache_hit(qpdb, oldheader);
bindrdataset(qpdb, qpnode, oldheader, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
if ((options & DNS_DBADD_EQUALOK) != 0) {
@ -2814,19 +2868,19 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
return DNS_R_UNCHANGED;
}
header->top->header = newheader;
newheader->top = header->top;
newheader->down = header;
oldheader->top->header = newheader;
newheader->top = oldheader->top;
newheader->down = oldheader;
ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
header->top, link);
oldheader->top, link);
qpcache_miss(qpdb, newheader, &nlocktype,
&tlocktype DNS__DB_FLARG_PASS);
mark_ancient(header);
if (sigheader != NULL) {
mark_ancient(sigheader);
mark_ancient(oldheader);
if (oldsigheader != NULL) {
mark_ancient(oldsigheader);
}
} else if (!EXISTS(newheader)) {
/*
@ -2873,7 +2927,11 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
expiretop = newtop;
}
mark_ancient(expiretop->header);
dns_slabheader_t *expireheader =
first_header(expiretop);
if (expireheader != NULL) {
mark_ancient(expiretop->header);
}
/*
* FIXME: In theory, we should mark the RRSIG
* and the header at the same time, but there is
@ -3343,9 +3401,10 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_RDLOCK(nlock, &nlocktype);
DNS_SLABTOP_FOREACH(top, qpnode->data) {
if (EXISTS(top->header) &&
(EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
dns_slabheader_t *header = first_existing_header(top);
if (EXPIREDOK(iterator) ||
(header != NULL && iterator_active(qpdb, iterator, header)))
{
iterator->current = top;
break;
@ -3379,9 +3438,10 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
NODE_RDLOCK(nlock, &nlocktype);
DNS_SLABTOP_FOREACH(top, next) {
if (EXISTS(top->header) &&
(EXPIREDOK(iterator) ||
iterator_active(qpdb, iterator, top->header)))
dns_slabheader_t *header = first_existing_header(top);
if (EXPIREDOK(iterator) ||
(header != NULL && iterator_active(qpdb, iterator, header)))
{
iterator->current = top;
break;
@ -3412,7 +3472,10 @@ rdatasetiter_current(dns_rdatasetiter_t *it,
NODE_RDLOCK(nlock, &nlocktype);
bindrdataset(qpdb, qpnode, top->header, iterator->common.now, nlocktype,
dns_slabheader_t *header = first_existing_header(top);
INSIST(header != NULL);
bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype,
isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);

View file

@ -57,6 +57,7 @@
#include <dns/rdatastruct.h>
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/types.h>
#include <dns/view.h>
#include <dns/zone.h>
@ -64,12 +65,13 @@
#include "qpzone_p.h"
#include "rdataslab_p.h"
#define CHECK(op) \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) \
goto failure; \
} while (0)
#define CHECK(op) \
{ \
result = (op); \
if (result != ISC_R_SUCCESS) { \
goto failure; \
} \
}
#define HEADERNODE(h) ((qpznode_t *)((h)->node))
@ -805,6 +807,51 @@ qpznode_acquire(qpznode_t *node DNS__DB_FLARG) {
qpznode_erefs_increment(node DNS__DB_FLARG_PASS);
}
static void
clean_multiple_headers(dns_slabtop_t *top) {
dns_slabheader_t *parent = top->header;
dns_slabheader_t *header = NULL, *header_down = NULL;
for (header = parent->down; header != NULL; header = header_down) {
header_down = header->down;
INSIST(header->serial <= parent->serial);
if (header->serial == parent->serial || IGNORE(header)) {
parent->down = header->down;
dns_slabheader_destroy(&header);
} else {
parent = header;
}
}
}
static void
check_top_header(dns_slabtop_t *top) {
dns_slabheader_t *header = top->header;
if (IGNORE(header)) {
top->header = header->down;
dns_slabheader_destroy(&header);
}
}
static bool
clean_multiple_versions(dns_slabtop_t *top, uint32_t least_serial) {
dns_slabheader_t *parent = top->header;
dns_slabheader_t *header = NULL, *header_down = NULL;
bool multiple = false;
for (header = parent->down; header != NULL; header = header_down) {
header_down = header->down;
if (header->serial < least_serial) {
parent->down = header->down;
dns_slabheader_destroy(&header);
} else {
multiple = true;
parent = header;
}
}
return multiple;
}
static void
clean_zone_node(qpznode_t *node, uint32_t least_serial) {
dns_slabtop_t *top_prev = NULL;
@ -823,59 +870,15 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
* with the same serial number, or that have the IGNORE
* attribute.
*/
dns_slabheader_t *dcurrent = NULL;
dns_slabheader_t *dcurrent_down = NULL, *dparent = NULL;
dparent = top->header;
for (dcurrent = dparent->down; dcurrent != NULL;
dcurrent = dcurrent_down)
{
dcurrent_down = dcurrent->down;
INSIST(dcurrent->serial <= dparent->serial);
if (dcurrent->serial == dparent->serial ||
IGNORE(dcurrent))
{
dparent->down = dcurrent_down;
dns_slabheader_destroy(&dcurrent);
} else {
dparent = dcurrent;
}
}
clean_multiple_headers(top);
/*
* We've now eliminated all IGNORE datasets with the possible
* exception of current, which we now check.
* All IGNORE datasets have been eliminated with the possible
* exception of the top header, which we now check.
*/
dcurrent = top->header;
if (IGNORE(dcurrent)) {
top->header = dcurrent->down;
dns_slabheader_destroy(&dcurrent);
}
check_top_header(top);
if (top->header == NULL) {
goto empty;
}
/*
* We now try to find the first down node less than the least
* serial, and if there are such rdatasets, delete it and any
* older versions.
*/
dparent = top->header;
for (dcurrent = dparent->down; dcurrent != NULL;
dcurrent = dcurrent_down)
{
dcurrent_down = dcurrent->down;
if (dcurrent->serial < least_serial) {
dparent->down = dcurrent_down;
dns_slabheader_destroy(&dcurrent);
} else {
dparent = dcurrent;
}
}
if (top->header == NULL) {
empty:
if (top_prev != NULL) {
top_prev->next = top->next;
} else {
@ -884,11 +887,17 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
dns_slabtop_destroy(node->mctx, &top);
} else {
/*
* Note. The serial number of 'current' might be less
* than least_serial too, but we cannot delete it
* Try to find the first down node less than the least
* serial, and if there are such rdatasets, delete it
* and any older versions.
*
* Note: The serial number of the top header might be
* less than least_serial too, but we cannot delete it
* because it is the most recent version.
*/
still_dirty = true;
still_dirty = clean_multiple_versions(top,
least_serial);
top_prev = top;
}
}
@ -1013,13 +1022,34 @@ bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header,
}
}
static dns_slabheader_t *
first_header(dns_slabtop_t *top, uint32_t serial) {
for (dns_slabheader_t *header = top->header; header != NULL;
header = header->down)
{
if (header->serial <= serial && !IGNORE(header)) {
return header;
}
}
return NULL;
}
static dns_slabheader_t *
first_existing_header(dns_slabtop_t *top, uint32_t serial) {
dns_slabheader_t *header = first_header(top, serial);
if (header != NULL && EXISTS(header)) {
return header;
}
return NULL;
}
static void
setnsec3parameters(dns_db_t *db, qpz_version_t *version) {
qpznode_t *node = NULL;
dns_rdata_nsec3param_t nsec3param;
isc_region_t region;
isc_result_t result;
dns_slabtop_t *top = NULL;
unsigned char *raw; /* RDATASLAB */
unsigned int count, length;
qpzonedb_t *qpdb = (qpzonedb_t *)db;
@ -1033,21 +1063,11 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) {
NODE_RDLOCK(nlock, &nlocktype);
top = node->data;
while (top != NULL && top->typepair != dns_rdatatype_nsec3param) {
top = top->next;
}
if (top != NULL) {
dns_slabheader_t *header = top->header;
while (header != NULL &&
(IGNORE(header) || header->serial > version->serial))
{
header = header->down;
}
if (header != NULL && EXISTS(header)) {
found = header;
DNS_SLABTOP_FOREACH(top, node->data) {
if (top->typepair != dns_rdatatype_nsec3param) {
continue;
}
found = first_existing_header(top, version->serial);
}
if (found != NULL) {
@ -1575,17 +1595,7 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
}
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
do {
if (header->serial <= serial && !IGNORE(header)) {
if (!EXISTS(header)) {
header = NULL;
}
break;
} else {
header = header->down;
}
} while (header != NULL);
dns_slabheader_t *header = first_existing_header(top, serial);
if (header != NULL) {
/*
* We have an active, extant rdataset. If it's a
@ -1694,7 +1704,6 @@ done:
static bool
cname_and_other(qpznode_t *node, uint32_t serial) {
bool cname = false, other = false;
dns_rdatatype_t rdtype;
/*
* Look for CNAME and "other data" rdatasets active in our version.
@ -1702,21 +1711,9 @@ cname_and_other(qpznode_t *node, uint32_t serial) {
* or RRSIG.
*/
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
rdtype = DNS_TYPEPAIR_TYPE(top->typepair);
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(top->typepair);
if (rdtype == dns_rdatatype_cname) {
do {
if (header->serial <= serial && !IGNORE(header))
{
if (!EXISTS(header)) {
header = NULL;
}
break;
}
header = header->down;
} while (header != NULL);
if (header != NULL) {
if (first_existing_header(top, serial) != NULL) {
cname = true;
}
} else if (rdtype != dns_rdatatype_key &&
@ -1724,17 +1721,7 @@ cname_and_other(qpznode_t *node, uint32_t serial) {
rdtype != dns_rdatatype_nsec &&
rdtype != dns_rdatatype_rrsig)
{
do {
if (header->serial <= serial && !IGNORE(header))
{
if (!EXISTS(header)) {
header = NULL;
}
break;
}
header = header->down;
} while (header != NULL);
if (header != NULL) {
if (first_existing_header(top, serial) != NULL) {
if (!prio_type(rdtype)) {
/*
* CNAME is in the priority list, so if
@ -2663,17 +2650,7 @@ step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction,
NODE_RDLOCK(nlock, &nlocktype);
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
while (header != NULL &&
(IGNORE(header) ||
header->serial > search->serial))
{
header = header->down;
}
if (header != NULL && EXISTS(header)) {
found = header;
break;
}
found = first_existing_header(top, search->serial);
}
NODE_UNLOCK(nlock, &nlocktype);
if (found != NULL) {
@ -3043,22 +3020,11 @@ again:
NODE_RDLOCK(nlock, &nlocktype);
empty_node = true;
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
/*
* Look for an active, extant NSEC or RRSIG NSEC.
*/
do {
if (header->serial <= search->serial &&
!IGNORE(header))
{
if (!EXISTS(header)) {
header = NULL;
}
break;
} else {
header = header->down;
}
} while (header != NULL);
dns_slabheader_t *header =
first_existing_header(top, search->serial);
if (header != NULL) {
/*
* We now know that there is at least one
@ -3186,23 +3152,12 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
* Look for an NS or DNAME rdataset active in our version.
*/
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname))
{
do {
if (header->serial <= search->serial &&
!IGNORE(header))
{
if (!EXISTS(header)) {
header = NULL;
}
break;
} else {
header = header->down;
}
} while (header != NULL);
dns_slabheader_t *header =
first_existing_header(top, search->serial);
if (header != NULL) {
if (top->typepair ==
DNS_TYPEPAIR(dns_rdatatype_dname))
@ -3516,21 +3471,11 @@ found:
sigpair = DNS_SIGTYPEPAIR(type);
empty_node = true;
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
/*
* Look for an active, extant rdataset.
*/
do {
if (header->serial <= search.serial && !IGNORE(header))
{
if (!EXISTS(header)) {
header = NULL;
}
break;
} else {
header = header->down;
}
} while (header != NULL);
dns_slabheader_t *header = first_existing_header(top,
search.serial);
if (header != NULL) {
/*
* We now know that there is at least one active
@ -4030,16 +3975,10 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
NODE_RDLOCK(nlock, &nlocktype);
DNS_SLABTOP_FOREACH(top, node->data) {
dns_slabheader_t *header = top->header;
while (header != NULL &&
(IGNORE(header) || header->serial > version->serial))
{
header = header->down;
}
qrditer->current = first_existing_header(top, version->serial);
if (header != NULL && EXISTS(header)) {
if (qrditer->current != NULL) {
qrditer->currenttop = top;
qrditer->current = header;
break;
}
}
@ -4075,16 +4014,9 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
* Find the start of the header chain for the next type.
*/
DNS_SLABTOP_FOREACH(top, next) {
dns_slabheader_t *header = top->header;
while (header != NULL &&
(IGNORE(header) || header->serial > version->serial))
{
header = header->down;
}
if (header != NULL && EXISTS(header)) {
qrditer->current = first_existing_header(top, version->serial);
if (qrditer->current != NULL) {
qrditer->currenttop = top;
qrditer->current = header;
break;
}
}