]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Convert slabtop to use the cds_list
authorOndřej Surý <ondrej@isc.org>
Fri, 12 Sep 2025 09:25:40 +0000 (11:25 +0200)
committerOndřej Surý <ondrej@isc.org>
Tue, 23 Sep 2025 09:21:47 +0000 (11:21 +0200)
This is the first commit in series that aims to reduce the node locking
by replacing the single-linked list of slabtop(s) with CDS linked list.
This commit doesn't do anything else beyond replacing .next link with
the cds_list_head.  RCU semantics is going to be added in the subsequent
commits.

lib/dns/include/dns/rdataslab.h
lib/dns/qpcache.c
lib/dns/qpzone.c
lib/dns/rdataslab.c
lib/isc/include/isc/urcu.h

index 5938702927780c26e53294b3e6024e6d05a8e3c7..bacec3bcf70cdf5fdf23c0fcd3918eaf6b9e0b0e 100644 (file)
@@ -64,15 +64,18 @@ struct dns_slabheader_proof {
        dns_rdatatype_t type;
 };
 
-#define DNS_SLABTOP_FOREACH(elt, first)                                    \
-       for (dns_slabtop_t *elt = first,                                   \
-                          *elt##_next = (elt != NULL) ? elt->next : NULL; \
-            elt != NULL;                                                  \
-            elt = elt##_next, elt##_next = (elt != NULL) ? elt->next : NULL)
+#define DNS_SLABTOP_FOREACH(pos, head)                 \
+       dns_slabtop_t *pos = NULL, *pos##_next = NULL; \
+       cds_list_for_each_entry_safe(pos, pos##_next, head, types_link)
+
+#define DNS_SLABTOP_FOREACH_FROM(pos, head, first)      \
+       dns_slabtop_t *pos = first, *pos##_next = NULL; \
+       cds_list_for_each_entry_safe_from(pos, pos##_next, head, types_link)
 
 typedef struct dns_slabtop dns_slabtop_t;
 struct dns_slabtop {
-       dns_slabtop_t    *next;
+       struct cds_list_head types_link;
+
        dns_slabheader_t *header;
        dns_typepair_t    typepair;
 
index efc987c12cc2561615c235477cc078808e62b7ec..e90277cb33cc29d6525fa7859f30c1e7743e5112 100644 (file)
@@ -157,7 +157,8 @@ struct qpcnode {
        isc_refcount_t references;
        isc_refcount_t erefs;
 
-       dns_slabtop_t *data;
+       struct cds_list_head types_list;
+       struct cds_list_head *data;
 
        /*%
         * NOTE: The 'dirty' flag is protected by the node lock, so
@@ -561,8 +562,6 @@ clean_cache_headers(dns_slabtop_t *top) {
 
 static void
 clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
-       dns_slabtop_t *top_prev = NULL;
-
        /*
         * Caller must be holding the node lock.
         */
@@ -584,11 +583,7 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
                 * If current slabtop is empty, we can clean it up.
                 */
                if (top->header == NULL) {
-                       if (top_prev != NULL) {
-                               top_prev->next = top->next;
-                       } else {
-                               node->data = top->next;
-                       }
+                       cds_list_del(&top->types_link);
 
                        if (ISC_LINK_LINKED(top, link)) {
                                ISC_SIEVE_UNLINK(
@@ -596,8 +591,6 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
                                        link);
                        }
                        dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top);
-               } else {
-                       top_prev = top;
                }
        }
 
@@ -750,7 +743,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
        }
 
        /* Handle easy and typical case first. */
-       if (!node->dirty && node->data != NULL) {
+       if (!node->dirty && !cds_list_empty(node->data)) {
                goto unref;
        }
 
@@ -781,7 +774,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
                clean_cache_node(qpdb, node);
        }
 
-       if (node->data != NULL) {
+       if (!cds_list_empty(node->data)) {
                goto unref;
        }
 
@@ -2383,6 +2376,8 @@ static qpcnode_t *
 new_qpcnode(qpcache_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
        qpcnode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
        *newdata = (qpcnode_t){
+               .types_list = CDS_LIST_HEAD_INIT(newdata->types_list),
+               .data = &newdata->types_list,
                .methods = &qpcnode_methods,
                .qpdb = qpdb,
                .name = DNS_NAME_INITEMPTY,
@@ -2888,16 +2883,13 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
 
                if (prio_header(newtop)) {
                        /* This is a priority type, prepend it */
-                       newtop->next = qpnode->data;
-                       qpnode->data = newtop;
+                       cds_list_add(&newtop->types_link, qpnode->data);
                } else if (priotop != NULL) {
                        /* Append after the priority headers */
-                       newtop->next = priotop->next;
-                       priotop->next = newtop;
+                       cds_list_add(&newtop->types_link, &priotop->types_link);
                } else {
                        /* There were no priority headers */
-                       newtop->next = qpnode->data;
-                       qpnode->data = newtop;
+                       cds_list_add(&newtop->types_link, qpnode->data);
                }
 
                if (overmaxtype(qpdb, ntypes)) {
@@ -3387,24 +3379,29 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) {
        qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node;
        isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
        isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
-       dns_slabtop_t *next = NULL;
+       dns_slabtop_t *from = NULL;
 
        if (iterator->current == NULL) {
                return ISC_R_NOMORE;
        }
-       next = iterator->current->next;
-       iterator->current = NULL;
 
        NODE_RDLOCK(nlock, &nlocktype);
 
-       DNS_SLABTOP_FOREACH(top, next) {
-               dns_slabheader_t *header = first_existing_header(top);
+       from = cds_list_entry(iterator->current->types_link.next, dns_slabtop_t,
+                             types_link);
+       iterator->current = NULL;
 
-               if (EXPIREDOK(iterator) ||
-                   (header != NULL && iterator_active(qpdb, iterator, header)))
-               {
-                       iterator->current = top;
-                       break;
+       if (from != NULL) {
+               DNS_SLABTOP_FOREACH_FROM(top, qpnode->data, from) {
+                       dns_slabheader_t *header = first_existing_header(top);
+
+                       if (EXPIREDOK(iterator) ||
+                           (header != NULL &&
+                            iterator_active(qpdb, iterator, header)))
+                       {
+                               iterator->current = top;
+                               break;
+                       }
                }
        }
 
index 9eaf4f28e79d5b8eb22cf8a5eeecd9544733cecd..567603eba793293f5e0f7967e9216461f5263a10 100644 (file)
@@ -198,7 +198,9 @@ struct qpznode {
        atomic_bool wild;
        atomic_bool delegating;
        atomic_bool dirty;
-       dns_slabtop_t *data;
+
+       struct cds_list_head types_list;
+       struct cds_list_head *data;
 };
 
 struct qpzonedb {
@@ -631,6 +633,8 @@ static qpznode_t *
 new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) {
        qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata));
        *newdata = (qpznode_t){
+               .types_list = CDS_LIST_HEAD_INIT(newdata->types_list),
+               .data = &newdata->types_list,
                .methods = &qpznode_methods,
                .name = DNS_NAME_INITEMPTY,
                .nspace = nspace,
@@ -848,7 +852,6 @@ clean_multiple_versions(dns_slabtop_t *top, uint32_t least_serial) {
 
 static void
 clean_zone_node(qpznode_t *node, uint32_t least_serial) {
-       dns_slabtop_t *top_prev = NULL;
        bool still_dirty = false;
 
        /*
@@ -873,11 +876,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
                check_top_header(top);
 
                if (top->header == NULL) {
-                       if (top_prev != NULL) {
-                               top_prev->next = top->next;
-                       } else {
-                               node->data = top->next;
-                       }
+                       cds_list_del(&top->types_link);
                        dns_slabtop_destroy(node->mctx, &top);
                } else {
                        /*
@@ -891,8 +890,6 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
                         */
                        still_dirty = clean_multiple_versions(top,
                                                              least_serial);
-
-                       top_prev = top;
                }
        }
        if (!still_dirty) {
@@ -942,7 +939,7 @@ qpznode_release(qpznode_t *node, uint32_t least_serial,
        }
 
        /* Handle easy and typical case first. */
-       if (!node->dirty && node->data != NULL) {
+       if (!node->dirty && !cds_list_empty(node->data)) {
                goto unref;
        }
 
@@ -1998,16 +1995,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
 
                        if (prio_type(newheader->typepair)) {
                                /* This is a priority type, prepend it */
-                               newtop->next = node->data;
-                               node->data = newtop;
+                               cds_list_add(&newtop->types_link, node->data);
                        } else if (priotop != NULL) {
                                /* Append after the priority headers */
-                               newtop->next = priotop->next;
-                               priotop->next = newtop;
+                               cds_list_add(&newtop->types_link,
+                                            &priotop->types_link);
                        } else {
                                /* There were no priority headers */
-                               newtop->next = node->data;
-                               node->data = newtop;
+                               cds_list_add(&newtop->types_link, node->data);
                        }
                }
        }
@@ -3964,25 +3959,30 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
        qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
        isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
        isc_rwlock_t *nlock = qpzone_get_lock(node);
-       dns_slabtop_t *next = NULL;
+       dns_slabtop_t *from = NULL;
 
        if (qrditer->currenttop == NULL) {
                return ISC_R_NOMORE;
        }
-       next = qrditer->currenttop->next;
-       qrditer->currenttop = NULL;
-       qrditer->current = NULL;
 
        NODE_RDLOCK(nlock, &nlocktype);
 
+       from = cds_list_entry(qrditer->currenttop->types_link.next,
+                             dns_slabtop_t, types_link);
+       qrditer->currenttop = NULL;
+       qrditer->current = NULL;
+
        /*
         * Find the start of the header chain for the next type.
         */
-       DNS_SLABTOP_FOREACH(top, next) {
-               qrditer->current = first_existing_header(top, version->serial);
-               if (qrditer->current != NULL) {
-                       qrditer->currenttop = top;
-                       break;
+       if (from != NULL) {
+               DNS_SLABTOP_FOREACH_FROM(top, node->data, from) {
+                       qrditer->current =
+                               first_existing_header(top, version->serial);
+                       if (qrditer->current != NULL) {
+                               qrditer->currenttop = top;
+                               break;
+                       }
                }
        }
 
index 3616b3aeadc00b89c39cc7f56dd4ebbe8b2e3fa6..beb5f38d019c70713d5a0c8bac14472ce3aaed46 100644 (file)
@@ -1179,6 +1179,7 @@ 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){
+               .types_link = CDS_LIST_HEAD_INIT(top->types_link),
                .typepair = typepair,
                .link = ISC_LINK_INITIALIZER,
        };
index cf62934632be1d50d35c8fac30f13f955f38ac71..88e68bf80ceb25a93a91b6d30137ac7a3e0b4745 100644 (file)
@@ -30,6 +30,7 @@
 #include <urcu-pointer.h>
 
 #include <urcu/compiler.h>
+#include <urcu/list.h>
 #include <urcu/rculfhash.h>
 #include <urcu/rculist.h>
 #include <urcu/wfstack.h>