From 5b714e5235e491f064d007c78a10496d909a3414 Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek.vavrusa@nic.cz> Date: Wed, 13 Feb 2013 14:42:30 +0100 Subject: [PATCH] Use trie along with AVL tree to check for differences. Needs cleanup, just to make things work for a while. --- src/libknot/zone/zone-contents.c | 46 ++-- src/libknot/zone/zone-tree-avl.c | 392 +++++++++++++++++++++++++++++++ src/libknot/zone/zone-tree.c | 206 +++++++++++++--- src/libknot/zone/zone-tree.h | 22 +- src/libknot/zone/zone.c | 2 +- 5 files changed, 606 insertions(+), 62 deletions(-) create mode 100644 src/libknot/zone/zone-tree-avl.c diff --git a/src/libknot/zone/zone-contents.c b/src/libknot/zone/zone-contents.c index cf813de9e..c1027e2a0 100644 --- a/src/libknot/zone/zone-contents.c +++ b/src/libknot/zone/zone-contents.c @@ -60,7 +60,7 @@ static void tree_apply_cb(knot_zone_tree_node_t *node, } knot_zone_tree_func_t *f = (knot_zone_tree_func_t *)data; - f->func(node, f->data); + f->func(node->node, f->data); } /*----------------------------------------------------------------------------*/ @@ -117,10 +117,11 @@ static void knot_zone_contents_destroy_node_rrsets_from_tree( knot_zone_tree_node_t *tnode, void *data) { assert(tnode != NULL); + knot_node_t *node = tnode->node; int free_rdata_dnames = (int)((intptr_t)data); - knot_node_free_rrsets(tnode, free_rdata_dnames); - knot_node_free(&tnode); + knot_node_free_rrsets(node, free_rdata_dnames); + knot_node_free(&node); } /*----------------------------------------------------------------------------*/ @@ -438,7 +439,7 @@ static void knot_zone_contents_adjust_node_in_tree( assert(tnode != NULL); knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; - knot_node_t *node = tnode; + knot_node_t *node = tnode->node; if (args->err != KNOT_EOK) { dbg_xfrin_detail("Error during adjusting: %s, skipping node.\n", @@ -470,7 +471,7 @@ static void knot_zone_contents_adjust_node_in_tree_ptr( assert(tnode != NULL); knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; - knot_node_t *node = tnode; + knot_node_t *node = tnode->node; /* * 1) Set previous node pointer. @@ -505,7 +506,7 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree( { assert(data != NULL); assert(tnode != NULL); - knot_node_t *node = tnode; + knot_node_t *node = tnode->node; knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; @@ -545,7 +546,7 @@ static void knot_zone_contents_adjust_nsec3_node_in_tree_ptr( assert(tnode != NULL); knot_zone_adjust_arg_t *args = (knot_zone_adjust_arg_t *)data; - knot_node_t *node = tnode; + knot_node_t *node = tnode->node; // set previous node knot_node_set_previous(node, args->previous_node); @@ -790,7 +791,7 @@ static void knot_zone_contents_check_loops_in_tree(knot_zone_tree_node_t *tnode, assert(data != NULL); loop_check_data_t *args = (loop_check_data_t *)data; - const knot_node_t *node = tnode; + const knot_node_t *node = tnode->node; assert(args->zone != NULL); @@ -889,7 +890,7 @@ static int knot_zc_nsec3_parameters_match(const knot_rrset_t *rrset, /*----------------------------------------------------------------------------*/ knot_zone_contents_t *knot_zone_contents_new(knot_node_t *apex, - uint node_count, + size_t node_count, int use_domain_table, struct knot_zone *zone) { @@ -1865,6 +1866,10 @@ int knot_zone_contents_adjust(knot_zone_contents_t *zone) if (zone == NULL) { return KNOT_EINVAL; } + + /* Heal zone indexes. */ + hattrie_build_index(zone->nodes->T); + hattrie_build_index(zone->nsec3_nodes->T); // load NSEC3PARAM (needed on adjusting function) knot_zone_contents_load_nsec3param(zone); @@ -2665,13 +2670,14 @@ void reset_child_count(knot_zone_tree_node_t *tree_node, void *data) assert(tree_node != NULL); assert(data != NULL); + knot_node_t *node = tree_node->node; knot_node_t **apex_copy = (knot_node_t **)data; if (*apex_copy == NULL) { - *apex_copy = tree_node; + *apex_copy = node; } if (tree_node != NULL) { - tree_node->children = 0; + node->children = 0; } } @@ -2680,11 +2686,12 @@ void reset_child_count(knot_zone_tree_node_t *tree_node, void *data) void count_children(knot_zone_tree_node_t *tree_node, void *data) { UNUSED(data); - if (tree_node != NULL && tree_node->parent != NULL) { - assert(tree_node->parent->new_node != NULL); + knot_node_t *node = tree_node->node; + if (node != NULL && node->parent != NULL) { + assert(node->parent->new_node != NULL); // fix parent pointer - tree_node->parent = tree_node->parent->new_node; - ++tree_node->parent->children; + node->parent = node->parent->new_node; + ++node->parent->children; } } @@ -2696,7 +2703,7 @@ void check_child_count(knot_zone_tree_node_t *tree_node, void *data) assert(data != NULL); check_data_t *check_data = (check_data_t *)data; - knot_node_t *node = tree_node; + knot_node_t *node = tree_node->node; // find corresponding node in the given contents const knot_node_t *found = NULL; @@ -2723,7 +2730,8 @@ static void reset_new_nodes(knot_zone_tree_node_t *tree_node, void *data) assert(tree_node != NULL); UNUSED(data); - knot_node_set_new_node(tree_node, NULL); + knot_node_t *node = tree_node->node; + knot_node_set_new_node(node, NULL); } ///*----------------------------------------------------------------------------*/ @@ -2853,13 +2861,13 @@ static void find_dname_in_rdata(knot_zone_tree_node_t *node, void *data) } /* For all RRSets in node. */ - const knot_rrset_t **rrsets = knot_node_rrsets(node); + const knot_rrset_t **rrsets = knot_node_rrsets(node->node); if (rrsets == NULL) { return; } - for (unsigned short i = 0; i < node->rrset_count; i++) { + for (unsigned short i = 0; i < node->node->rrset_count; i++) { knot_dname_t *dname = NULL; /* For all DNAMEs in RRSet. */ while ((dname = knot_rrset_get_next_dname(rrsets[i], NULL))!=NULL) { diff --git a/src/libknot/zone/zone-tree-avl.c b/src/libknot/zone/zone-tree-avl.c new file mode 100644 index 000000000..b06815ded --- /dev/null +++ b/src/libknot/zone/zone-tree-avl.c @@ -0,0 +1,392 @@ +/* AVL implementation for checking. */ + +TREE_DEFINE(knot_zone_tree_node, avl); + +static int knot_zone_tree_node_compare(knot_zone_tree_node_t *node1, + knot_zone_tree_node_t *node2) +{ + assert(node1 != NULL); + assert(node2 != NULL); + assert(node1->node != NULL); + assert(node2->node != NULL); + assert(knot_node_owner(node1->node) != NULL); + assert(knot_node_owner(node2->node) != NULL); + + return knot_node_compare(node1->node, node2->node); +} + +static void knot_zone_tree_free_node(knot_zone_tree_node_t *node, + int free_data) +{ + if (node == NULL) { + return; + } + + knot_zone_tree_free_node(node->avl.avl_left, free_data); + + knot_zone_tree_free_node(node->avl.avl_right, free_data); + + if (free_data) { + knot_node_free(&node->node); + } + + free(node); +} + +static void knot_zone_tree_delete_subtree(knot_zone_tree_node_t *root) +{ + if (root == NULL) { + return; + } + + knot_zone_tree_delete_subtree(root->avl.avl_left); + knot_zone_tree_delete_subtree(root->avl.avl_right); + free(root); +} + +static int knot_zone_tree_copy_node(knot_zone_tree_node_t *from, + knot_zone_tree_node_t **to) +{ + if (from == NULL) { + *to = NULL; + return KNOT_EOK; + } + + *to = (knot_zone_tree_node_t *) + malloc(sizeof(knot_zone_tree_node_t)); + if (*to == NULL) { + return KNOT_ENOMEM; + } + + (*to)->node = from->node; + (*to)->avl.avl_height = from->avl.avl_height; + + int ret = knot_zone_tree_copy_node(from->avl.avl_left, + &(*to)->avl.avl_left); + if (ret != KNOT_EOK) { + return ret; + } + + ret = knot_zone_tree_copy_node(from->avl.avl_right, + &(*to)->avl.avl_right); + if (ret != KNOT_EOK) { + knot_zone_tree_delete_subtree((*to)->avl.avl_left); + (*to)->avl.avl_left = NULL; + free(*to); + *to = NULL; + return ret; + } + + return KNOT_EOK; +} + + +static int knot_zone_tree_deep_copy_node(knot_zone_tree_node_t *from, + knot_zone_tree_node_t **to) +{ + if (from == NULL) { + *to = NULL; + return KNOT_EOK; + } + + *to = (knot_zone_tree_node_t *)malloc(sizeof(knot_zone_tree_node_t)); + if (*to == NULL) { + return KNOT_ENOMEM; + } + + int ret = knot_node_shallow_copy(from->node, &(*to)->node); + + if (ret != KNOT_EOK) { + dbg_zone_verb("Failed to do shallow copy of node.\n"); + free(*to); + return ret; + } + + (*to)->avl.avl_height = from->avl.avl_height; + + ret = knot_zone_tree_deep_copy_node(from->avl.avl_left, + &(*to)->avl.avl_left); + if (ret != KNOT_EOK) { + dbg_zone_verb("Failed to do shallow copy of left subtree.\n"); + return ret; + } + + ret = knot_zone_tree_deep_copy_node(from->avl.avl_right, + &(*to)->avl.avl_right); + if (ret != KNOT_EOK) { + dbg_zone_verb("Failed to do shallow copy of right subtree.\n"); + knot_zone_tree_free_node((*to)->avl.avl_left, 1); + (*to)->avl.avl_left = NULL; + knot_node_free(&(*to)->node); + free(*to); + *to = NULL; + return ret; + } + + knot_node_set_new_node(from->node, (*to)->node); + + return KNOT_EOK; +} + +static void avl_create(knot_zone_avl_tree_t *tree) +{ + TREE_INIT(tree, knot_zone_tree_node_compare); +} + +static int avl_insert(knot_zone_avl_tree_t *tree, knot_zone_tree_node_t *znode) +{ + znode->avl.avl_left = NULL; + znode->avl.avl_right = NULL; + znode->avl.avl_height = 0; + + /*! \todo How to know if this was successful? */ + TREE_INSERT(tree, knot_zone_tree_node, avl, znode); + + return KNOT_EOK; +} + + +int avl_get(knot_zone_avl_tree_t *tree, const knot_dname_t *owner, + knot_node_t **found) +{ + if (tree == NULL || owner == NULL) { + return KNOT_EINVAL; + } + + *found = NULL; + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, + tmp); + + knot_node_free(&tmp_data); + free(tmp); + + if (n != NULL) { + *found = n->node; + } + + return KNOT_EOK; +} + +int avl_get_less_or_equal(knot_zone_avl_tree_t *tree, + const knot_dname_t *owner, + knot_node_t **found, + knot_node_t **previous) +{ + if (tree == NULL || owner == NULL || found == NULL + || previous == NULL) { + return KNOT_EINVAL; + } + + knot_zone_tree_node_t *f = NULL, *prev = NULL; + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + int exact_match = TREE_FIND_LESS_EQUAL( + tree, knot_zone_tree_node, avl, tmp, &f, &prev); + + knot_node_free(&tmp_data); + free(tmp); + + *found = (exact_match > 0) ? f->node : NULL; + + dbg_zone_exec_detail( + char *name = knot_dname_to_str(owner); + char *name_f = (*found != NULL) + ? knot_dname_to_str(knot_node_owner(*found)) + : "none"; + + dbg_zone_detail("Searched for owner %s in zone tree.\n", + name); + dbg_zone_detail("Exact match: %d\n", ret); + dbg_zone_detail("Found node: %p: %s.\n", *found, name_f); + dbg_zone_detail("Previous node: %p.\n", *previous); + + free(name); + if (*found != NULL) { + free(name_f); + } + ); + + if (exact_match < 0) { + // previous is not really previous but should be the leftmost + // node in the tree; take it's previous + assert(prev != NULL); + *previous = knot_node_get_previous(prev->node); + exact_match = 0; + } else if (prev == NULL) { + // either the returned node is the root of the tree, or + // it is the leftmost node in the tree; in both cases + // node was found set the previous node of the found + // node + assert(exact_match > 0); + assert(f != NULL); + *previous = knot_node_get_previous(f->node); + } else { + // otherwise check if the previous node is not an empty + // non-terminal + /*! \todo Here we assume that the 'prev' pointer always points + * to an empty non-terminal. + */ + /*! \todo What did I mean by the previous TODO?? + * Nevertheless, it seems to me that node->prev can be + * an empty non-terminal too, cannot it? + */ + dbg_zone_detail("Previous: %p\n", prev->node); + *previous = (knot_node_rrset_count(prev->node) == 0) + ? knot_node_get_previous(prev->node) + : prev->node; + dbg_zone_detail("Previous: %p, is empty: %d\n", *previous, + (*previous) ? knot_node_is_empty(*previous) + : -1); + } + + assert(exact_match >= 0); + + return exact_match; +} + +int avl_remove(knot_zone_avl_tree_t *tree, + const knot_dname_t *owner, + knot_zone_tree_node_t **removed) +{ + if (tree == NULL || owner == NULL || removed == NULL) { + return KNOT_EINVAL; + } + + // create dummy node to use for lookup + knot_zone_tree_node_t *tmp = (knot_zone_tree_node_t *)malloc( + sizeof(knot_zone_tree_node_t)); + if (tmp == NULL) { + return KNOT_ENOMEM; + } + + // create dummy data node to use for lookup + knot_node_t *tmp_data = knot_node_new( + (knot_dname_t *)owner, NULL, 0); + if (tmp_data == NULL) { + free(tmp); + return KNOT_ENOMEM; + } + tmp->node = tmp_data; + + // we must first find the node, so that it may be destroyed + knot_zone_tree_node_t *n = TREE_FIND(tree, knot_zone_tree_node, avl, + tmp); + + /*! \todo How to know if this was successful? */ + TREE_REMOVE(tree, knot_zone_tree_node, avl, tmp); + + knot_node_free(&tmp_data); + free(tmp); + + *removed = n; + + return KNOT_EOK; +} + +int avl_forward_apply_inorder(knot_zone_avl_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EINVAL; + } + + TREE_FORWARD_APPLY(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +int avl_forward_apply_postorder(knot_zone_avl_tree_t *tree, + void (*function)( + knot_zone_tree_node_t *node, + void *data), + void *data) +{ + if (tree == NULL || function == NULL) { + return KNOT_EINVAL; + } + + TREE_POST_ORDER_APPLY(tree, knot_zone_tree_node, avl, + function, data); + + return KNOT_EOK; +} + +int avl_shallow_copy(knot_zone_avl_tree_t *from, + knot_zone_avl_tree_t *to) +{ + if (to == NULL || from == NULL) { + return KNOT_EINVAL; + } + /* + * This function will copy the tree by hand, so that the nodes + * do not have to be inserted the normal way. It should be substantially + * faster. + */ + + to->th_cmp = from->th_cmp; + + return knot_zone_tree_copy_node(from->th_root, &to->th_root); +} + +int avl_deep_copy(knot_zone_avl_tree_t *from, + knot_zone_avl_tree_t *to) +{ + if (to == NULL || from == NULL) { + return KNOT_EINVAL; + } + /* + * This function will copy the tree by hand, so that the nodes + * do not have to be inserted the normal way. It should be substantially + * faster. + */ + + to->th_cmp = from->th_cmp; + + return knot_zone_tree_deep_copy_node(from->th_root, &to->th_root); +} + +void avl_free(knot_zone_avl_tree_t *tree) +{ + if (tree == NULL) { + return; + } + knot_zone_tree_free_node(tree->th_root, 0); +} + + diff --git a/src/libknot/zone/zone-tree.c b/src/libknot/zone/zone-tree.c index fd3061b98..d20a79207 100644 --- a/src/libknot/zone/zone-tree.c +++ b/src/libknot/zone/zone-tree.c @@ -18,40 +18,90 @@ #include <stdlib.h> #include <stdio.h> -#include "common/hattrie/hat-trie.h" -#include "zone-tree.h" +#include "zone/zone-tree.h" #include "zone/node.h" #include "util/debug.h" +#include "common/hattrie/hat-trie.h" /*----------------------------------------------------------------------------*/ /* Non-API functions */ /*----------------------------------------------------------------------------*/ +typedef char dname_lft; /* dname lookup format */ +#define DNAME_LFT_MAXLEN 256 /* maximum lookup format length */ + +static int dname_lf(dname_lft *dst, const knot_dname_t *src, size_t nb) { + if (src->size > nb) return KNOT_ESPACE; + *dst++ = src->size - 1; + *dst = '\0'; +// dname_lft* pdst = dst; + uint8_t* l = src->name; + uint8_t lstack[127]; + uint8_t *sp = lstack; + while(*l != 0) { /* build label stack */ + *sp++ = (l - src->name); + l += 1 + *l; + } + while(sp != lstack) { /* consume stack */ + l = src->name + *--sp; /* fetch rightmost label */ + memcpy(dst, l+1, *l); /* write label */ + dst += *l; + *dst++ = '\0'; /* label separator */ + } + +// /*! DEBUG ---> */ +// printf("dname_lf: '%s' => '", knot_dname_to_str(src)); +// for(unsigned i = 0; i < src->size - 1; ++i) { +// dname_lft *c = pdst + i; +// if (*c == '\0') printf("0"); +// else printf("%c", *c); +// } +// printf("'\n"); +// /*! <--- DEBUG */ + return KNOT_EOK; +} + +/* TAG:AVL */ +#include "libknot/zone/zone-tree-avl.c" + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ knot_zone_tree_t* knot_zone_tree_create() { - return hattrie_create(); + knot_zone_tree_t *tree = malloc(sizeof(knot_zone_tree_t)); + if (!tree) return NULL; + tree->T = hattrie_create(); + + /* TAG:AVL */ + avl_create(&tree->avl); + return tree; } /*----------------------------------------------------------------------------*/ size_t knot_zone_tree_weight(knot_zone_tree_t* tree) { - return hattrie_weight(tree); + return hattrie_weight(tree->T); } /*----------------------------------------------------------------------------*/ int knot_zone_tree_insert(knot_zone_tree_t *tree, knot_node_t *node) { - char *tmp = knot_dname_to_str(node->owner); - free(tmp); assert(tree && node && node->owner); - knot_dname_t* owner = node->owner; - *hattrie_get(tree, owner->name, owner->size) = node; + dname_lft lf[DNAME_LFT_MAXLEN]; + dname_lf(lf, node->owner, sizeof(lf)); + + knot_zone_tree_node_t *n = malloc(sizeof(knot_zone_tree_node_t)); + memset(n, 0, sizeof(knot_zone_tree_node_t)); + n->node = node; + + *hattrie_get(tree->T, lf+1, *lf) = n; + + /* TAG:AVL */ + avl_insert(&tree->avl, n); return KNOT_EOK; } @@ -78,15 +128,23 @@ int knot_zone_tree_get(knot_zone_tree_t *tree, const knot_dname_t *owner, if (tree == NULL || owner == NULL) { return KNOT_EINVAL; } + + dname_lft lf[DNAME_LFT_MAXLEN]; + dname_lf(lf, owner, sizeof(lf)); - value_t *val = hattrie_tryget(tree, owner->name, owner->size); + value_t *val = hattrie_tryget(tree->T, lf+1, *lf); if (val == NULL) { *found = NULL; -// return KNOT_ENOENT; } else { - *found = *val; + *found = ((knot_zone_tree_node_t*)(*val))->node; } - + + /* TAG:AVL */ + knot_node_t *avl_found = NULL; + avl_get(&tree->avl, owner, &avl_found); + if (avl_found != *found) + fprintf(stderr, "%s: avl=%p, ht=%p\n", __func__, avl_found, *found); + return KNOT_EOK; } @@ -101,7 +159,7 @@ int knot_zone_tree_find_less_or_equal(knot_zone_tree_t *tree, return KNOT_EINVAL; } - knot_node_t *f, *p; + knot_node_t *f = NULL, *p = NULL; int ret = knot_zone_tree_get_less_or_equal(tree, owner, &f, &p); *found = f; @@ -117,30 +175,33 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree, knot_node_t **found, knot_node_t **previous) { - assert(0); if (tree == NULL || owner == NULL || found == NULL || previous == NULL) { return KNOT_EINVAL; } + + dname_lft lf[DNAME_LFT_MAXLEN]; + dname_lf(lf, owner, sizeof(lf)); value_t* fval = NULL; - int ret = hattrie_find_leq(tree, owner->name, owner->size, &fval); - *found = *fval; + int ret = hattrie_find_leq(tree->T, lf+1, *lf, &fval); + if (*fval) *found = ((knot_zone_tree_node_t *)(*fval))->node; + int exact_match = 0; if (ret == 0) { *previous = knot_node_get_previous(*found); - } - if (ret < 0) { + exact_match = 1; + } else if (ret < 0) { *previous = *found; *found = NULL; - ret = 0; /*! \todo why? */ - } - if (ret > 0) { + } else if (ret > 0) { /* node is before first node in the trie */ assert(0); } - /*! \todo handle non-terminals ? */ - assert(!*previous || knot_node_rrset_count(*previous) > 0); + /* Check if previous node is not an empty non-terminal. */ + if (knot_node_rrset_count(*previous) == 0) { + *previous = knot_node_get_previous(*previous); + } dbg_zone_exec_detail( char *name = knot_dname_to_str(owner); @@ -150,7 +211,7 @@ dbg_zone_exec_detail( dbg_zone_detail("Searched for owner %s in zone tree.\n", name); - dbg_zone_detail("Exact match: %d\n", ret); + dbg_zone_detail("Exact match: %d\n", exact_match); dbg_zone_detail("Found node: %p: %s.\n", *found, name_f); dbg_zone_detail("Previous node: %p.\n", *previous); @@ -159,8 +220,24 @@ dbg_zone_exec_detail( free(name_f); } ); + + /* TAG:AVL */ + knot_node_t *avl_found = NULL; + knot_node_t *avl_prev = NULL; + int avl_em = avl_get_less_or_equal(&tree->avl, owner, &avl_found, &avl_prev); + if(!(exact_match == avl_em && *found == avl_found && *previous == avl_prev)) { + fprintf(stderr, "%s: '%s' (ht,avl)\n...exact_match=(%d,%d)\n...found=(%s, %s)\n...prev=(%s, %s)\n", + __func__, knot_dname_to_str(owner), exact_match, avl_em, + knot_dname_to_str((*found)->owner), + knot_dname_to_str(avl_found->owner), + knot_dname_to_str((*previous)->owner), + knot_dname_to_str(avl_prev->owner)); + assert(knot_node_compare(*previous, avl_prev) >= 0 && knot_node_compare(*previous, *found) < 0); + + } + - return ret; + return exact_match; } /*----------------------------------------------------------------------------*/ @@ -172,13 +249,26 @@ int knot_zone_tree_remove(knot_zone_tree_t *tree, if (tree == NULL || owner == NULL) { return KNOT_EINVAL; } + + dname_lft lf[DNAME_LFT_MAXLEN]; + dname_lf(lf, owner, sizeof(lf)); - *removed = hattrie_tryget(tree, owner->name, owner->size); - if (*removed == NULL) { + value_t *rval = hattrie_tryget(tree->T, lf+1, *lf); + if (rval == NULL) { return KNOT_ENOENT; + } else { + *removed = (*rval); } - hattrie_del(tree, owner->name, owner->size); + + hattrie_del(tree->T, lf+1, *lf); + + /* TAG:AVL */ + knot_zone_tree_node_t *avl_removed = NULL; + avl_remove(&tree->avl, owner, &avl_removed); + if (*removed != avl_removed) + fprintf(stderr, "%s: ht=%p, avl=%p\n", __func__, *removed, avl_removed); + return KNOT_EOK; } @@ -193,12 +283,15 @@ int knot_zone_tree_apply_inorder(knot_zone_tree_t *tree, return KNOT_EINVAL; } - hattrie_iter_t *i = hattrie_iter_begin(tree, 1); + hattrie_iter_t *i = hattrie_iter_begin(tree->T, 1); while(!hattrie_iter_finished(i)) { function(*hattrie_iter_val(i), data); hattrie_iter_next(i); } hattrie_iter_free(i); + + /* TAG:AVL */ +// avl_forward_apply_inorder(&tree->avl, function, data); return KNOT_EOK; } @@ -207,7 +300,7 @@ int knot_zone_tree_apply_inorder(knot_zone_tree_t *tree, int knot_zone_tree_apply_recursive(knot_zone_tree_t *tree, void (*function)( - knot_node_t *node, + knot_zone_tree_node_t *node, void *data), void *data) { @@ -215,7 +308,11 @@ int knot_zone_tree_apply_recursive(knot_zone_tree_t *tree, return KNOT_EINVAL; } - hattrie_apply_rev(tree, function, data); + hattrie_apply_rev(tree->T, (void (*)(void*,void*))function, data); + + /* TAG:AVL */ +// avl_forward_apply_postorder(&tree->avl, function, data); + return KNOT_EOK; } @@ -223,20 +320,38 @@ int knot_zone_tree_apply_recursive(knot_zone_tree_t *tree, /*----------------------------------------------------------------------------*/ int knot_zone_tree_apply(knot_zone_tree_t *tree, - void (*function)(knot_node_t *node, void *data), + void (*function)(knot_zone_tree_node_t *node, void *data), void *data) { - hattrie_iter_t *i = hattrie_iter_begin(tree, 0); + hattrie_iter_t *i = hattrie_iter_begin(tree->T, 0); while(!hattrie_iter_finished(i)) { function(*hattrie_iter_val(i), data); hattrie_iter_next(i); } hattrie_iter_free(i); + + /* TAG:AVL */ +// avl_forward_apply_inorder(&tree->avl, function, data); + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ +value_t knot_zone_node_copy(value_t v) { + knot_zone_tree_node_t *n = (knot_zone_tree_node_t *)v; + knot_zone_tree_node_t *nv = malloc(sizeof(knot_zone_tree_node_t)); + nv->node = n->node; + return (value_t)nv; +} + +value_t knot_zone_node_deep_copy(value_t v) { + knot_zone_tree_node_t *n = (knot_zone_tree_node_t *)v; + knot_zone_tree_node_t *nv = malloc(sizeof(knot_zone_tree_node_t)); + knot_node_shallow_copy(n->node, &nv->node); + return (value_t)nv; +} + int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, knot_zone_tree_t **to) { @@ -244,7 +359,12 @@ int knot_zone_tree_shallow_copy(knot_zone_tree_t *from, return KNOT_EINVAL; } - *to = hattrie_dup(from); + *to = malloc(sizeof(knot_zone_tree_t)); + (*to)->T = hattrie_dup(from->T, knot_zone_node_copy); + + /* TAG:AVL */ + avl_shallow_copy(&from->avl, &(*to)->avl); + return KNOT_EOK; } @@ -257,7 +377,11 @@ int knot_zone_tree_deep_copy(knot_zone_tree_t *from, return KNOT_EINVAL; } - *to = hattrie_dup(from); + *to = malloc(sizeof(knot_zone_tree_t)); + (*to)->T = hattrie_dup(from->T, knot_zone_node_deep_copy); + + /* TAG:AVL */ + avl_deep_copy(&from->avl, &(*to)->avl); return KNOT_EOK; } @@ -268,8 +392,10 @@ void knot_zone_tree_free(knot_zone_tree_t **tree) if (tree == NULL || *tree == NULL) { return; } - hattrie_free(*tree); - *tree = NULL; + hattrie_free((*tree)->T); + + /* TAG:AVL */ + avl_free(&(*tree)->avl); } /*----------------------------------------------------------------------------*/ @@ -282,8 +408,10 @@ void knot_zone_tree_deep_free(knot_zone_tree_t **tree) /*! \todo free node data */ - hattrie_free(*tree); - *tree = NULL; + knot_zone_tree_free(tree); + + /* TAG:AVL */ + knot_zone_tree_free_node((*tree)->avl.th_root, 1); } /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/zone/zone-tree.h b/src/libknot/zone/zone-tree.h index bba641c0d..8a6df7619 100644 --- a/src/libknot/zone/zone-tree.h +++ b/src/libknot/zone/zone-tree.h @@ -30,15 +30,31 @@ #define _KNOT_ZONE_TREE_H_ #include "common/hattrie/hat-trie.h" +#include "common/tree.h" #include "zone/node.h" /*----------------------------------------------------------------------------*/ -typedef knot_node_t knot_zone_tree_node_t; +/* TAG:AVL */ +typedef struct knot_zone_tree_node { + /*! \brief Structure for connecting this node to an AVL tree. */ + TREE_ENTRY(knot_zone_tree_node) avl; + /*! \brief Zone tree data. */ + knot_node_t *node; +} knot_zone_tree_node_t; /*----------------------------------------------------------------------------*/ -typedef hattrie_t knot_zone_tree_t; +/* TAG:AVL */ +typedef TREE_HEAD(knot_zone_tree, knot_zone_tree_node) knot_zone_avl_tree_t; + +/*----------------------------------------------------------------------------*/ + +/* TAG:AVL */ +typedef struct { + hattrie_t *T; + knot_zone_avl_tree_t avl; +} knot_zone_tree_t; /*----------------------------------------------------------------------------*/ /*! @@ -214,7 +230,7 @@ int knot_zone_tree_apply_recursive(knot_zone_tree_t *tree, * \retval KNOT_EINVAL */ int knot_zone_tree_apply(knot_zone_tree_t *tree, - void (*function)(knot_node_t *node, void *data), + void (*function)(knot_zone_tree_node_t *node, void *data), void *data); /*! diff --git a/src/libknot/zone/zone.c b/src/libknot/zone/zone.c index 5783c5b02..fb1c28c7b 100644 --- a/src/libknot/zone/zone.c +++ b/src/libknot/zone/zone.c @@ -69,7 +69,7 @@ knot_zone_t *knot_zone_new_empty(knot_dname_t *name) /*----------------------------------------------------------------------------*/ -knot_zone_t *knot_zone_new(knot_node_t *apex, uint node_count, +knot_zone_t *knot_zone_new(knot_node_t *apex, size_t node_count, int use_domain_table) { knot_zone_t *zone = knot_zone_new_empty( -- GitLab