uint64_t records;
uint64_t xfrsize;
- struct cds_lfht *glue_table;
+ struct cds_wfs_stack glue_stack;
};
typedef ISC_LIST(qpz_version_t) qpz_versionlist_t;
isc_stdtime_t now;
} qpz_search_t;
-typedef struct dns_gluenode_t {
- isc_mem_t *mctx;
-
- struct dns_glue *glue;
-
- qpznode_t *node;
-
- struct cds_lfht_node ht_node;
- struct rcu_head rcu_head;
-} dns_gluenode_t;
-
/*%
* Load Context
*/
}
static void
-free_gluenode(dns_gluenode_t *gluenode);
+freeglue(dns_glue_t *glue_list) {
+ if (glue_list == (void *)-1) {
+ return;
+ }
+
+ dns_glue_t *glue = glue_list;
+ while (glue != NULL) {
+ dns_glue_t *next = glue->next;
+
+ if (dns_rdataset_isassociated(&glue->rdataset_a)) {
+ dns_rdataset_disassociate(&glue->rdataset_a);
+ }
+ if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
+ dns_rdataset_disassociate(&glue->sigrdataset_a);
+ }
+
+ if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
+ dns_rdataset_disassociate(&glue->rdataset_aaaa);
+ }
+ if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
+ dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
+ }
+
+ dns_rdataset_invalidate(&glue->rdataset_a);
+ dns_rdataset_invalidate(&glue->sigrdataset_a);
+ dns_rdataset_invalidate(&glue->rdataset_aaaa);
+ dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
+
+ isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue));
+
+ glue = next;
+ }
+}
static void
-free_gluetable(struct cds_lfht *glue_table) {
- struct cds_lfht_iter iter;
- dns_gluenode_t *gluenode = NULL;
+free_gluelist_rcu(struct rcu_head *rcu_head) {
+ dns_glue_t *glue = caa_container_of(rcu_head, dns_glue_t, rcu_head);
+
+ freeglue(glue);
+}
+
+static void
+free_gluetable(struct cds_wfs_stack *glue_stack) {
+ struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
+ struct cds_wfs_node *node = NULL, *next = NULL;
rcu_read_lock();
- cds_lfht_for_each_entry(glue_table, &iter, gluenode, ht_node) {
- INSIST(!cds_lfht_del(glue_table, &gluenode->ht_node));
- free_gluenode(gluenode);
+ cds_wfs_for_each_blocking_safe(head, node, next) {
+ dns_slabheader_t *header =
+ caa_container_of(node, dns_slabheader_t, wfs_node);
+ dns_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL);
+
+ call_rcu(&glue->rcu_head, free_gluelist_rcu);
}
rcu_read_unlock();
-
- cds_lfht_destroy(glue_table, NULL);
}
static void
isc_refcount_destroy(&qpdb->current_version->references);
UNLINK(qpdb->open_versions, qpdb->current_version, link);
+ cds_wfs_destroy(&qpdb->current_version->glue_stack);
isc_rwlock_destroy(&qpdb->current_version->rwlock);
isc_mem_put(qpdb->common.mctx, qpdb->current_version,
sizeof(*qpdb->current_version));
* node count below.
*/
if (qpdb->current_version != NULL) {
- free_gluetable(qpdb->current_version->glue_table);
+ free_gluetable(&qpdb->current_version->glue_stack);
}
/*
.changed_list = ISC_LIST_INITIALIZER,
.resigned_list = ISC_LIST_INITIALIZER,
.link = ISC_LINK_INITIALIZER,
- .glue_table = cds_lfht_new(GLUETABLE_INIT_SIZE,
- GLUETABLE_MIN_SIZE, 0,
- CDS_LFHT_AUTO_RESIZE, NULL),
};
+ cds_wfs_init(&version->glue_stack);
isc_rwlock_init(&version->rwlock);
isc_refcount_init(&version->references, references);
if (cleanup_version != NULL) {
isc_refcount_destroy(&cleanup_version->references);
INSIST(EMPTY(cleanup_version->changed_list));
- free_gluetable(cleanup_version->glue_table);
+ free_gluetable(&cleanup_version->glue_stack);
+ cds_wfs_destroy(&cleanup_version->glue_stack);
isc_rwlock_destroy(&cleanup_version->rwlock);
isc_mem_put(qpdb->common.mctx, cleanup_version,
sizeof(*cleanup_version));
RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
}
header->heap_index = 0;
+
+ if (header->glue_list) {
+ freeglue(header->glue_list);
+ }
}
/*
*glue = (dns_glue_t){ 0 };
dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
+ isc_mem_attach(mctx, &glue->mctx);
dns_name_copy(name, gluename);
return glue;
}
static dns_glue_t *
-newglue(dns_db_t *db, qpz_version_t *version, qpznode_t *node,
+newglue(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
dns_rdataset_t *rdataset) {
dns_fixedname_t nodename;
dns_glue_additionaldata_ctx_t ctx = {
- .db = db,
+ .db = (dns_db_t *)qpdb,
.version = (dns_dbversion_t *)version,
.nodename = dns_fixedname_initname(&nodename),
};
return ctx.glue_list;
}
-static dns_gluenode_t *
-new_gluenode(dns_db_t *db, qpz_version_t *version, qpznode_t *node,
- dns_rdataset_t *rdataset) {
- dns_gluenode_t *gluenode = isc_mem_get(db->mctx, sizeof(*gluenode));
- *gluenode = (dns_gluenode_t){
- .glue = newglue(db, version, node, rdataset),
- };
-
- isc_mem_attach(db->mctx, &gluenode->mctx);
- qpznode_attach(node, &gluenode->node);
-
- return gluenode;
-}
-
-static void
-freeglue(isc_mem_t *mctx, dns_glue_t *glue) {
- while (glue != NULL) {
- dns_glue_t *next = glue->next;
-
- if (dns_rdataset_isassociated(&glue->rdataset_a)) {
- dns_rdataset_disassociate(&glue->rdataset_a);
- }
- if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
- dns_rdataset_disassociate(&glue->sigrdataset_a);
- }
-
- if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
- dns_rdataset_disassociate(&glue->rdataset_aaaa);
- }
- if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
- dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
- }
-
- dns_rdataset_invalidate(&glue->rdataset_a);
- dns_rdataset_invalidate(&glue->sigrdataset_a);
- dns_rdataset_invalidate(&glue->rdataset_aaaa);
- dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
-
- isc_mem_put(mctx, glue, sizeof(*glue));
-
- glue = next;
- }
-}
-
-static void
-free_gluenode_rcu(struct rcu_head *rcu_head) {
- dns_gluenode_t *gluenode = caa_container_of(rcu_head, dns_gluenode_t,
- rcu_head);
-
- freeglue(gluenode->mctx, gluenode->glue);
-
- qpznode_detach(&gluenode->node);
-
- isc_mem_putanddetach(&gluenode->mctx, gluenode, sizeof(*gluenode));
-}
-
-static void
-free_gluenode(dns_gluenode_t *gluenode) {
- call_rcu(&gluenode->rcu_head, free_gluenode_rcu);
-}
-
-static uint32_t
-qpznode_hash(const qpznode_t *node) {
- const uintptr_t key = (uintptr_t)node;
- return isc_hash32(&key, sizeof(key), true);
-}
-
-static int
-qpznode_match(struct cds_lfht_node *ht_node, const void *key) {
- const dns_gluenode_t *gluenode =
- caa_container_of(ht_node, dns_gluenode_t, ht_node);
- const qpznode_t *node = key;
-
- return gluenode->node == node;
-}
-
-static uint32_t
-gluenode_hash(const dns_gluenode_t *gluenode) {
- return qpznode_hash(gluenode->node);
-}
-
-static int
-gluenode_match(struct cds_lfht_node *ht_node, const void *key) {
- const dns_gluenode_t *gluenode = key;
-
- return qpznode_match(ht_node, gluenode->node);
-}
-
static void
addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
dns_message_t *msg) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpz_version_t *version = (qpz_version_t *)dbversion;
qpznode_t *node = (qpznode_t *)rdataset->slab.node;
- dns_gluenode_t *gluenode = NULL;
+ dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
REQUIRE(rdataset->type == dns_rdatatype_ns);
REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db);
REQUIRE(qpdb == version->qpdb);
REQUIRE(!IS_STUB(qpdb));
- /*
- * The glue table cache that forms a part of the DB version
- * structure is not explicitly bounded and there's no cache
- * cleaning. The zone data size itself is an implicit bound.
- *
- * The key into the glue hashtable is the node pointer. This is
- * because the glue hashtable is a property of the DB version,
- * and the glue is keyed for the ownername/NS tuple. We don't
- * bother with using an expensive dns_name_t comparison here as
- * the node pointer is a fixed value that won't change for a DB
- * version and can be compared directly.
- */
-
rcu_read_lock();
- struct cds_lfht_iter iter;
- cds_lfht_lookup(version->glue_table, qpznode_hash(node), qpznode_match,
- node, &iter);
-
- gluenode = cds_lfht_entry(cds_lfht_iter_get_node(&iter), dns_gluenode_t,
- ht_node);
- if (gluenode == NULL) {
+ dns_glue_t *glue = rcu_dereference(header->glue_list);
+ if (glue == NULL) {
/* No cached glue was found in the table. Get new glue. */
- gluenode = new_gluenode(db, version, node, rdataset);
-
- struct cds_lfht_node *ht_node = cds_lfht_add_unique(
- version->glue_table, gluenode_hash(gluenode),
- gluenode_match, gluenode, &gluenode->ht_node);
-
- if (ht_node != &gluenode->ht_node) {
- free_gluenode_rcu(&gluenode->rcu_head);
-
- gluenode = cds_lfht_entry(ht_node, dns_gluenode_t,
- ht_node);
+ glue = newglue(qpdb, version, node, rdataset);
+
+ /* Cache the glue or (void *)-1 if no glue was found. */
+ dns_glue_t *old_glue = rcu_cmpxchg_pointer(
+ &header->glue_list, NULL, (glue) ? glue : (void *)-1);
+ if (old_glue != NULL) {
+ /* Somebody else was faster */
+ freeglue(glue);
+ glue = old_glue;
+ } else if (glue != NULL) {
+ cds_wfs_push(&version->glue_stack, &header->wfs_node);
}
}
- INSIST(gluenode != NULL);
+ /* We have a cached result. Add it to the message and return. */
- dns_glue_t *glue = gluenode->glue;
- isc_statscounter_t counter = dns_gluecachestatscounter_hits_present;
+ if (qpdb->gluecachestats != NULL) {
+ isc_stats_increment(
+ qpdb->gluecachestats,
+ (glue == (void *)-1)
+ ? dns_gluecachestatscounter_hits_absent
+ : dns_gluecachestatscounter_hits_present);
+ }
- if (glue != NULL) {
- /* We have a cached result. Add it to the message and return. */
+ /*
+ * (void *)-1 is a special value that means no glue is present in the
+ * zone.
+ */
+ if (glue != (void *)-1) {
addglue_to_message(glue, msg);
- } else {
- counter = dns_gluecachestatscounter_hits_absent;
}
rcu_read_unlock();
-
- if (qpdb->gluecachestats != NULL) {
- isc_stats_increment(qpdb->gluecachestats, counter);
- }
}
static void