]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
additionals_tree: using deduplicated dynarray for storing pointers in nodes
authorLibor Peltan <libor.peltan@nic.cz>
Thu, 9 May 2019 17:48:12 +0000 (19:48 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Tue, 14 May 2019 14:50:15 +0000 (16:50 +0200)
src/contrib/dynarray.h
src/knot/zone/adds_tree.c
src/knot/zone/adds_tree.h

index 211a18e277fae6275f3a2074de87343491a17248..5859fd6a517fb2ab0acf4f6ca73e95c4b7037715 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
        } \
        \
        __attribute__((unused)) \
+       visibility void prefix ## _dynarray_remove(struct prefix ## _dynarray *dynarray, \
+                                                  ntype const *to_remove) \
+       { \
+               ntype *orig_arr = prefix ## _dynarray_arr(dynarray); \
+               dynarray_foreach(prefix, ntype, removable, *dynarray) { \
+                       if (memcmp(removable, to_remove, sizeof(*to_remove)) == 0) { \
+                               if (removable != orig_arr + --dynarray->size) { \
+                                       *removable = orig_arr[dynarray->size]; \
+                               } \
+                       } \
+               } /* TODO enable lowering capacity, take care of capacity going back to initial! */ \
+       } \
+       \
+       __attribute__((unused)) \
+       static int prefix ## _dynarray_memb_cmp(const void *a, const void *b) { \
+               return memcmp(a, b, sizeof(ntype)); \
+       } \
+       \
+       __attribute__((unused)) \
+       visibility void prefix ## _dynarray_sort(struct prefix ## _dynarray *dynarray) \
+       { \
+               ntype *arr = prefix ## _dynarray_arr(dynarray); \
+               qsort(arr, dynarray->size, sizeof(*arr), prefix ## _dynarray_memb_cmp); \
+       } \
+       \
+       __attribute__((unused)) \
+       visibility void prefix ## _dynarray_sort_dedup(struct prefix ## _dynarray *dynarray) \
+       { \
+               if (dynarray->size > 1) { \
+                       prefix ## _dynarray_sort(dynarray); \
+                       ntype *arr = prefix ## _dynarray_arr(dynarray); \
+                       ntype *rd = arr + 1; \
+                       ntype *wr = arr + 1; \
+                       ntype *end = arr + dynarray->size; \
+                       while (rd != end) { \
+                               if (memcmp(rd - 1, rd, sizeof(*rd)) != 0) { \
+                                       if (wr != rd) { \
+                                               *wr = *rd; \
+                                       } \
+                                       wr++; \
+                               } \
+                               rd++; \
+                       } \
+                       dynarray->size = wr - arr; \
+               } \
+       } \
+       __attribute__((unused)) \
        visibility void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
        { \
                prefix ## _dynarray_free__(dynarray); \
index 4dc25a0415cd015c90aa77733c06e65ba01cca23..9414671d2cb4f75c5dcedfb4990fc7937c478083 100644 (file)
 
 #include "knot/zone/adds_tree.h"
 
+#include "contrib/dynarray.h"
 #include "libknot/error.h"
 #include "libknot/rrtype/rdname.h"
 
-static bool same_node(const zone_node_t *a, const zone_node_t *b)
-{
-       return (a == b || binode_counterpart((zone_node_t *)a) == b);
-}
+dynarray_declare(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_STATIC, 2)
+dynarray_define(nodeptr, zone_node_t *, DYNARRAY_VISIBILITY_STATIC)
+
+typedef struct {
+       nodeptr_dynarray_t array;
+       bool deduplicated;
+} a_t_node_t;
 
 static int free_a_t_node(trie_val_t *val, void *null)
 {
        assert(null == NULL);
-       list_t *nodes = *(list_t **)val;
-       ptrlist_free(nodes, NULL);
+       a_t_node_t *nodes = *(a_t_node_t **)val;
+       nodeptr_dynarray_free(&nodes->array);
        free(nodes);
        return 0;
 }
@@ -79,22 +83,17 @@ static int remove_node_from_a_t(const knot_dname_t *name, void *a_ctx)
                return KNOT_EOK;
        }
 
-       list_t *nodes = *(list_t **)val;
+       a_t_node_t *nodes = *(a_t_node_t **)val;
        if (nodes == NULL) {
-               goto rem_empty;
+               trie_del(ctx->a_t, lf + 1, *lf, NULL);
+               return KNOT_EOK;
        }
 
-       ptrnode_t *node_in_list = NULL, *next = NULL;
-       WALK_LIST_DELSAFE(node_in_list, next, *nodes) {
-               if (same_node(node_in_list->d, ctx->node)) {
-                       rem_node(&node_in_list->n);
-                       free(node_in_list);
-               }
-       }
+       nodeptr_dynarray_remove(&nodes->array, &ctx->node);
 
-       if (EMPTY_LIST(*nodes)) {
+       if (nodes->array.size == 0) {
+               nodeptr_dynarray_free(&nodes->array);
                free(nodes);
-rem_empty:
                trie_del(ctx->a_t, lf + 1, *lf, NULL);
        }
 
@@ -110,24 +109,15 @@ static int add_node_to_a_t(const knot_dname_t *name, void *a_ctx)
 
        trie_val_t *val = trie_get_ins(ctx->a_t, lf + 1, *lf);
        if (*val == NULL) {
-               *val = malloc(sizeof(list_t));
+               *val = calloc(1, sizeof(a_t_node_t));
                if (*val == NULL) {
                        return KNOT_ENOMEM;
                }
-               init_list(*(list_t **)val);
        }
 
-       list_t *nodes = *(list_t **)val;
-
-       ptrnode_t *node_in_list = NULL;
-       // TODO optimize more
-       WALK_LIST(node_in_list, *nodes) {
-               if (node_in_list->d == ctx->node) { // optimization: yes a bi-node can be stored twice, but solving it is too slow
-                       return KNOT_EOK;
-               }
-       }
-
-       ptrlist_add(nodes, ctx->node, NULL);
+       a_t_node_t *nodes = *(a_t_node_t **)val;
+       nodeptr_dynarray_add(&nodes->array, &ctx->node);
+       nodes->deduplicated = false;
        return KNOT_EOK;
 }
 
@@ -143,13 +133,13 @@ int additionals_tree_update_node(additionals_tree_t *a_t, const knot_dname_t *zo
 
        // for every additional in old_node rrsets, remove mentioning of this node in tree
        if (old_node != NULL && !(old_node->flags & NODE_FLAGS_DELETED)) {
-               ctx.node = old_node;
+               ctx.node = binode_node(old_node, false);
                ret = zone_node_additionals_foreach(old_node, zone_apex, remove_node_from_a_t, &ctx);
        }
 
        // for every additional in new_node rrsets, add reverse link into the tree
        if (new_node != NULL && !(new_node->flags & NODE_FLAGS_DELETED) && ret == KNOT_EOK) {
-               ctx.node = new_node;
+               ctx.node = binode_node(new_node, false);
                ret = zone_node_additionals_foreach(new_node, zone_apex, add_node_to_a_t, &ctx);
        }
        return ret;
@@ -202,14 +192,18 @@ int additionals_reverse_apply(additionals_tree_t *a_t, const knot_dname_t *name,
                return KNOT_EOK;
        }
 
-       list_t *nodes = *(list_t **)val;
+       a_t_node_t *nodes = *(a_t_node_t **)val;
        if (nodes == NULL) {
                return KNOT_EOK;
        }
 
-       ptrnode_t *node_in_list = NULL;
-       WALK_LIST(node_in_list, *nodes) {
-               int ret = cb(node_in_list->d, ctx);
+       if (!nodes->deduplicated) {
+               nodeptr_dynarray_sort_dedup(&nodes->array);
+               nodes->deduplicated = true;
+       }
+
+       dynarray_foreach(nodeptr, zone_node_t *, node_in_arr, nodes->array) {
+               int ret = cb(*node_in_arr, ctx);
                if (ret != KNOT_EOK) {
                        return ret;
                }
index 7ec4252472714301be732201b58fa785445402a8..947277bffbf495be77907ebfd55096eefedf1dfc 100644 (file)
@@ -17,7 +17,6 @@
 #pragma once
 
 #include "contrib/qp-trie/trie.h"
-#include "contrib/ucw/lists.h"
 #include "knot/zone/contents.h"
 
 typedef trie_t additionals_tree_t;