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