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

when committing a new qpzone version, delete dead nodes

if all data has been deleted from a node in the qpzone
database, delete the node too.
This commit is contained in:
Evan Hunt
2025-02-11 21:43:09 -08:00
parent 74c9ff384e
commit e58ce19cf2
2 changed files with 94 additions and 11 deletions

View File

@@ -202,10 +202,9 @@ struct qpcnode {
uint8_t : 0; uint8_t : 0;
/*% /*%
* Used for dead nodes cleaning. This linked list is used to mark nodes * Used for dead node cleaning. The deadnodes queue is used
* which have no data any longer, but we cannot unlink at that exact * for nodes that have no data any longer, but we can't unlink
* moment because we did not or could not obtain a write lock on the * yet because we don't have a tree lock.
* tree.
*/ */
isc_queue_node_t deadlink; isc_queue_node_t deadlink;
}; };
@@ -216,9 +215,8 @@ struct qpcnode {
* to reduce contention between threads. * to reduce contention between threads.
*/ */
typedef struct qpcache_bucket { typedef struct qpcache_bucket {
/*% /*
* Temporary storage for stale cache nodes and dynamically * Temporary storage for cache nodes that need to be deleted.
* deleted nodes that await being cleaned up.
*/ */
isc_queue_t deadnodes; isc_queue_t deadnodes;

View File

@@ -874,6 +874,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
} }
top_prev = current; top_prev = current;
} }
if (!still_dirty) { if (!still_dirty) {
node->dirty = false; node->dirty = false;
} }
@@ -1518,10 +1519,8 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
NODE_UNLOCK(nlock, &nlocktype); NODE_UNLOCK(nlock, &nlocktype);
} }
if (EMPTY(cleanup_list)) { dns_qp_t *tree = NULL, *nsec = NULL, *nsec3 = NULL;
*versionp = NULL; bool need_tree = false, need_nsec = false, need_nsec3 = false;
return;
}
for (changed = HEAD(cleanup_list); changed != NULL; for (changed = HEAD(cleanup_list); changed != NULL;
changed = next_changed) changed = next_changed)
@@ -1537,14 +1536,100 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
if (rollback) { if (rollback) {
rollback_node(node, serial); rollback_node(node, serial);
} }
qpznode_ref(node);
qpznode_release(qpdb, node, least_serial, qpznode_release(qpdb, node, least_serial,
&nlocktype DNS__DB_FILELINE); &nlocktype DNS__DB_FILELINE);
/* If the node is now empty, we can delete it. */
if (commit && node->data == NULL) {
switch ((int)node->nsec) {
case DNS_DB_NSEC_HAS_NSEC:
/*
* Delete the matching node from the NSEC tree
* first, then fall through to the main tree.
*/
if (nsec == NULL) {
need_nsec = true;
next_changed = changed;
} else {
dns_qp_deletename(nsec, &node->name,
NULL, NULL);
}
FALLTHROUGH;
case DNS_DB_NSEC_NORMAL:
if (tree == NULL) {
need_tree = true;
next_changed = changed;
} else {
dns_qp_deletename(tree, &node->name,
NULL, NULL);
}
break;
case DNS_DB_NSEC_NSEC:
if (nsec == NULL) {
need_nsec = true;
next_changed = changed;
} else {
dns_qp_deletename(nsec, &node->name,
NULL, NULL);
}
break;
case DNS_DB_NSEC_NSEC3:
if (nsec3 == NULL) {
need_nsec3 = true;
next_changed = changed;
} else {
dns_qp_deletename(nsec3, &node->name,
NULL, NULL);
}
break;
default:
UNREACHABLE();
}
}
qpznode_detach(&node);
NODE_UNLOCK(nlock, &nlocktype); NODE_UNLOCK(nlock, &nlocktype);
if (next_changed == changed) {
/*
* We found a node to delete but didn't have a
* QP writer open, so we open one now, then go
* back to delete the node. If there's a next
* time, we'll already have the writer open,
* so we won't need this extra step.
*/
if (need_tree && tree == NULL) {
dns_qpmulti_write(qpdb->tree, &tree);
}
if (need_nsec && nsec == NULL) {
dns_qpmulti_write(qpdb->nsec, &nsec);
}
if (need_nsec3 && nsec3 == NULL) {
dns_qpmulti_write(qpdb->nsec3, &nsec3);
}
continue;
}
isc_mem_put(qpdb->common.mctx, changed, sizeof(*changed)); isc_mem_put(qpdb->common.mctx, changed, sizeof(*changed));
} }
if (tree != NULL) {
dns_qp_compact(tree, DNS_QPGC_MAYBE);
dns_qpmulti_commit(qpdb->tree, &tree);
}
if (nsec != NULL) {
dns_qp_compact(nsec, DNS_QPGC_MAYBE);
dns_qpmulti_commit(qpdb->nsec, &nsec);
}
if (nsec3 != NULL) {
dns_qp_compact(nsec3, DNS_QPGC_MAYBE);
dns_qpmulti_commit(qpdb->nsec3, &nsec3);
}
*versionp = NULL; *versionp = NULL;
} }