]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Create list of dirty dirty headers that needs cleaning
authorOndřej Surý <ondrej@isc.org>
Tue, 28 Oct 2025 22:11:37 +0000 (23:11 +0100)
committerOndřej Surý <ondrej@isc.org>
Mon, 8 Dec 2025 18:23:34 +0000 (19:23 +0100)
Instead of just flagging the qpcache node to be dirty, add the headers
to be cleaned to the dirty list and when cleaning the node, only walk
through the dirty node, not all the slabtops.

lib/dns/include/dns/rdataslab.h
lib/dns/qpcache.c
lib/dns/rdataslab.c

index b160f3494d26d8b3155457dbc7802779ae09c39a..421c7df8aa6640ee3f34da840f6dc69d638eb639 100644 (file)
@@ -113,6 +113,11 @@ struct dns_slabheader {
        dns_slabheader_proof_t *noqname;
        dns_slabheader_proof_t *closest;
 
+       /*%
+        * Used for cleaning.
+        */
+       ISC_LINK(dns_slabheader_t) dirtylink;
+
        /*%
         * Points to the top slabtop structure for the type.
         */
index 725d51fe9c5ca51bfe0cbabc986ed4865f2b7451..52ea84506c5a83c44379507f51d382db5f3939f1 100644 (file)
@@ -23,6 +23,7 @@
 #include <isc/file.h>
 #include <isc/heap.h>
 #include <isc/hex.h>
+#include <isc/list.h>
 #include <isc/log.h>
 #include <isc/loop.h>
 #include <isc/mem.h>
@@ -152,15 +153,7 @@ struct qpcnode {
        struct cds_list_head types_list;
        struct cds_list_head *data;
 
-       /*%
-        * NOTE: The 'dirty' flag is protected by the node lock, so
-        * this bitfield has to be separated from the one above.
-        * We don't want it to share the same qword with bits
-        * that can be accessed without the node lock.
-        */
-       uint8_t       : 0;
-       uint8_t dirty : 1;
-       uint8_t       : 0;
+       ISC_LIST(dns_slabheader_t) dirty;
 
        /*%
         * Used for dead nodes cleaning.  This linked list is used to mark nodes
@@ -579,7 +572,17 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
         * Caller must be holding the node lock.
         */
 
-       DNS_SLABTOP_FOREACH(top, node->data) {
+       /*
+        * We can't use ordinary loop because multiple headers to be cleaned can
+        * be stashed under a single slabtop.
+        */
+       for (dns_slabheader_t *dirty = ISC_LIST_HEAD(node->dirty);
+            dirty != NULL; dirty = ISC_LIST_HEAD(node->dirty))
+       {
+               dns_slabtop_t *top = dirty->top;
+
+               ISC_LIST_UNLINK(node->dirty, dirty, dirtylink);
+
                clean_cache_headers(top);
 
                /*
@@ -617,8 +620,6 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
                        dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
                }
        }
-
-       node->dirty = false;
 }
 
 /*
@@ -767,7 +768,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
        }
 
        /* Handle easy and typical case first. */
-       if (!node->dirty && !cds_list_empty(node->data)) {
+       if (ISC_LIST_EMPTY(node->dirty) && !cds_list_empty(node->data)) {
                goto unref;
        }
 
@@ -794,7 +795,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
                }
        }
 
-       if (node->dirty) {
+       if (!ISC_LIST_EMPTY(node->dirty)) {
                clean_cache_node(qpdb, node);
        }
 
@@ -926,7 +927,9 @@ static void
 mark_ancient(dns_slabheader_t *header) {
        setttl(header, 0);
        mark(header, DNS_SLABHEADERATTR_ANCIENT);
-       HEADERNODE(header)->dirty = 1;
+       if (!ISC_LINK_LINKED(header, dirtylink)) {
+               ISC_LIST_APPEND(HEADERNODE(header)->dirty, header, dirtylink);
+       }
 }
 
 /*
@@ -2425,6 +2428,7 @@ new_qpcnode(qpcache_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
                .nspace = nspace,
                .references = ISC_REFCOUNT_INITIALIZER(1),
                .locknum = isc_random_uniform(qpdb->buckets_count),
+               .dirty = ISC_LIST_INITIALIZER,
        };
 
        isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
@@ -3741,6 +3745,10 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
        dns_slabheader_t *header = data;
        qpcache_t *qpdb = HEADERNODE(header)->qpdb;
 
+       if (ISC_LINK_LINKED(header, dirtylink)) {
+               ISC_LIST_UNLINK(HEADERNODE(header)->dirty, header, dirtylink);
+       }
+
        if (header->heap != NULL && header->heap_index != 0) {
                isc_heap_delete(header->heap, header->heap_index);
        }
index 2fa0f30c1b0f0a6b756decc00bd608ad37e8ef0c..2754b9ec7014fc7a4ef813276ca2f65f9860142e 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <isc/ascii.h>
 #include <isc/atomic.h>
+#include <isc/list.h>
 #include <isc/mem.h>
 #include <isc/region.h>
 #include <isc/result.h>
@@ -327,6 +328,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
                        .typepair = typepair,
                        .trust = rdataset->trust,
                        .ttl = rdataset->ttl,
+                       .dirtylink = ISC_LINK_INITIALIZER,
                };
        }
 
@@ -833,6 +835,8 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
        atomic_init(&h->attributes, 0);
        atomic_init(&h->last_refresh_fail_ts, 0);
 
+       ISC_LINK_INIT(h, dirtylink);
+
        STATIC_ASSERT(sizeof(h->attributes) == 2,
                      "The .attributes field of dns_slabheader_t needs to be "
                      "16-bit int type exactly.");
@@ -845,6 +849,7 @@ dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) {
        h = isc_mem_get(mctx, sizeof(*h));
        *h = (dns_slabheader_t){
                .node = node,
+               .dirtylink = ISC_LINK_INITIALIZER,
        };
        return h;
 }