Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / rbt.c
blob155e253f9aa023c8baf3bf30242cdcc1b6019b51
1 /*
2 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: rbt.c,v 1.138.36.5 2009/01/19 23:47:02 tbox Exp $ */
20 /*! \file */
22 /* Principal Authors: DCL */
24 #include <config.h>
26 #include <isc/mem.h>
27 #include <isc/platform.h>
28 #include <isc/print.h>
29 #include <isc/refcount.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
33 /*%
34 * This define is so dns/name.h (included by dns/fixedname.h) uses more
35 * efficient macro calls instead of functions for a few operations.
37 #define DNS_NAME_USEINLINE 1
39 #include <dns/fixedname.h>
40 #include <dns/log.h>
41 #include <dns/rbt.h>
42 #include <dns/result.h>
44 #define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+')
45 #define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
48 * XXXDCL Since parent pointers were added in again, I could remove all of the
49 * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
50 * _lastnode. This would involve pretty major change to the API.
52 #define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-')
53 #define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
55 #define RBT_HASH_SIZE 64
57 #ifdef RBT_MEM_TEST
58 #undef RBT_HASH_SIZE
59 #define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
60 #endif
62 struct dns_rbt {
63 unsigned int magic;
64 isc_mem_t * mctx;
65 dns_rbtnode_t * root;
66 void (*data_deleter)(void *, void *);
67 void * deleter_arg;
68 unsigned int nodecount;
69 unsigned int hashsize;
70 dns_rbtnode_t ** hashtable;
73 #define RED 0
74 #define BLACK 1
76 /*%
77 * Elements of the rbtnode structure.
79 #define PARENT(node) ((node)->parent)
80 #define LEFT(node) ((node)->left)
81 #define RIGHT(node) ((node)->right)
82 #define DOWN(node) ((node)->down)
83 #define DATA(node) ((node)->data)
84 #define HASHNEXT(node) ((node)->hashnext)
85 #define HASHVAL(node) ((node)->hashval)
86 #define COLOR(node) ((node)->color)
87 #define NAMELEN(node) ((node)->namelen)
88 #define OFFSETLEN(node) ((node)->offsetlen)
89 #define ATTRS(node) ((node)->attributes)
90 #define PADBYTES(node) ((node)->padbytes)
91 #define IS_ROOT(node) ISC_TF((node)->is_root == 1)
92 #define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1)
94 /*%
95 * Structure elements from the rbtdb.c, not
96 * used as part of the rbt.c algorithms.
98 #define DIRTY(node) ((node)->dirty)
99 #define WILD(node) ((node)->wild)
100 #define LOCKNUM(node) ((node)->locknum)
103 * The variable length stuff stored after the node.
105 #define NAME(node) ((unsigned char *)((node) + 1))
106 #define OFFSETS(node) (NAME(node) + NAMELEN(node))
108 #define NODE_SIZE(node) (sizeof(*node) + \
109 NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node))
112 * Color management.
114 #define IS_RED(node) ((node) != NULL && (node)->color == RED)
115 #define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
116 #define MAKE_RED(node) ((node)->color = RED)
117 #define MAKE_BLACK(node) ((node)->color = BLACK)
120 * Chain management.
122 * The "ancestors" member of chains were removed, with their job now
123 * being wholly handled by parent pointers (which didn't exist, because
124 * of memory concerns, when chains were first implemented).
126 #define ADD_LEVEL(chain, node) \
127 (chain)->levels[(chain)->level_count++] = (node)
130 * The following macros directly access normally private name variables.
131 * These macros are used to avoid a lot of function calls in the critical
132 * path of the tree traversal code.
135 #define NODENAME(node, name) \
136 do { \
137 (name)->length = NAMELEN(node); \
138 (name)->labels = OFFSETLEN(node); \
139 (name)->ndata = NAME(node); \
140 (name)->offsets = OFFSETS(node); \
141 (name)->attributes = ATTRS(node); \
142 (name)->attributes |= DNS_NAMEATTR_READONLY; \
143 } while (0)
145 #ifdef DNS_RBT_USEHASH
146 static isc_result_t
147 inithash(dns_rbt_t *rbt);
148 #endif
150 #ifdef DEBUG
151 #define inline
153 * A little something to help out in GDB.
155 dns_name_t Name(dns_rbtnode_t *node);
156 dns_name_t
157 Name(dns_rbtnode_t *node) {
158 dns_name_t name;
160 dns_name_init(&name, NULL);
161 if (node != NULL)
162 NODENAME(node, &name);
164 return (name);
167 static void dns_rbt_printnodename(dns_rbtnode_t *node);
168 #endif
170 static inline dns_rbtnode_t *
171 find_up(dns_rbtnode_t *node) {
172 dns_rbtnode_t *root;
175 * Return the node in the level above the argument node that points
176 * to the level the argument node is in. If the argument node is in
177 * the top level, the return value is NULL.
179 for (root = node; ! IS_ROOT(root); root = PARENT(root))
180 ; /* Nothing. */
182 return (PARENT(root));
186 * Forward declarations.
188 static isc_result_t
189 create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
191 #ifdef DNS_RBT_USEHASH
192 static inline void
193 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name);
194 static inline void
195 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
196 #else
197 #define hash_node(rbt, node, name) (ISC_R_SUCCESS)
198 #define unhash_node(rbt, node)
199 #endif
201 static inline void
202 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
203 static inline void
204 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
206 static void
207 dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
208 dns_rbtnode_t **rootp);
210 static void
211 dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
213 static isc_result_t
214 dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
216 static void
217 dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
218 dns_rbtnode_t **nodep);
221 * Initialize a red/black tree of trees.
223 isc_result_t
224 dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
225 void *deleter_arg, dns_rbt_t **rbtp)
227 #ifdef DNS_RBT_USEHASH
228 isc_result_t result;
229 #endif
230 dns_rbt_t *rbt;
233 REQUIRE(mctx != NULL);
234 REQUIRE(rbtp != NULL && *rbtp == NULL);
235 REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
237 rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
238 if (rbt == NULL)
239 return (ISC_R_NOMEMORY);
241 rbt->mctx = mctx;
242 rbt->data_deleter = deleter;
243 rbt->deleter_arg = deleter_arg;
244 rbt->root = NULL;
245 rbt->nodecount = 0;
246 rbt->hashtable = NULL;
247 rbt->hashsize = 0;
249 #ifdef DNS_RBT_USEHASH
250 result = inithash(rbt);
251 if (result != ISC_R_SUCCESS) {
252 isc_mem_put(mctx, rbt, sizeof(*rbt));
253 return (result);
255 #endif
257 rbt->magic = RBT_MAGIC;
259 *rbtp = rbt;
261 return (ISC_R_SUCCESS);
265 * Deallocate a red/black tree of trees.
267 void
268 dns_rbt_destroy(dns_rbt_t **rbtp) {
269 RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
272 isc_result_t
273 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
274 dns_rbt_t *rbt;
276 REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
278 rbt = *rbtp;
280 dns_rbt_deletetreeflat(rbt, quantum, &rbt->root);
281 if (rbt->root != NULL)
282 return (ISC_R_QUOTA);
284 INSIST(rbt->nodecount == 0);
286 if (rbt->hashtable != NULL)
287 isc_mem_put(rbt->mctx, rbt->hashtable,
288 rbt->hashsize * sizeof(dns_rbtnode_t *));
290 rbt->magic = 0;
292 isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
293 *rbtp = NULL;
294 return (ISC_R_SUCCESS);
297 unsigned int
298 dns_rbt_nodecount(dns_rbt_t *rbt) {
299 REQUIRE(VALID_RBT(rbt));
300 return (rbt->nodecount);
303 static inline isc_result_t
304 chain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
305 isc_boolean_t include_chain_end)
307 dns_name_t nodename;
308 isc_result_t result = ISC_R_SUCCESS;
309 int i;
311 dns_name_init(&nodename, NULL);
313 if (include_chain_end && chain->end != NULL) {
314 NODENAME(chain->end, &nodename);
315 result = dns_name_copy(&nodename, name, NULL);
316 if (result != ISC_R_SUCCESS)
317 return (result);
318 } else
319 dns_name_reset(name);
321 for (i = (int)chain->level_count - 1; i >= 0; i--) {
322 NODENAME(chain->levels[i], &nodename);
323 result = dns_name_concatenate(name, &nodename, name, NULL);
325 if (result != ISC_R_SUCCESS)
326 return (result);
328 return (result);
331 static inline isc_result_t
332 move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
333 do {
335 * Go as far right and then down as much as possible,
336 * as long as the rightmost node has a down pointer.
338 while (RIGHT(node) != NULL)
339 node = RIGHT(node);
341 if (DOWN(node) == NULL)
342 break;
344 ADD_LEVEL(chain, node);
345 node = DOWN(node);
346 } while (1);
348 chain->end = node;
350 return (ISC_R_SUCCESS);
354 * Add 'name' to tree, initializing its data pointer with 'data'.
357 isc_result_t
358 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
360 * Does this thing have too many variables or what?
362 dns_rbtnode_t **root, *parent, *child, *current, *new_current;
363 dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
364 dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
365 dns_offsets_t current_offsets;
366 dns_namereln_t compared;
367 isc_result_t result = ISC_R_SUCCESS;
368 dns_rbtnodechain_t chain;
369 unsigned int common_labels;
370 unsigned int nlabels, hlabels;
371 int order;
373 REQUIRE(VALID_RBT(rbt));
374 REQUIRE(dns_name_isabsolute(name));
375 REQUIRE(nodep != NULL && *nodep == NULL);
378 * Create a copy of the name so the original name structure is
379 * not modified.
381 dns_fixedname_init(&fixedcopy);
382 add_name = dns_fixedname_name(&fixedcopy);
383 dns_name_clone(name, add_name);
385 if (rbt->root == NULL) {
386 result = create_node(rbt->mctx, add_name, &new_current);
387 if (result == ISC_R_SUCCESS) {
388 rbt->nodecount++;
389 new_current->is_root = 1;
390 rbt->root = new_current;
391 *nodep = new_current;
392 hash_node(rbt, new_current, name);
394 return (result);
397 dns_rbtnodechain_init(&chain, rbt->mctx);
399 dns_fixedname_init(&fixedprefix);
400 dns_fixedname_init(&fixedsuffix);
401 prefix = dns_fixedname_name(&fixedprefix);
402 suffix = dns_fixedname_name(&fixedsuffix);
404 root = &rbt->root;
405 INSIST(IS_ROOT(*root));
406 parent = NULL;
407 current = NULL;
408 child = *root;
409 dns_name_init(&current_name, current_offsets);
410 dns_fixedname_init(&fnewname);
411 new_name = dns_fixedname_name(&fnewname);
412 nlabels = dns_name_countlabels(name);
413 hlabels = 0;
415 do {
416 current = child;
418 NODENAME(current, &current_name);
419 compared = dns_name_fullcompare(add_name, &current_name,
420 &order, &common_labels);
422 if (compared == dns_namereln_equal) {
423 *nodep = current;
424 result = ISC_R_EXISTS;
425 break;
429 if (compared == dns_namereln_none) {
431 if (order < 0) {
432 parent = current;
433 child = LEFT(current);
435 } else if (order > 0) {
436 parent = current;
437 child = RIGHT(current);
441 } else {
443 * This name has some suffix in common with the
444 * name at the current node. If the name at
445 * the current node is shorter, that means the
446 * new name should be in a subtree. If the
447 * name at the current node is longer, that means
448 * the down pointer to this tree should point
449 * to a new tree that has the common suffix, and
450 * the non-common parts of these two names should
451 * start a new tree.
453 hlabels += common_labels;
454 if (compared == dns_namereln_subdomain) {
456 * All of the existing labels are in common,
457 * so the new name is in a subtree.
458 * Whack off the common labels for the
459 * not-in-common part to be searched for
460 * in the next level.
462 dns_name_split(add_name, common_labels,
463 add_name, NULL);
466 * Follow the down pointer (possibly NULL).
468 root = &DOWN(current);
470 INSIST(*root == NULL ||
471 (IS_ROOT(*root) &&
472 PARENT(*root) == current));
474 parent = NULL;
475 child = DOWN(current);
476 ADD_LEVEL(&chain, current);
478 } else {
480 * The number of labels in common is fewer
481 * than the number of labels at the current
482 * node, so the current node must be adjusted
483 * to have just the common suffix, and a down
484 * pointer made to a new tree.
487 INSIST(compared == dns_namereln_commonancestor
488 || compared == dns_namereln_contains);
491 * Ensure the number of levels in the tree
492 * does not exceed the number of logical
493 * levels allowed by DNSSEC.
495 * XXXDCL need a better error result?
497 * XXXDCL Since chain ancestors were removed,
498 * no longer used by dns_rbt_addonlevel(),
499 * this is the only real use of chains in the
500 * function. It could be done instead with
501 * a simple integer variable, but I am pressed
502 * for time.
504 if (chain.level_count ==
505 (sizeof(chain.levels) /
506 sizeof(*chain.levels))) {
507 result = ISC_R_NOSPACE;
508 break;
512 * Split the name into two parts, a prefix
513 * which is the not-in-common parts of the
514 * two names and a suffix that is the common
515 * parts of them.
517 dns_name_split(&current_name, common_labels,
518 prefix, suffix);
519 result = create_node(rbt->mctx, suffix,
520 &new_current);
522 if (result != ISC_R_SUCCESS)
523 break;
526 * Reproduce the tree attributes of the
527 * current node.
529 new_current->is_root = current->is_root;
530 PARENT(new_current) = PARENT(current);
531 LEFT(new_current) = LEFT(current);
532 RIGHT(new_current) = RIGHT(current);
533 COLOR(new_current) = COLOR(current);
536 * Fix pointers that were to the current node.
538 if (parent != NULL) {
539 if (LEFT(parent) == current)
540 LEFT(parent) = new_current;
541 else
542 RIGHT(parent) = new_current;
544 if (LEFT(new_current) != NULL)
545 PARENT(LEFT(new_current)) =
546 new_current;
547 if (RIGHT(new_current) != NULL)
548 PARENT(RIGHT(new_current)) =
549 new_current;
550 if (*root == current)
551 *root = new_current;
553 NAMELEN(current) = prefix->length;
554 OFFSETLEN(current) = prefix->labels;
555 memcpy(OFFSETS(current), prefix->offsets,
556 prefix->labels);
557 PADBYTES(current) +=
558 (current_name.length - prefix->length) +
559 (current_name.labels - prefix->labels);
562 * Set up the new root of the next level.
563 * By definition it will not be the top
564 * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
566 current->is_root = 1;
567 PARENT(current) = new_current;
568 DOWN(new_current) = current;
569 root = &DOWN(new_current);
571 ADD_LEVEL(&chain, new_current);
573 LEFT(current) = NULL;
574 RIGHT(current) = NULL;
576 MAKE_BLACK(current);
577 ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
579 rbt->nodecount++;
580 dns_name_getlabelsequence(name,
581 nlabels - hlabels,
582 hlabels, new_name);
583 hash_node(rbt, new_current, new_name);
585 if (common_labels ==
586 dns_name_countlabels(add_name)) {
588 * The name has been added by pushing
589 * the not-in-common parts down to
590 * a new level.
592 *nodep = new_current;
593 return (ISC_R_SUCCESS);
595 } else {
597 * The current node has no data,
598 * because it is just a placeholder.
599 * Its data pointer is already NULL
600 * from create_node()), so there's
601 * nothing more to do to it.
605 * The not-in-common parts of the new
606 * name will be inserted into the new
607 * level following this loop (unless
608 * result != ISC_R_SUCCESS, which
609 * is tested after the loop ends).
611 dns_name_split(add_name, common_labels,
612 add_name, NULL);
614 break;
621 } while (child != NULL);
623 if (result == ISC_R_SUCCESS)
624 result = create_node(rbt->mctx, add_name, &new_current);
626 if (result == ISC_R_SUCCESS) {
627 dns_rbt_addonlevel(new_current, current, order, root);
628 rbt->nodecount++;
629 *nodep = new_current;
630 hash_node(rbt, new_current, name);
633 return (result);
637 * Add a name to the tree of trees, associating it with some data.
639 isc_result_t
640 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
641 isc_result_t result;
642 dns_rbtnode_t *node;
644 REQUIRE(VALID_RBT(rbt));
645 REQUIRE(dns_name_isabsolute(name));
647 node = NULL;
649 result = dns_rbt_addnode(rbt, name, &node);
652 * dns_rbt_addnode will report the node exists even when
653 * it does not have data associated with it, but the
654 * dns_rbt_*name functions all behave depending on whether
655 * there is data associated with a node.
657 if (result == ISC_R_SUCCESS ||
658 (result == ISC_R_EXISTS && DATA(node) == NULL)) {
659 DATA(node) = data;
660 result = ISC_R_SUCCESS;
663 return (result);
667 * Find the node for "name" in the tree of trees.
669 isc_result_t
670 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
671 dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
672 unsigned int options, dns_rbtfindcallback_t callback,
673 void *callback_arg)
675 dns_rbtnode_t *current, *last_compared, *current_root;
676 dns_rbtnodechain_t localchain;
677 dns_name_t *search_name, current_name, *callback_name;
678 dns_fixedname_t fixedcallbackname, fixedsearchname;
679 dns_namereln_t compared;
680 isc_result_t result, saved_result;
681 unsigned int common_labels;
682 unsigned int hlabels = 0;
683 int order;
685 REQUIRE(VALID_RBT(rbt));
686 REQUIRE(dns_name_isabsolute(name));
687 REQUIRE(node != NULL && *node == NULL);
688 REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
689 != (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
692 * If there is a chain it needs to appear to be in a sane state,
693 * otherwise a chain is still needed to generate foundname and
694 * callback_name.
696 if (chain == NULL) {
697 options |= DNS_RBTFIND_NOPREDECESSOR;
698 chain = &localchain;
699 dns_rbtnodechain_init(chain, rbt->mctx);
700 } else
701 dns_rbtnodechain_reset(chain);
703 if (rbt->root == NULL)
704 return (ISC_R_NOTFOUND);
705 else {
707 * Appease GCC about variables it incorrectly thinks are
708 * possibly used uninitialized.
710 compared = dns_namereln_none;
711 last_compared = NULL;
714 dns_fixedname_init(&fixedcallbackname);
715 callback_name = dns_fixedname_name(&fixedcallbackname);
718 * search_name is the name segment being sought in each tree level.
719 * By using a fixedname, the search_name will definitely have offsets
720 * for use by any splitting.
721 * By using dns_name_clone, no name data should be copied thanks to
722 * the lack of bitstring labels.
724 dns_fixedname_init(&fixedsearchname);
725 search_name = dns_fixedname_name(&fixedsearchname);
726 dns_name_clone(name, search_name);
728 dns_name_init(&current_name, NULL);
730 saved_result = ISC_R_SUCCESS;
731 current = rbt->root;
732 current_root = rbt->root;
734 while (current != NULL) {
735 NODENAME(current, &current_name);
736 compared = dns_name_fullcompare(search_name, &current_name,
737 &order, &common_labels);
738 last_compared = current;
740 if (compared == dns_namereln_equal)
741 break;
743 if (compared == dns_namereln_none) {
744 #ifdef DNS_RBT_USEHASH
745 dns_name_t hash_name;
746 dns_rbtnode_t *hnode;
747 dns_rbtnode_t *up_current;
748 unsigned int nlabels;
749 unsigned int tlabels = 1;
750 unsigned int hash;
753 * If there is no hash table, hashing can't be done.
755 if (rbt->hashtable == NULL)
756 goto nohash;
759 * The case of current != current_root, that
760 * means a left or right pointer was followed,
761 * only happens when the algorithm fell through to
762 * the traditional binary search because of a
763 * bitstring label. Since we dropped the bitstring
764 * support, this should not happen.
766 INSIST(current == current_root);
768 nlabels = dns_name_countlabels(search_name);
771 * current_root is the root of the current level, so
772 * it's parent is the same as it's "up" pointer.
774 up_current = PARENT(current_root);
775 dns_name_init(&hash_name, NULL);
777 hashagain:
779 * Hash includes tail.
781 dns_name_getlabelsequence(name,
782 nlabels - tlabels,
783 hlabels + tlabels,
784 &hash_name);
785 hash = dns_name_fullhash(&hash_name, ISC_FALSE);
786 dns_name_getlabelsequence(search_name,
787 nlabels - tlabels,
788 tlabels, &hash_name);
790 for (hnode = rbt->hashtable[hash % rbt->hashsize];
791 hnode != NULL;
792 hnode = hnode->hashnext)
794 dns_name_t hnode_name;
796 if (hash != HASHVAL(hnode))
797 continue;
798 if (find_up(hnode) != up_current)
799 continue;
800 dns_name_init(&hnode_name, NULL);
801 NODENAME(hnode, &hnode_name);
802 if (dns_name_equal(&hnode_name, &hash_name))
803 break;
806 if (hnode != NULL) {
807 current = hnode;
809 * This is an optimization. If hashing found
810 * the right node, the next call to
811 * dns_name_fullcompare() would obviously
812 * return _equal or _subdomain. Determine
813 * which of those would be the case by
814 * checking if the full name was hashed. Then
815 * make it look like dns_name_fullcompare
816 * was called and jump to the right place.
818 if (tlabels == nlabels) {
819 compared = dns_namereln_equal;
820 break;
821 } else {
822 common_labels = tlabels;
823 compared = dns_namereln_subdomain;
824 goto subdomain;
828 if (tlabels++ < nlabels)
829 goto hashagain;
832 * All of the labels have been tried against the hash
833 * table. Since we dropped the support of bitstring
834 * labels, the name isn't in the table.
836 current = NULL;
837 continue;
839 nohash:
840 #endif /* DNS_RBT_USEHASH */
842 * Standard binary search tree movement.
844 if (order < 0)
845 current = LEFT(current);
846 else
847 current = RIGHT(current);
849 } else {
851 * The names have some common suffix labels.
853 * If the number in common are equal in length to
854 * the current node's name length, then follow the
855 * down pointer and search in the new tree.
857 if (compared == dns_namereln_subdomain) {
858 subdomain:
860 * Whack off the current node's common parts
861 * for the name to search in the next level.
863 dns_name_split(search_name, common_labels,
864 search_name, NULL);
865 hlabels += common_labels;
867 * This might be the closest enclosing name.
869 if (DATA(current) != NULL ||
870 (options & DNS_RBTFIND_EMPTYDATA) != 0)
871 *node = current;
874 * Point the chain to the next level. This
875 * needs to be done before 'current' is pointed
876 * there because the callback in the next
877 * block of code needs the current 'current',
878 * but in the event the callback requests that
879 * the search be stopped then the
880 * DNS_R_PARTIALMATCH code at the end of this
881 * function needs the chain pointed to the
882 * next level.
884 ADD_LEVEL(chain, current);
887 * The caller may want to interrupt the
888 * downward search when certain special nodes
889 * are traversed. If this is a special node,
890 * the callback is used to learn what the
891 * caller wants to do.
893 if (callback != NULL &&
894 FINDCALLBACK(current)) {
895 result = chain_name(chain,
896 callback_name,
897 ISC_FALSE);
898 if (result != ISC_R_SUCCESS) {
899 dns_rbtnodechain_reset(chain);
900 return (result);
903 result = (callback)(current,
904 callback_name,
905 callback_arg);
906 if (result != DNS_R_CONTINUE) {
907 saved_result = result;
909 * Treat this node as if it
910 * had no down pointer.
912 current = NULL;
913 break;
918 * Finally, head to the next tree level.
920 current = DOWN(current);
921 current_root = current;
923 } else {
925 * Though there are labels in common, the
926 * entire name at this node is not common
927 * with the search name so the search
928 * name does not exist in the tree.
930 INSIST(compared == dns_namereln_commonancestor
931 || compared == dns_namereln_contains);
933 current = NULL;
939 * If current is not NULL, NOEXACT is not disallowing exact matches,
940 * and either the node has data or an empty node is ok, return
941 * ISC_R_SUCCESS to indicate an exact match.
943 if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
944 (DATA(current) != NULL ||
945 (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
947 * Found an exact match.
949 chain->end = current;
950 chain->level_matches = chain->level_count;
952 if (foundname != NULL)
953 result = chain_name(chain, foundname, ISC_TRUE);
954 else
955 result = ISC_R_SUCCESS;
957 if (result == ISC_R_SUCCESS) {
958 *node = current;
959 result = saved_result;
960 } else
961 *node = NULL;
962 } else {
964 * Did not find an exact match (or did not want one).
966 if (*node != NULL) {
968 * ... but found a partially matching superdomain.
969 * Unwind the chain to the partial match node
970 * to set level_matches to the level above the node,
971 * and then to derive the name.
973 * chain->level_count is guaranteed to be at least 1
974 * here because by definition of finding a superdomain,
975 * the chain is pointed to at least the first subtree.
977 chain->level_matches = chain->level_count - 1;
979 while (chain->levels[chain->level_matches] != *node) {
980 INSIST(chain->level_matches > 0);
981 chain->level_matches--;
984 if (foundname != NULL) {
985 unsigned int saved_count = chain->level_count;
987 chain->level_count = chain->level_matches + 1;
989 result = chain_name(chain, foundname,
990 ISC_FALSE);
992 chain->level_count = saved_count;
993 } else
994 result = ISC_R_SUCCESS;
996 if (result == ISC_R_SUCCESS)
997 result = DNS_R_PARTIALMATCH;
999 } else
1000 result = ISC_R_NOTFOUND;
1002 if (current != NULL) {
1004 * There was an exact match but either
1005 * DNS_RBTFIND_NOEXACT was set, or
1006 * DNS_RBTFIND_EMPTYDATA was set and the node had no
1007 * data. A policy decision was made to set the
1008 * chain to the exact match, but this is subject
1009 * to change if it becomes apparent that something
1010 * else would be more useful. It is important that
1011 * this case is handled here, because the predecessor
1012 * setting code below assumes the match was not exact.
1014 INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
1015 ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
1016 DATA(current) == NULL));
1017 chain->end = current;
1019 } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
1021 * Ensure the chain points nowhere.
1023 chain->end = NULL;
1025 } else {
1027 * Since there was no exact match, the chain argument
1028 * needs to be pointed at the DNSSEC predecessor of
1029 * the search name.
1031 if (compared == dns_namereln_subdomain) {
1033 * Attempted to follow a down pointer that was
1034 * NULL, which means the searched for name was
1035 * a subdomain of a terminal name in the tree.
1036 * Since there are no existing subdomains to
1037 * order against, the terminal name is the
1038 * predecessor.
1040 INSIST(chain->level_count > 0);
1041 INSIST(chain->level_matches <
1042 chain->level_count);
1043 chain->end =
1044 chain->levels[--chain->level_count];
1046 } else {
1047 isc_result_t result2;
1050 * Point current to the node that stopped
1051 * the search.
1053 * With the hashing modification that has been
1054 * added to the algorithm, the stop node of a
1055 * standard binary search is not known. So it
1056 * has to be found. There is probably a more
1057 * clever way of doing this.
1059 * The assignment of current to NULL when
1060 * the relationship is *not* dns_namereln_none,
1061 * even though it later gets set to the same
1062 * last_compared anyway, is simply to not push
1063 * the while loop in one more level of
1064 * indentation.
1066 if (compared == dns_namereln_none)
1067 current = last_compared;
1068 else
1069 current = NULL;
1071 while (current != NULL) {
1072 NODENAME(current, &current_name);
1073 compared = dns_name_fullcompare(
1074 search_name,
1075 &current_name,
1076 &order,
1077 &common_labels);
1079 last_compared = current;
1082 * Standard binary search movement.
1084 if (order < 0)
1085 current = LEFT(current);
1086 else
1087 current = RIGHT(current);
1091 current = last_compared;
1094 * Reached a point within a level tree that
1095 * positively indicates the name is not
1096 * present, but the stop node could be either
1097 * less than the desired name (order > 0) or
1098 * greater than the desired name (order < 0).
1100 * If the stop node is less, it is not
1101 * necessarily the predecessor. If the stop
1102 * node has a down pointer, then the real
1103 * predecessor is at the end of a level below
1104 * (not necessarily the next level).
1105 * Move down levels until the rightmost node
1106 * does not have a down pointer.
1108 * When the stop node is greater, it is
1109 * the successor. All the logic for finding
1110 * the predecessor is handily encapsulated
1111 * in dns_rbtnodechain_prev. In the event
1112 * that the search name is less than anything
1113 * else in the tree, the chain is reset.
1114 * XXX DCL What is the best way for the caller
1115 * to know that the search name has
1116 * no predecessor?
1120 if (order > 0) {
1121 if (DOWN(current) != NULL) {
1122 ADD_LEVEL(chain, current);
1124 result2 =
1125 move_chain_to_last(chain,
1126 DOWN(current));
1128 if (result2 != ISC_R_SUCCESS)
1129 result = result2;
1130 } else
1132 * Ah, the pure and simple
1133 * case. The stop node is the
1134 * predecessor.
1136 chain->end = current;
1138 } else {
1139 INSIST(order < 0);
1141 chain->end = current;
1143 result2 = dns_rbtnodechain_prev(chain,
1144 NULL,
1145 NULL);
1146 if (result2 == ISC_R_SUCCESS ||
1147 result2 == DNS_R_NEWORIGIN)
1148 ; /* Nothing. */
1149 else if (result2 == ISC_R_NOMORE)
1151 * There is no predecessor.
1153 dns_rbtnodechain_reset(chain);
1154 else
1155 result = result2;
1162 ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
1164 return (result);
1168 * Get the data pointer associated with 'name'.
1170 isc_result_t
1171 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
1172 dns_name_t *foundname, void **data) {
1173 dns_rbtnode_t *node = NULL;
1174 isc_result_t result;
1176 REQUIRE(data != NULL && *data == NULL);
1178 result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
1179 options, NULL, NULL);
1181 if (node != NULL &&
1182 (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
1183 *data = DATA(node);
1184 else
1185 result = ISC_R_NOTFOUND;
1187 return (result);
1191 * Delete a name from the tree of trees.
1193 isc_result_t
1194 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
1195 dns_rbtnode_t *node = NULL;
1196 isc_result_t result;
1198 REQUIRE(VALID_RBT(rbt));
1199 REQUIRE(dns_name_isabsolute(name));
1202 * First, find the node.
1204 * When searching, the name might not have an exact match:
1205 * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
1206 * elements of a tree, which would make layer 1 a single
1207 * node tree of "b.a.com" and layer 2 a three node tree of
1208 * a, b, and c. Deleting a.com would find only a partial depth
1209 * match in the first layer. Should it be a requirement that
1210 * that the name to be deleted have data? For now, it is.
1212 * ->dirty, ->locknum and ->references are ignored; they are
1213 * solely the province of rbtdb.c.
1215 result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
1216 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
1218 if (result == ISC_R_SUCCESS) {
1219 if (DATA(node) != NULL)
1220 result = dns_rbt_deletenode(rbt, node, recurse);
1221 else
1222 result = ISC_R_NOTFOUND;
1224 } else if (result == DNS_R_PARTIALMATCH)
1225 result = ISC_R_NOTFOUND;
1227 return (result);
1231 * Remove a node from the tree of trees.
1233 * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
1234 * a sequence of additions to be deletions will not generally get the
1235 * tree back to the state it started in. For example, if the addition
1236 * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
1237 * then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
1238 * restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it
1239 * turned out to be a bad idea because it could corrupt an active nodechain
1240 * that had "b.c" as one of its levels -- and the RBT has no idea what
1241 * nodechains are in use by callers, so it can't even *try* to helpfully
1242 * fix them up (which would probably be doomed to failure anyway).
1244 * Similarly, it is possible to leave the tree in a state where a supposedly
1245 * deleted node still exists. The first case of this is obvious; take
1246 * the tree which has "b.c" on one level, pointing to "a". Now deleted "b.c".
1247 * It was just established in the previous paragraph why we can't pull "a"
1248 * back up to its parent level. But what happens when "a" then gets deleted?
1249 * "b.c" is left hanging around without data or children. This condition
1250 * is actually pretty easy to detect, but ... should it really be removed?
1251 * Is a chain pointing to it? An iterator? Who knows! (Note that the
1252 * references structure member cannot be looked at because it is private to
1253 * rbtdb.) This is ugly and makes me unhappy, but after hours of trying to
1254 * make it more aesthetically proper and getting nowhere, this is the way it
1255 * is going to stay until such time as it proves to be a *real* problem.
1257 * Finally, for reference, note that the original routine that did node
1258 * joining was called join_nodes(). It has been excised, living now only
1259 * in the CVS history, but comments have been left behind that point to it just
1260 * in case someone wants to muck with this some more.
1262 * The one positive aspect of all of this is that joining used to have a
1263 * case where it might fail. Without trying to join, now this function always
1264 * succeeds. It still returns isc_result_t, though, so the API wouldn't change.
1266 isc_result_t
1267 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
1269 dns_rbtnode_t *parent;
1271 REQUIRE(VALID_RBT(rbt));
1272 REQUIRE(DNS_RBTNODE_VALID(node));
1274 if (DOWN(node) != NULL) {
1275 if (recurse)
1276 RUNTIME_CHECK(dns_rbt_deletetree(rbt, DOWN(node))
1277 == ISC_R_SUCCESS);
1278 else {
1279 if (DATA(node) != NULL && rbt->data_deleter != NULL)
1280 rbt->data_deleter(DATA(node), rbt->deleter_arg);
1281 DATA(node) = NULL;
1284 * Since there is at least one node below this one and
1285 * no recursion was requested, the deletion is
1286 * complete. The down node from this node might be all
1287 * by itself on a single level, so join_nodes() could
1288 * be used to collapse the tree (with all the caveats
1289 * of the comment at the start of this function).
1291 return (ISC_R_SUCCESS);
1296 * Note the node that points to the level of the node that is being
1297 * deleted. If the deleted node is the top level, parent will be set
1298 * to NULL.
1300 parent = find_up(node);
1303 * This node now has no down pointer (either because it didn't
1304 * have one to start, or because it was recursively removed).
1305 * So now the node needs to be removed from this level.
1307 dns_rbt_deletefromlevel(node, parent == NULL ? &rbt->root :
1308 &DOWN(parent));
1310 if (DATA(node) != NULL && rbt->data_deleter != NULL)
1311 rbt->data_deleter(DATA(node), rbt->deleter_arg);
1313 unhash_node(rbt, node);
1314 #if DNS_RBT_USEMAGIC
1315 node->magic = 0;
1316 #endif
1317 dns_rbtnode_refdestroy(node);
1318 isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
1319 rbt->nodecount--;
1322 * There are now two special cases that can exist that would
1323 * not have existed if the tree had been created using only
1324 * the names that now exist in it. (This is all related to
1325 * join_nodes() as described in this function's introductory comment.)
1326 * Both cases exist when the deleted node's parent (the node
1327 * that pointed to the deleted node's level) is not null but
1328 * it has no data: parent != NULL && DATA(parent) == NULL.
1330 * The first case is that the deleted node was the last on its level:
1331 * DOWN(parent) == NULL. This case can only exist if the parent was
1332 * previously deleted -- and so now, apparently, the parent should go
1333 * away. That can't be done though because there might be external
1334 * references to it, such as through a nodechain.
1336 * The other case also involves a parent with no data, but with the
1337 * deleted node being the next-to-last node instead of the last:
1338 * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
1339 * Presumably now the remaining node on the level should be joined
1340 * with the parent, but it's already been described why that can't be
1341 * done.
1345 * This function never fails.
1347 return (ISC_R_SUCCESS);
1350 void
1351 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
1353 REQUIRE(DNS_RBTNODE_VALID(node));
1354 REQUIRE(name != NULL);
1355 REQUIRE(name->offsets == NULL);
1357 NODENAME(node, name);
1360 isc_result_t
1361 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
1362 dns_name_t current;
1363 isc_result_t result;
1365 REQUIRE(DNS_RBTNODE_VALID(node));
1366 REQUIRE(name != NULL);
1367 REQUIRE(name->buffer != NULL);
1369 dns_name_init(&current, NULL);
1370 dns_name_reset(name);
1372 do {
1373 INSIST(node != NULL);
1375 NODENAME(node, &current);
1377 result = dns_name_concatenate(name, &current, name, NULL);
1378 if (result != ISC_R_SUCCESS)
1379 break;
1381 node = find_up(node);
1382 } while (! dns_name_isabsolute(name));
1384 return (result);
1387 char *
1388 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
1390 dns_fixedname_t fixedname;
1391 dns_name_t *name;
1392 isc_result_t result;
1394 REQUIRE(DNS_RBTNODE_VALID(node));
1395 REQUIRE(printname != NULL);
1397 dns_fixedname_init(&fixedname);
1398 name = dns_fixedname_name(&fixedname);
1399 result = dns_rbt_fullnamefromnode(node, name);
1400 if (result == ISC_R_SUCCESS)
1401 dns_name_format(name, printname, size);
1402 else
1403 snprintf(printname, size, "<error building name: %s>",
1404 dns_result_totext(result));
1406 return (printname);
1409 static isc_result_t
1410 create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
1411 dns_rbtnode_t *node;
1412 isc_region_t region;
1413 unsigned int labels;
1415 REQUIRE(name->offsets != NULL);
1417 dns_name_toregion(name, &region);
1418 labels = dns_name_countlabels(name);
1419 ENSURE(labels > 0);
1422 * Allocate space for the node structure, the name, and the offsets.
1424 node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) +
1425 region.length + labels);
1427 if (node == NULL)
1428 return (ISC_R_NOMEMORY);
1430 node->is_root = 0;
1431 PARENT(node) = NULL;
1432 RIGHT(node) = NULL;
1433 LEFT(node) = NULL;
1434 DOWN(node) = NULL;
1435 DATA(node) = NULL;
1436 #ifdef DNS_RBT_USEHASH
1437 HASHNEXT(node) = NULL;
1438 HASHVAL(node) = 0;
1439 #endif
1441 ISC_LINK_INIT(node, deadlink);
1443 LOCKNUM(node) = 0;
1444 WILD(node) = 0;
1445 DIRTY(node) = 0;
1446 dns_rbtnode_refinit(node, 0);
1447 node->find_callback = 0;
1449 MAKE_BLACK(node);
1452 * The following is stored to make reconstructing a name from the
1453 * stored value in the node easy: the length of the name, the number
1454 * of labels, whether the name is absolute or not, the name itself,
1455 * and the name's offsets table.
1457 * XXX RTH
1458 * The offsets table could be made smaller by eliminating the
1459 * first offset, which is always 0. This requires changes to
1460 * lib/dns/name.c.
1462 NAMELEN(node) = region.length;
1463 PADBYTES(node) = 0;
1464 OFFSETLEN(node) = labels;
1465 ATTRS(node) = name->attributes;
1467 memcpy(NAME(node), region.base, region.length);
1468 memcpy(OFFSETS(node), name->offsets, labels);
1470 #if DNS_RBT_USEMAGIC
1471 node->magic = DNS_RBTNODE_MAGIC;
1472 #endif
1473 *nodep = node;
1475 return (ISC_R_SUCCESS);
1478 #ifdef DNS_RBT_USEHASH
1479 static inline void
1480 hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
1481 unsigned int hash;
1483 HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
1485 hash = HASHVAL(node) % rbt->hashsize;
1486 HASHNEXT(node) = rbt->hashtable[hash];
1488 rbt->hashtable[hash] = node;
1491 static isc_result_t
1492 inithash(dns_rbt_t *rbt) {
1493 unsigned int bytes;
1495 rbt->hashsize = RBT_HASH_SIZE;
1496 bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
1497 rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
1499 if (rbt->hashtable == NULL)
1500 return (ISC_R_NOMEMORY);
1502 memset(rbt->hashtable, 0, bytes);
1504 return (ISC_R_SUCCESS);
1507 static void
1508 rehash(dns_rbt_t *rbt) {
1509 unsigned int oldsize;
1510 dns_rbtnode_t **oldtable;
1511 dns_rbtnode_t *node;
1512 unsigned int hash;
1513 unsigned int i;
1515 oldsize = rbt->hashsize;
1516 oldtable = rbt->hashtable;
1517 rbt->hashsize *= 2 + 1;
1518 rbt->hashtable = isc_mem_get(rbt->mctx,
1519 rbt->hashsize * sizeof(dns_rbtnode_t *));
1520 if (rbt->hashtable == NULL) {
1521 rbt->hashtable = oldtable;
1522 rbt->hashsize = oldsize;
1523 return;
1526 for (i = 0; i < rbt->hashsize; i++)
1527 rbt->hashtable[i] = NULL;
1529 for (i = 0; i < oldsize; i++) {
1530 node = oldtable[i];
1531 while (node != NULL) {
1532 hash = HASHVAL(node) % rbt->hashsize;
1533 oldtable[i] = HASHNEXT(node);
1534 HASHNEXT(node) = rbt->hashtable[hash];
1535 rbt->hashtable[hash] = node;
1536 node = oldtable[i];
1540 isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
1543 static inline void
1544 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
1546 REQUIRE(DNS_RBTNODE_VALID(node));
1548 if (rbt->nodecount >= (rbt->hashsize *3))
1549 rehash(rbt);
1551 hash_add_node(rbt, node, name);
1554 static inline void
1555 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
1556 unsigned int bucket;
1557 dns_rbtnode_t *bucket_node;
1559 REQUIRE(DNS_RBTNODE_VALID(node));
1561 if (rbt->hashtable != NULL) {
1562 bucket = HASHVAL(node) % rbt->hashsize;
1563 bucket_node = rbt->hashtable[bucket];
1565 if (bucket_node == node)
1566 rbt->hashtable[bucket] = HASHNEXT(node);
1567 else {
1568 while (HASHNEXT(bucket_node) != node) {
1569 INSIST(HASHNEXT(bucket_node) != NULL);
1570 bucket_node = HASHNEXT(bucket_node);
1572 HASHNEXT(bucket_node) = HASHNEXT(node);
1576 #endif /* DNS_RBT_USEHASH */
1578 static inline void
1579 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
1580 dns_rbtnode_t *child;
1582 REQUIRE(DNS_RBTNODE_VALID(node));
1583 REQUIRE(rootp != NULL);
1585 child = RIGHT(node);
1586 INSIST(child != NULL);
1588 RIGHT(node) = LEFT(child);
1589 if (LEFT(child) != NULL)
1590 PARENT(LEFT(child)) = node;
1591 LEFT(child) = node;
1593 if (child != NULL)
1594 PARENT(child) = PARENT(node);
1596 if (IS_ROOT(node)) {
1597 *rootp = child;
1598 child->is_root = 1;
1599 node->is_root = 0;
1601 } else {
1602 if (LEFT(PARENT(node)) == node)
1603 LEFT(PARENT(node)) = child;
1604 else
1605 RIGHT(PARENT(node)) = child;
1608 PARENT(node) = child;
1611 static inline void
1612 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
1613 dns_rbtnode_t *child;
1615 REQUIRE(DNS_RBTNODE_VALID(node));
1616 REQUIRE(rootp != NULL);
1618 child = LEFT(node);
1619 INSIST(child != NULL);
1621 LEFT(node) = RIGHT(child);
1622 if (RIGHT(child) != NULL)
1623 PARENT(RIGHT(child)) = node;
1624 RIGHT(child) = node;
1626 if (child != NULL)
1627 PARENT(child) = PARENT(node);
1629 if (IS_ROOT(node)) {
1630 *rootp = child;
1631 child->is_root = 1;
1632 node->is_root = 0;
1634 } else {
1635 if (LEFT(PARENT(node)) == node)
1636 LEFT(PARENT(node)) = child;
1637 else
1638 RIGHT(PARENT(node)) = child;
1641 PARENT(node) = child;
1645 * This is the real workhorse of the insertion code, because it does the
1646 * true red/black tree on a single level.
1648 static void
1649 dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
1650 dns_rbtnode_t **rootp)
1652 dns_rbtnode_t *child, *root, *parent, *grandparent;
1653 dns_name_t add_name, current_name;
1654 dns_offsets_t add_offsets, current_offsets;
1656 REQUIRE(rootp != NULL);
1657 REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
1658 RIGHT(node) == NULL);
1659 REQUIRE(current != NULL);
1661 root = *rootp;
1662 if (root == NULL) {
1664 * First node of a level.
1666 MAKE_BLACK(node);
1667 node->is_root = 1;
1668 PARENT(node) = current;
1669 *rootp = node;
1670 return;
1673 child = root;
1675 dns_name_init(&add_name, add_offsets);
1676 NODENAME(node, &add_name);
1678 dns_name_init(&current_name, current_offsets);
1679 NODENAME(current, &current_name);
1681 if (order < 0) {
1682 INSIST(LEFT(current) == NULL);
1683 LEFT(current) = node;
1684 } else {
1685 INSIST(RIGHT(current) == NULL);
1686 RIGHT(current) = node;
1689 INSIST(PARENT(node) == NULL);
1690 PARENT(node) = current;
1692 MAKE_RED(node);
1694 while (node != root && IS_RED(PARENT(node))) {
1696 * XXXDCL could do away with separate parent and grandparent
1697 * variables. They are vestiges of the days before parent
1698 * pointers. However, they make the code a little clearer.
1701 parent = PARENT(node);
1702 grandparent = PARENT(parent);
1704 if (parent == LEFT(grandparent)) {
1705 child = RIGHT(grandparent);
1706 if (child != NULL && IS_RED(child)) {
1707 MAKE_BLACK(parent);
1708 MAKE_BLACK(child);
1709 MAKE_RED(grandparent);
1710 node = grandparent;
1711 } else {
1712 if (node == RIGHT(parent)) {
1713 rotate_left(parent, &root);
1714 node = parent;
1715 parent = PARENT(node);
1716 grandparent = PARENT(parent);
1718 MAKE_BLACK(parent);
1719 MAKE_RED(grandparent);
1720 rotate_right(grandparent, &root);
1722 } else {
1723 child = LEFT(grandparent);
1724 if (child != NULL && IS_RED(child)) {
1725 MAKE_BLACK(parent);
1726 MAKE_BLACK(child);
1727 MAKE_RED(grandparent);
1728 node = grandparent;
1729 } else {
1730 if (node == LEFT(parent)) {
1731 rotate_right(parent, &root);
1732 node = parent;
1733 parent = PARENT(node);
1734 grandparent = PARENT(parent);
1736 MAKE_BLACK(parent);
1737 MAKE_RED(grandparent);
1738 rotate_left(grandparent, &root);
1743 MAKE_BLACK(root);
1744 ENSURE(IS_ROOT(root));
1745 *rootp = root;
1747 return;
1751 * This is the real workhorse of the deletion code, because it does the
1752 * true red/black tree on a single level.
1754 static void
1755 dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
1756 dns_rbtnode_t *child, *sibling, *parent;
1757 dns_rbtnode_t *successor;
1759 REQUIRE(delete != NULL);
1762 * Verify that the parent history is (apparently) correct.
1764 INSIST((IS_ROOT(delete) && *rootp == delete) ||
1765 (! IS_ROOT(delete) &&
1766 (LEFT(PARENT(delete)) == delete ||
1767 RIGHT(PARENT(delete)) == delete)));
1769 child = NULL;
1771 if (LEFT(delete) == NULL) {
1772 if (RIGHT(delete) == NULL) {
1773 if (IS_ROOT(delete)) {
1775 * This is the only item in the tree.
1777 *rootp = NULL;
1778 return;
1780 } else
1782 * This node has one child, on the right.
1784 child = RIGHT(delete);
1786 } else if (RIGHT(delete) == NULL)
1788 * This node has one child, on the left.
1790 child = LEFT(delete);
1791 else {
1792 dns_rbtnode_t holder, *tmp = &holder;
1795 * This node has two children, so it cannot be directly
1796 * deleted. Find its immediate in-order successor and
1797 * move it to this location, then do the deletion at the
1798 * old site of the successor.
1800 successor = RIGHT(delete);
1801 while (LEFT(successor) != NULL)
1802 successor = LEFT(successor);
1805 * The successor cannot possibly have a left child;
1806 * if there is any child, it is on the right.
1808 if (RIGHT(successor) != NULL)
1809 child = RIGHT(successor);
1812 * Swap the two nodes; it would be simpler to just replace
1813 * the value being deleted with that of the successor,
1814 * but this rigamarole is done so the caller has complete
1815 * control over the pointers (and memory allocation) of
1816 * all of nodes. If just the key value were removed from
1817 * the tree, the pointer to the node would be unchanged.
1821 * First, put the successor in the tree location of the
1822 * node to be deleted. Save its existing tree pointer
1823 * information, which will be needed when linking up
1824 * delete to the successor's old location.
1826 memcpy(tmp, successor, sizeof(dns_rbtnode_t));
1828 if (IS_ROOT(delete)) {
1829 *rootp = successor;
1830 successor->is_root = ISC_TRUE;
1831 delete->is_root = ISC_FALSE;
1833 } else
1834 if (LEFT(PARENT(delete)) == delete)
1835 LEFT(PARENT(delete)) = successor;
1836 else
1837 RIGHT(PARENT(delete)) = successor;
1839 PARENT(successor) = PARENT(delete);
1840 LEFT(successor) = LEFT(delete);
1841 RIGHT(successor) = RIGHT(delete);
1842 COLOR(successor) = COLOR(delete);
1844 if (LEFT(successor) != NULL)
1845 PARENT(LEFT(successor)) = successor;
1846 if (RIGHT(successor) != successor)
1847 PARENT(RIGHT(successor)) = successor;
1850 * Now relink the node to be deleted into the
1851 * successor's previous tree location. PARENT(tmp)
1852 * is the successor's original parent.
1854 INSIST(! IS_ROOT(delete));
1856 if (PARENT(tmp) == delete) {
1858 * Node being deleted was successor's parent.
1860 RIGHT(successor) = delete;
1861 PARENT(delete) = successor;
1863 } else {
1864 LEFT(PARENT(tmp)) = delete;
1865 PARENT(delete) = PARENT(tmp);
1869 * Original location of successor node has no left.
1871 LEFT(delete) = NULL;
1872 RIGHT(delete) = RIGHT(tmp);
1873 COLOR(delete) = COLOR(tmp);
1877 * Remove the node by removing the links from its parent.
1879 if (! IS_ROOT(delete)) {
1880 if (LEFT(PARENT(delete)) == delete)
1881 LEFT(PARENT(delete)) = child;
1882 else
1883 RIGHT(PARENT(delete)) = child;
1885 if (child != NULL)
1886 PARENT(child) = PARENT(delete);
1888 } else {
1890 * This is the root being deleted, and at this point
1891 * it is known to have just one child.
1893 *rootp = child;
1894 child->is_root = 1;
1895 PARENT(child) = PARENT(delete);
1899 * Fix color violations.
1901 if (IS_BLACK(delete)) {
1902 parent = PARENT(delete);
1904 while (child != *rootp && IS_BLACK(child)) {
1905 INSIST(child == NULL || ! IS_ROOT(child));
1907 if (LEFT(parent) == child) {
1908 sibling = RIGHT(parent);
1910 if (IS_RED(sibling)) {
1911 MAKE_BLACK(sibling);
1912 MAKE_RED(parent);
1913 rotate_left(parent, rootp);
1914 sibling = RIGHT(parent);
1917 if (IS_BLACK(LEFT(sibling)) &&
1918 IS_BLACK(RIGHT(sibling))) {
1919 MAKE_RED(sibling);
1920 child = parent;
1922 } else {
1924 if (IS_BLACK(RIGHT(sibling))) {
1925 MAKE_BLACK(LEFT(sibling));
1926 MAKE_RED(sibling);
1927 rotate_right(sibling, rootp);
1928 sibling = RIGHT(parent);
1931 COLOR(sibling) = COLOR(parent);
1932 MAKE_BLACK(parent);
1933 MAKE_BLACK(RIGHT(sibling));
1934 rotate_left(parent, rootp);
1935 child = *rootp;
1938 } else {
1940 * Child is parent's right child.
1941 * Everything is done the same as above,
1942 * except mirrored.
1944 sibling = LEFT(parent);
1946 if (IS_RED(sibling)) {
1947 MAKE_BLACK(sibling);
1948 MAKE_RED(parent);
1949 rotate_right(parent, rootp);
1950 sibling = LEFT(parent);
1953 if (IS_BLACK(LEFT(sibling)) &&
1954 IS_BLACK(RIGHT(sibling))) {
1955 MAKE_RED(sibling);
1956 child = parent;
1958 } else {
1959 if (IS_BLACK(LEFT(sibling))) {
1960 MAKE_BLACK(RIGHT(sibling));
1961 MAKE_RED(sibling);
1962 rotate_left(sibling, rootp);
1963 sibling = LEFT(parent);
1966 COLOR(sibling) = COLOR(parent);
1967 MAKE_BLACK(parent);
1968 MAKE_BLACK(LEFT(sibling));
1969 rotate_right(parent, rootp);
1970 child = *rootp;
1974 parent = PARENT(child);
1977 if (IS_RED(child))
1978 MAKE_BLACK(child);
1983 * This should only be used on the root of a tree, because no color fixup
1984 * is done at all.
1986 * NOTE: No root pointer maintenance is done, because the function is only
1987 * used for two cases:
1988 * + deleting everything DOWN from a node that is itself being deleted, and
1989 * + deleting the entire tree of trees from dns_rbt_destroy.
1990 * In each case, the root pointer is no longer relevant, so there
1991 * is no need for a root parameter to this function.
1993 * If the function is ever intended to be used to delete something where
1994 * a pointer needs to be told that this tree no longer exists,
1995 * this function would need to adjusted accordingly.
1997 static isc_result_t
1998 dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) {
1999 isc_result_t result = ISC_R_SUCCESS;
2000 REQUIRE(VALID_RBT(rbt));
2002 if (node == NULL)
2003 return (result);
2005 if (LEFT(node) != NULL) {
2006 result = dns_rbt_deletetree(rbt, LEFT(node));
2007 if (result != ISC_R_SUCCESS)
2008 goto done;
2009 LEFT(node) = NULL;
2011 if (RIGHT(node) != NULL) {
2012 result = dns_rbt_deletetree(rbt, RIGHT(node));
2013 if (result != ISC_R_SUCCESS)
2014 goto done;
2015 RIGHT(node) = NULL;
2017 if (DOWN(node) != NULL) {
2018 result = dns_rbt_deletetree(rbt, DOWN(node));
2019 if (result != ISC_R_SUCCESS)
2020 goto done;
2021 DOWN(node) = NULL;
2023 done:
2024 if (result != ISC_R_SUCCESS)
2025 return (result);
2027 if (DATA(node) != NULL && rbt->data_deleter != NULL)
2028 rbt->data_deleter(DATA(node), rbt->deleter_arg);
2030 unhash_node(rbt, node);
2031 #if DNS_RBT_USEMAGIC
2032 node->magic = 0;
2033 #endif
2035 isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
2036 rbt->nodecount--;
2037 return (result);
2040 static void
2041 dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
2042 dns_rbtnode_t **nodep)
2044 dns_rbtnode_t *parent;
2045 dns_rbtnode_t *node = *nodep;
2046 REQUIRE(VALID_RBT(rbt));
2048 again:
2049 if (node == NULL) {
2050 *nodep = NULL;
2051 return;
2054 traverse:
2055 if (LEFT(node) != NULL) {
2056 node = LEFT(node);
2057 goto traverse;
2059 if (DOWN(node) != NULL) {
2060 node = DOWN(node);
2061 goto traverse;
2064 if (DATA(node) != NULL && rbt->data_deleter != NULL)
2065 rbt->data_deleter(DATA(node), rbt->deleter_arg);
2068 * Note: we don't call unhash_node() here as we are destroying
2069 * the complete rbt tree.
2071 #if DNS_RBT_USEMAGIC
2072 node->magic = 0;
2073 #endif
2074 parent = PARENT(node);
2075 if (RIGHT(node) != NULL)
2076 PARENT(RIGHT(node)) = parent;
2077 if (parent != NULL) {
2078 if (LEFT(parent) == node)
2079 LEFT(parent) = RIGHT(node);
2080 else if (DOWN(parent) == node)
2081 DOWN(parent) = RIGHT(node);
2082 } else
2083 parent = RIGHT(node);
2085 isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
2086 rbt->nodecount--;
2087 node = parent;
2088 if (quantum != 0 && --quantum == 0) {
2089 *nodep = node;
2090 return;
2092 goto again;
2095 static void
2096 dns_rbt_indent(int depth) {
2097 int i;
2099 for (i = 0; i < depth; i++)
2100 putchar('\t');
2103 static void
2104 dns_rbt_printnodename(dns_rbtnode_t *node) {
2105 isc_region_t r;
2106 dns_name_t name;
2107 char buffer[DNS_NAME_FORMATSIZE];
2108 dns_offsets_t offsets;
2110 r.length = NAMELEN(node);
2111 r.base = NAME(node);
2113 dns_name_init(&name, offsets);
2114 dns_name_fromregion(&name, &r);
2116 dns_name_format(&name, buffer, sizeof(buffer));
2118 printf("%s", buffer);
2121 static void
2122 dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent, int depth) {
2123 dns_rbt_indent(depth);
2125 if (root != NULL) {
2126 dns_rbt_printnodename(root);
2127 printf(" (%s", IS_RED(root) ? "RED" : "black");
2128 if (parent) {
2129 printf(" from ");
2130 dns_rbt_printnodename(parent);
2133 if ((! IS_ROOT(root) && PARENT(root) != parent) ||
2134 ( IS_ROOT(root) && depth > 0 &&
2135 DOWN(PARENT(root)) != root)) {
2137 printf(" (BAD parent pointer! -> ");
2138 if (PARENT(root) != NULL)
2139 dns_rbt_printnodename(PARENT(root));
2140 else
2141 printf("NULL");
2142 printf(")");
2145 printf(")\n");
2148 depth++;
2150 if (DOWN(root)) {
2151 dns_rbt_indent(depth);
2152 printf("++ BEG down from ");
2153 dns_rbt_printnodename(root);
2154 printf("\n");
2155 dns_rbt_printtree(DOWN(root), NULL, depth);
2156 dns_rbt_indent(depth);
2157 printf("-- END down from ");
2158 dns_rbt_printnodename(root);
2159 printf("\n");
2162 if (IS_RED(root) && IS_RED(LEFT(root)))
2163 printf("** Red/Red color violation on left\n");
2164 dns_rbt_printtree(LEFT(root), root, depth);
2166 if (IS_RED(root) && IS_RED(RIGHT(root)))
2167 printf("** Red/Red color violation on right\n");
2168 dns_rbt_printtree(RIGHT(root), root, depth);
2170 } else
2171 printf("NULL\n");
2174 void
2175 dns_rbt_printall(dns_rbt_t *rbt) {
2176 REQUIRE(VALID_RBT(rbt));
2178 dns_rbt_printtree(rbt->root, NULL, 0);
2182 * Chain Functions
2185 void
2186 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
2188 * Initialize 'chain'.
2191 REQUIRE(chain != NULL);
2193 chain->mctx = mctx;
2194 chain->end = NULL;
2195 chain->level_count = 0;
2196 chain->level_matches = 0;
2197 memset(chain->levels, 0, sizeof(chain->levels));
2199 chain->magic = CHAIN_MAGIC;
2202 isc_result_t
2203 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
2204 dns_name_t *origin, dns_rbtnode_t **node)
2206 isc_result_t result = ISC_R_SUCCESS;
2208 REQUIRE(VALID_CHAIN(chain));
2210 if (node != NULL)
2211 *node = chain->end;
2213 if (chain->end == NULL)
2214 return (ISC_R_NOTFOUND);
2216 if (name != NULL) {
2217 NODENAME(chain->end, name);
2219 if (chain->level_count == 0) {
2221 * Names in the top level tree are all absolute.
2222 * Always make 'name' relative.
2224 INSIST(dns_name_isabsolute(name));
2227 * This is cheaper than dns_name_getlabelsequence().
2229 name->labels--;
2230 name->length--;
2231 name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
2235 if (origin != NULL) {
2236 if (chain->level_count > 0)
2237 result = chain_name(chain, origin, ISC_FALSE);
2238 else
2239 result = dns_name_copy(dns_rootname, origin, NULL);
2242 return (result);
2245 isc_result_t
2246 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
2247 dns_name_t *origin)
2249 dns_rbtnode_t *current, *previous, *predecessor;
2250 isc_result_t result = ISC_R_SUCCESS;
2251 isc_boolean_t new_origin = ISC_FALSE;
2253 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
2255 predecessor = NULL;
2257 current = chain->end;
2259 if (LEFT(current) != NULL) {
2261 * Moving left one then right as far as possible is the
2262 * previous node, at least for this level.
2264 current = LEFT(current);
2266 while (RIGHT(current) != NULL)
2267 current = RIGHT(current);
2269 predecessor = current;
2271 } else {
2273 * No left links, so move toward the root. If at any point on
2274 * the way there the link from parent to child is a right
2275 * link, then the parent is the previous node, at least
2276 * for this level.
2278 while (! IS_ROOT(current)) {
2279 previous = current;
2280 current = PARENT(current);
2282 if (RIGHT(current) == previous) {
2283 predecessor = current;
2284 break;
2289 if (predecessor != NULL) {
2291 * Found a predecessor node in this level. It might not
2292 * really be the predecessor, however.
2294 if (DOWN(predecessor) != NULL) {
2296 * The predecessor is really down at least one level.
2297 * Go down and as far right as possible, and repeat
2298 * as long as the rightmost node has a down pointer.
2300 do {
2302 * XXX DCL Need to do something about origins
2303 * here. See whether to go down, and if so
2304 * whether it is truly what Bob calls a
2305 * new origin.
2307 ADD_LEVEL(chain, predecessor);
2308 predecessor = DOWN(predecessor);
2310 /* XXX DCL duplicated from above; clever
2311 * way to unduplicate? */
2313 while (RIGHT(predecessor) != NULL)
2314 predecessor = RIGHT(predecessor);
2315 } while (DOWN(predecessor) != NULL);
2317 /* XXX DCL probably needs work on the concept */
2318 if (origin != NULL)
2319 new_origin = ISC_TRUE;
2322 } else if (chain->level_count > 0) {
2324 * Dang, didn't find a predecessor in this level.
2325 * Got to the root of this level without having traversed
2326 * any right links. Ascend the tree one level; the
2327 * node that points to this tree is the predecessor.
2329 INSIST(chain->level_count > 0 && IS_ROOT(current));
2330 predecessor = chain->levels[--chain->level_count];
2332 /* XXX DCL probably needs work on the concept */
2334 * Don't declare an origin change when the new origin is "."
2335 * at the top level tree, because "." is declared as the origin
2336 * for the second level tree.
2338 if (origin != NULL &&
2339 (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
2340 new_origin = ISC_TRUE;
2343 if (predecessor != NULL) {
2344 chain->end = predecessor;
2346 if (new_origin) {
2347 result = dns_rbtnodechain_current(chain, name, origin,
2348 NULL);
2349 if (result == ISC_R_SUCCESS)
2350 result = DNS_R_NEWORIGIN;
2352 } else
2353 result = dns_rbtnodechain_current(chain, name, NULL,
2354 NULL);
2356 } else
2357 result = ISC_R_NOMORE;
2359 return (result);
2362 isc_result_t
2363 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
2364 dns_name_t *origin)
2366 dns_rbtnode_t *current, *previous, *successor;
2367 isc_result_t result = ISC_R_SUCCESS;
2368 isc_boolean_t new_origin = ISC_FALSE;
2370 REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
2372 successor = NULL;
2374 current = chain->end;
2377 * If there is a level below this node, the next node is the leftmost
2378 * node of the next level.
2380 if (DOWN(current) != NULL) {
2382 * Don't declare an origin change when the new origin is "."
2383 * at the second level tree, because "." is already declared
2384 * as the origin for the top level tree.
2386 if (chain->level_count > 0 ||
2387 OFFSETLEN(current) > 1)
2388 new_origin = ISC_TRUE;
2390 ADD_LEVEL(chain, current);
2391 current = DOWN(current);
2393 while (LEFT(current) != NULL)
2394 current = LEFT(current);
2396 successor = current;
2398 } else if (RIGHT(current) == NULL) {
2400 * The successor is up, either in this level or a previous one.
2401 * Head back toward the root of the tree, looking for any path
2402 * that was via a left link; the successor is the node that has
2403 * that left link. In the event the root of the level is
2404 * reached without having traversed any left links, ascend one
2405 * level and look for either a right link off the point of
2406 * ascent, or search for a left link upward again, repeating
2407 * ascends until either case is true.
2409 do {
2410 while (! IS_ROOT(current)) {
2411 previous = current;
2412 current = PARENT(current);
2414 if (LEFT(current) == previous) {
2415 successor = current;
2416 break;
2420 if (successor == NULL) {
2422 * Reached the root without having traversed
2423 * any left pointers, so this level is done.
2425 if (chain->level_count == 0)
2426 break;
2428 current = chain->levels[--chain->level_count];
2429 new_origin = ISC_TRUE;
2431 if (RIGHT(current) != NULL)
2432 break;
2434 } while (successor == NULL);
2437 if (successor == NULL && RIGHT(current) != NULL) {
2438 current = RIGHT(current);
2440 while (LEFT(current) != NULL)
2441 current = LEFT(current);
2443 successor = current;
2446 if (successor != NULL) {
2447 chain->end = successor;
2450 * It is not necessary to use dns_rbtnodechain_current like
2451 * the other functions because this function will never
2452 * find a node in the topmost level. This is because the
2453 * root level will never be more than one name, and everything
2454 * in the megatree is a successor to that node, down at
2455 * the second level or below.
2458 if (name != NULL)
2459 NODENAME(chain->end, name);
2461 if (new_origin) {
2462 if (origin != NULL)
2463 result = chain_name(chain, origin, ISC_FALSE);
2465 if (result == ISC_R_SUCCESS)
2466 result = DNS_R_NEWORIGIN;
2468 } else
2469 result = ISC_R_SUCCESS;
2471 } else
2472 result = ISC_R_NOMORE;
2474 return (result);
2477 isc_result_t
2478 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
2479 dns_name_t *name, dns_name_t *origin)
2482 isc_result_t result;
2484 REQUIRE(VALID_RBT(rbt));
2485 REQUIRE(VALID_CHAIN(chain));
2487 dns_rbtnodechain_reset(chain);
2489 chain->end = rbt->root;
2491 result = dns_rbtnodechain_current(chain, name, origin, NULL);
2493 if (result == ISC_R_SUCCESS)
2494 result = DNS_R_NEWORIGIN;
2496 return (result);
2499 isc_result_t
2500 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
2501 dns_name_t *name, dns_name_t *origin)
2504 isc_result_t result;
2506 REQUIRE(VALID_RBT(rbt));
2507 REQUIRE(VALID_CHAIN(chain));
2509 dns_rbtnodechain_reset(chain);
2511 result = move_chain_to_last(chain, rbt->root);
2512 if (result != ISC_R_SUCCESS)
2513 return (result);
2515 result = dns_rbtnodechain_current(chain, name, origin, NULL);
2517 if (result == ISC_R_SUCCESS)
2518 result = DNS_R_NEWORIGIN;
2520 return (result);
2524 void
2525 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
2527 * Free any dynamic storage associated with 'chain', and then
2528 * reinitialize 'chain'.
2531 REQUIRE(VALID_CHAIN(chain));
2533 chain->end = NULL;
2534 chain->level_count = 0;
2535 chain->level_matches = 0;
2538 void
2539 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
2541 * Free any dynamic storage associated with 'chain', and then
2542 * invalidate 'chain'.
2545 dns_rbtnodechain_reset(chain);
2547 chain->magic = 0;