rbt.c revision c5944292e9ebee4a39fe939b9a16fe5596808556
a7c412f37cc73d0332887a746e81220cbf09dd00Mark Andrews * Copyright (C) 1999, 2000 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * purpose with or without fee is hereby granted, provided that the above
1633838b8255282d10af15c5c84cee5a51466712Bob Halley * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28a8f5b0de57d269cf2845c69cb6abe18cbd3b3aMark Andrews/* $Id: rbt.c,v 1.89 2000/07/31 23:27:24 tale Exp $ */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/* Principal Authors: DCL */
94e25967cda41b886e33ec254b917d21df21a187Bob Halley * This define is so dns/name.h (included by dns/fixedname.h) uses more
6e3a8256eed85f6704861d269ccfb35bdaeed5ffDavid Lawrence * efficient macro calls instead of functions for a few operations.
94e25967cda41b886e33ec254b917d21df21a187Bob Halley#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein * XXXDCL Since parent pointers were added in again, I could remove all of the
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * _lastnode. This would involve pretty major change to the API.
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence unsigned int magic;
df0f58959ed82a2a43ca8d816ce9592541df9f2fMark Andrews void (*data_deleter)(void *, void *);
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halley * Elements of the rbtnode structure.
70ec7dd74103fa9e92a6d56a0e3b0fc30e17af0dMark Andrews#define FINDCALLBACK(node) ((node)->find_callback)
70ec7dd74103fa9e92a6d56a0e3b0fc30e17af0dMark Andrews * Structure elements from the rbtdb.c, not
70ec7dd74103fa9e92a6d56a0e3b0fc30e17af0dMark Andrews * used as part of the rbt.c algorithms.
70ec7dd74103fa9e92a6d56a0e3b0fc30e17af0dMark Andrews * The variable length stuff stored after the node.
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley#define NAME(node) ((unsigned char *)((node) + 1))
3740b569ae76295b941d57a724a43beb75b533baBob Halley#define OFFSETS(node) (NAME(node) + NAMELEN(node))
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node))
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley * Color management.
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley#define IS_RED(node) ((node) != NULL && (node)->color == RED)
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
26f327f1f53afdb8256affa1c197ed138bf3cb2fAndreas Gustafsson#define MAKE_BLACK(node) ((node)->color = BLACK)
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley * Chain management.
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley if ((chain)->ancestor_count == (chain)->ancestor_maxitems && \
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley (chain)->ancestors[(chain)->ancestor_count++] = (node); \
27809a2ee5db141b684e53bf1d94da26e9f92d3aMark Andrews (chain)->levels[(chain)->level_count++] = (node)
585529aaeb95a71cd3d95df2602a4688fc7c3292David Lawrence * The following macros directly access normally private name variables.
585529aaeb95a71cd3d95df2602a4688fc7c3292David Lawrence * These macros are used to avoid a lot of function calls in the critical
232fd751edcb5dd2b1fd2666e039efe83d2e2b55Michael Sawyer * path of the tree traversal code.
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley#define inline
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley * A little something to help out in GDB.
94e25967cda41b886e33ec254b917d21df21a187Bob Halleystatic void dns_rbt_printnodename(dns_rbtnode_t *node);
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews#define DNS_RBT_ANCESTORBLOCK 1 /* To give the reallocation code a workout. */
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * Forward declarations.
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencecreate_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencejoin_nodes(dns_rbt_t *rbt, dns_rbtnode_t *node);
70ec7dd74103fa9e92a6d56a0e3b0fc30e17af0dMark Andrewsstatic inline void
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencestatic inline void
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencerotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
df0f58959ed82a2a43ca8d816ce9592541df9f2fMark Andrewsstatic inline void
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencerotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencedns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence dns_rbtnode_t **rootp, dns_rbtnodechain_t *chain);
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencedns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
94e25967cda41b886e33ec254b917d21df21a187Bob Halleydns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
94e25967cda41b886e33ec254b917d21df21a187Bob Halley * Initialize a red/black tree of trees.
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halleydns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halley REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
4b87939256ede703385e9cab92d3c58d03c31098Mark Andrews rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * Deallocate a red/black tree of trees.
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halley * The next three functions for chains, get_ancestor_mem, put_ancestor_mem
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halley * and chain_name, appear early in this file so they can be effectively
afdb3abb9b06ed4070ac9021f1f4427b4cb3a286Bob Halley * inlined by the other rbt functions that use them.
26f327f1f53afdb8256affa1c197ed138bf3cb2fAndreas Gustafssonget_ancestor_mem(dns_rbtnodechain_t *chain) {
bf6d2e39124ab3d51c253f7acad9a4abef059be6Bob Halley oldsize = chain->ancestor_maxitems * sizeof(dns_rbtnode_t *);
94e25967cda41b886e33ec254b917d21df21a187Bob Halley newsize = oldsize + DNS_RBT_ANCESTORBLOCK * sizeof(dns_rbtnode_t *);
bf6d2e39124ab3d51c253f7acad9a4abef059be6Bob Halley ancestor_mem = isc_mem_get(chain->mctx, newsize);
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence memcpy(ancestor_mem, chain->ancestors, oldsize);
26f327f1f53afdb8256affa1c197ed138bf3cb2fAndreas Gustafsson if (chain->ancestor_maxitems > DNS_RBT_ANCESTORBLOCK)
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley isc_mem_put(chain->mctx, chain->ancestors, oldsize);
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence chain->ancestor_maxitems += DNS_RBT_ANCESTORBLOCK;
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * This is used by functions that are popping the chain off their
94e25967cda41b886e33ec254b917d21df21a187Bob Halley * own stack, and so do not need to have ancestor_maxitems or the
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley * ancestors pointer reset. Functions that will be reusing a chain
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley * structure need to call dns_rbtnodechain_reset() instead.
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halleystatic inline void
94e25967cda41b886e33ec254b917d21df21a187Bob Halley if (chain->ancestor_maxitems > DNS_RBT_ANCESTORBLOCK)
26f327f1f53afdb8256affa1c197ed138bf3cb2fAndreas Gustafssonchain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence unsigned int i;
4bed2e84a34b37259b85e5c092d51c122ef58c3cBob Halley result = dns_name_concatenate(&nodename, name, name, NULL);
4ad9b25e6ddf948ffb3b8198c5540d251f26c52eDavid Lawrence result = dns_name_concatenate(&nodename, name, name, NULL);
4ad9b25e6ddf948ffb3b8198c5540d251f26c52eDavid Lawrencemove_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
4ad9b25e6ddf948ffb3b8198c5540d251f26c52eDavid Lawrence * Go as far right and then down as much as possible,
4ad9b25e6ddf948ffb3b8198c5540d251f26c52eDavid Lawrence * as long as the rightmost node has a down pointer.
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * Add 'name' to tree, initializing its data pointer with 'data'.
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrencedns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * Does this thing have too many variables or what?
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence dns_rbtnode_t **root, *parent, *child, *current, *new_current;
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence dns_name_t *add_name, current_name, *prefix, *suffix;
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix;
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence unsigned int common_labels, common_bits, add_bits;
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * Create a copy of the name so the original name structure is
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * not modified. The name data needs to be modifiable when
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence * a node is split on a bitstring label.
6fa1cb5754695d550a58c6e8978fda65f5146af7David Lawrence result = create_node(rbt->mctx, add_name, &new_current);
c8563aaf86c04f0e2284bcc8e444a0651c157ea0Andreas Gustafsson prefix = dns_fixedname_name(&fixedprefix);
c8563aaf86c04f0e2284bcc8e444a0651c157ea0Andreas Gustafsson suffix = dns_fixedname_name(&fixedsuffix);
a6f0e9c985220f0e4509777e6528afb64e0ad576Mukund Sivaraman chain.ancestors[chain.ancestor_count - 1] == NULL) ||
a6f0e9c985220f0e4509777e6528afb64e0ad576Mukund Sivaraman chain.ancestors[chain.ancestor_count - 1] ==
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews compared = dns_name_fullcompare(add_name, ¤t_name,
789252d55f025db52ee02aa933c9f09a4aadfa97Evan Hunt } else if (order > 0) {
789252d55f025db52ee02aa933c9f09a4aadfa97Evan Hunt * This name has some suffix in common with the
789252d55f025db52ee02aa933c9f09a4aadfa97Evan Hunt * name at the current node. If the name at
789252d55f025db52ee02aa933c9f09a4aadfa97Evan Hunt * the current node is shorter, that means the
789252d55f025db52ee02aa933c9f09a4aadfa97Evan Hunt * new name should be in a subtree. If the
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * name at the current node is longer, that means
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * the down pointer to this tree should point
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * to a new tree that has the common suffix, and
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * the non-common parts of these two names should
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * start a new tree.
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * All of the existing labels are in common,
186e7f37c9fc985a7a7264cc8170e48a25bed434Mark Andrews * so the new name is in a subtree.
&new_current);
if (common_bits > 0) {
&label);
&label);
add_bits = 0;
if (common_labels ==
return (ISC_R_SUCCESS);
NULL);
return (result);
return (result);
void *callback_arg)
int order;
return (ISC_R_NOTFOUND);
&order,
if (order < 0)
return (result);
return (result);
if (order > 0) {
result2 =
NULL,
NULL);
return (result);
return (result);
* 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
* solely the province of rbtdb.c.
return (result);
if (recurse)
return (ISC_R_SUCCESS);
return (result);
return (result);
static isc_result_t
unsigned int labels;
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
static isc_result_t
return (result);
return (result);
unsigned int depth;
if (order < 0) {
for (i = 0; i < depth; i++)
isc_region_t r;
if (parent) {
depth++;
return (ISC_R_NOTFOUND);
return (result);
if (new_origin) {
NULL);
NULL);
return (result);
NULL) {
current =
if (new_origin) {
return (result);
return (result);
return (result);
return (result);