]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
zone-tree: implemented subtree deletion
authorLibor Peltan <libor.peltan@nic.cz>
Thu, 4 Dec 2025 13:22:45 +0000 (14:22 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Sun, 7 Dec 2025 20:35:17 +0000 (21:35 +0100)
src/knot/zone/adds_tree.c
src/knot/zone/adds_tree.h
src/knot/zone/zone-tree.c
src/knot/zone/zone-tree.h
tests/knot/test_zone-tree.c

index c604d7d7a6b7c69158ad3dd3015caaa9987f746e..8a1e9536713a742cdffc611ea0e5a549324482a1 100644 (file)
@@ -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;
index 408b0ea080f281c44c572eb18a96e805734e4115..ad94738da7253ae7a69a0bbdda439f60df05139a 100644 (file)
@@ -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.
  *
index 4217038579d8136cb7de85320f4cdf23a903f654..d933238af7326112946971e6bb85a940da3d3127 100644 (file)
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 
 #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) {
index 57b90b6918c688fd2bc4c63df6c85bc802021eb7..d3d97327ed6521d51ea69df17e746d75a206f975 100644 (file)
@@ -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.
  *
index f1c9671a9eb6cd7d87e498b65fe0c40b70ba8e88..193fad290343597fb15ed78b9ed52c52434256f5 100644 (file)
@@ -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;
 }