rbt.h revision 170222
1135446Strhodes/*
2170222Sdougb * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2002  Internet Software Consortium.
4135446Strhodes *
5135446Strhodes * Permission to use, copy, modify, and distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18170222Sdougb/* $Id: rbt.h,v 1.59.18.5 2005/10/13 01:26:07 marka Exp $ */
19135446Strhodes
20135446Strhodes#ifndef DNS_RBT_H
21135446Strhodes#define DNS_RBT_H 1
22135446Strhodes
23170222Sdougb/*! \file */
24170222Sdougb
25135446Strhodes#include <isc/lang.h>
26135446Strhodes#include <isc/magic.h>
27170222Sdougb#include <isc/refcount.h>
28135446Strhodes
29135446Strhodes#include <dns/types.h>
30135446Strhodes
31135446StrhodesISC_LANG_BEGINDECLS
32135446Strhodes
33135446Strhodes#define DNS_RBT_USEHASH 1
34135446Strhodes
35170222Sdougb/*@{*/
36170222Sdougb/*%
37135446Strhodes * Option values for dns_rbt_findnode() and dns_rbt_findname().
38135446Strhodes * These are used to form a bitmask.
39135446Strhodes */
40135446Strhodes#define DNS_RBTFIND_NOOPTIONS			0x00
41135446Strhodes#define DNS_RBTFIND_EMPTYDATA			0x01
42135446Strhodes#define DNS_RBTFIND_NOEXACT			0x02
43135446Strhodes#define DNS_RBTFIND_NOPREDECESSOR		0x04
44170222Sdougb/*@}*/
45135446Strhodes
46170222Sdougb#ifndef DNS_RBT_USEISCREFCOUNT
47170222Sdougb#ifdef ISC_REFCOUNT_HAVEATOMIC
48170222Sdougb#define DNS_RBT_USEISCREFCOUNT 1
49170222Sdougb#endif
50170222Sdougb#endif
51170222Sdougb
52135446Strhodes/*
53135446Strhodes * These should add up to 30.
54135446Strhodes */
55135446Strhodes#define DNS_RBT_LOCKLENGTH			10
56135446Strhodes#define DNS_RBT_REFLENGTH			20
57135446Strhodes
58135446Strhodes#define DNS_RBTNODE_MAGIC		ISC_MAGIC('R','B','N','O')
59135446Strhodes#if DNS_RBT_USEMAGIC
60135446Strhodes#define DNS_RBTNODE_VALID(n)		ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
61135446Strhodes#else
62135446Strhodes#define DNS_RBTNODE_VALID(n)		ISC_TRUE
63135446Strhodes#endif
64135446Strhodes
65170222Sdougb/*%
66135446Strhodes * This is the structure that is used for each node in the red/black
67135446Strhodes * tree of trees.  NOTE WELL:  the implementation manages this as a variable
68135446Strhodes * length structure, with the actual wire-format name and other data
69135446Strhodes * appended to this structure.  Allocating a contiguous block of memory for
70135446Strhodes * multiple dns_rbtnode structures will not work.
71135446Strhodes */
72135446Strhodestypedef struct dns_rbtnode {
73135446Strhodes#if DNS_RBT_USEMAGIC
74135446Strhodes	unsigned int magic;
75135446Strhodes#endif
76135446Strhodes	struct dns_rbtnode *parent;
77135446Strhodes	struct dns_rbtnode *left;
78135446Strhodes	struct dns_rbtnode *right;
79135446Strhodes	struct dns_rbtnode *down;
80135446Strhodes#ifdef DNS_RBT_USEHASH
81135446Strhodes	struct dns_rbtnode *hashnext;
82135446Strhodes#endif
83170222Sdougb	/*@{*/
84170222Sdougb	/*!
85135446Strhodes	 * The following bitfields add up to a total bitwidth of 32.
86135446Strhodes	 * The range of values necessary for each item is indicated,
87135446Strhodes	 * but in the case of "attributes" the field is wider to accomodate
88135446Strhodes	 * possible future expansion.  "offsetlen" could be one bit
89135446Strhodes	 * narrower by always adjusting its value by 1 to find the real
90135446Strhodes	 * offsetlen, but doing so does not gain anything (except perhaps
91135446Strhodes	 * another bit for "attributes", which doesn't yet need any more).
92135446Strhodes	 *
93135446Strhodes	 * In each case below the "range" indicated is what's _necessary_ for
94135446Strhodes	 * the bitfield to hold, not what it actually _can_ hold.
95135446Strhodes	 */
96170222Sdougb	unsigned int is_root : 1;	/*%< range is 0..1 */
97170222Sdougb	unsigned int color : 1;		/*%< range is 0..1 */
98170222Sdougb	unsigned int find_callback : 1;	/*%< range is 0..1 */
99170222Sdougb	unsigned int attributes : 4;	/*%< range is 0..2 */
100170222Sdougb	unsigned int namelen : 8;	/*%< range is 1..255 */
101170222Sdougb	unsigned int offsetlen : 8;	/*%< range is 1..128 */
102170222Sdougb	unsigned int padbytes : 9;	/*%< range is 0..380 */
103170222Sdougb	/*@}*/
104135446Strhodes
105135446Strhodes#ifdef DNS_RBT_USEHASH
106135446Strhodes	unsigned int hashval;
107135446Strhodes#endif
108135446Strhodes
109170222Sdougb	/*@{*/
110170222Sdougb	/*!
111135446Strhodes	 * These values are used in the RBT DB implementation.  The appropriate
112135446Strhodes	 * node lock must be held before accessing them.
113135446Strhodes	 */
114135446Strhodes	void *data;
115135446Strhodes	unsigned int dirty:1;
116135446Strhodes	unsigned int wild:1;
117135446Strhodes	unsigned int locknum:DNS_RBT_LOCKLENGTH;
118170222Sdougb#ifndef DNS_RBT_USEISCREFCOUNT
119135446Strhodes	unsigned int references:DNS_RBT_REFLENGTH;
120170222Sdougb#else
121170222Sdougb	isc_refcount_t references; /* note that this is not in the bitfield */
122170222Sdougb#endif
123170222Sdougb	/*@}*/
124135446Strhodes} dns_rbtnode_t;
125135446Strhodes
126135446Strhodestypedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
127135446Strhodes					      dns_name_t *name,
128135446Strhodes					      void *callback_arg);
129135446Strhodes
130135446Strhodes/*****
131135446Strhodes *****	Chain Info
132135446Strhodes *****/
133135446Strhodes
134170222Sdougb/*!
135135446Strhodes * A chain is used to keep track of the sequence of nodes to reach any given
136135446Strhodes * node from the root of the tree.  Originally nodes did not have parent
137135446Strhodes * pointers in them (for memory usage reasons) so there was no way to find
138135446Strhodes * the path back to the root from any given node.  Now that nodes have parent
139135446Strhodes * pointers, chains might be going away in a future release, though the
140135446Strhodes * movement functionality would remain.
141135446Strhodes *
142135446Strhodes * In any event, parent information, whether via parent pointers or chains, is
143135446Strhodes * necessary information for iterating through the tree or for basic internal
144135446Strhodes * tree maintenance issues (ie, the rotations that are done to rebalance the
145135446Strhodes * tree when a node is added).  The obvious implication of this is that for a
146135446Strhodes * chain to remain valid, the tree has to be locked down against writes for the
147135446Strhodes * duration of the useful life of the chain, because additions or removals can
148135446Strhodes * change the path from the root to the node the chain has targetted.
149135446Strhodes *
150135446Strhodes * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take
151135446Strhodes * dns_name_t parameters for the name and the origin, which can be NULL.  If
152135446Strhodes * non-NULL, 'name' will end up pointing to the name data and offsets that are
153135446Strhodes * stored at the node (and thus it will be read-only), so it should be a
154135446Strhodes * regular dns_name_t that has been initialized with dns_name_init.  When
155135446Strhodes * 'origin' is non-NULL, it will get the name of the origin stored in it, so it
156135446Strhodes * needs to have its own buffer space and offsets, which is most easily
157135446Strhodes * accomplished with a dns_fixedname_t.  It is _not_ necessary to reinitialize
158135446Strhodes * either 'name' or 'origin' between calls to the chain functions.
159135446Strhodes *
160135446Strhodes * NOTE WELL: even though the name data at the root of the tree of trees will
161135446Strhodes * be absolute (typically just "."), it will will be made into a relative name
162135446Strhodes * with an origin of "." -- an empty name when the node is ".".  This is
163135446Strhodes * because a common on operation on 'name' and 'origin' is to use
164135446Strhodes * dns_name_concatenate() on them to generate the complete name.  An empty name
165135446Strhodes * can be detected when dns_name_countlabels == 0, and is printed by
166135446Strhodes * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's
167135446Strhodes * definition of "@" as the current origin.
168135446Strhodes *
169135446Strhodes * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next
170135446Strhodes * functions but additionally can provide the node to which the chain points.
171135446Strhodes */
172135446Strhodes
173170222Sdougb/*%
174135446Strhodes * The number of level blocks to allocate at a time.  Currently the maximum
175135446Strhodes * number of levels is allocated directly in the structure, but future
176135446Strhodes * revisions of this code might have a static initial block with dynamic
177135446Strhodes * growth.  Allocating space for 256 levels when the tree is almost never that
178135446Strhodes * deep is wasteful, but it's not clear that it matters, since the waste is
179135446Strhodes * only 2MB for 1000 concurrently active chains on a system with 64-bit
180135446Strhodes * pointers.
181135446Strhodes */
182135446Strhodes#define DNS_RBT_LEVELBLOCK 254
183135446Strhodes
184135446Strhodestypedef struct dns_rbtnodechain {
185135446Strhodes	unsigned int		magic;
186135446Strhodes	isc_mem_t *		mctx;
187170222Sdougb	/*%
188135446Strhodes	 * The terminal node of the chain.  It is not in levels[].
189135446Strhodes	 * This is ostensibly private ... but in a pinch it could be
190135446Strhodes	 * used tell that the chain points nowhere without needing to
191135446Strhodes	 * call dns_rbtnodechain_current().
192135446Strhodes	 */
193135446Strhodes	dns_rbtnode_t *		end;
194170222Sdougb	/*%
195135446Strhodes	 * The maximum number of labels in a name is 128; bitstrings mean
196135446Strhodes	 * a conceptually very large number (which I have not bothered to
197135446Strhodes	 * compute) of logical levels because splitting can potentially occur
198135446Strhodes	 * at each bit.  However, DNSSEC restricts the number of "logical"
199135446Strhodes	 * labels in a name to 255, meaning only 254 pointers are needed
200135446Strhodes	 * in the worst case.
201135446Strhodes	 */
202135446Strhodes	dns_rbtnode_t *		levels[DNS_RBT_LEVELBLOCK];
203170222Sdougb	/*%
204135446Strhodes	 * level_count indicates how deep the chain points into the
205135446Strhodes	 * tree of trees, and is the index into the levels[] array.
206135446Strhodes	 * Thus, levels[level_count - 1] is the last level node stored.
207135446Strhodes	 * A chain that points to the top level of the tree of trees has
208135446Strhodes	 * a level_count of 0, the first level has a level_count of 1, and
209135446Strhodes	 * so on.
210135446Strhodes	 */
211135446Strhodes	unsigned int		level_count;
212170222Sdougb	/*%
213135446Strhodes	 * level_matches tells how many levels matched above the node
214135446Strhodes	 * returned by dns_rbt_findnode().  A match (partial or exact) found
215135446Strhodes	 * in the first level thus results in level_matches being set to 1.
216135446Strhodes	 * This is used by the rbtdb to set the start point for a recursive
217135446Strhodes	 * search of superdomains until the RR it is looking for is found.
218135446Strhodes	 */
219135446Strhodes	unsigned int		level_matches;
220135446Strhodes} dns_rbtnodechain_t;
221135446Strhodes
222135446Strhodes/*****
223135446Strhodes ***** Public interfaces.
224135446Strhodes *****/
225135446Strhodesisc_result_t
226135446Strhodesdns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
227135446Strhodes	       void *deleter_arg, dns_rbt_t **rbtp);
228170222Sdougb/*%<
229135446Strhodes * Initialize a red-black tree of trees.
230135446Strhodes *
231135446Strhodes * Notes:
232170222Sdougb *\li	The deleter argument, if non-null, points to a function that is
233135446Strhodes *	responsible for cleaning up any memory associated with the data
234135446Strhodes *	pointer of a node when the node is deleted.  It is passed the
235135446Strhodes *	deleted node's data pointer as its first argument and deleter_arg
236135446Strhodes *	as its second argument.
237135446Strhodes *
238135446Strhodes * Requires:
239170222Sdougb * \li	mctx is a pointer to a valid memory context.
240170222Sdougb *\li	rbtp != NULL && *rbtp == NULL
241170222Sdougb *\li	arg == NULL iff deleter == NULL
242135446Strhodes *
243135446Strhodes * Ensures:
244170222Sdougb *\li	If result is ISC_R_SUCCESS:
245135446Strhodes *		*rbtp points to a valid red-black tree manager
246135446Strhodes *
247170222Sdougb *\li	If result is failure:
248135446Strhodes *		*rbtp does not point to a valid red-black tree manager.
249135446Strhodes *
250135446Strhodes * Returns:
251170222Sdougb *\li	#ISC_R_SUCCESS	Success
252170222Sdougb *\li	#ISC_R_NOMEMORY	Resource limit: Out of Memory
253135446Strhodes */
254135446Strhodes
255135446Strhodesisc_result_t
256135446Strhodesdns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
257170222Sdougb/*%<
258135446Strhodes * Add 'name' to the tree of trees, associated with 'data'.
259135446Strhodes *
260135446Strhodes * Notes:
261170222Sdougb *\li	'data' is never required to be non-NULL, but specifying it
262135446Strhodes *	when the name is added is faster than searching for 'name'
263135446Strhodes *	again and then setting the data pointer.  The lack of a data pointer
264135446Strhodes *	for a node also has other ramifications regarding whether
265135446Strhodes *	dns_rbt_findname considers a node to exist, or dns_rbt_deletename
266135446Strhodes *	joins nodes.
267135446Strhodes *
268135446Strhodes * Requires:
269170222Sdougb *\li	rbt is a valid rbt manager.
270170222Sdougb *\li	dns_name_isabsolute(name) == TRUE
271135446Strhodes *
272135446Strhodes * Ensures:
273170222Sdougb *\li	'name' is not altered in any way.
274135446Strhodes *
275170222Sdougb *\li	Any external references to nodes in the tree are unaffected by
276135446Strhodes *	node splits that are necessary to insert the new name.
277135446Strhodes *
278170222Sdougb *\li	If result is #ISC_R_SUCCESS:
279135446Strhodes *		'name' is findable in the red/black tree of trees in O(log N).
280135446Strhodes *		The data pointer of the node for 'name' is set to 'data'.
281135446Strhodes *
282170222Sdougb *\li	If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
283135446Strhodes *		The tree of trees is unaltered.
284135446Strhodes *
285170222Sdougb *\li	If result is #ISC_R_NOMEMORY:
286135446Strhodes *		No guarantees.
287135446Strhodes *
288135446Strhodes * Returns:
289170222Sdougb *\li	#ISC_R_SUCCESS	Success
290170222Sdougb *\li	#ISC_R_EXISTS	The name already exists with associated data.
291170222Sdougb *\li	#ISC_R_NOSPACE 	The name had more logical labels than are allowed.
292170222Sdougb *\li	#ISC_R_NOMEMORY	Resource Limit: Out of Memory
293135446Strhodes */
294135446Strhodes
295135446Strhodesisc_result_t
296135446Strhodesdns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
297135446Strhodes
298170222Sdougb/*%<
299135446Strhodes * Just like dns_rbt_addname, but returns the address of the node.
300135446Strhodes *
301135446Strhodes * Requires:
302170222Sdougb *\li	rbt is a valid rbt structure.
303170222Sdougb *\li	dns_name_isabsolute(name) == TRUE
304170222Sdougb *\li	nodep != NULL && *nodep == NULL
305135446Strhodes *
306135446Strhodes * Ensures:
307170222Sdougb *\li	'name' is not altered in any way.
308135446Strhodes *
309170222Sdougb *\li	Any external references to nodes in the tree are unaffected by
310135446Strhodes *	node splits that are necessary to insert the new name.
311135446Strhodes *
312170222Sdougb *\li	If result is ISC_R_SUCCESS:
313135446Strhodes *		'name' is findable in the red/black tree of trees in O(log N).
314135446Strhodes *		*nodep is the node that was added for 'name'.
315135446Strhodes *
316170222Sdougb *\li	If result is ISC_R_EXISTS:
317135446Strhodes *		The tree of trees is unaltered.
318135446Strhodes *		*nodep is the existing node for 'name'.
319135446Strhodes *
320170222Sdougb *\li	If result is ISC_R_NOMEMORY:
321135446Strhodes *		No guarantees.
322135446Strhodes *
323135446Strhodes * Returns:
324170222Sdougb *\li	#ISC_R_SUCCESS	Success
325170222Sdougb *\li	#ISC_R_EXISTS	The name already exists, possibly without data.
326170222Sdougb *\li	#ISC_R_NOMEMORY	Resource Limit: Out of Memory
327135446Strhodes */
328135446Strhodes
329135446Strhodesisc_result_t
330135446Strhodesdns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
331135446Strhodes		 dns_name_t *foundname, void **data);
332170222Sdougb/*%<
333135446Strhodes * Get the data pointer associated with 'name'.
334135446Strhodes *
335135446Strhodes * Notes:
336170222Sdougb *\li	When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
337170222Sdougb *      returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is
338135446Strhodes *	an exact match in the tree.
339135446Strhodes *
340170222Sdougb *\li   A node that has no data is considered not to exist for this function,
341170222Sdougb *      unless the #DNS_RBTFIND_EMPTYDATA option is set.
342135446Strhodes *
343135446Strhodes * Requires:
344170222Sdougb *\li	rbt is a valid rbt manager.
345170222Sdougb *\li	dns_name_isabsolute(name) == TRUE
346170222Sdougb *\li	data != NULL && *data == NULL
347135446Strhodes *
348135446Strhodes * Ensures:
349170222Sdougb *\li	'name' and the tree are not altered in any way.
350135446Strhodes *
351170222Sdougb *\li	If result is ISC_R_SUCCESS:
352135446Strhodes *		*data is the data associated with 'name'.
353135446Strhodes *
354170222Sdougb *\li	If result is DNS_R_PARTIALMATCH:
355135446Strhodes *		*data is the data associated with the deepest superdomain
356135446Strhodes * 		of 'name' which has data.
357135446Strhodes *
358170222Sdougb *\li	If result is ISC_R_NOTFOUND:
359135446Strhodes *		Neither the name nor a superdomain was found with data.
360135446Strhodes *
361135446Strhodes * Returns:
362170222Sdougb *\li	#ISC_R_SUCCESS		Success
363170222Sdougb *\li	#DNS_R_PARTIALMATCH	Superdomain found with data
364170222Sdougb *\li	#ISC_R_NOTFOUND		No match
365170222Sdougb *\li	#ISC_R_NOSPACE		Concatenating nodes to form foundname failed
366135446Strhodes */
367135446Strhodes
368135446Strhodesisc_result_t
369135446Strhodesdns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
370135446Strhodes		 dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
371135446Strhodes		 unsigned int options, dns_rbtfindcallback_t callback,
372135446Strhodes		 void *callback_arg);
373170222Sdougb/*%<
374135446Strhodes * Find the node for 'name'.
375135446Strhodes *
376135446Strhodes * Notes:
377170222Sdougb *\li	A node that has no data is considered not to exist for this function,
378135446Strhodes *	unless the DNS_RBTFIND_EMPTYDATA option is set.  This applies to both
379135446Strhodes *	exact matches and partial matches.
380135446Strhodes *
381170222Sdougb *\li	If the chain parameter is non-NULL, then the path through the tree
382135446Strhodes *	to the DNSSEC predecessor of the searched for name is maintained,
383135446Strhodes *	unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
384135446Strhodes *	is used. (For more details on those options, see below.)
385135446Strhodes *
386170222Sdougb *\li	If there is no predecessor, then the chain will point to nowhere, as
387135446Strhodes *	indicated by chain->end being NULL or dns_rbtnodechain_current
388135446Strhodes *	returning ISC_R_NOTFOUND.  Note that in a normal Internet DNS RBT
389135446Strhodes *	there will always be a predecessor for all names except the root
390135446Strhodes *	name, because '.' will exist and '.' is the predecessor of
391135446Strhodes *	everything.  But you can certainly construct a trivial tree and a
392135446Strhodes *	search for it that has no predecessor.
393135446Strhodes *
394170222Sdougb *\li	Within the chain structure, the 'levels' member of the structure holds
395135446Strhodes *	the root node of each level except the first.
396135446Strhodes *
397170222Sdougb *\li	The 'level_count' of the chain indicates how deep the chain to the
398135446Strhodes *	predecessor name is, as an index into the 'levels[]' array.  It does
399135446Strhodes *	not count name elements, per se, but only levels of the tree of trees,
400135446Strhodes *	the distinction arrising because multiple labels from a name can be
401135446Strhodes *	stored on only one level.  It is also does not include the level
402135446Strhodes *	that has the node, since that level is not stored in levels[].
403135446Strhodes *
404170222Sdougb *\li	The chain's 'level_matches' is not directly related to the predecessor.
405135446Strhodes *	It is the number of levels above the level of the found 'node',
406135446Strhodes *	regardless of whether it was a partial match or exact match.  When
407135446Strhodes *	the node is found in the top level tree, or no node is found at all,
408135446Strhodes *	level_matches is 0.
409135446Strhodes *
410170222Sdougb *\li	When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
411135446Strhodes *      returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
412135446Strhodes *      there is an exact match in the tree.  In this case, the chain
413135446Strhodes *	will not point to the DNSSEC predecessor, but will instead point
414135446Strhodes *	to the exact match, if there was any.  Thus the preceding paragraphs
415135446Strhodes *	should have "exact match" substituted for "predecessor" to describe
416135446Strhodes *	how the various elements of the chain are set.  This was done to
417135446Strhodes * 	ensure that the chain's state was sane, and to prevent problems that
418135446Strhodes *	occurred when running the predecessor location code under conditions
419135446Strhodes *	it was not designed for.  It is not clear *where* the chain should
420135446Strhodes *	point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
421135446Strhodes *	with this option because you want a particular node, let us know
422135446Strhodes *	where you want the chain pointed, so this can be made more firm.
423135446Strhodes *
424135446Strhodes * Requires:
425170222Sdougb *\li	rbt is a valid rbt manager.
426170222Sdougb *\li	dns_name_isabsolute(name) == TRUE.
427170222Sdougb *\li	node != NULL && *node == NULL.
428170222Sdougb *\li	#DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutally
429135446Strhodes *		exclusive.
430135446Strhodes *
431135446Strhodes * Ensures:
432170222Sdougb *\li	'name' and the tree are not altered in any way.
433135446Strhodes *
434170222Sdougb *\li	If result is ISC_R_SUCCESS:
435170222Sdougb *\verbatim
436135446Strhodes *		*node is the terminal node for 'name'.
437170222Sdougb
438135446Strhodes *		'foundname' and 'name' represent the same name (though not
439135446Strhodes *		the same memory).
440170222Sdougb
441135446Strhodes *		'chain' points to the DNSSEC predecessor, if any, of 'name'.
442135446Strhodes *
443135446Strhodes *		chain->level_matches and chain->level_count are equal.
444170222Sdougb *\endverbatim
445135446Strhodes *
446135446Strhodes * 	If result is DNS_R_PARTIALMATCH:
447170222Sdougb *\verbatim
448135446Strhodes *		*node is the data associated with the deepest superdomain
449135446Strhodes * 		of 'name' which has data.
450135446Strhodes *
451135446Strhodes *		'foundname' is the name of deepest superdomain (which has
452135446Strhodes *		data, unless the DNS_RBTFIND_EMPTYDATA option is set).
453135446Strhodes *
454135446Strhodes *		'chain' points to the DNSSEC predecessor, if any, of 'name'.
455170222Sdougb *\endverbatim
456135446Strhodes *
457170222Sdougb *\li	If result is ISC_R_NOTFOUND:
458170222Sdougb *\verbatim
459135446Strhodes *		Neither the name nor a superdomain was found.  *node is NULL.
460135446Strhodes *
461135446Strhodes *		'chain' points to the DNSSEC predecessor, if any, of 'name'.
462135446Strhodes *
463135446Strhodes *		chain->level_matches is 0.
464170222Sdougb *\endverbatim
465135446Strhodes *
466135446Strhodes * Returns:
467170222Sdougb *\li	#ISC_R_SUCCESS		Success
468170222Sdougb *\li	#DNS_R_PARTIALMATCH	Superdomain found with data
469170222Sdougb *\li	#ISC_R_NOTFOUND		No match, or superdomain with no data
470170222Sdougb *\li	#ISC_R_NOSPACE Concatenating nodes to form foundname failed
471135446Strhodes */
472135446Strhodes
473135446Strhodesisc_result_t
474135446Strhodesdns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse);
475170222Sdougb/*%<
476135446Strhodes * Delete 'name' from the tree of trees.
477135446Strhodes *
478135446Strhodes * Notes:
479170222Sdougb *\li	When 'name' is removed, if recurse is ISC_TRUE then all of its
480135446Strhodes *      subnames are removed too.
481135446Strhodes *
482135446Strhodes * Requires:
483170222Sdougb *\li	rbt is a valid rbt manager.
484170222Sdougb *\li	dns_name_isabsolute(name) == TRUE
485135446Strhodes *
486135446Strhodes * Ensures:
487170222Sdougb *\li	'name' is not altered in any way.
488135446Strhodes *
489170222Sdougb *\li	Does NOT ensure that any external references to nodes in the tree
490135446Strhodes *	are unaffected by node joins.
491135446Strhodes *
492170222Sdougb *\li	If result is ISC_R_SUCCESS:
493135446Strhodes *		'name' does not appear in the tree with data; however,
494135446Strhodes *		the node for the name might still exist which can be
495135446Strhodes *		found with dns_rbt_findnode (but not dns_rbt_findname).
496135446Strhodes *
497170222Sdougb *\li	If result is ISC_R_NOTFOUND:
498135446Strhodes *		'name' does not appear in the tree with data, because
499135446Strhodes *		it did not appear in the tree before the function was called.
500135446Strhodes *
501170222Sdougb *\li	If result is something else:
502135446Strhodes *		See result codes for dns_rbt_findnode (if it fails, the
503135446Strhodes *		node is not deleted) or dns_rbt_deletenode (if it fails,
504135446Strhodes *		the node is deleted, but the tree is not optimized when
505135446Strhodes *		it could have been).
506135446Strhodes *
507135446Strhodes * Returns:
508170222Sdougb *\li	#ISC_R_SUCCESS	Success
509170222Sdougb *\li	#ISC_R_NOTFOUND	No match
510170222Sdougb *\li	something_else	Any return code from dns_rbt_findnode except
511135446Strhodes *			DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
512135446Strhodes *			to be returned instead), and any code from
513135446Strhodes *			dns_rbt_deletenode.
514135446Strhodes */
515135446Strhodes
516135446Strhodesisc_result_t
517135446Strhodesdns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse);
518170222Sdougb/*%<
519135446Strhodes * Delete 'node' from the tree of trees.
520135446Strhodes *
521135446Strhodes * Notes:
522170222Sdougb *\li	When 'node' is removed, if recurse is ISC_TRUE then all nodes
523135446Strhodes *	in levels down from it are removed too.
524135446Strhodes *
525135446Strhodes * Requires:
526170222Sdougb *\li	rbt is a valid rbt manager.
527170222Sdougb *\li	node != NULL.
528135446Strhodes *
529135446Strhodes * Ensures:
530170222Sdougb *\li	Does NOT ensure that any external references to nodes in the tree
531135446Strhodes *	are unaffected by node joins.
532135446Strhodes *
533170222Sdougb *\li	If result is ISC_R_SUCCESS:
534135446Strhodes *		'node' does not appear in the tree with data; however,
535135446Strhodes *		the node might still exist if it serves as a pointer to
536135446Strhodes *		a lower tree level as long as 'recurse' was false, hence
537135446Strhodes *		the node could can be found with dns_rbt_findnode whem
538135446Strhodes *		that function's empty_data_ok parameter is true.
539135446Strhodes *
540170222Sdougb *\li	If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
541135446Strhodes *		The node was deleted, but the tree structure was not
542135446Strhodes *		optimized.
543135446Strhodes *
544135446Strhodes * Returns:
545170222Sdougb *\li	#ISC_R_SUCCESS	Success
546170222Sdougb *\li	#ISC_R_NOMEMORY	Resource Limit: Out of Memory when joining nodes.
547170222Sdougb *\li	#ISC_R_NOSPACE	dns_name_concatenate failed when joining nodes.
548135446Strhodes */
549135446Strhodes
550135446Strhodesvoid
551135446Strhodesdns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
552170222Sdougb/*%<
553135446Strhodes * Convert the sequence of labels stored at 'node' into a 'name'.
554135446Strhodes *
555135446Strhodes * Notes:
556170222Sdougb *\li	This function does not return the full name, from the root, but
557135446Strhodes *	just the labels at the indicated node.
558135446Strhodes *
559170222Sdougb *\li	The name data pointed to by 'name' is the information stored
560135446Strhodes *	in the node, not a copy.  Altering the data at this pointer
561135446Strhodes *	will likely cause grief.
562135446Strhodes *
563135446Strhodes * Requires:
564170222Sdougb * \li	name->offsets == NULL
565135446Strhodes *
566135446Strhodes * Ensures:
567170222Sdougb * \li	'name' is DNS_NAMEATTR_READONLY.
568135446Strhodes *
569170222Sdougb * \li	'name' will point directly to the labels stored after the
570135446Strhodes *	dns_rbtnode_t struct.
571135446Strhodes *
572170222Sdougb * \li	'name' will have offsets that also point to the information stored
573135446Strhodes *	as part of the node.
574135446Strhodes */
575135446Strhodes
576135446Strhodesisc_result_t
577135446Strhodesdns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
578170222Sdougb/*%<
579135446Strhodes * Like dns_rbt_namefromnode, but returns the full name from the root.
580135446Strhodes *
581135446Strhodes * Notes:
582170222Sdougb * \li	Unlike dns_rbt_namefromnode, the name will not point directly
583135446Strhodes *	to node data.  Rather, dns_name_concatenate will be used to copy
584135446Strhodes *	the name data from each node into the 'name' argument.
585135446Strhodes *
586135446Strhodes * Requires:
587170222Sdougb * \li	name != NULL
588170222Sdougb * \li	name has a dedicated buffer.
589135446Strhodes *
590135446Strhodes * Returns:
591170222Sdougb * \li	ISC_R_SUCCESS
592170222Sdougb * \li	ISC_R_NOSPACE		(possible via dns_name_concatenate)
593170222Sdougb * \li	DNS_R_NAMETOOLONG	(possible via dns_name_concatenate)
594135446Strhodes */
595135446Strhodes
596135446Strhodeschar *
597135446Strhodesdns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
598135446Strhodes		       unsigned int size);
599170222Sdougb/*%<
600135446Strhodes * Format the full name of a node for printing, using dns_name_format().
601135446Strhodes *
602135446Strhodes * Notes:
603170222Sdougb * \li	'size' is the length of the printname buffer.  This should be
604135446Strhodes *	DNS_NAME_FORMATSIZE or larger.
605135446Strhodes *
606135446Strhodes * Requires:
607170222Sdougb * \li	node and printname are not NULL.
608135446Strhodes *
609135446Strhodes * Returns:
610170222Sdougb * \li	The 'printname' pointer.
611135446Strhodes */
612135446Strhodes
613135446Strhodesunsigned int
614135446Strhodesdns_rbt_nodecount(dns_rbt_t *rbt);
615170222Sdougb/*%<
616135446Strhodes * Obtain the number of nodes in the tree of trees.
617135446Strhodes *
618135446Strhodes * Requires:
619170222Sdougb * \li	rbt is a valid rbt manager.
620135446Strhodes */
621135446Strhodes
622135446Strhodesvoid
623135446Strhodesdns_rbt_destroy(dns_rbt_t **rbtp);
624135446Strhodesisc_result_t
625135446Strhodesdns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum);
626170222Sdougb/*%<
627143731Sdougb * Stop working with a red-black tree of trees.
628143731Sdougb * If 'quantum' is zero then the entire tree will be destroyed.
629143731Sdougb * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
630143731Sdougb * allowing the rbt to be incrementally destroyed by repeated calls to
631143731Sdougb * dns_rbt_destroy2().  Once dns_rbt_destroy2() has been called no other
632143731Sdougb * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
633143731Sdougb * performed on the tree of trees.
634143731Sdougb *
635135446Strhodes * Requires:
636170222Sdougb * \li	*rbt is a valid rbt manager.
637135446Strhodes *
638143731Sdougb * Ensures on ISC_R_SUCCESS:
639170222Sdougb * \li	All space allocated by the RBT library has been returned.
640135446Strhodes *
641170222Sdougb * \li	*rbt is invalidated as an rbt manager.
642135446Strhodes *
643135446Strhodes * Returns:
644170222Sdougb * \li	ISC_R_SUCCESS
645170222Sdougb * \li	ISC_R_QUOTA if 'quantum' nodes have been destroyed.
646135446Strhodes */
647135446Strhodes
648135446Strhodesvoid
649135446Strhodesdns_rbt_printall(dns_rbt_t *rbt);
650170222Sdougb/*%<
651135446Strhodes * Print an ASCII representation of the internal structure of the red-black
652135446Strhodes * tree of trees.
653135446Strhodes *
654135446Strhodes * Notes:
655170222Sdougb * \li	The name stored at each node, along with the node's color, is printed.
656135446Strhodes *	Then the down pointer, left and right pointers are displayed
657135446Strhodes *	recursively in turn.  NULL down pointers are silently omitted;
658135446Strhodes *	NULL left and right pointers are printed.
659135446Strhodes */
660135446Strhodes
661135446Strhodes/*****
662135446Strhodes ***** Chain Functions
663135446Strhodes *****/
664135446Strhodes
665135446Strhodesvoid
666135446Strhodesdns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx);
667170222Sdougb/*%<
668135446Strhodes * Initialize 'chain'.
669135446Strhodes *
670135446Strhodes * Requires:
671170222Sdougb *\li	'chain' is a valid pointer.
672135446Strhodes *
673170222Sdougb *\li	'mctx' is a valid memory context.
674135446Strhodes *
675135446Strhodes * Ensures:
676170222Sdougb *\li	'chain' is suitable for use.
677135446Strhodes */
678135446Strhodes
679135446Strhodesvoid
680135446Strhodesdns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
681170222Sdougb/*%<
682135446Strhodes * Free any dynamic storage associated with 'chain', and then reinitialize
683135446Strhodes * 'chain'.
684135446Strhodes *
685135446Strhodes * Requires:
686170222Sdougb *\li	'chain' is a valid pointer.
687135446Strhodes *
688135446Strhodes * Ensures:
689170222Sdougb *\li	'chain' is suitable for use, and uses no dynamic storage.
690135446Strhodes */
691135446Strhodes
692135446Strhodesvoid
693135446Strhodesdns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
694170222Sdougb/*%<
695135446Strhodes * Free any dynamic storage associated with 'chain', and then invalidates it.
696135446Strhodes *
697135446Strhodes * Notes:
698170222Sdougb *\li 	Future calls to any dns_rbtnodechain_ function will need to call
699135446Strhodes * 	dns_rbtnodechain_init on the chain first (except, of course,
700135446Strhodes *	dns_rbtnodechain_init itself).
701135446Strhodes *
702135446Strhodes * Requires:
703170222Sdougb *\li	'chain' is a valid chain.
704135446Strhodes *
705135446Strhodes * Ensures:
706170222Sdougb *\li	'chain' is no longer suitable for use, and uses no dynamic storage.
707135446Strhodes */
708135446Strhodes
709135446Strhodesisc_result_t
710135446Strhodesdns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
711135446Strhodes			 dns_name_t *origin, dns_rbtnode_t **node);
712170222Sdougb/*%<
713135446Strhodes * Provide the name, origin and node to which the chain is currently pointed.
714135446Strhodes *
715135446Strhodes * Notes:
716170222Sdougb *\li	The tree need not have be locked against additions for the chain
717135446Strhodes *	to remain valid, however there are no guarantees if any deletion
718135446Strhodes *	has been made since the chain was established.
719135446Strhodes *
720135446Strhodes * Requires:
721170222Sdougb *\li	'chain' is a valid chain.
722135446Strhodes *
723135446Strhodes * Ensures:
724170222Sdougb *\li	'node', if non-NULL, is the node to which the chain was pointed
725135446Strhodes *	by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
726135446Strhodes *	If none were called for the chain since it was initialized or reset,
727135446Strhodes *	or if the was no predecessor to the name searched for with
728135446Strhodes *	dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
729135446Strhodes *
730170222Sdougb *\li	'name', if non-NULL, is the name stored at the terminal level of
731135446Strhodes *	the chain.  This is typically a single label, like the "www" of
732135446Strhodes *	"www.isc.org", but need not be so.  At the root of the tree of trees,
733135446Strhodes *	if the node is "." then 'name' is ".", otherwise it is relative to ".".
734135446Strhodes *	(Minimalist and atypical case:  if the tree has just the name
735135446Strhodes *	"isc.org." then the root node's stored name is "isc.org." but 'name'
736135446Strhodes *	will be "isc.org".)
737135446Strhodes *
738170222Sdougb *\li	'origin', if non-NULL, is the sequence of labels in the levels
739135446Strhodes *	above the terminal level, such as "isc.org." in the above example.
740135446Strhodes *	'origin' is always "." for the root node.
741135446Strhodes *
742135446Strhodes *
743135446Strhodes * Returns:
744170222Sdougb *\li	#ISC_R_SUCCESS		name, origin & node were successfully set.
745170222Sdougb *\li	#ISC_R_NOTFOUND		The chain does not point to any node.
746170222Sdougb *\li	&lt;something_else>	Any error return from dns_name_concatenate.
747135446Strhodes */
748135446Strhodes
749135446Strhodesisc_result_t
750135446Strhodesdns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
751135446Strhodes		       dns_name_t *name, dns_name_t *origin);
752170222Sdougb/*%<
753135446Strhodes * Set the chain to the lexically first node in the tree of trees.
754135446Strhodes *
755135446Strhodes * Notes:
756170222Sdougb *\li	By the definition of ordering for DNS names, the root of the tree of
757135446Strhodes *	trees is the very first node, since everything else in the megatree
758135446Strhodes *	uses it as a common suffix.
759135446Strhodes *
760135446Strhodes * Requires:
761170222Sdougb *\li	'chain' is a valid chain.
762170222Sdougb *\li	'rbt' is a valid rbt manager.
763135446Strhodes *
764135446Strhodes * Ensures:
765170222Sdougb *\li	The chain points to the very first node of the tree.
766135446Strhodes *
767170222Sdougb *\li	'name' and 'origin', if non-NULL, are set as described for
768135446Strhodes *	dns_rbtnodechain_current.  Thus 'origin' will always be ".".
769135446Strhodes *
770135446Strhodes * Returns:
771170222Sdougb *\li	#DNS_R_NEWORIGIN		The name & origin were successfully set.
772170222Sdougb *\li	&lt;something_else>	Any error result from dns_rbtnodechain_current.
773135446Strhodes */
774135446Strhodes
775135446Strhodesisc_result_t
776135446Strhodesdns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
777135446Strhodes		       dns_name_t *name, dns_name_t *origin);
778170222Sdougb/*%<
779135446Strhodes * Set the chain to the lexically last node in the tree of trees.
780135446Strhodes *
781135446Strhodes * Requires:
782170222Sdougb *\li	'chain' is a valid chain.
783170222Sdougb *\li	'rbt' is a valid rbt manager.
784135446Strhodes *
785135446Strhodes * Ensures:
786170222Sdougb *\li	The chain points to the very last node of the tree.
787135446Strhodes *
788170222Sdougb *\li	'name' and 'origin', if non-NULL, are set as described for
789135446Strhodes *	dns_rbtnodechain_current.
790135446Strhodes *
791135446Strhodes * Returns:
792170222Sdougb *\li	#DNS_R_NEWORIGIN		The name & origin were successfully set.
793170222Sdougb *\li	#ISC_R_NOMEMORY		Resource Limit: Out of Memory building chain.
794170222Sdougb *\li	&lt;something_else>	Any error result from dns_name_concatenate.
795135446Strhodes */
796135446Strhodes
797135446Strhodesisc_result_t
798135446Strhodesdns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
799135446Strhodes		      dns_name_t *origin);
800170222Sdougb/*%<
801135446Strhodes * Adjusts chain to point the DNSSEC predecessor of the name to which it
802135446Strhodes * is currently pointed.
803135446Strhodes *
804135446Strhodes * Requires:
805170222Sdougb *\li	'chain' is a valid chain.
806170222Sdougb *\li	'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
807135446Strhodes *	dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
808135446Strhodes *	dns_rbt_findnode is not guaranteed to point the chain somewhere,
809135446Strhodes *	since there may have been no predecessor to the searched for name.
810135446Strhodes *
811135446Strhodes * Ensures:
812170222Sdougb *\li	The chain is pointed to the predecessor of its current target.
813135446Strhodes *
814170222Sdougb *\li	'name' and 'origin', if non-NULL, are set as described for
815135446Strhodes *	dns_rbtnodechain_current.
816135446Strhodes *
817170222Sdougb *\li	'origin' is only if a new origin was found.
818135446Strhodes *
819135446Strhodes * Returns:
820170222Sdougb *\li	#ISC_R_SUCCESS		The predecessor was found and 'name' was set.
821170222Sdougb *\li	#DNS_R_NEWORIGIN		The predecessor was found with a different
822135446Strhodes *				origin and 'name' and 'origin' were set.
823170222Sdougb *\li	#ISC_R_NOMORE		There was no predecessor.
824170222Sdougb *\li	&lt;something_else>	Any error result from dns_rbtnodechain_current.
825135446Strhodes */
826135446Strhodes
827135446Strhodesisc_result_t
828135446Strhodesdns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
829135446Strhodes		      dns_name_t *origin);
830170222Sdougb/*%<
831135446Strhodes * Adjusts chain to point the DNSSEC successor of the name to which it
832135446Strhodes * is currently pointed.
833135446Strhodes *
834135446Strhodes * Requires:
835170222Sdougb *\li	'chain' is a valid chain.
836170222Sdougb *\li	'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
837135446Strhodes *	dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
838135446Strhodes *	dns_rbt_findnode is not guaranteed to point the chain somewhere,
839135446Strhodes *	since there may have been no predecessor to the searched for name.
840135446Strhodes *
841135446Strhodes * Ensures:
842170222Sdougb *\li	The chain is pointed to the successor of its current target.
843135446Strhodes *
844170222Sdougb *\li	'name' and 'origin', if non-NULL, are set as described for
845135446Strhodes *	dns_rbtnodechain_current.
846135446Strhodes *
847170222Sdougb *\li	'origin' is only if a new origin was found.
848135446Strhodes *
849135446Strhodes * Returns:
850170222Sdougb *\li	#ISC_R_SUCCESS		The successor was found and 'name' was set.
851170222Sdougb *\li	#DNS_R_NEWORIGIN		The successor was found with a different
852135446Strhodes *				origin and 'name' and 'origin' were set.
853170222Sdougb *\li	#ISC_R_NOMORE		There was no successor.
854170222Sdougb *\li	&lt;something_else>	Any error result from dns_name_concatenate.
855135446Strhodes */
856135446Strhodes
857170222Sdougb/*
858170222Sdougb * Wrapper macros for manipulating the rbtnode reference counter:
859170222Sdougb *   Since we selectively use isc_refcount_t for the reference counter of
860170222Sdougb *   a rbtnode, operations on the counter depend on the actual type of it.
861170222Sdougb *   The following macros provide a common interface to these operations,
862170222Sdougb *   hiding the back-end.  The usage is the same as that of isc_refcount_xxx().
863170222Sdougb */
864170222Sdougb#ifdef DNS_RBT_USEISCREFCOUNT
865170222Sdougb#define dns_rbtnode_refinit(node, n)				\
866170222Sdougb	do {							\
867170222Sdougb 		isc_refcount_init(&(node)->references, (n));	\
868170222Sdougb	} while (0)
869170222Sdougb#define dns_rbtnode_refdestroy(node)				\
870170222Sdougb	do {							\
871170222Sdougb		isc_refcount_destroy(&(node)->references);	\
872170222Sdougb	} while (0)
873170222Sdougb#define dns_rbtnode_refcurrent(node)				\
874170222Sdougb	isc_refcount_current(&(node)->references)
875170222Sdougb#define dns_rbtnode_refincrement0(node, refs)			\
876170222Sdougb	do {							\
877170222Sdougb		isc_refcount_increment0(&(node)->references, (refs)); \
878170222Sdougb	} while (0)
879170222Sdougb#define dns_rbtnode_refincrement(node, refs)			\
880170222Sdougb	do {							\
881170222Sdougb		isc_refcount_increment(&(node)->references, (refs)); \
882170222Sdougb	} while (0)
883170222Sdougb#define dns_rbtnode_refdecrement(node, refs)			\
884170222Sdougb	do {							\
885170222Sdougb		isc_refcount_decrement(&(node)->references, (refs)); \
886170222Sdougb	} while (0)
887170222Sdougb#else  /* DNS_RBT_USEISCREFCOUNT */
888170222Sdougb#define dns_rbtnode_refinit(node, n)	((node)->references = (n))
889170222Sdougb#define dns_rbtnode_refdestroy(node)	(REQUIRE((node)->references == 0))
890170222Sdougb#define dns_rbtnode_refcurrent(node)	((node)->references)
891170222Sdougb#define dns_rbtnode_refincrement0(node, refs)			\
892170222Sdougb	do {							\
893170222Sdougb		unsigned int *_tmp = (unsigned int *)(refs);	\
894170222Sdougb		(node)->references++;				\
895170222Sdougb		if ((_tmp) != NULL)				\
896170222Sdougb			(*_tmp) = (node)->references;		\
897170222Sdougb	} while (0)
898170222Sdougb#define dns_rbtnode_refincrement(node, refs)			\
899170222Sdougb	do {							\
900170222Sdougb		REQUIRE((node)->references > 0);		\
901170222Sdougb		(node)->references++;				\
902170222Sdougb		if ((refs) != NULL)				\
903170222Sdougb			(*refs) = (node)->references;		\
904170222Sdougb	} while (0)
905170222Sdougb#define dns_rbtnode_refdecrement(node, refs)			\
906170222Sdougb	do {							\
907170222Sdougb		REQUIRE((node)->references > 0);		\
908170222Sdougb		(node)->references--;				\
909170222Sdougb		if ((refs) != NULL)				\
910170222Sdougb			(*refs) = (node)->references;		\
911170222Sdougb	} while (0)
912170222Sdougb#endif /* DNS_RBT_USEISCREFCOUNT */
913170222Sdougb
914135446StrhodesISC_LANG_ENDDECLS
915135446Strhodes
916135446Strhodes#endif /* DNS_RBT_H */
917