Commit 73d62a89 authored by David Lawrence's avatar David Lawrence
Browse files

A variety of changes.

  dns_rbt_node_t changed to dns_rbtnode_t to match ISC conventions.

  main() test routine and support functions removed, to be put in
    bin/tests/rbt_test.c

  adding a node and rotating left/right taught to not use parent pointers.

  deletion disabled because it currently does not know how to not use
    parent pointers, and since they are not being maintained by insertion,
    deleting has no prayer of working.

  several isc_result_t returns changed to dns_result_t.
parent 10c05796
/*
* Copyright (C) 1999 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <isc/result.h>
#include <isc/region.h>
#include <isc/mem.h>
#include <dns/types.h>
#include <dns/name.h>
......@@ -26,8 +43,8 @@ typedef struct dns_rbt_node {
struct dns_rbt_node *down;
enum { red, black } color;
void *data;
int name_length;
} dns_rbt_node_t;
unsigned int name_length;
} dns_rbtnode_t;
isc_result_t dns_rbt_create(isc_mem_t *mctx, dns_rbt_t **rbtp);
void dns_rbt_destroy(dns_rbt_t **rbtp);
......@@ -87,7 +104,7 @@ isc_result_t dns_rbt_delete_name(dns_rbt_t *rbt, dns_name_t *name);
* will likely cause grief.
*
*/
void dns_rbt_namefromnode(dns_rbt_node_t *node, dns_name_t *name);
void dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
/*
* Find the node for 'name'.
......@@ -102,8 +119,8 @@ void dns_rbt_namefromnode(dns_rbt_node_t *node, dns_name_t *name);
* It is _not_ required that the node associated with 'name'
* has a non-NULL data pointer.
*/
dns_rbt_node_t *dns_rbt_find_node(dns_rbt_t *rbt,
dns_name_t *name, dns_rbt_node_t **up);
dns_rbtnode_t *dns_rbt_find_node(dns_rbt_t *rbt,
dns_name_t *name, dns_rbtnode_t **up);
/*
* Return the data pointer associated with 'name'.
......@@ -113,3 +130,8 @@ dns_rbt_node_t *dns_rbt_find_node(dns_rbt_t *rbt,
* if the name is found but has a NULL data pointer.
*/
void *dns_rbt_find_name(dns_rbt_t *rbt, dns_name_t *name);
void dns_rbt_indent(int depth);
void dns_rbt_printnodename(dns_rbtnode_t *node);
void dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent, int depth);
void dns_rbt_printall(dns_rbt_t *rbt);
/*
* Copyright (C) 1996, 1997, 1998, 1999 Internet Software Consortium.
* Copyright (C) 1999 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -24,8 +24,10 @@
#include <isc/assertions.h>
#include <isc/error.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <dns/redblack.h>
#include <dns/rbt.h>
#include <dns/result.h>
#define RBT_MAGIC 0x5242542BU /* RBT+. */
#define VALID_RBT(rbt) ((rbt) != NULL && (rbt)->magic == RBT_MAGIC)
......@@ -33,9 +35,13 @@
struct dns_rbt {
unsigned int magic;
isc_mem_t * mctx;
dns_rbt_node_t * root;
dns_rbtnode_t * root;
};
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#define PARENT(node) ((node)->parent)
#define LEFT(node) ((node)->left)
#define RIGHT(node) ((node)->right)
......@@ -67,9 +73,9 @@ struct dns_rbt {
/*
* A little something to help out in GDB.
*/
isc_region_t Name(dns_rbt_node_t *node);
isc_region_t Name(dns_rbtnode_t *node);
isc_region_t
Name(dns_rbt_node_t *node) {
Name(dns_rbtnode_t *node) {
isc_region_t r;
r.length = NAMELEN(node);
......@@ -80,37 +86,35 @@ Name(dns_rbt_node_t *node) {
#else
#endif
#if 0
dns_rbt_node_t *Root; /* The Root of All Ev... er, DNS. */
#endif
/*
* Forward declarations.
*/
static isc_result_t create_node(isc_mem_t *mctx,
dns_name_t *name, dns_rbt_node_t **nodep);
static dns_result_t create_node(isc_mem_t *mctx,
dns_name_t *name, dns_rbtnode_t **nodep);
static int cmp_label(dns_label_t *a, dns_label_t *b);
static inline int cmp_names_on_level(dns_name_t *a, dns_name_t *b);
static inline int cmp_names_for_depth(dns_name_t *a, dns_name_t *b);
static inline void rotate_left(dns_rbt_node_t *node, dns_rbt_node_t **rootp);
static inline void rotate_right(dns_rbt_node_t *node, dns_rbt_node_t **rootp);
static inline void rotate_left(dns_rbtnode_t *node, dns_rbtnode_t *parent,
dns_rbtnode_t **rootp);
static inline void rotate_right(dns_rbtnode_t *node, dns_rbtnode_t *parent,
dns_rbtnode_t **rootp);
static isc_result_t dns_rbt_add_node(dns_rbt_node_t *node,
dns_rbt_node_t **rootp);
static isc_result_t dns_rbt_delete_workhorse(dns_rbt_node_t *delete,
dns_rbt_node_t **rootp);
static void dns_rbt_delete_node(isc_mem_t *mctx,
dns_rbt_node_t *node, dns_rbt_node_t **root);
static void dns_rbt_delete_tree(isc_mem_t *mctx,
dns_rbt_node_t *node, dns_rbt_node_t **root);
static dns_result_t dns_rbt_add_node(dns_rbtnode_t *node,
dns_rbtnode_t **rootp);
static dns_result_t dns_rbt_delete_workhorse(dns_rbtnode_t *delete,
dns_rbtnode_t **rootp);
static void dns_rbt_deletenode(isc_mem_t *mctx,
dns_rbtnode_t *node, dns_rbtnode_t **root);
static void dns_rbt_deletetree(isc_mem_t *mctx,
dns_rbtnode_t *node, dns_rbtnode_t **root);
/*
* Initialize a red/black tree of trees.
*/
isc_result_t
dns_result_t
dns_rbt_create(isc_mem_t *mctx, dns_rbt_t **rbtp) {
dns_rbt_t *rbt;
......@@ -119,7 +123,7 @@ dns_rbt_create(isc_mem_t *mctx, dns_rbt_t **rbtp) {
rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
if (rbt == NULL)
return (ISC_R_NOMEMORY);
return (DNS_R_NOMEMORY);
rbt->mctx = mctx;
rbt->root = NULL;
......@@ -127,7 +131,7 @@ dns_rbt_create(isc_mem_t *mctx, dns_rbt_t **rbtp) {
*rbtp = rbt;
return (ISC_R_SUCCESS);
return (DNS_R_SUCCESS);
}
/*
......@@ -141,7 +145,9 @@ dns_rbt_destroy(dns_rbt_t **rbtp) {
rbt = *rbtp;
dns_rbt_delete_tree(rbt->mctx, rbt->root, &rbt->root);
dns_rbt_deletetree(rbt->mctx, rbt->root, &rbt->root);
rbt->magic = 0;
isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
......@@ -152,12 +158,12 @@ dns_rbt_destroy(dns_rbt_t **rbtp) {
* Add 'name' to tree, initializing its data pointer with 'data'.
*/
isc_result_t
dns_result_t
dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
dns_rbt_node_t **root, *current, *child, *new_node, *new_current;
dns_rbtnode_t **root, *current, *child, *new_node, *new_current, *parent;
dns_name_t add_name, current_name, new_name, tmp_name;
int compared, add_labels, current_labels, keep_labels, start_label;
isc_result_t result;
dns_result_t result;
REQUIRE(dns_name_isabsolute(name));
......@@ -175,13 +181,12 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
if (rbt->root == NULL) {
result = create_node(rbt->mctx, &add_name, &new_node);
if (result == ISC_R_SUCCESS)
result = dns_rbt_add_node(new_node, &rbt->root);
rbt->root = new_node;
return (result);
}
root = &rbt->root;
parent = NULL;
child = *root;
dns_name_init(&current_name, NULL);
do {
......@@ -192,18 +197,20 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
if (compared == BOTH_ARE_EQUAL)
if (DATA(current) != NULL)
return(ISC_R_EXISTS);
return(DNS_R_EXISTS); /* @@@ DNS_R_DISALLOWED */
else {
DATA(current) = data; /* @@@ ? */
return(ISC_R_SUCCESS);
DATA(current) = data;
return(DNS_R_SUCCESS);
}
else if (compared == FIRST_IS_LESS)
else if (compared == FIRST_IS_LESS) {
parent = current;
child = LEFT(current);
else if (compared == FIRST_IS_MORE)
} else if (compared == FIRST_IS_MORE) {
parent = current;
child = RIGHT(current);
else {
} else {
/*
* This name has some suffix in common with the
* name at the current node. If the name at
......@@ -247,8 +254,9 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
/*
* Follow the down pointer (possibly NULL).
*/
child = DOWN(current);
root = &DOWN(current);
parent = NULL;
child = DOWN(current);
} else {
/*
......@@ -277,7 +285,7 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
result = create_node(rbt->mctx,
&tmp_name, &new_current);
if (result != ISC_R_SUCCESS)
if (result != DNS_R_SUCCESS)
return (result);
/*
......@@ -290,13 +298,11 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
/*
* Fix pointers that were to the current node.
*/
if (PARENT(current) != NULL)
if (LEFT(PARENT(current)) == current)
SET_LEFT(PARENT(current),
new_current);
if (parent != NULL)
if (LEFT(parent) == current)
SET_LEFT(parent, new_current);
else
SET_RIGHT(PARENT(current),
new_current);
SET_RIGHT(parent, new_current);
if (*root == current)
*root = new_current;
......@@ -320,7 +326,7 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
result = create_node(rbt->mctx,
&new_name, &new_node);
if (result != ISC_R_SUCCESS)
if (result != DNS_R_SUCCESS)
return (result);
DATA(new_node) = DATA(new_current);
......@@ -337,17 +343,10 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
current = new_current;
/*
* Set up the new root of the next level
* and start the next tree.
* Set up the new root of the next level.
*/
DOWN(current) = NULL;
DOWN(current) = new_node;
root = &DOWN(current);
result = dns_rbt_add_node(new_node, root);
/*
* This should never happen, eh?
*/
if (result != ISC_R_SUCCESS)
return(result);
if (compared == add_labels) {
/*
......@@ -361,7 +360,7 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
* Since the new name has had its
* data placed, the job is done!
*/
return(ISC_R_SUCCESS);
return(DNS_R_SUCCESS);
} else {
/*
* The current node has no name data,
......@@ -382,6 +381,7 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
&add_name);
current = new_node;
parent = NULL; /* @@@ ? only necessary if used outside loop */
child = NULL;
}
......@@ -393,7 +393,7 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
result = create_node(rbt->mctx,
&add_name, &new_node);
if (result == ISC_R_SUCCESS) {
if (result == DNS_R_SUCCESS) {
DATA(new_node) = data;
result = dns_rbt_add_node(new_node, root);
}
......@@ -406,9 +406,9 @@ dns_rbt_add_name(dns_rbt_t *rbt, dns_name_t *name, void *data) {
* If second argument "up" is non-NULL, set it to the node that has
* the down pointer for the found node.
*/
dns_rbt_node_t *
dns_rbt_find_node(dns_rbt_t *rbt, dns_name_t *name, dns_rbt_node_t **up) {
dns_rbt_node_t *current;
dns_rbtnode_t *
dns_rbt_find_node(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **up) {
dns_rbtnode_t *current;
dns_name_t *search_name, *new_search_name, *current_name;
dns_name_t holder1, holder2;
int compared, current_labels, keep_labels, dont_count_root_label;
......@@ -512,7 +512,7 @@ dns_rbt_find_node(dns_rbt_t *rbt, dns_name_t *name, dns_rbt_node_t **up) {
void *
dns_rbt_find_name(dns_rbt_t *rbt, dns_name_t *name) {
dns_rbt_node_t *node;
dns_rbtnode_t *node;
node = dns_rbt_find_node(rbt, name, NULL);
......@@ -522,6 +522,7 @@ dns_rbt_find_name(dns_rbt_t *rbt, dns_name_t *name) {
return(NULL);
}
#if 0
/* @@@ WHEN DELETING, IF A TREE IS LEFT WITH NO RIGHT OR LEFT NODES
THEN IT SHOULD HAVE ITS NAME GLOMMED INTO THE NAME ABOVE IT. THIS
COULD STAND A dns_name_prefix_name FUNCTION OR SOME SUCH. */
......@@ -532,9 +533,22 @@ dns_rbt_find_name(dns_rbt_t *rbt, dns_name_t *name) {
* This will remove all subnames of the name, too.
* @@@ (Should it? If not, what should happen to those subnames?)
*/
isc_result_t
dns_rbt_delete_name(dns_rbt_t *rbt, dns_name_t *name) {
dns_rbt_node_t *node, *up, **root;
dns_result_t
dns_rbt_deletename(isc_mem_t *mctx, dns_name_t *name) {
dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name) {
/*
* find the node, building the ancestor chain.
* when searching, the name might not have an exact match:
* consider a.b.a.com, b.b.a.com and c.b.a.com as the only
* elements of a tree, which would make layer 1 a single
* node tree of "b.a.com" and layer 2 a three node tree of
* a, b, and c. deleting a.com would find only a partial depth
* match in the first layer.
* deletes ALL subnames of the name.
* delete all ancestors that have no data???
* if so, will also need chain of UP pointers
*/
dns_rbtnode_t *node, *up, **root;
REQUIRE(dns_name_isabsolute(name));
......@@ -542,7 +556,7 @@ dns_rbt_delete_name(dns_rbt_t *rbt, dns_name_t *name) {
if (node != NULL) {
if (DOWN(node))
dns_rbt_delete_tree(rbt->mctx,
dns_rbt_deletetree(rbt->mctx,
DOWN(node), &DOWN(node));
if (up != NULL)
......@@ -550,16 +564,17 @@ dns_rbt_delete_name(dns_rbt_t *rbt, dns_name_t *name) {
else
root = &rbt->root;
dns_rbt_delete_node(rbt->mctx, node, root);
dns_rbt_deletenode(rbt->mctx, node, root);
return(ISC_R_SUCCESS);
return(DNS_R_SUCCESS);
} else
return(ISC_R_NOTFOUND);
return(DNS_R_NOTFOUND); /* @@@ DNS_R_RANGE? */
}
#endif
void
dns_rbt_namefromnode(dns_rbt_node_t *node, dns_name_t *name) {
dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
isc_region_t r;
r.length = NAMELEN(node);
......@@ -568,34 +583,35 @@ dns_rbt_namefromnode(dns_rbt_node_t *node, dns_name_t *name) {
dns_name_fromregion(name, &r);
}
static isc_result_t
create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbt_node_t **nodep) {
dns_rbt_node_t *node;
static dns_result_t
create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
dns_rbtnode_t *node;
isc_region_t region;
dns_name_toregion(name, &region);
node = (dns_rbt_node_t *)isc_mem_get(mctx,
sizeof(*node) + region.length);
node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) + region.length);
if (node == NULL)
return (ISC_R_NOMEMORY);
return (DNS_R_NOMEMORY);
PARENT(node) = NULL;
/* PARENT(node) = NULL; */
LEFT(node) = NULL;
RIGHT(node) = NULL;
DOWN(node) = NULL;
MAKE_BLACK(node);
NAMELEN(node) = region.length;
memcpy(NAME(node), region.base, region.length);
*nodep = node;
return (ISC_R_SUCCESS);
return (DNS_R_SUCCESS);
}
static inline void
rotate_left(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
dns_rbt_node_t *child;
rotate_left(dns_rbtnode_t *node, dns_rbtnode_t *parent, dns_rbtnode_t **rootp) {
dns_rbtnode_t *child;
REQUIRE(node != NULL);
REQUIRE(rootp != NULL);
......@@ -604,26 +620,21 @@ rotate_left(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
REQUIRE(child != NULL);
SET_RIGHT(node, LEFT(child));
if (LEFT(child) != NULL)
SET_PARENT(LEFT(child), node);
SET_LEFT(child, node);
SET_PARENT(child, PARENT(node));
if (PARENT(node) != NULL) {
if (LEFT(PARENT(node)) == node)
SET_LEFT(PARENT(node), child);
if (parent != NULL) {
if (LEFT(parent) == node)
SET_LEFT(parent, child);
else {
SET_RIGHT(PARENT(node), child);
SET_RIGHT(parent, child);
}
} else
*rootp = child;
SET_PARENT(node, child);
}
static inline void
rotate_right(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
dns_rbt_node_t *child;
rotate_right(dns_rbtnode_t *node, dns_rbtnode_t *parent, dns_rbtnode_t **rootp) {
dns_rbtnode_t *child;
REQUIRE(node != NULL);
REQUIRE(rootp != NULL);
......@@ -632,28 +643,24 @@ rotate_right(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
REQUIRE(child != NULL);
SET_LEFT(node, RIGHT(child));
if (RIGHT(child) != NULL)
SET_PARENT(RIGHT(child), node);
SET_RIGHT(child, node);
SET_PARENT(child, PARENT(node));
if (PARENT(node) != NULL) {
if (LEFT(PARENT(node)) == node)
SET_LEFT(PARENT(node), child);
if (parent != NULL) {
if (LEFT(parent) == node)
SET_LEFT(parent, child);
else
SET_RIGHT(PARENT(node), child);
SET_RIGHT(parent, child);
} else
*rootp = child;
SET_PARENT(node, child);
}
static isc_result_t
dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
dns_rbt_node_t *current, *child, *root, *parent, *grandparent;
static dns_result_t
dns_rbt_add_node(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
dns_rbtnode_t *current, *child, *root, *tmp;
dns_rbtnode_t *ancestors[64], *parent, *grandparent; /* @@@ dynamic 64 */
dns_name_t add_name, current_name;
dns_offsets_t offsets;
int i;
int i, depth;
REQUIRE(rootp != NULL);
REQUIRE(LEFT(node) == NULL && RIGHT(node) == NULL);
......@@ -662,11 +669,12 @@ dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
if (root == NULL) {
MAKE_BLACK(node);
*rootp = node;
return (ISC_R_SUCCESS);
return (DNS_R_SUCCESS);
}
current = NULL;
child = root;
depth = 0;
dns_name_init(&add_name, offsets);
dns_rbt_namefromnode(node, &add_name);
......@@ -674,29 +682,32 @@ dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
dns_name_init(&current_name, NULL);
do {
ancestors[depth++] = current;
current = child;
dns_rbt_namefromnode(current, &current_name);
i = cmp_names_on_level(&add_name, &current_name);
if (i == 0)
return (ISC_R_EXISTS);
return (DNS_R_EXISTS); /* @@@ DNS_R_DISALLOWED? */
if (i < 0)
child = LEFT(current);
else
child = RIGHT(current);
} while (child != NULL);
/* insist depth < space available */
ancestors[depth] = current;
if (i < 0)
SET_LEFT(current, node);
else
SET_RIGHT(current, node);
MAKE_RED(node);
SET_PARENT(node, current);
while (node != root && IS_RED(PARENT(node))) {
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
while (node != root && IS_RED(ancestors[depth])) {
parent = ancestors[depth];
grandparent = ancestors[depth - 1];
if (parent == LEFT(grandparent)) {
child = RIGHT(grandparent);
......@@ -705,16 +716,19 @@ dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
depth -= 2;
} else {
if (node == RIGHT(parent)) {
rotate_left(parent, grandparent, &root);
tmp = node;
node = parent;
rotate_left(node, &root);
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
parent = tmp;
ancestors[depth] = parent;
}
MAKE_BLACK(parent);
MAKE_RED(grandparent);
rotate_right(grandparent, &root);
rotate_right(grandparent, ancestors[depth - 2],
&root);
}
} else {
child = LEFT(grandparent);
......@@ -723,16 +737,19 @@ dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
MAKE_BLACK(child);
MAKE_RED(grandparent);
node = grandparent;
depth -= 2;
} else {
if (node == LEFT(parent)) {
rotate_right(parent, grandparent, &root);
tmp = node;
node = parent;
rotate_right(node, &root);
parent = PARENT(node);
grandparent = PARENT(PARENT(node));
parent = tmp;
ancestors[depth] = parent;
}
MAKE_BLACK(parent);
MAKE_RED(grandparent);
rotate_left(grandparent, &root);
rotate_left(grandparent, ancestors[depth - 2],
&root);
}
}
}
......@@ -740,12 +757,12 @@ dns_rbt_add_node(dns_rbt_node_t *node, dns_rbt_node_t **rootp) {
MAKE_BLACK(root);
*rootp = root;
return (ISC_R_SUCCESS);
return (DNS_R_SUCCESS);