2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Refactoring in qpcache.c:add()

There were several consequtive foreach loops when adding new entry into
the cache.  Merge the multiple foreach loops into a single pass loop
with some effort and a lot of comments.
This commit is contained in:
Ondřej Surý
2025-08-27 06:58:39 +02:00
parent e3c0a2a0fd
commit 7b7901494d

View File

@@ -2533,6 +2533,48 @@ qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
qpcache_detach(&qpdb);
}
static isc_result_t
expire_ncache_entry(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabtop_t *top,
dns_slabheader_t *newheader, dns_trust_t trust,
dns_rdataset_t *addedrdataset, isc_stdtime_t now,
isc_rwlocktype_t nlocktype,
isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->typepair);
dns_typepair_t sigpair = !dns_rdatatype_issig(rdtype)
? DNS_SIGTYPEPAIR(rdtype)
: dns_typepair_none;
/*
* 1. If we find a cached NXDOMAIN, don't cache anything else
* (dns_typepair_any).
*
* 2. Don't cache an RRSIG if it covers a type for which we have a
* cached NODATA record.
*/
if ((top->typepair == dns_typepair_any) ||
(sigpair != dns_rdatatype_none && newheader->typepair == sigpair &&
DNS_TYPEPAIR_TYPE(top->typepair) == covers))
{
if (trust < top->header->trust) {
/*
* The NXDOMAIN/NODATA(QTYPE=ANY) is more trusted.
*/
bindrdataset(qpdb, qpnode, top->header, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
return DNS_R_UNCHANGED;
}
/*
* The new rdataset is better. Expire the ncache entry.
*/
mark_ancient(top->header);
return ISC_R_SUCCESS;
}
return DNS_R_CONTINUE;
}
static isc_result_t
add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now,
@@ -2543,9 +2585,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
uint32_t ntypes = 0;
dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair);
dns_rdatatype_t covers = DNS_TYPEPAIR_COVERS(newheader->typepair);
dns_typepair_t sigpair = !dns_rdatatype_issig(rdtype)
? DNS_SIGTYPEPAIR(rdtype)
: dns_typepair_none;
dns_typepair_t sigpair = dns_typepair_none;
REQUIRE(rdtype != dns_rdatatype_none);
if (dns_rdatatype_issig(rdtype)) {
@@ -2564,120 +2604,101 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
trust = newheader->trust;
}
if (EXISTS(newheader)) {
if (NEGATIVE(newheader)) {
/*
* We're adding a negative cache entry.
*/
if (rdtype == dns_rdatatype_any) {
/*
* If we're adding an negative cache entry
* which covers all types (NXDOMAIN,
* NODATA(QTYPE=ANY)),
*
* We make all other data ancient so that the
* only rdataset that can be found at this
* node is the negative cache entry.
*/
DNS_SLABTOP_FOREACH(top, qpnode->data) {
mark_ancient(top->header);
}
goto find_header;
}
if (EXISTS(newheader) && NEGATIVE(newheader) &&
!dns_rdatatype_issig(rdtype))
{
/*
* Look for any RRSIGs of the given type in the main search loop
* so they can be also marked ancient later.
*/
sigpair = DNS_SIGTYPEPAIR(rdtype);
}
if (rdtype == dns_rdatatype_rrsig) {
/*
* If we're adding a proof that a signature
* doesn't exist, mark all signatures as
* ancient. This is basically the same as
* above, but just for RRSIGs.
*/
bool scan_all = false;
DNS_SLABTOP_FOREACH(top, qpnode->data) {
if (DNS_TYPEPAIR_TYPE(top->typepair) ==
dns_rdatatype_rrsig)
{
mark_ancient(top->header);
}
}
goto find_header;
}
if (EXISTS(newheader) && NEGATIVE(newheader) &&
(rdtype == dns_rdatatype_any || rdtype == dns_rdatatype_rrsig))
{
/*
* We're adding an negative cache entry which covers all types
* (NXDOMAIN, NODATA(QTYPE=ANY)) or we are adding a proof that a
* signature doesn't exist -> we need to scan all the entries.
*/
scan_all = true;
}
/*
* Otherwise look for any RRSIGs of the given
* type so they can be marked ancient later.
*/
DNS_SLABTOP_FOREACH(top, qpnode->data) {
if (top->typepair == sigpair) {
sigheader = top->header;
break;
}
}
} else {
dns_slabtop_t *foundtop = NULL;
/*
* We're adding something that isn't a
* negative cache entry.
*/
DNS_SLABTOP_FOREACH(top, qpnode->data) {
/*
* Look for any existing negative cache
* entries.
*/
if (!NEGATIVE(top->header)) {
continue;
}
/*
* If we find a cached NXDOMAIN, don't
* cache anything else.
*/
if (top->typepair == dns_typepair_any) {
foundtop = top;
break;
}
/*
* Don't cache an RRSIG if it covers a type
* for which we have a cached NODATA record.
*/
if (newheader->typepair == sigpair &&
DNS_TYPEPAIR_TYPE(top->typepair) == covers)
{
foundtop = top;
break;
}
}
if (foundtop != NULL && EXISTS(foundtop->header) &&
ACTIVE(foundtop->header, now))
{
/*
* Found one.
*/
if (trust < foundtop->header->trust) {
/*
* The NXDOMAIN/NODATA(QTYPE=ANY)
* is more trusted.
*/
bindrdataset(
qpdb, qpnode, foundtop->header,
now, nlocktype, tlocktype,
addedrdataset
DNS__DB_FLARG_PASS);
return DNS_R_UNCHANGED;
}
/*
* The new rdataset is better. Expire the
* ncache entry.
*/
mark_ancient(foundtop->header);
goto find_header;
}
}
if (EXISTS(newheader) && !NEGATIVE(newheader)) {
/*
* We are adding negative header, we need to scan all entries
* for existing NXDOMAIN/NODATA(QTYPE=ANY) or the existing
* negative covered type if we are adding a RRSIG(type).
*/
scan_all = true;
}
DNS_SLABTOP_FOREACH(top, qpnode->data) {
if (EXISTS(newheader) && NEGATIVE(newheader) &&
rdtype == dns_rdatatype_any)
{
/*
* We're adding an negative cache entry which covers all
* types (NXDOMAIN, NODATA(QTYPE=ANY)).
*
* Make all other data ancient so that the only rdataset
* that can be found at this node is the negative cache
* entry.
*/
mark_ancient(top->header);
}
if (EXISTS(newheader) && NEGATIVE(newheader) &&
rdtype == dns_rdatatype_rrsig)
{
/*
* We're adding a proof that a signature doesn't exist.
*
* Mark all existing signatures as ancient.
*/
if (DNS_TYPEPAIR_TYPE(top->typepair) ==
dns_rdatatype_rrsig)
{
mark_ancient(top->header);
}
}
if (EXISTS(newheader) && !NEGATIVE(newheader) &&
NEGATIVE(top->header) && EXISTS(top->header) &&
ACTIVE(top->header, now))
{
/*
* Look for existing active NXDOMAIN or negative covered
* type if we are adding RRSIG.
*/
isc_result_t result = expire_ncache_entry(
qpdb, qpnode, top, newheader, trust,
addedrdataset, now, nlocktype, tlocktype);
if (result == DNS_R_UNCHANGED) {
/*
* The existing negative entry is more trusted
* than the new rdataset.
*/
return DNS_R_UNCHANGED;
} else if (result == ISC_R_SUCCESS) {
/*
* The new rdataset is better. Since we just
* expired the negative cache entry, we can exit
* the loop early as we are not going to find
* anything.
*/
INSIST(header == NULL);
INSIST(sigheader == NULL);
if (!scan_all) {
break;
}
}
INSIST(result == DNS_R_CONTINUE);
}
if (ACTIVE(top->header, now)) {
++ntypes;
expiretop = top;
@@ -2688,16 +2709,31 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
if (top->typepair == newheader->typepair) {
header = top->header;
}
if (sigpair != dns_rdatatype_none && top->typepair == sigpair) {
sigheader = top->header;
}
if (scan_all) {
continue;
}
if (header != NULL && sigpair == dns_rdatatype_none) {
/*
* We found the right type and we are not looking for
* matching RRSIG.
*/
break;
} else if (header != NULL && sigheader != NULL) {
/*
* We found the right type and the matching RRSIG.
*/
break;
}
}
find_header:
if (header != NULL) {
/*
* We've found the right type.
*/
/*
* Deleting an already non-existent rdataset has no effect.
*/