Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / include / dns / rbt.h
1 /*
2  * Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: rbt.h,v 1.69.36.2 2009/01/19 23:47:03 tbox Exp $ */
19
20 #ifndef DNS_RBT_H
21 #define DNS_RBT_H 1
22
23 /*! \file dns/rbt.h */
24
25 #include <isc/lang.h>
26 #include <isc/magic.h>
27 #include <isc/refcount.h>
28
29 #include <dns/types.h>
30
31 ISC_LANG_BEGINDECLS
32
33 #define DNS_RBT_USEHASH 1
34
35 /*@{*/
36 /*%
37  * Option values for dns_rbt_findnode() and dns_rbt_findname().
38  * These are used to form a bitmask.
39  */
40 #define DNS_RBTFIND_NOOPTIONS                   0x00
41 #define DNS_RBTFIND_EMPTYDATA                   0x01
42 #define DNS_RBTFIND_NOEXACT                     0x02
43 #define DNS_RBTFIND_NOPREDECESSOR               0x04
44 /*@}*/
45
46 #ifndef DNS_RBT_USEISCREFCOUNT
47 #ifdef ISC_REFCOUNT_HAVEATOMIC
48 #define DNS_RBT_USEISCREFCOUNT 1
49 #endif
50 #endif
51
52 /*
53  * These should add up to 30.
54  */
55 #define DNS_RBT_LOCKLENGTH                      10
56 #define DNS_RBT_REFLENGTH                       20
57
58 #define DNS_RBTNODE_MAGIC               ISC_MAGIC('R','B','N','O')
59 #if DNS_RBT_USEMAGIC
60 #define DNS_RBTNODE_VALID(n)            ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
61 #else
62 #define DNS_RBTNODE_VALID(n)            ISC_TRUE
63 #endif
64
65 /*%
66  * This is the structure that is used for each node in the red/black
67  * tree of trees.  NOTE WELL:  the implementation manages this as a variable
68  * length structure, with the actual wire-format name and other data
69  * appended to this structure.  Allocating a contiguous block of memory for
70  * multiple dns_rbtnode structures will not work.
71  */
72 typedef struct dns_rbtnode dns_rbtnode_t;
73 struct dns_rbtnode {
74 #if DNS_RBT_USEMAGIC
75         unsigned int magic;
76 #endif
77         dns_rbtnode_t *parent;
78         dns_rbtnode_t *left;
79         dns_rbtnode_t *right;
80         dns_rbtnode_t *down;
81 #ifdef DNS_RBT_USEHASH
82         dns_rbtnode_t *hashnext;
83 #endif
84
85         /*%
86          * Used for LRU cache.  This linked list is used to mark nodes which
87          * have no data any longer, but we cannot unlink at that exact moment
88          * because we did not or could not obtain a write lock on the tree.
89          */
90         ISC_LINK(dns_rbtnode_t) deadlink;
91
92         /*@{*/
93         /*!
94          * The following bitfields add up to a total bitwidth of 32.
95          * The range of values necessary for each item is indicated,
96          * but in the case of "attributes" the field is wider to accommodate
97          * possible future expansion.  "offsetlen" could be one bit
98          * narrower by always adjusting its value by 1 to find the real
99          * offsetlen, but doing so does not gain anything (except perhaps
100          * another bit for "attributes", which doesn't yet need any more).
101          *
102          * In each case below the "range" indicated is what's _necessary_ for
103          * the bitfield to hold, not what it actually _can_ hold.
104          */
105         unsigned int is_root : 1;       /*%< range is 0..1 */
106         unsigned int color : 1;         /*%< range is 0..1 */
107         unsigned int find_callback : 1; /*%< range is 0..1 */
108         unsigned int attributes : 4;    /*%< range is 0..2 */
109         unsigned int namelen : 8;       /*%< range is 1..255 */
110         unsigned int offsetlen : 8;     /*%< range is 1..128 */
111         unsigned int padbytes : 9;      /*%< range is 0..380 */
112         /*@}*/
113
114 #ifdef DNS_RBT_USEHASH
115         unsigned int hashval;
116 #endif
117
118         /*@{*/
119         /*!
120          * These values are used in the RBT DB implementation.  The appropriate
121          * node lock must be held before accessing them.
122          */
123         void *data;
124         unsigned int dirty:1;
125         unsigned int wild:1;
126         unsigned int locknum:DNS_RBT_LOCKLENGTH;
127 #ifndef DNS_RBT_USEISCREFCOUNT
128         unsigned int references:DNS_RBT_REFLENGTH;
129 #else
130         isc_refcount_t references; /* note that this is not in the bitfield */
131 #endif
132         /*@}*/
133 };
134
135 typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
136                                               dns_name_t *name,
137                                               void *callback_arg);
138
139 /*****
140  *****  Chain Info
141  *****/
142
143 /*!
144  * A chain is used to keep track of the sequence of nodes to reach any given
145  * node from the root of the tree.  Originally nodes did not have parent
146  * pointers in them (for memory usage reasons) so there was no way to find
147  * the path back to the root from any given node.  Now that nodes have parent
148  * pointers, chains might be going away in a future release, though the
149  * movement functionality would remain.
150  *
151  * In any event, parent information, whether via parent pointers or chains, is
152  * necessary information for iterating through the tree or for basic internal
153  * tree maintenance issues (ie, the rotations that are done to rebalance the
154  * tree when a node is added).  The obvious implication of this is that for a
155  * chain to remain valid, the tree has to be locked down against writes for the
156  * duration of the useful life of the chain, because additions or removals can
157  * change the path from the root to the node the chain has targeted.
158  *
159  * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take
160  * dns_name_t parameters for the name and the origin, which can be NULL.  If
161  * non-NULL, 'name' will end up pointing to the name data and offsets that are
162  * stored at the node (and thus it will be read-only), so it should be a
163  * regular dns_name_t that has been initialized with dns_name_init.  When
164  * 'origin' is non-NULL, it will get the name of the origin stored in it, so it
165  * needs to have its own buffer space and offsets, which is most easily
166  * accomplished with a dns_fixedname_t.  It is _not_ necessary to reinitialize
167  * either 'name' or 'origin' between calls to the chain functions.
168  *
169  * NOTE WELL: even though the name data at the root of the tree of trees will
170  * be absolute (typically just "."), it will will be made into a relative name
171  * with an origin of "." -- an empty name when the node is ".".  This is
172  * because a common on operation on 'name' and 'origin' is to use
173  * dns_name_concatenate() on them to generate the complete name.  An empty name
174  * can be detected when dns_name_countlabels == 0, and is printed by
175  * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's
176  * definition of "@" as the current origin.
177  *
178  * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next
179  * functions but additionally can provide the node to which the chain points.
180  */
181
182 /*%
183  * The number of level blocks to allocate at a time.  Currently the maximum
184  * number of levels is allocated directly in the structure, but future
185  * revisions of this code might have a static initial block with dynamic
186  * growth.  Allocating space for 256 levels when the tree is almost never that
187  * deep is wasteful, but it's not clear that it matters, since the waste is
188  * only 2MB for 1000 concurrently active chains on a system with 64-bit
189  * pointers.
190  */
191 #define DNS_RBT_LEVELBLOCK 254
192
193 typedef struct dns_rbtnodechain {
194         unsigned int            magic;
195         isc_mem_t *             mctx;
196         /*%
197          * The terminal node of the chain.  It is not in levels[].
198          * This is ostensibly private ... but in a pinch it could be
199          * used tell that the chain points nowhere without needing to
200          * call dns_rbtnodechain_current().
201          */
202         dns_rbtnode_t *         end;
203         /*%
204          * The maximum number of labels in a name is 128; bitstrings mean
205          * a conceptually very large number (which I have not bothered to
206          * compute) of logical levels because splitting can potentially occur
207          * at each bit.  However, DNSSEC restricts the number of "logical"
208          * labels in a name to 255, meaning only 254 pointers are needed
209          * in the worst case.
210          */
211         dns_rbtnode_t *         levels[DNS_RBT_LEVELBLOCK];
212         /*%
213          * level_count indicates how deep the chain points into the
214          * tree of trees, and is the index into the levels[] array.
215          * Thus, levels[level_count - 1] is the last level node stored.
216          * A chain that points to the top level of the tree of trees has
217          * a level_count of 0, the first level has a level_count of 1, and
218          * so on.
219          */
220         unsigned int            level_count;
221         /*%
222          * level_matches tells how many levels matched above the node
223          * returned by dns_rbt_findnode().  A match (partial or exact) found
224          * in the first level thus results in level_matches being set to 1.
225          * This is used by the rbtdb to set the start point for a recursive
226          * search of superdomains until the RR it is looking for is found.
227          */
228         unsigned int            level_matches;
229 } dns_rbtnodechain_t;
230
231 /*****
232  ***** Public interfaces.
233  *****/
234 isc_result_t
235 dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
236                void *deleter_arg, dns_rbt_t **rbtp);
237 /*%<
238  * Initialize a red-black tree of trees.
239  *
240  * Notes:
241  *\li   The deleter argument, if non-null, points to a function that is
242  *      responsible for cleaning up any memory associated with the data
243  *      pointer of a node when the node is deleted.  It is passed the
244  *      deleted node's data pointer as its first argument and deleter_arg
245  *      as its second argument.
246  *
247  * Requires:
248  * \li  mctx is a pointer to a valid memory context.
249  *\li   rbtp != NULL && *rbtp == NULL
250  *\li   arg == NULL iff deleter == NULL
251  *
252  * Ensures:
253  *\li   If result is ISC_R_SUCCESS:
254  *              *rbtp points to a valid red-black tree manager
255  *
256  *\li   If result is failure:
257  *              *rbtp does not point to a valid red-black tree manager.
258  *
259  * Returns:
260  *\li   #ISC_R_SUCCESS  Success
261  *\li   #ISC_R_NOMEMORY Resource limit: Out of Memory
262  */
263
264 isc_result_t
265 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
266 /*%<
267  * Add 'name' to the tree of trees, associated with 'data'.
268  *
269  * Notes:
270  *\li   'data' is never required to be non-NULL, but specifying it
271  *      when the name is added is faster than searching for 'name'
272  *      again and then setting the data pointer.  The lack of a data pointer
273  *      for a node also has other ramifications regarding whether
274  *      dns_rbt_findname considers a node to exist, or dns_rbt_deletename
275  *      joins nodes.
276  *
277  * Requires:
278  *\li   rbt is a valid rbt manager.
279  *\li   dns_name_isabsolute(name) == TRUE
280  *
281  * Ensures:
282  *\li   'name' is not altered in any way.
283  *
284  *\li   Any external references to nodes in the tree are unaffected by
285  *      node splits that are necessary to insert the new name.
286  *
287  *\li   If result is #ISC_R_SUCCESS:
288  *              'name' is findable in the red/black tree of trees in O(log N).
289  *              The data pointer of the node for 'name' is set to 'data'.
290  *
291  *\li   If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
292  *              The tree of trees is unaltered.
293  *
294  *\li   If result is #ISC_R_NOMEMORY:
295  *              No guarantees.
296  *
297  * Returns:
298  *\li   #ISC_R_SUCCESS  Success
299  *\li   #ISC_R_EXISTS   The name already exists with associated data.
300  *\li   #ISC_R_NOSPACE  The name had more logical labels than are allowed.
301  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
302  */
303
304 isc_result_t
305 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
306
307 /*%<
308  * Just like dns_rbt_addname, but returns the address of the node.
309  *
310  * Requires:
311  *\li   rbt is a valid rbt structure.
312  *\li   dns_name_isabsolute(name) == TRUE
313  *\li   nodep != NULL && *nodep == NULL
314  *
315  * Ensures:
316  *\li   'name' is not altered in any way.
317  *
318  *\li   Any external references to nodes in the tree are unaffected by
319  *      node splits that are necessary to insert the new name.
320  *
321  *\li   If result is ISC_R_SUCCESS:
322  *              'name' is findable in the red/black tree of trees in O(log N).
323  *              *nodep is the node that was added for 'name'.
324  *
325  *\li   If result is ISC_R_EXISTS:
326  *              The tree of trees is unaltered.
327  *              *nodep is the existing node for 'name'.
328  *
329  *\li   If result is ISC_R_NOMEMORY:
330  *              No guarantees.
331  *
332  * Returns:
333  *\li   #ISC_R_SUCCESS  Success
334  *\li   #ISC_R_EXISTS   The name already exists, possibly without data.
335  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
336  */
337
338 isc_result_t
339 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
340                  dns_name_t *foundname, void **data);
341 /*%<
342  * Get the data pointer associated with 'name'.
343  *
344  * Notes:
345  *\li   When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
346  *      returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is
347  *      an exact match in the tree.
348  *
349  *\li   A node that has no data is considered not to exist for this function,
350  *      unless the #DNS_RBTFIND_EMPTYDATA option is set.
351  *
352  * Requires:
353  *\li   rbt is a valid rbt manager.
354  *\li   dns_name_isabsolute(name) == TRUE
355  *\li   data != NULL && *data == NULL
356  *
357  * Ensures:
358  *\li   'name' and the tree are not altered in any way.
359  *
360  *\li   If result is ISC_R_SUCCESS:
361  *              *data is the data associated with 'name'.
362  *
363  *\li   If result is DNS_R_PARTIALMATCH:
364  *              *data is the data associated with the deepest superdomain
365  *              of 'name' which has data.
366  *
367  *\li   If result is ISC_R_NOTFOUND:
368  *              Neither the name nor a superdomain was found with data.
369  *
370  * Returns:
371  *\li   #ISC_R_SUCCESS          Success
372  *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
373  *\li   #ISC_R_NOTFOUND         No match
374  *\li   #ISC_R_NOSPACE          Concatenating nodes to form foundname failed
375  */
376
377 isc_result_t
378 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
379                  dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
380                  unsigned int options, dns_rbtfindcallback_t callback,
381                  void *callback_arg);
382 /*%<
383  * Find the node for 'name'.
384  *
385  * Notes:
386  *\li   A node that has no data is considered not to exist for this function,
387  *      unless the DNS_RBTFIND_EMPTYDATA option is set.  This applies to both
388  *      exact matches and partial matches.
389  *
390  *\li   If the chain parameter is non-NULL, then the path through the tree
391  *      to the DNSSEC predecessor of the searched for name is maintained,
392  *      unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
393  *      is used. (For more details on those options, see below.)
394  *
395  *\li   If there is no predecessor, then the chain will point to nowhere, as
396  *      indicated by chain->end being NULL or dns_rbtnodechain_current
397  *      returning ISC_R_NOTFOUND.  Note that in a normal Internet DNS RBT
398  *      there will always be a predecessor for all names except the root
399  *      name, because '.' will exist and '.' is the predecessor of
400  *      everything.  But you can certainly construct a trivial tree and a
401  *      search for it that has no predecessor.
402  *
403  *\li   Within the chain structure, the 'levels' member of the structure holds
404  *      the root node of each level except the first.
405  *
406  *\li   The 'level_count' of the chain indicates how deep the chain to the
407  *      predecessor name is, as an index into the 'levels[]' array.  It does
408  *      not count name elements, per se, but only levels of the tree of trees,
409  *      the distinction arising because multiple labels from a name can be
410  *      stored on only one level.  It is also does not include the level
411  *      that has the node, since that level is not stored in levels[].
412  *
413  *\li   The chain's 'level_matches' is not directly related to the predecessor.
414  *      It is the number of levels above the level of the found 'node',
415  *      regardless of whether it was a partial match or exact match.  When
416  *      the node is found in the top level tree, or no node is found at all,
417  *      level_matches is 0.
418  *
419  *\li   When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
420  *      returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
421  *      there is an exact match in the tree.  In this case, the chain
422  *      will not point to the DNSSEC predecessor, but will instead point
423  *      to the exact match, if there was any.  Thus the preceding paragraphs
424  *      should have "exact match" substituted for "predecessor" to describe
425  *      how the various elements of the chain are set.  This was done to
426  *      ensure that the chain's state was sane, and to prevent problems that
427  *      occurred when running the predecessor location code under conditions
428  *      it was not designed for.  It is not clear *where* the chain should
429  *      point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
430  *      with this option because you want a particular node, let us know
431  *      where you want the chain pointed, so this can be made more firm.
432  *
433  * Requires:
434  *\li   rbt is a valid rbt manager.
435  *\li   dns_name_isabsolute(name) == TRUE.
436  *\li   node != NULL && *node == NULL.
437  *\li   #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually
438  *              exclusive.
439  *
440  * Ensures:
441  *\li   'name' and the tree are not altered in any way.
442  *
443  *\li   If result is ISC_R_SUCCESS:
444  *\verbatim
445  *              *node is the terminal node for 'name'.
446
447  *              'foundname' and 'name' represent the same name (though not
448  *              the same memory).
449
450  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
451  *
452  *              chain->level_matches and chain->level_count are equal.
453  *\endverbatim
454  *
455  *      If result is DNS_R_PARTIALMATCH:
456  *\verbatim
457  *              *node is the data associated with the deepest superdomain
458  *              of 'name' which has data.
459  *
460  *              'foundname' is the name of deepest superdomain (which has
461  *              data, unless the DNS_RBTFIND_EMPTYDATA option is set).
462  *
463  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
464  *\endverbatim
465  *
466  *\li   If result is ISC_R_NOTFOUND:
467  *\verbatim
468  *              Neither the name nor a superdomain was found.  *node is NULL.
469  *
470  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
471  *
472  *              chain->level_matches is 0.
473  *\endverbatim
474  *
475  * Returns:
476  *\li   #ISC_R_SUCCESS          Success
477  *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
478  *\li   #ISC_R_NOTFOUND         No match, or superdomain with no data
479  *\li   #ISC_R_NOSPACE Concatenating nodes to form foundname failed
480  */
481
482 isc_result_t
483 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse);
484 /*%<
485  * Delete 'name' from the tree of trees.
486  *
487  * Notes:
488  *\li   When 'name' is removed, if recurse is ISC_TRUE then all of its
489  *      subnames are removed too.
490  *
491  * Requires:
492  *\li   rbt is a valid rbt manager.
493  *\li   dns_name_isabsolute(name) == TRUE
494  *
495  * Ensures:
496  *\li   'name' is not altered in any way.
497  *
498  *\li   Does NOT ensure that any external references to nodes in the tree
499  *      are unaffected by node joins.
500  *
501  *\li   If result is ISC_R_SUCCESS:
502  *              'name' does not appear in the tree with data; however,
503  *              the node for the name might still exist which can be
504  *              found with dns_rbt_findnode (but not dns_rbt_findname).
505  *
506  *\li   If result is ISC_R_NOTFOUND:
507  *              'name' does not appear in the tree with data, because
508  *              it did not appear in the tree before the function was called.
509  *
510  *\li   If result is something else:
511  *              See result codes for dns_rbt_findnode (if it fails, the
512  *              node is not deleted) or dns_rbt_deletenode (if it fails,
513  *              the node is deleted, but the tree is not optimized when
514  *              it could have been).
515  *
516  * Returns:
517  *\li   #ISC_R_SUCCESS  Success
518  *\li   #ISC_R_NOTFOUND No match
519  *\li   something_else  Any return code from dns_rbt_findnode except
520  *                      DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
521  *                      to be returned instead), and any code from
522  *                      dns_rbt_deletenode.
523  */
524
525 isc_result_t
526 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse);
527 /*%<
528  * Delete 'node' from the tree of trees.
529  *
530  * Notes:
531  *\li   When 'node' is removed, if recurse is ISC_TRUE then all nodes
532  *      in levels down from it are removed too.
533  *
534  * Requires:
535  *\li   rbt is a valid rbt manager.
536  *\li   node != NULL.
537  *
538  * Ensures:
539  *\li   Does NOT ensure that any external references to nodes in the tree
540  *      are unaffected by node joins.
541  *
542  *\li   If result is ISC_R_SUCCESS:
543  *              'node' does not appear in the tree with data; however,
544  *              the node might still exist if it serves as a pointer to
545  *              a lower tree level as long as 'recurse' was false, hence
546  *              the node could can be found with dns_rbt_findnode when
547  *              that function's empty_data_ok parameter is true.
548  *
549  *\li   If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
550  *              The node was deleted, but the tree structure was not
551  *              optimized.
552  *
553  * Returns:
554  *\li   #ISC_R_SUCCESS  Success
555  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes.
556  *\li   #ISC_R_NOSPACE  dns_name_concatenate failed when joining nodes.
557  */
558
559 void
560 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
561 /*%<
562  * Convert the sequence of labels stored at 'node' into a 'name'.
563  *
564  * Notes:
565  *\li   This function does not return the full name, from the root, but
566  *      just the labels at the indicated node.
567  *
568  *\li   The name data pointed to by 'name' is the information stored
569  *      in the node, not a copy.  Altering the data at this pointer
570  *      will likely cause grief.
571  *
572  * Requires:
573  * \li  name->offsets == NULL
574  *
575  * Ensures:
576  * \li  'name' is DNS_NAMEATTR_READONLY.
577  *
578  * \li  'name' will point directly to the labels stored after the
579  *      dns_rbtnode_t struct.
580  *
581  * \li  'name' will have offsets that also point to the information stored
582  *      as part of the node.
583  */
584
585 isc_result_t
586 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
587 /*%<
588  * Like dns_rbt_namefromnode, but returns the full name from the root.
589  *
590  * Notes:
591  * \li  Unlike dns_rbt_namefromnode, the name will not point directly
592  *      to node data.  Rather, dns_name_concatenate will be used to copy
593  *      the name data from each node into the 'name' argument.
594  *
595  * Requires:
596  * \li  name != NULL
597  * \li  name has a dedicated buffer.
598  *
599  * Returns:
600  * \li  ISC_R_SUCCESS
601  * \li  ISC_R_NOSPACE           (possible via dns_name_concatenate)
602  * \li  DNS_R_NAMETOOLONG       (possible via dns_name_concatenate)
603  */
604
605 char *
606 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
607                        unsigned int size);
608 /*%<
609  * Format the full name of a node for printing, using dns_name_format().
610  *
611  * Notes:
612  * \li  'size' is the length of the printname buffer.  This should be
613  *      DNS_NAME_FORMATSIZE or larger.
614  *
615  * Requires:
616  * \li  node and printname are not NULL.
617  *
618  * Returns:
619  * \li  The 'printname' pointer.
620  */
621
622 unsigned int
623 dns_rbt_nodecount(dns_rbt_t *rbt);
624 /*%<
625  * Obtain the number of nodes in the tree of trees.
626  *
627  * Requires:
628  * \li  rbt is a valid rbt manager.
629  */
630
631 void
632 dns_rbt_destroy(dns_rbt_t **rbtp);
633 isc_result_t
634 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum);
635 /*%<
636  * Stop working with a red-black tree of trees.
637  * If 'quantum' is zero then the entire tree will be destroyed.
638  * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
639  * allowing the rbt to be incrementally destroyed by repeated calls to
640  * dns_rbt_destroy2().  Once dns_rbt_destroy2() has been called no other
641  * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
642  * performed on the tree of trees.
643  *
644  * Requires:
645  * \li  *rbt is a valid rbt manager.
646  *
647  * Ensures on ISC_R_SUCCESS:
648  * \li  All space allocated by the RBT library has been returned.
649  *
650  * \li  *rbt is invalidated as an rbt manager.
651  *
652  * Returns:
653  * \li  ISC_R_SUCCESS
654  * \li  ISC_R_QUOTA if 'quantum' nodes have been destroyed.
655  */
656
657 void
658 dns_rbt_printall(dns_rbt_t *rbt);
659 /*%<
660  * Print an ASCII representation of the internal structure of the red-black
661  * tree of trees.
662  *
663  * Notes:
664  * \li  The name stored at each node, along with the node's color, is printed.
665  *      Then the down pointer, left and right pointers are displayed
666  *      recursively in turn.  NULL down pointers are silently omitted;
667  *      NULL left and right pointers are printed.
668  */
669
670 /*****
671  ***** Chain Functions
672  *****/
673
674 void
675 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx);
676 /*%<
677  * Initialize 'chain'.
678  *
679  * Requires:
680  *\li   'chain' is a valid pointer.
681  *
682  *\li   'mctx' is a valid memory context.
683  *
684  * Ensures:
685  *\li   'chain' is suitable for use.
686  */
687
688 void
689 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
690 /*%<
691  * Free any dynamic storage associated with 'chain', and then reinitialize
692  * 'chain'.
693  *
694  * Requires:
695  *\li   'chain' is a valid pointer.
696  *
697  * Ensures:
698  *\li   'chain' is suitable for use, and uses no dynamic storage.
699  */
700
701 void
702 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
703 /*%<
704  * Free any dynamic storage associated with 'chain', and then invalidates it.
705  *
706  * Notes:
707  *\li   Future calls to any dns_rbtnodechain_ function will need to call
708  *      dns_rbtnodechain_init on the chain first (except, of course,
709  *      dns_rbtnodechain_init itself).
710  *
711  * Requires:
712  *\li   'chain' is a valid chain.
713  *
714  * Ensures:
715  *\li   'chain' is no longer suitable for use, and uses no dynamic storage.
716  */
717
718 isc_result_t
719 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
720                          dns_name_t *origin, dns_rbtnode_t **node);
721 /*%<
722  * Provide the name, origin and node to which the chain is currently pointed.
723  *
724  * Notes:
725  *\li   The tree need not have be locked against additions for the chain
726  *      to remain valid, however there are no guarantees if any deletion
727  *      has been made since the chain was established.
728  *
729  * Requires:
730  *\li   'chain' is a valid chain.
731  *
732  * Ensures:
733  *\li   'node', if non-NULL, is the node to which the chain was pointed
734  *      by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
735  *      If none were called for the chain since it was initialized or reset,
736  *      or if the was no predecessor to the name searched for with
737  *      dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
738  *
739  *\li   'name', if non-NULL, is the name stored at the terminal level of
740  *      the chain.  This is typically a single label, like the "www" of
741  *      "www.isc.org", but need not be so.  At the root of the tree of trees,
742  *      if the node is "." then 'name' is ".", otherwise it is relative to ".".
743  *      (Minimalist and atypical case:  if the tree has just the name
744  *      "isc.org." then the root node's stored name is "isc.org." but 'name'
745  *      will be "isc.org".)
746  *
747  *\li   'origin', if non-NULL, is the sequence of labels in the levels
748  *      above the terminal level, such as "isc.org." in the above example.
749  *      'origin' is always "." for the root node.
750  *
751  *
752  * Returns:
753  *\li   #ISC_R_SUCCESS          name, origin & node were successfully set.
754  *\li   #ISC_R_NOTFOUND         The chain does not point to any node.
755  *\li   &lt;something_else>     Any error return from dns_name_concatenate.
756  */
757
758 isc_result_t
759 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
760                        dns_name_t *name, dns_name_t *origin);
761 /*%<
762  * Set the chain to the lexically first node in the tree of trees.
763  *
764  * Notes:
765  *\li   By the definition of ordering for DNS names, the root of the tree of
766  *      trees is the very first node, since everything else in the megatree
767  *      uses it as a common suffix.
768  *
769  * Requires:
770  *\li   'chain' is a valid chain.
771  *\li   'rbt' is a valid rbt manager.
772  *
773  * Ensures:
774  *\li   The chain points to the very first node of the tree.
775  *
776  *\li   'name' and 'origin', if non-NULL, are set as described for
777  *      dns_rbtnodechain_current.  Thus 'origin' will always be ".".
778  *
779  * Returns:
780  *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
781  *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
782  */
783
784 isc_result_t
785 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
786                        dns_name_t *name, dns_name_t *origin);
787 /*%<
788  * Set the chain to the lexically last node in the tree of trees.
789  *
790  * Requires:
791  *\li   'chain' is a valid chain.
792  *\li   'rbt' is a valid rbt manager.
793  *
794  * Ensures:
795  *\li   The chain points to the very last node of the tree.
796  *
797  *\li   'name' and 'origin', if non-NULL, are set as described for
798  *      dns_rbtnodechain_current.
799  *
800  * Returns:
801  *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
802  *\li   #ISC_R_NOMEMORY         Resource Limit: Out of Memory building chain.
803  *\li   &lt;something_else>     Any error result from dns_name_concatenate.
804  */
805
806 isc_result_t
807 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
808                       dns_name_t *origin);
809 /*%<
810  * Adjusts chain to point the DNSSEC predecessor of the name to which it
811  * is currently pointed.
812  *
813  * Requires:
814  *\li   'chain' is a valid chain.
815  *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
816  *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
817  *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
818  *      since there may have been no predecessor to the searched for name.
819  *
820  * Ensures:
821  *\li   The chain is pointed to the predecessor of its current target.
822  *
823  *\li   'name' and 'origin', if non-NULL, are set as described for
824  *      dns_rbtnodechain_current.
825  *
826  *\li   'origin' is only if a new origin was found.
827  *
828  * Returns:
829  *\li   #ISC_R_SUCCESS          The predecessor was found and 'name' was set.
830  *\li   #DNS_R_NEWORIGIN                The predecessor was found with a different
831  *                              origin and 'name' and 'origin' were set.
832  *\li   #ISC_R_NOMORE           There was no predecessor.
833  *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
834  */
835
836 isc_result_t
837 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
838                       dns_name_t *origin);
839 /*%<
840  * Adjusts chain to point the DNSSEC successor of the name to which it
841  * is currently pointed.
842  *
843  * Requires:
844  *\li   'chain' is a valid chain.
845  *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
846  *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
847  *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
848  *      since there may have been no predecessor to the searched for name.
849  *
850  * Ensures:
851  *\li   The chain is pointed to the successor of its current target.
852  *
853  *\li   'name' and 'origin', if non-NULL, are set as described for
854  *      dns_rbtnodechain_current.
855  *
856  *\li   'origin' is only if a new origin was found.
857  *
858  * Returns:
859  *\li   #ISC_R_SUCCESS          The successor was found and 'name' was set.
860  *\li   #DNS_R_NEWORIGIN                The successor was found with a different
861  *                              origin and 'name' and 'origin' were set.
862  *\li   #ISC_R_NOMORE           There was no successor.
863  *\li   &lt;something_else>     Any error result from dns_name_concatenate.
864  */
865
866 /*
867  * Wrapper macros for manipulating the rbtnode reference counter:
868  *   Since we selectively use isc_refcount_t for the reference counter of
869  *   a rbtnode, operations on the counter depend on the actual type of it.
870  *   The following macros provide a common interface to these operations,
871  *   hiding the back-end.  The usage is the same as that of isc_refcount_xxx().
872  */
873 #ifdef DNS_RBT_USEISCREFCOUNT
874 #define dns_rbtnode_refinit(node, n)                            \
875         do {                                                    \
876                 isc_refcount_init(&(node)->references, (n));    \
877         } while (0)
878 #define dns_rbtnode_refdestroy(node)                            \
879         do {                                                    \
880                 isc_refcount_destroy(&(node)->references);      \
881         } while (0)
882 #define dns_rbtnode_refcurrent(node)                            \
883         isc_refcount_current(&(node)->references)
884 #define dns_rbtnode_refincrement0(node, refs)                   \
885         do {                                                    \
886                 isc_refcount_increment0(&(node)->references, (refs)); \
887         } while (0)
888 #define dns_rbtnode_refincrement(node, refs)                    \
889         do {                                                    \
890                 isc_refcount_increment(&(node)->references, (refs)); \
891         } while (0)
892 #define dns_rbtnode_refdecrement(node, refs)                    \
893         do {                                                    \
894                 isc_refcount_decrement(&(node)->references, (refs)); \
895         } while (0)
896 #else  /* DNS_RBT_USEISCREFCOUNT */
897 #define dns_rbtnode_refinit(node, n)    ((node)->references = (n))
898 #define dns_rbtnode_refdestroy(node)    (REQUIRE((node)->references == 0))
899 #define dns_rbtnode_refcurrent(node)    ((node)->references)
900 #define dns_rbtnode_refincrement0(node, refs)                   \
901         do {                                                    \
902                 unsigned int *_tmp = (unsigned int *)(refs);    \
903                 (node)->references++;                           \
904                 if ((_tmp) != NULL)                             \
905                         (*_tmp) = (node)->references;           \
906         } while (0)
907 #define dns_rbtnode_refincrement(node, refs)                    \
908         do {                                                    \
909                 REQUIRE((node)->references > 0);                \
910                 (node)->references++;                           \
911                 if ((refs) != NULL)                             \
912                         (*refs) = (node)->references;           \
913         } while (0)
914 #define dns_rbtnode_refdecrement(node, refs)                    \
915         do {                                                    \
916                 REQUIRE((node)->references > 0);                \
917                 (node)->references--;                           \
918                 if ((refs) != NULL)                             \
919                         (*refs) = (node)->references;           \
920         } while (0)
921 #endif /* DNS_RBT_USEISCREFCOUNT */
922
923 ISC_LANG_ENDDECLS
924
925 #endif /* DNS_RBT_H */