Convert slabtop to use the cds_list

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.
This commit is contained in:
Ondřej Surý 2025-09-12 11:25:40 +02:00
parent 2924f59cb3
commit 63389b8ce6
No known key found for this signature in database
GPG key ID: 2820F37E873DEA41
5 changed files with 61 additions and 59 deletions

View 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;

View 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;
}
}
}

View 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;
}
}
}

View 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,
};

View 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>