-/* 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); \
#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;
}
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);
}
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;
}
// 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;
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;
}