From: Libor Peltan Date: Thu, 9 May 2019 17:48:12 +0000 (+0200) Subject: additionals_tree: using deduplicated dynarray for storing pointers in nodes X-Git-Tag: v2.9.0~274^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb8d6cd39af829d0be05e8593f6140a42cec729b;p=thirdparty%2Fknot-dns.git additionals_tree: using deduplicated dynarray for storing pointers in nodes --- diff --git a/src/contrib/dynarray.h b/src/contrib/dynarray.h index 211a18e277..5859fd6a51 100644 --- a/src/contrib/dynarray.h +++ b/src/contrib/dynarray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 CZ.NIC, z.s.p.o. +/* Copyright (C) 2019 CZ.NIC, z.s.p.o. 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 @@ -116,6 +116,53 @@ } \ \ __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); \ diff --git a/src/knot/zone/adds_tree.c b/src/knot/zone/adds_tree.c index 4dc25a0415..9414671d2c 100644 --- a/src/knot/zone/adds_tree.c +++ b/src/knot/zone/adds_tree.c @@ -19,19 +19,23 @@ #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; } diff --git a/src/knot/zone/adds_tree.h b/src/knot/zone/adds_tree.h index 7ec4252472..947277bffb 100644 --- a/src/knot/zone/adds_tree.h +++ b/src/knot/zone/adds_tree.h @@ -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;