From: Libor Peltan Date: Thu, 4 Dec 2025 13:22:45 +0000 (+0100) Subject: zone-tree: implemented subtree deletion X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7041161113587a9b2fb6dcf032c218f3a2e7e9cb;p=thirdparty%2Fknot-dns.git zone-tree: implemented subtree deletion --- diff --git a/src/knot/zone/adds_tree.c b/src/knot/zone/adds_tree.c index c604d7d7a6..8a1e953671 100644 --- a/src/knot/zone/adds_tree.c +++ b/src/knot/zone/adds_tree.c @@ -12,8 +12,7 @@ #include "libknot/error.h" #include "libknot/rrtype/rdname.h" -knot_dynarray_declare(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_STATIC, 2) -knot_dynarray_define(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_STATIC) +knot_dynarray_define(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_NORMAL) typedef struct { nodeptr_dynarray_t array; diff --git a/src/knot/zone/adds_tree.h b/src/knot/zone/adds_tree.h index 408b0ea080..ad94738da7 100644 --- a/src/knot/zone/adds_tree.h +++ b/src/knot/zone/adds_tree.h @@ -14,6 +14,8 @@ typedef trie_t additionals_tree_t; inline static additionals_tree_t *additionals_tree_new(void) { return trie_create(NULL); } void additionals_tree_free(additionals_tree_t *a_t); +knot_dynarray_declare(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_NORMAL, 2) + /*! * \brief Foreach additional in all node RRSets, do sth. * diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c index 4217038579..d933238af7 100644 --- a/src/knot/zone/zone-tree.c +++ b/src/knot/zone/zone-tree.c @@ -7,6 +7,7 @@ #include #include "knot/zone/zone-tree.h" +#include "knot/zone/adds_tree.h" #include "libknot/consts.h" #include "libknot/errcode.h" #include "libknot/packet/wire.h" @@ -272,6 +273,33 @@ int zone_tree_del_node(zone_tree_t *tree, zone_node_t *node, bool free_deleted) return ret; } +static int clear_rrs(zone_node_t *node, void *ctx) +{ + nodeptr_dynarray_t *leaves = ctx; + binode_unify(node, false, NULL); + node_free_rrsets(node, NULL); + if (node->children == 0) { + (void)nodeptr_dynarray_add(leaves, &node); // if ENOMEM, we just leak + } + return KNOT_EOK; +} + +int zone_tree_del_subtree(zone_tree_t *tree, const knot_dname_t *subroot, bool excl_root) +{ + nodeptr_dynarray_t leaves = { 0 }; + int ret = zone_tree_sub_apply(tree, subroot, excl_root, clear_rrs, &leaves); + if (ret == KNOT_EOK) { + knot_dynarray_foreach(nodeptr, zone_node_t *, n, leaves) { + ret = zone_tree_del_node(tree, *n, true); + if (ret != KNOT_EOK) { + break; + } + } + } + nodeptr_dynarray_free(&leaves); + return ret; +} + int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data) { if (function == NULL) { diff --git a/src/knot/zone/zone-tree.h b/src/knot/zone/zone-tree.h index 57b90b6918..d3d97327ed 100644 --- a/src/knot/zone/zone-tree.h +++ b/src/knot/zone/zone-tree.h @@ -198,6 +198,17 @@ int zone_tree_add_node(zone_tree_t *tree, zone_node_t *apex, const knot_dname_t */ int zone_tree_del_node(zone_tree_t *tree, zone_node_t *node, bool free_deleted); +/*! + * \brief Remove a subtree, freeing removed nodes and their RRsets. + * + * \param tree Zone tree to remove from. + * \param subroot Subtree root name. + * \param excl_root Skip removing the root of the subtree. + * + * \return KNOT_E* + */ +int zone_tree_del_subtree(zone_tree_t *tree, const knot_dname_t *subroot, bool excl_root); + /*! * \brief Applies the given function to each node in the zone in order. * diff --git a/tests/knot/test_zone-tree.c b/tests/knot/test_zone-tree.c index f1c9671a9e..193fad2903 100644 --- a/tests/knot/test_zone-tree.c +++ b/tests/knot/test_zone-tree.c @@ -11,7 +11,7 @@ #define NCOUNT 4 static knot_dname_t* NAME[NCOUNT]; -static zone_node_t NODEE[NCOUNT]; +static zone_node_t* NODEE[NCOUNT]; static knot_dname_t* ORDER[NCOUNT]; static void ztree_init_data(void) { @@ -21,15 +21,19 @@ static void ztree_init_data(void) NAME[3] = knot_dname_from_str_alloc("ns."); knot_dname_t *order[NCOUNT] = { - NAME[0], NAME[2], NAME[1], NAME[3] + NAME[0], NAME[2], NAME[1], NAME[3] }; memcpy(ORDER, order, NCOUNT * sizeof(knot_dname_t*)); + const char *rd = "\x02\x00\x01\x00"; + knot_rrset_t rr = { .rrs = { .count = 1, .size = 4, .rdata = (knot_rdata_t *)&rd } }; + for (unsigned i = 0; i < NCOUNT; ++i) { - memset(NODEE + i, 0, sizeof(zone_node_t)); - NODEE[i].owner = NAME[i]; - NODEE[i].prev = NODEE + ((NCOUNT + i - 1) % NCOUNT); - NODEE[i].rrset_count = 1; /* required for ordered search */ + NODEE[i] = node_new(NAME[i], false, false, NULL); + NODEE[i]->prev = *(NODEE + ((NCOUNT + i - 1) % NCOUNT)); + + rr.owner = NAME[i]; + node_add_rrset(NODEE[i], &rr, NULL); } } @@ -45,7 +49,7 @@ static int ztree_iter_data(zone_node_t *node, void *data) unsigned *i = (unsigned *)data; knot_dname_t *owner = node->owner; int result = KNOT_EOK; - if (owner != ORDER[*i]) { + if (!knot_dname_is_equal(owner, ORDER[*i])) { result = KNOT_ERROR; char *exp_s = knot_dname_to_str_alloc(ORDER[*i]); char *owner_s = knot_dname_to_str_alloc(owner); @@ -78,7 +82,7 @@ int main(int argc, char *argv[]) /* 2. insert test */ unsigned passed = 1; for (unsigned i = 0; i < NCOUNT; ++i) { - zone_node_t *node = NODEE + i; + zone_node_t *node = NODEE[i]; if (zone_tree_insert(t, &node) != KNOT_EOK) { passed = 0; break; @@ -90,7 +94,7 @@ int main(int argc, char *argv[]) passed = 1; for (unsigned i = 0; i < NCOUNT; ++i) { zone_node_t *node = zone_tree_get(t, NAME[i]); - if (node == NULL || node != NODEE + i) { + if (node == NULL || node != NODEE[i]) { passed = 0; break; } @@ -103,7 +107,7 @@ int main(int argc, char *argv[]) knot_dname_t *tmp_dn = knot_dname_from_str_alloc("z.ac."); zone_tree_get_less_or_equal(t, tmp_dn, &node, &prev); knot_dname_free(tmp_dn, NULL); - ok(prev == NODEE + 1, "ztree: ordered lookup"); + ok(prev == NODEE[1], "ztree: ordered lookup"); /* 5. ordered traversal */ unsigned i = 0; @@ -118,7 +122,19 @@ int main(int argc, char *argv[]) ret = zone_tree_sub_apply(t, (const knot_dname_t *)"\x02""ac", true, ztree_node_counter, &counter); ok(ret == KNOT_EOK && counter == 1, "ztree: subtree iteration excluding root"); + /* 7. subtree deletion */ + ret = zone_tree_del_subtree(t, (const knot_dname_t *)"\x02""ac", true); + ok(ret == KNOT_EOK && zone_tree_get(t, NAME[1]) == NULL && zone_tree_get(t, NAME[2]) != NULL, "ztree: subtree deletion w/o root"); + ret = zone_tree_del_subtree(t, (const knot_dname_t *)"\x02""ns", false); + ok(ret == KNOT_EOK && zone_tree_get(t, NAME[3]) == NULL, "ztree: subtree deletion with root"); + zone_tree_free(&t); + + // free exactly what left + node_free_rrsets(NODEE[0], NULL); + node_free(NODEE[0], NULL); + node_free_rrsets(NODEE[2], NULL); + node_free(NODEE[2], NULL); ztree_free_data(); return 0; }