rbt.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2012-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: rbt.h,v 1.77.666.4 2012/02/08 19:53:30 each Exp $ */
00019 
00020 #ifndef DNS_RBT_H
00021 #define DNS_RBT_H 1
00022 
00023 /*! \file dns/rbt.h */
00024 
00025 #include <isc/crc64.h>
00026 #include <isc/lang.h>
00027 #include <isc/magic.h>
00028 #include <isc/refcount.h>
00029 
00030 #include <dns/types.h>
00031 
00032 ISC_LANG_BEGINDECLS
00033 
00034 #define DNS_RBT_USEHASH 1
00035 
00036 /*@{*/
00037 /*%
00038  * Option values for dns_rbt_findnode() and dns_rbt_findname().
00039  * These are used to form a bitmask.
00040  */
00041 #define DNS_RBTFIND_NOOPTIONS                   0x00
00042 #define DNS_RBTFIND_EMPTYDATA                   0x01
00043 #define DNS_RBTFIND_NOEXACT                     0x02
00044 #define DNS_RBTFIND_NOPREDECESSOR               0x04
00045 /*@}*/
00046 
00047 #ifndef DNS_RBT_USEISCREFCOUNT
00048 #ifdef ISC_REFCOUNT_HAVEATOMIC
00049 #define DNS_RBT_USEISCREFCOUNT 1
00050 #endif
00051 #endif
00052 
00053 #define DNS_RBT_USEMAGIC 1
00054 
00055 /*
00056  * These should add up to 30.
00057  */
00058 #define DNS_RBT_LOCKLENGTH                      10
00059 #define DNS_RBT_REFLENGTH                       20
00060 
00061 #define DNS_RBTNODE_MAGIC               ISC_MAGIC('R','B','N','O')
00062 #if DNS_RBT_USEMAGIC
00063 #define DNS_RBTNODE_VALID(n)            ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
00064 #else
00065 #define DNS_RBTNODE_VALID(n)            ISC_TRUE
00066 #endif
00067 
00068 /*%
00069  * This is the structure that is used for each node in the red/black
00070  * tree of trees.  NOTE WELL:  the implementation manages this as a variable
00071  * length structure, with the actual wire-format name and other data
00072  * appended to this structure.  Allocating a contiguous block of memory for
00073  * multiple dns_rbtnode structures will not work.
00074  */
00075 typedef struct dns_rbtnode dns_rbtnode_t;
00076 enum {
00077         DNS_RBT_NSEC_NORMAL=0,      /* in main tree */
00078         DNS_RBT_NSEC_HAS_NSEC=1,    /* also has node in nsec tree */
00079         DNS_RBT_NSEC_NSEC=2,        /* in nsec tree */
00080         DNS_RBT_NSEC_NSEC3=3        /* in nsec3 tree */
00081 };
00082 struct dns_rbtnode {
00083 #if DNS_RBT_USEMAGIC
00084         unsigned int magic;
00085 #endif
00086         dns_rbtnode_t *parent;
00087         dns_rbtnode_t *left;
00088         dns_rbtnode_t *right;
00089         dns_rbtnode_t *down;
00090 #ifdef DNS_RBT_USEHASH
00091         dns_rbtnode_t *hashnext;
00092 #endif
00093 
00094         /*%
00095          * Used for LRU cache.  This linked list is used to mark nodes which
00096          * have no data any longer, but we cannot unlink at that exact moment
00097          * because we did not or could not obtain a write lock on the tree.
00098          */
00099         ISC_LINK(dns_rbtnode_t) deadlink;
00100 
00101         /*@{*/
00102         /*!
00103          * The following bitfields add up to a total bitwidth of 32.
00104          * The range of values necessary for each item is indicated,
00105          * but in the case of "attributes" the field is wider to accommodate
00106          * possible future expansion.
00107          *
00108          * In each case below the "range" indicated is what's _necessary_ for
00109          * the bitfield to hold, not what it actually _can_ hold.
00110          */
00111         unsigned int is_root : 1;       /*%< range is 0..1 */
00112         unsigned int color : 1;         /*%< range is 0..1 */
00113         unsigned int find_callback : 1; /*%< range is 0..1 */
00114         unsigned int attributes : 3;    /*%< range is 0..2 */
00115         unsigned int nsec : 2;          /*%< range is 0..3 */
00116         unsigned int namelen : 8;       /*%< range is 1..255 */
00117         unsigned int offsetlen : 8;     /*%< range is 1..128 */
00118         unsigned int oldnamelen : 8;    /*%< range is 1..255 */
00119         /*@}*/
00120 
00121         /* flags needed for serialization to file*/
00122         unsigned int is_mmapped : 1;
00123         unsigned int parent_is_relative : 1;
00124         unsigned int left_is_relative : 1;
00125         unsigned int right_is_relative : 1;
00126         unsigned int down_is_relative : 1;
00127         unsigned int data_is_relative : 1;
00128 
00129         /* node needs to be cleaned from rpz */
00130         unsigned int rpz : 1;
00131 
00132 #ifdef DNS_RBT_USEHASH
00133         unsigned int hashval;
00134 #endif
00135 
00136         /*@{*/
00137         /*!
00138          * These values are used in the RBT DB implementation.  The appropriate
00139          * node lock must be held before accessing them.
00140          */
00141         void *data;
00142         unsigned int dirty:1;
00143         unsigned int wild:1;
00144         unsigned int locknum:DNS_RBT_LOCKLENGTH;
00145 #ifndef DNS_RBT_USEISCREFCOUNT
00146         unsigned int references:DNS_RBT_REFLENGTH;
00147 #else
00148         isc_refcount_t references; /* note that this is not in the bitfield */
00149 #endif
00150         /*@}*/
00151 };
00152 
00153 typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
00154                                               dns_name_t *name,
00155                                               void *callback_arg);
00156 
00157 typedef isc_result_t (*dns_rbtdatawriter_t)(FILE *file,
00158                                             unsigned char *data,
00159                                             void *arg,
00160                                             isc_uint64_t *crc);
00161 
00162 typedef isc_result_t (*dns_rbtdatafixer_t)(dns_rbtnode_t *rbtnode,
00163                                            void *base, size_t offset,
00164                                            void *arg, isc_uint64_t *crc);
00165 
00166 typedef void (*dns_rbtdeleter_t)(void *, void *);
00167 
00168 /*****
00169  *****  Chain Info
00170  *****/
00171 
00172 /*!
00173  * A chain is used to keep track of the sequence of nodes to reach any given
00174  * node from the root of the tree.  Originally nodes did not have parent
00175  * pointers in them (for memory usage reasons) so there was no way to find
00176  * the path back to the root from any given node.  Now that nodes have parent
00177  * pointers, chains might be going away in a future release, though the
00178  * movement functionality would remain.
00179  *
00180  * In any event, parent information, whether via parent pointers or chains, is
00181  * necessary information for iterating through the tree or for basic internal
00182  * tree maintenance issues (ie, the rotations that are done to rebalance the
00183  * tree when a node is added).  The obvious implication of this is that for a
00184  * chain to remain valid, the tree has to be locked down against writes for the
00185  * duration of the useful life of the chain, because additions or removals can
00186  * change the path from the root to the node the chain has targeted.
00187  *
00188  * The dns_rbtnodechain_ functions _first, _last, _prev and _next all take
00189  * dns_name_t parameters for the name and the origin, which can be NULL.  If
00190  * non-NULL, 'name' will end up pointing to the name data and offsets that are
00191  * stored at the node (and thus it will be read-only), so it should be a
00192  * regular dns_name_t that has been initialized with dns_name_init.  When
00193  * 'origin' is non-NULL, it will get the name of the origin stored in it, so it
00194  * needs to have its own buffer space and offsets, which is most easily
00195  * accomplished with a dns_fixedname_t.  It is _not_ necessary to reinitialize
00196  * either 'name' or 'origin' between calls to the chain functions.
00197  *
00198  * NOTE WELL: even though the name data at the root of the tree of trees will
00199  * be absolute (typically just "."), it will will be made into a relative name
00200  * with an origin of "." -- an empty name when the node is ".".  This is
00201  * because a common on operation on 'name' and 'origin' is to use
00202  * dns_name_concatenate() on them to generate the complete name.  An empty name
00203  * can be detected when dns_name_countlabels == 0, and is printed by
00204  * dns_name_totext()/dns_name_format() as "@", consistent with RFC1035's
00205  * definition of "@" as the current origin.
00206  *
00207  * dns_rbtnodechain_current is similar to the _first, _last, _prev and _next
00208  * functions but additionally can provide the node to which the chain points.
00209  */
00210 
00211 /*%
00212  * The number of level blocks to allocate at a time.  Currently the maximum
00213  * number of levels is allocated directly in the structure, but future
00214  * revisions of this code might have a static initial block with dynamic
00215  * growth.  Allocating space for 256 levels when the tree is almost never that
00216  * deep is wasteful, but it's not clear that it matters, since the waste is
00217  * only 2MB for 1000 concurrently active chains on a system with 64-bit
00218  * pointers.
00219  */
00220 #define DNS_RBT_LEVELBLOCK 254
00221 
00222 typedef struct dns_rbtnodechain {
00223         unsigned int            magic;
00224         isc_mem_t *             mctx;
00225         /*%
00226          * The terminal node of the chain.  It is not in levels[].
00227          * This is ostensibly private ... but in a pinch it could be
00228          * used tell that the chain points nowhere without needing to
00229          * call dns_rbtnodechain_current().
00230          */
00231         dns_rbtnode_t *         end;
00232         /*%
00233          * The maximum number of labels in a name is 128; bitstrings mean
00234          * a conceptually very large number (which I have not bothered to
00235          * compute) of logical levels because splitting can potentially occur
00236          * at each bit.  However, DNSSEC restricts the number of "logical"
00237          * labels in a name to 255, meaning only 254 pointers are needed
00238          * in the worst case.
00239          */
00240         dns_rbtnode_t *         levels[DNS_RBT_LEVELBLOCK];
00241         /*%
00242          * level_count indicates how deep the chain points into the
00243          * tree of trees, and is the index into the levels[] array.
00244          * Thus, levels[level_count - 1] is the last level node stored.
00245          * A chain that points to the top level of the tree of trees has
00246          * a level_count of 0, the first level has a level_count of 1, and
00247          * so on.
00248          */
00249         unsigned int            level_count;
00250         /*%
00251          * level_matches tells how many levels matched above the node
00252          * returned by dns_rbt_findnode().  A match (partial or exact) found
00253          * in the first level thus results in level_matches being set to 1.
00254          * This is used by the rbtdb to set the start point for a recursive
00255          * search of superdomains until the RR it is looking for is found.
00256          */
00257         unsigned int            level_matches;
00258 } dns_rbtnodechain_t;
00259 
00260 /*****
00261  ***** Public interfaces.
00262  *****/
00263 isc_result_t
00264 dns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter,
00265                void *deleter_arg, dns_rbt_t **rbtp);
00266 /*%<
00267  * Initialize a red-black tree of trees.
00268  *
00269  * Notes:
00270  *\li   The deleter argument, if non-null, points to a function that is
00271  *      responsible for cleaning up any memory associated with the data
00272  *      pointer of a node when the node is deleted.  It is passed the
00273  *      deleted node's data pointer as its first argument and deleter_arg
00274  *      as its second argument.
00275  *
00276  * Requires:
00277  * \li  mctx is a pointer to a valid memory context.
00278  *\li   rbtp != NULL && *rbtp == NULL
00279  *\li   arg == NULL iff deleter == NULL
00280  *
00281  * Ensures:
00282  *\li   If result is ISC_R_SUCCESS:
00283  *              *rbtp points to a valid red-black tree manager
00284  *
00285  *\li   If result is failure:
00286  *              *rbtp does not point to a valid red-black tree manager.
00287  *
00288  * Returns:
00289  *\li   #ISC_R_SUCCESS  Success
00290  *\li   #ISC_R_NOMEMORY Resource limit: Out of Memory
00291  */
00292 
00293 isc_result_t
00294 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
00295 /*%<
00296  * Add 'name' to the tree of trees, associated with 'data'.
00297  *
00298  * Notes:
00299  *\li   'data' is never required to be non-NULL, but specifying it
00300  *      when the name is added is faster than searching for 'name'
00301  *      again and then setting the data pointer.  The lack of a data pointer
00302  *      for a node also has other ramifications regarding whether
00303  *      dns_rbt_findname considers a node to exist, or dns_rbt_deletename
00304  *      joins nodes.
00305  *
00306  * Requires:
00307  *\li   rbt is a valid rbt manager.
00308  *\li   dns_name_isabsolute(name) == TRUE
00309  *
00310  * Ensures:
00311  *\li   'name' is not altered in any way.
00312  *
00313  *\li   Any external references to nodes in the tree are unaffected by
00314  *      node splits that are necessary to insert the new name.
00315  *
00316  *\li   If result is #ISC_R_SUCCESS:
00317  *              'name' is findable in the red/black tree of trees in O(log N).
00318  *              The data pointer of the node for 'name' is set to 'data'.
00319  *
00320  *\li   If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
00321  *              The tree of trees is unaltered.
00322  *
00323  *\li   If result is #ISC_R_NOMEMORY:
00324  *              No guarantees.
00325  *
00326  * Returns:
00327  *\li   #ISC_R_SUCCESS  Success
00328  *\li   #ISC_R_EXISTS   The name already exists with associated data.
00329  *\li   #ISC_R_NOSPACE  The name had more logical labels than are allowed.
00330  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
00331  */
00332 
00333 isc_result_t
00334 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
00335 
00336 /*%<
00337  * Just like dns_rbt_addname, but returns the address of the node.
00338  *
00339  * Requires:
00340  *\li   rbt is a valid rbt structure.
00341  *\li   dns_name_isabsolute(name) == TRUE
00342  *\li   nodep != NULL && *nodep == NULL
00343  *
00344  * Ensures:
00345  *\li   'name' is not altered in any way.
00346  *
00347  *\li   Any external references to nodes in the tree are unaffected by
00348  *      node splits that are necessary to insert the new name.
00349  *
00350  *\li   If result is ISC_R_SUCCESS:
00351  *              'name' is findable in the red/black tree of trees in O(log N).
00352  *              *nodep is the node that was added for 'name'.
00353  *
00354  *\li   If result is ISC_R_EXISTS:
00355  *              The tree of trees is unaltered.
00356  *              *nodep is the existing node for 'name'.
00357  *
00358  *\li   If result is ISC_R_NOMEMORY:
00359  *              No guarantees.
00360  *
00361  * Returns:
00362  *\li   #ISC_R_SUCCESS  Success
00363  *\li   #ISC_R_EXISTS   The name already exists, possibly without data.
00364  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
00365  */
00366 
00367 isc_result_t
00368 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
00369                  dns_name_t *foundname, void **data);
00370 /*%<
00371  * Get the data pointer associated with 'name'.
00372  *
00373  * Notes:
00374  *\li   When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
00375  *      returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is
00376  *      an exact match in the tree.
00377  *
00378  *\li   A node that has no data is considered not to exist for this function,
00379  *      unless the #DNS_RBTFIND_EMPTYDATA option is set.
00380  *
00381  * Requires:
00382  *\li   rbt is a valid rbt manager.
00383  *\li   dns_name_isabsolute(name) == TRUE
00384  *\li   data != NULL && *data == NULL
00385  *
00386  * Ensures:
00387  *\li   'name' and the tree are not altered in any way.
00388  *
00389  *\li   If result is ISC_R_SUCCESS:
00390  *              *data is the data associated with 'name'.
00391  *
00392  *\li   If result is DNS_R_PARTIALMATCH:
00393  *              *data is the data associated with the deepest superdomain
00394  *              of 'name' which has data.
00395  *
00396  *\li   If result is ISC_R_NOTFOUND:
00397  *              Neither the name nor a superdomain was found with data.
00398  *
00399  * Returns:
00400  *\li   #ISC_R_SUCCESS          Success
00401  *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
00402  *\li   #ISC_R_NOTFOUND         No match
00403  *\li   #ISC_R_NOSPACE          Concatenating nodes to form foundname failed
00404  */
00405 
00406 isc_result_t
00407 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
00408                  dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
00409                  unsigned int options, dns_rbtfindcallback_t callback,
00410                  void *callback_arg);
00411 /*%<
00412  * Find the node for 'name'.
00413  *
00414  * Notes:
00415  *\li   A node that has no data is considered not to exist for this function,
00416  *      unless the DNS_RBTFIND_EMPTYDATA option is set.  This applies to both
00417  *      exact matches and partial matches.
00418  *
00419  *\li   If the chain parameter is non-NULL, then the path through the tree
00420  *      to the DNSSEC predecessor of the searched for name is maintained,
00421  *      unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
00422  *      is used. (For more details on those options, see below.)
00423  *
00424  *\li   If there is no predecessor, then the chain will point to nowhere, as
00425  *      indicated by chain->end being NULL or dns_rbtnodechain_current
00426  *      returning ISC_R_NOTFOUND.  Note that in a normal Internet DNS RBT
00427  *      there will always be a predecessor for all names except the root
00428  *      name, because '.' will exist and '.' is the predecessor of
00429  *      everything.  But you can certainly construct a trivial tree and a
00430  *      search for it that has no predecessor.
00431  *
00432  *\li   Within the chain structure, the 'levels' member of the structure holds
00433  *      the root node of each level except the first.
00434  *
00435  *\li   The 'level_count' of the chain indicates how deep the chain to the
00436  *      predecessor name is, as an index into the 'levels[]' array.  It does
00437  *      not count name elements, per se, but only levels of the tree of trees,
00438  *      the distinction arising because multiple labels from a name can be
00439  *      stored on only one level.  It is also does not include the level
00440  *      that has the node, since that level is not stored in levels[].
00441  *
00442  *\li   The chain's 'level_matches' is not directly related to the predecessor.
00443  *      It is the number of levels above the level of the found 'node',
00444  *      regardless of whether it was a partial match or exact match.  When
00445  *      the node is found in the top level tree, or no node is found at all,
00446  *      level_matches is 0.
00447  *
00448  *\li   When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
00449  *      returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
00450  *      there is an exact match in the tree.  In this case, the chain
00451  *      will not point to the DNSSEC predecessor, but will instead point
00452  *      to the exact match, if there was any.  Thus the preceding paragraphs
00453  *      should have "exact match" substituted for "predecessor" to describe
00454  *      how the various elements of the chain are set.  This was done to
00455  *      ensure that the chain's state was sane, and to prevent problems that
00456  *      occurred when running the predecessor location code under conditions
00457  *      it was not designed for.  It is not clear *where* the chain should
00458  *      point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
00459  *      with this option because you want a particular node, let us know
00460  *      where you want the chain pointed, so this can be made more firm.
00461  *
00462  * Requires:
00463  *\li   rbt is a valid rbt manager.
00464  *\li   dns_name_isabsolute(name) == TRUE.
00465  *\li   node != NULL && *node == NULL.
00466  *\li   #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutually
00467  *              exclusive.
00468  *
00469  * Ensures:
00470  *\li   'name' and the tree are not altered in any way.
00471  *
00472  *\li   If result is ISC_R_SUCCESS:
00473  *\verbatim
00474  *              *node is the terminal node for 'name'.
00475 
00476  *              'foundname' and 'name' represent the same name (though not
00477  *              the same memory).
00478 
00479  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
00480  *
00481  *              chain->level_matches and chain->level_count are equal.
00482  *\endverbatim
00483  *
00484  *      If result is DNS_R_PARTIALMATCH:
00485  *\verbatim
00486  *              *node is the data associated with the deepest superdomain
00487  *              of 'name' which has data.
00488  *
00489  *              'foundname' is the name of deepest superdomain (which has
00490  *              data, unless the DNS_RBTFIND_EMPTYDATA option is set).
00491  *
00492  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
00493  *\endverbatim
00494  *
00495  *\li   If result is ISC_R_NOTFOUND:
00496  *\verbatim
00497  *              Neither the name nor a superdomain was found.  *node is NULL.
00498  *
00499  *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
00500  *
00501  *              chain->level_matches is 0.
00502  *\endverbatim
00503  *
00504  * Returns:
00505  *\li   #ISC_R_SUCCESS          Success
00506  *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
00507  *\li   #ISC_R_NOTFOUND         No match, or superdomain with no data
00508  *\li   #ISC_R_NOSPACE Concatenating nodes to form foundname failed
00509  */
00510 
00511 isc_result_t
00512 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse);
00513 /*%<
00514  * Delete 'name' from the tree of trees.
00515  *
00516  * Notes:
00517  *\li   When 'name' is removed, if recurse is ISC_TRUE then all of its
00518  *      subnames are removed too.
00519  *
00520  * Requires:
00521  *\li   rbt is a valid rbt manager.
00522  *\li   dns_name_isabsolute(name) == TRUE
00523  *
00524  * Ensures:
00525  *\li   'name' is not altered in any way.
00526  *
00527  *\li   Does NOT ensure that any external references to nodes in the tree
00528  *      are unaffected by node joins.
00529  *
00530  *\li   If result is ISC_R_SUCCESS:
00531  *              'name' does not appear in the tree with data; however,
00532  *              the node for the name might still exist which can be
00533  *              found with dns_rbt_findnode (but not dns_rbt_findname).
00534  *
00535  *\li   If result is ISC_R_NOTFOUND:
00536  *              'name' does not appear in the tree with data, because
00537  *              it did not appear in the tree before the function was called.
00538  *
00539  *\li   If result is something else:
00540  *              See result codes for dns_rbt_findnode (if it fails, the
00541  *              node is not deleted) or dns_rbt_deletenode (if it fails,
00542  *              the node is deleted, but the tree is not optimized when
00543  *              it could have been).
00544  *
00545  * Returns:
00546  *\li   #ISC_R_SUCCESS  Success
00547  *\li   #ISC_R_NOTFOUND No match
00548  *\li   something_else  Any return code from dns_rbt_findnode except
00549  *                      DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
00550  *                      to be returned instead), and any code from
00551  *                      dns_rbt_deletenode.
00552  */
00553 
00554 isc_result_t
00555 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse);
00556 /*%<
00557  * Delete 'node' from the tree of trees.
00558  *
00559  * Notes:
00560  *\li   When 'node' is removed, if recurse is ISC_TRUE then all nodes
00561  *      in levels down from it are removed too.
00562  *
00563  * Requires:
00564  *\li   rbt is a valid rbt manager.
00565  *\li   node != NULL.
00566  *
00567  * Ensures:
00568  *\li   Does NOT ensure that any external references to nodes in the tree
00569  *      are unaffected by node joins.
00570  *
00571  *\li   If result is ISC_R_SUCCESS:
00572  *              'node' does not appear in the tree with data; however,
00573  *              the node might still exist if it serves as a pointer to
00574  *              a lower tree level as long as 'recurse' was false, hence
00575  *              the node could can be found with dns_rbt_findnode when
00576  *              that function's empty_data_ok parameter is true.
00577  *
00578  *\li   If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
00579  *              The node was deleted, but the tree structure was not
00580  *              optimized.
00581  *
00582  * Returns:
00583  *\li   #ISC_R_SUCCESS  Success
00584  *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes.
00585  *\li   #ISC_R_NOSPACE  dns_name_concatenate failed when joining nodes.
00586  */
00587 
00588 void
00589 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
00590 /*%<
00591  * Convert the sequence of labels stored at 'node' into a 'name'.
00592  *
00593  * Notes:
00594  *\li   This function does not return the full name, from the root, but
00595  *      just the labels at the indicated node.
00596  *
00597  *\li   The name data pointed to by 'name' is the information stored
00598  *      in the node, not a copy.  Altering the data at this pointer
00599  *      will likely cause grief.
00600  *
00601  * Requires:
00602  * \li  name->offsets == NULL
00603  *
00604  * Ensures:
00605  * \li  'name' is DNS_NAMEATTR_READONLY.
00606  *
00607  * \li  'name' will point directly to the labels stored after the
00608  *      dns_rbtnode_t struct.
00609  *
00610  * \li  'name' will have offsets that also point to the information stored
00611  *      as part of the node.
00612  */
00613 
00614 isc_result_t
00615 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
00616 /*%<
00617  * Like dns_rbt_namefromnode, but returns the full name from the root.
00618  *
00619  * Notes:
00620  * \li  Unlike dns_rbt_namefromnode, the name will not point directly
00621  *      to node data.  Rather, dns_name_concatenate will be used to copy
00622  *      the name data from each node into the 'name' argument.
00623  *
00624  * Requires:
00625  * \li  name != NULL
00626  * \li  name has a dedicated buffer.
00627  *
00628  * Returns:
00629  * \li  ISC_R_SUCCESS
00630  * \li  ISC_R_NOSPACE           (possible via dns_name_concatenate)
00631  * \li  DNS_R_NAMETOOLONG       (possible via dns_name_concatenate)
00632  */
00633 
00634 char *
00635 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
00636                        unsigned int size);
00637 /*%<
00638  * Format the full name of a node for printing, using dns_name_format().
00639  *
00640  * Notes:
00641  * \li  'size' is the length of the printname buffer.  This should be
00642  *      DNS_NAME_FORMATSIZE or larger.
00643  *
00644  * Requires:
00645  * \li  node and printname are not NULL.
00646  *
00647  * Returns:
00648  * \li  The 'printname' pointer.
00649  */
00650 
00651 unsigned int
00652 dns_rbt_nodecount(dns_rbt_t *rbt);
00653 /*%<
00654  * Obtain the number of nodes in the tree of trees.
00655  *
00656  * Requires:
00657  * \li  rbt is a valid rbt manager.
00658  */
00659 
00660 unsigned int
00661 dns_rbt_hashsize(dns_rbt_t *rbt);
00662 /*%<
00663  * Obtain the current number of buckets in the 'rbt' hash table.
00664  *
00665  * Requires:
00666  * \li  rbt is a valid rbt manager.
00667  */
00668 
00669 void
00670 dns_rbt_destroy(dns_rbt_t **rbtp);
00671 isc_result_t
00672 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum);
00673 /*%<
00674  * Stop working with a red-black tree of trees.
00675  * If 'quantum' is zero then the entire tree will be destroyed.
00676  * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
00677  * allowing the rbt to be incrementally destroyed by repeated calls to
00678  * dns_rbt_destroy2().  Once dns_rbt_destroy2() has been called no other
00679  * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
00680  * performed on the tree of trees.
00681  *
00682  * Requires:
00683  * \li  *rbt is a valid rbt manager.
00684  *
00685  * Ensures on ISC_R_SUCCESS:
00686  * \li  All space allocated by the RBT library has been returned.
00687  *
00688  * \li  *rbt is invalidated as an rbt manager.
00689  *
00690  * Returns:
00691  * \li  ISC_R_SUCCESS
00692  * \li  ISC_R_QUOTA if 'quantum' nodes have been destroyed.
00693  */
00694 
00695 off_t
00696 dns_rbt_serialize_align(off_t target);
00697 /*%<
00698  * Align the provided integer to a pointer-size boundary.
00699  * This should be used if, during serialization of data to a will-be
00700  * mmap()ed file, a pointer alignment is needed for some data.
00701  */
00702 
00703 isc_result_t
00704 dns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt,
00705                        dns_rbtdatawriter_t datawriter,
00706                        void *writer_arg, off_t *offset);
00707 /*%<
00708  * Write out the RBT structure and its data to a file.
00709  *
00710  * Notes:
00711  * \li  The file must be an actual file which allows seek() calls, so it cannot
00712  *      be a stream.  Returns ISC_R_INVALIDFILE if not.
00713  */
00714 
00715 isc_result_t
00716 dns_rbt_deserialize_tree(void *base_address, size_t filesize,
00717                          off_t header_offset, isc_mem_t *mctx,
00718                          dns_rbtdeleter_t deleter, void *deleter_arg,
00719                          dns_rbtdatafixer_t datafixer, void *fixer_arg,
00720                          dns_rbtnode_t **originp, dns_rbt_t **rbtp);
00721 /*%<
00722  * Read a RBT structure and its data from a file.
00723  *
00724  * If 'originp' is not NULL, then it is pointed to the root node of the RBT.
00725  *
00726  * Notes:
00727  * \li  The file must be an actual file which allows seek() calls, so it cannot
00728  *      be a stream.  This condition is not checked in the code.
00729  */
00730 
00731 void
00732 dns_rbt_printtext(dns_rbt_t *rbt,
00733                   void (*data_printer)(FILE *, void *), FILE *f);
00734 /*%<
00735  * Print an ASCII representation of the internal structure of the red-black
00736  * tree of trees to the passed stream.
00737  *
00738  * data_printer is a callback function that is called to print the data
00739  * in a node. It should print it to the passed FILE stream.
00740  *
00741  * Notes:
00742  * \li  The name stored at each node, along with the node's color, is printed.
00743  *      Then the down pointer, left and right pointers are displayed
00744  *      recursively in turn.  NULL down pointers are silently omitted;
00745  *      NULL left and right pointers are printed.
00746  */
00747 
00748 void
00749 dns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f);
00750 /*%<
00751  * Print a GraphViz dot representation of the internal structure of the
00752  * red-black tree of trees to the passed stream.
00753  *
00754  * If show_pointers is TRUE, pointers are also included in the generated
00755  * graph.
00756  *
00757  * Notes:
00758  * \li  The name stored at each node, along with the node's color is displayed.
00759  *      Then the down pointer, left and right pointers are displayed
00760  *      recursively in turn.  NULL left, right and down pointers are
00761  *      silently omitted.
00762  */
00763 
00764 void
00765 dns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f);
00766 /*%<
00767  * Print out various information about a node
00768  *
00769  * Requires:
00770  *\li   'n' is a valid pointer.
00771  *
00772  *\li   'f' points to a valid open FILE structure that allows writing.
00773  */
00774 
00775 
00776 size_t
00777 dns__rbt_getheight(dns_rbt_t *rbt);
00778 /*%<
00779  * Return the maximum height of sub-root nodes found in the red-black
00780  * forest.
00781  *
00782  * The height of a node is defined as the number of nodes in the longest
00783  * path from the node to a leaf. For each subtree in the forest, this
00784  * function determines the height of its root node. Then it returns the
00785  * maximum such height in the forest.
00786  *
00787  * Note: This function exists for testing purposes. Non-test code must
00788  * not use it.
00789  *
00790  * Requires:
00791  * \li  rbt is a valid rbt manager.
00792  */
00793 
00794 isc_boolean_t
00795 dns__rbt_checkproperties(dns_rbt_t *rbt);
00796 /*%<
00797  * Check red-black properties of the forest.
00798  *
00799  * Note: This function exists for testing purposes. Non-test code must
00800  * not use it.
00801  *
00802  * Requires:
00803  * \li  rbt is a valid rbt manager.
00804  */
00805 
00806 size_t
00807 dns__rbtnode_getdistance(dns_rbtnode_t *node);
00808 /*%<
00809  * Return the distance (in nodes) from the node to its upper node of its
00810  * subtree. The root node has a distance of 1. A child of the root node
00811  * has a distance of 2.
00812  */
00813 
00814 /*****
00815  ***** Chain Functions
00816  *****/
00817 
00818 void
00819 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx);
00820 /*%<
00821  * Initialize 'chain'.
00822  *
00823  * Requires:
00824  *\li   'chain' is a valid pointer.
00825  *
00826  *\li   'mctx' is a valid memory context.
00827  *
00828  * Ensures:
00829  *\li   'chain' is suitable for use.
00830  */
00831 
00832 void
00833 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
00834 /*%<
00835  * Free any dynamic storage associated with 'chain', and then reinitialize
00836  * 'chain'.
00837  *
00838  * Requires:
00839  *\li   'chain' is a valid pointer.
00840  *
00841  * Ensures:
00842  *\li   'chain' is suitable for use, and uses no dynamic storage.
00843  */
00844 
00845 void
00846 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
00847 /*%<
00848  * Free any dynamic storage associated with 'chain', and then invalidates it.
00849  *
00850  * Notes:
00851  *\li   Future calls to any dns_rbtnodechain_ function will need to call
00852  *      dns_rbtnodechain_init on the chain first (except, of course,
00853  *      dns_rbtnodechain_init itself).
00854  *
00855  * Requires:
00856  *\li   'chain' is a valid chain.
00857  *
00858  * Ensures:
00859  *\li   'chain' is no longer suitable for use, and uses no dynamic storage.
00860  */
00861 
00862 isc_result_t
00863 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
00864                          dns_name_t *origin, dns_rbtnode_t **node);
00865 /*%<
00866  * Provide the name, origin and node to which the chain is currently pointed.
00867  *
00868  * Notes:
00869  *\li   The tree need not have be locked against additions for the chain
00870  *      to remain valid, however there are no guarantees if any deletion
00871  *      has been made since the chain was established.
00872  *
00873  * Requires:
00874  *\li   'chain' is a valid chain.
00875  *
00876  * Ensures:
00877  *\li   'node', if non-NULL, is the node to which the chain was pointed
00878  *      by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
00879  *      If none were called for the chain since it was initialized or reset,
00880  *      or if the was no predecessor to the name searched for with
00881  *      dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
00882  *
00883  *\li   'name', if non-NULL, is the name stored at the terminal level of
00884  *      the chain.  This is typically a single label, like the "www" of
00885  *      "www.isc.org", but need not be so.  At the root of the tree of trees,
00886  *      if the node is "." then 'name' is ".", otherwise it is relative to ".".
00887  *      (Minimalist and atypical case:  if the tree has just the name
00888  *      "isc.org." then the root node's stored name is "isc.org." but 'name'
00889  *      will be "isc.org".)
00890  *
00891  *\li   'origin', if non-NULL, is the sequence of labels in the levels
00892  *      above the terminal level, such as "isc.org." in the above example.
00893  *      'origin' is always "." for the root node.
00894  *
00895  *
00896  * Returns:
00897  *\li   #ISC_R_SUCCESS          name, origin & node were successfully set.
00898  *\li   #ISC_R_NOTFOUND         The chain does not point to any node.
00899  *\li   &lt;something_else>     Any error return from dns_name_concatenate.
00900  */
00901 
00902 isc_result_t
00903 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
00904                        dns_name_t *name, dns_name_t *origin);
00905 /*%<
00906  * Set the chain to the lexically first node in the tree of trees.
00907  *
00908  * Notes:
00909  *\li   By the definition of ordering for DNS names, the root of the tree of
00910  *      trees is the very first node, since everything else in the megatree
00911  *      uses it as a common suffix.
00912  *
00913  * Requires:
00914  *\li   'chain' is a valid chain.
00915  *\li   'rbt' is a valid rbt manager.
00916  *
00917  * Ensures:
00918  *\li   The chain points to the very first node of the tree.
00919  *
00920  *\li   'name' and 'origin', if non-NULL, are set as described for
00921  *      dns_rbtnodechain_current.  Thus 'origin' will always be ".".
00922  *
00923  * Returns:
00924  *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
00925  *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
00926  */
00927 
00928 isc_result_t
00929 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
00930                        dns_name_t *name, dns_name_t *origin);
00931 /*%<
00932  * Set the chain to the lexically last node in the tree of trees.
00933  *
00934  * Requires:
00935  *\li   'chain' is a valid chain.
00936  *\li   'rbt' is a valid rbt manager.
00937  *
00938  * Ensures:
00939  *\li   The chain points to the very last node of the tree.
00940  *
00941  *\li   'name' and 'origin', if non-NULL, are set as described for
00942  *      dns_rbtnodechain_current.
00943  *
00944  * Returns:
00945  *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
00946  *\li   #ISC_R_NOMEMORY         Resource Limit: Out of Memory building chain.
00947  *\li   &lt;something_else>     Any error result from dns_name_concatenate.
00948  */
00949 
00950 isc_result_t
00951 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
00952                       dns_name_t *origin);
00953 /*%<
00954  * Adjusts chain to point the DNSSEC predecessor of the name to which it
00955  * is currently pointed.
00956  *
00957  * Requires:
00958  *\li   'chain' is a valid chain.
00959  *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
00960  *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
00961  *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
00962  *      since there may have been no predecessor to the searched for name.
00963  *
00964  * Ensures:
00965  *\li   The chain is pointed to the predecessor of its current target.
00966  *
00967  *\li   'name' and 'origin', if non-NULL, are set as described for
00968  *      dns_rbtnodechain_current.
00969  *
00970  *\li   'origin' is only if a new origin was found.
00971  *
00972  * Returns:
00973  *\li   #ISC_R_SUCCESS          The predecessor was found and 'name' was set.
00974  *\li   #DNS_R_NEWORIGIN                The predecessor was found with a different
00975  *                              origin and 'name' and 'origin' were set.
00976  *\li   #ISC_R_NOMORE           There was no predecessor.
00977  *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
00978  */
00979 
00980 isc_result_t
00981 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
00982                       dns_name_t *origin);
00983 /*%<
00984  * Adjusts chain to point the DNSSEC successor of the name to which it
00985  * is currently pointed.
00986  *
00987  * Requires:
00988  *\li   'chain' is a valid chain.
00989  *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
00990  *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
00991  *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
00992  *      since there may have been no predecessor to the searched for name.
00993  *
00994  * Ensures:
00995  *\li   The chain is pointed to the successor of its current target.
00996  *
00997  *\li   'name' and 'origin', if non-NULL, are set as described for
00998  *      dns_rbtnodechain_current.
00999  *
01000  *\li   'origin' is only if a new origin was found.
01001  *
01002  * Returns:
01003  *\li   #ISC_R_SUCCESS          The successor was found and 'name' was set.
01004  *\li   #DNS_R_NEWORIGIN                The successor was found with a different
01005  *                              origin and 'name' and 'origin' were set.
01006  *\li   #ISC_R_NOMORE           There was no successor.
01007  *\li   &lt;something_else>     Any error result from dns_name_concatenate.
01008  */
01009 
01010 isc_result_t
01011 dns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
01012                       dns_name_t *origin);
01013 /*%<
01014  * Descend down if possible.
01015  */
01016 
01017 isc_result_t
01018 dns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name);
01019 /*%<
01020  * Find the next node at the current depth in DNSSEC order.
01021  */
01022 
01023 /*
01024  * Wrapper macros for manipulating the rbtnode reference counter:
01025  *   Since we selectively use isc_refcount_t for the reference counter of
01026  *   a rbtnode, operations on the counter depend on the actual type of it.
01027  *   The following macros provide a common interface to these operations,
01028  *   hiding the back-end.  The usage is the same as that of isc_refcount_xxx().
01029  */
01030 #ifdef DNS_RBT_USEISCREFCOUNT
01031 #define dns_rbtnode_refinit(node, n)                            \
01032         do {                                                    \
01033                 isc_refcount_init(&(node)->references, (n));    \
01034         } while (0)
01035 #define dns_rbtnode_refdestroy(node)                            \
01036         do {                                                    \
01037                 isc_refcount_destroy(&(node)->references);      \
01038         } while (0)
01039 #define dns_rbtnode_refcurrent(node)                            \
01040         isc_refcount_current(&(node)->references)
01041 #define dns_rbtnode_refincrement0(node, refs)                   \
01042         do {                                                    \
01043                 isc_refcount_increment0(&(node)->references, (refs)); \
01044         } while (0)
01045 #define dns_rbtnode_refincrement(node, refs)                    \
01046         do {                                                    \
01047                 isc_refcount_increment(&(node)->references, (refs)); \
01048         } while (0)
01049 #define dns_rbtnode_refdecrement(node, refs)                    \
01050         do {                                                    \
01051                 isc_refcount_decrement(&(node)->references, (refs)); \
01052         } while (0)
01053 #else  /* DNS_RBT_USEISCREFCOUNT */
01054 #define dns_rbtnode_refinit(node, n)    ((node)->references = (n))
01055 #define dns_rbtnode_refdestroy(node)    REQUIRE((node)->references == 0)
01056 #define dns_rbtnode_refcurrent(node)    ((node)->references)
01057 
01058 #if (__STDC_VERSION__ + 0) >= 199901L || defined __GNUC__
01059 static inline void
01060 dns_rbtnode_refincrement0(dns_rbtnode_t *node, unsigned int *refs) {
01061         node->references++;
01062         if (refs != NULL)
01063                 *refs = node->references;
01064 }
01065 
01066 static inline void
01067 dns_rbtnode_refincrement(dns_rbtnode_t *node, unsigned int *refs) {
01068         REQUIRE(node->references > 0);
01069         node->references++;
01070         if (refs != NULL)
01071                 *refs = node->references;
01072 }
01073 
01074 static inline void
01075 dns_rbtnode_refdecrement(dns_rbtnode_t *node, unsigned int *refs) {
01076         REQUIRE(node->references > 0);
01077         node->references--;
01078         if (refs != NULL)
01079                 *refs = node->references;
01080 }
01081 #else
01082 #define dns_rbtnode_refincrement0(node, refs)                   \
01083         do {                                                    \
01084                 unsigned int *_tmp = (unsigned int *)(refs);    \
01085                 (node)->references++;                           \
01086                 if ((_tmp) != NULL)                             \
01087                         (*_tmp) = (node)->references;           \
01088         } while (0)
01089 #define dns_rbtnode_refincrement(node, refs)                    \
01090         do {                                                    \
01091                 REQUIRE((node)->references > 0);                \
01092                 (node)->references++;                           \
01093                 if ((refs) != NULL)                             \
01094                         (*refs) = (node)->references;           \
01095         } while (0)
01096 #define dns_rbtnode_refdecrement(node, refs)                    \
01097         do {                                                    \
01098                 REQUIRE((node)->references > 0);                \
01099                 (node)->references--;                           \
01100                 if ((refs) != NULL)                             \
01101                         (*refs) = (node)->references;           \
01102         } while (0)
01103 #endif
01104 #endif /* DNS_RBT_USEISCREFCOUNT */
01105 
01106 void
01107 dns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name);
01108 
01109 dns_rbtnode_t *
01110 dns_rbt_root(dns_rbt_t *rbt);
01111 
01112 ISC_LANG_ENDDECLS
01113 
01114 #endif /* DNS_RBT_H */

Generated on Tue Apr 28 17:40:57 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha