6fb9b25791778f69002eb72be6235e20d98ec452Tinderbox User * Copyright (C) 1999-2005, 2007-2009, 2011-2017 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
d09197467bbb156dccf0cbe72bb5c63480d5cfdcDavid Lawrence/* Principal Authors: DCL */
891a1bead8d02d29eb7b4993d7c0975047b0963dDavid Lawrence * This define is so dns/name.h (included by dns/fixedname.h) uses more
891a1bead8d02d29eb7b4993d7c0975047b0963dDavid Lawrence * efficient macro calls instead of functions for a few operations.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb } while (0)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define RBT_MAGIC ISC_MAGIC('R', 'B', 'T', '+')
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * XXXDCL Since parent pointers were added in again, I could remove all of the
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * _lastnode. This would involve pretty major change to the API.
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-')
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
c9611b45736af157e2993c6ef852e55e8e24ca83Evan Hunt * This is the header for map-format RBT images. It is populated,
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * and then written, as the LAST thing done to the file before returning.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * Writing this last (with zeros in the header area initially) will ensure
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * that the header is only valid when the RBT image is also valid.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb/* Pad to 32 bytes */
7829fad4093f2c1985b1efb7cea00287ff015d2bckb/* Header length, always the same size regardless of structure size */
c9611b45736af157e2993c6ef852e55e8e24ca83Evan Hunt * information about the system on which the map file was generated
c9611b45736af157e2993c6ef852e55e8e24ca83Evan Hunt * will be used to tell if we can load the map file or not
7829fad4093f2c1985b1efb7cea00287ff015d2bckb unsigned int bigendian:1; /* big or little endian system */
7829fad4093f2c1985b1efb7cea00287ff015d2bckb unsigned int rdataset_fixed:1; /* compiled with --enable-rrset-fixed */
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * The following declarations are for the serialization of an RBT:
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * step one: write out a zeroed header of 1024 bytes
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * step two: walk the tree in a depth-first, left-right-down order, writing
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * out the nodes, reserving space as we go, correcting addresses to point
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox User * at the proper offset in the file, and setting a flag for each pointer to
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox User * indicate that it is a reference to a location in the file, rather than in
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox User * step three: write out the header, adding the information that will be
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * needed to re-create the tree object itself.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * The RBTDB object will do this three times, once for each of the three
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * RBT objects it contains.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * Note: 'file' must point an actual open file that can be mmapped
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * and fseeked, not to a pipe or stream
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Huntwrite_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox Userserialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User uintptr_t right, uintptr_t down, uintptr_t parent,
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox Userserialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox User * The following functions allow you to get the actual address of a pointer
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox User * without having to use an if statement to check to see if that address is
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * relative or not
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline dns_rbtnode_t *
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User adjusted_address += node->parent_is_relative * (uintptr_t)header;
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline dns_rbtnode_t *
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User adjusted_address += node->left_is_relative * (uintptr_t)header;
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline dns_rbtnode_t *
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User adjusted_address += node->right_is_relative * (uintptr_t)header;
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline dns_rbtnode_t *
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User adjusted_address += node->down_is_relative * (uintptr_t)header;
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline dns_rbtnode_t *
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User adjusted_address += node->data_is_relative * (uintptr_t)header;
f036af2c718147408d738081cdb0a564b981b4cdDavid Lawrence * Elements of the rbtnode structure.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman#define IS_EMPTY(node) ((node)->data == NULL)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define IS_ROOT(node) ISC_TF((node)->is_root == 1)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1)
f036af2c718147408d738081cdb0a564b981b4cdDavid Lawrence * Structure elements from the rbtdb.c, not
f036af2c718147408d738081cdb0a564b981b4cdDavid Lawrence * used as part of the rbt.c algorithms.
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews * The variable length stuff stored after the node has the following
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews * structure.
ad9772c559c6aa42f8930f4acf1a2d833a08040aMichał Kępień * <name_data>{1..255}<oldoffsetlen>{1}<offsets>{1..128}
ad9772c559c6aa42f8930f4acf1a2d833a08040aMichał Kępień * <name_data> contains the name of the node when it was created.
ad9772c559c6aa42f8930f4acf1a2d833a08040aMichał Kępień * <oldoffsetlen> contains the length of <offsets> when the node was created.
ad9772c559c6aa42f8930f4acf1a2d833a08040aMichał Kępień * <offsets> contains the offets into name for each label when the node was
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define NAME(node) ((unsigned char *)((node) + 1))
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews#define OFFSETS(node) (NAME(node) + OLDNAMELEN(node) + 1)
f036af2c718147408d738081cdb0a564b981b4cdDavid Lawrence * Color management.
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define IS_RED(node) ((node) != NULL && (node)->color == RED)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
b239c8294a5653d21876d084e0c5b029f6b9fc5dMichael Graff#define MAKE_BLACK(node) ((node)->color = BLACK)
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrence * Chain management.
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrence * The "ancestors" member of chains were removed, with their job now
47b7dfffe5d806c6a5e99ef17f07bcde812c2132Francis Dupont * being wholly handled by parent pointers (which didn't exist, because
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrence * of memory concerns, when chains were first implemented).
b16d99bac1d100735224ab3eaa84632537ff21b5Mark Andrews INSIST((chain)->level_count < DNS_RBT_LEVELBLOCK); \
b16d99bac1d100735224ab3eaa84632537ff21b5Mark Andrews (chain)->levels[(chain)->level_count++] = (node); \
1630fce031f7a3e33f0579e477a3e17d1993e1f9Bob Halley * The following macros directly access normally private name variables.
1630fce031f7a3e33f0579e477a3e17d1993e1f9Bob Halley * These macros are used to avoid a lot of function calls in the critical
1630fce031f7a3e33f0579e477a3e17d1993e1f9Bob Halley * path of the tree traversal code.
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic inline void
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramandns_rbtnode_nodename(dns_rbtnode_t *node, dns_name_t *name) {
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence#define inline
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * A little something to help out in GDB.
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunthexdump(const char *desc, unsigned char *data, size_t size) {
3911e7610f29dc664cbe8336f35c0652cd74652eMark Andrews r.length = bytes = (size > BUFSIZ) ? BUFSIZ : size;
3911e7610f29dc664cbe8336f35c0652cd74652eMark Andrews } while (size > 0);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman#endif /* DEBUG */
f21d2ee372125a7d0648387581a6712e05feeb52Evan Hunt * Upper node is the parent of the root of the passed node's
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * subtree. The passed node must not be NULL.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaramanfixup_uppernodes_helper(dns_rbtnode_t *node, dns_rbtnode_t *uppernode) {
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman fixup_uppernodes_helper(LEFT(node), uppernode);
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman fixup_uppernodes_helper(RIGHT(node), uppernode);
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * This function is used to fixup uppernode members of all dns_rbtnodes
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * after deserialization.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman/* The passed node must not be NULL. */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman/* Upper node is the parent of the root of the passed node's
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * subtree. The passed node must not be NULL.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman dns_rbtnode_t *root = get_subtree_root(node);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Return the node in the level above the argument node that points
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to the level the argument node is in. If the argument node is in
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the top level, the return value is NULL.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramandns__rbtnode_getdistance(dns_rbtnode_t *node) {
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * Forward declarations.
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencecreate_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep);
7554feaef6057f5ea2926076900ac7634b911456Mark Andrewsstatic inline void
40e7c805a8f38ad9b20dd6c688496fc09fc971c2Mark Andrewshash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name);
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencestatic inline void
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrenceunhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node);
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencestatic inline void
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencerotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencestatic inline void
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencerotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
7829fad4093f2c1985b1efb7cea00287ff015d2bckbaddonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrewsdeletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp);
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic void
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaramandeletetreeflat(dns_rbt_t *rbt, unsigned int quantum, isc_boolean_t unhash,
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic void
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramanprintnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f);
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic void
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * Write out a zeroed header as a placeholder. Doing this ensures
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * that the file will not read while it is partially written, should
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * writing fail or be interrupted.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb result = isc_stdio_write(buffer, 1, HEADER_LENGTH, file, NULL);
e7c0f978425f45731b08be1363f20626b0344f23Evan Hunt INSIST(n > 0 && (unsigned int)n < sizeof(FILE_VERSION));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * Write out the real header, including NodeDump version information
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * and the offset of the first node.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * Any information stored in the rbt object itself should be stored
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Huntwrite_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
e7c0f978425f45731b08be1363f20626b0344f23Evan Hunt RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt memmove(header.version1, FILE_VERSION, sizeof(header.version1));
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt memmove(header.version2, FILE_VERSION, sizeof(header.version2));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb CHECK(isc_stdio_write(&header, 1, sizeof(file_header_t), file, NULL));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Ensure we are always at the end of the file. */
e7c0f978425f45731b08be1363f20626b0344f23Evan Hunt RUNTIME_CHECK(isc_once_do(&once, init_file_version) == ISC_R_SUCCESS);
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox Userserialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User uintptr_t right, uintptr_t down, uintptr_t parent,
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * If the next node is not NULL, calculate the next node's location
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * in the file. Note that this will have to change when the data
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * structure changes, and it also assumes that we always write the
7829fad4093f2c1985b1efb7cea00287ff015d2bckb * nodes out in list order (which we currently do.)
7829fad4093f2c1985b1efb7cea00287ff015d2bckb node_data = (unsigned char *) node + sizeof(dns_rbtnode_t);
7829fad4093f2c1985b1efb7cea00287ff015d2bckb CHECK(isc_stdio_write(&temp_node, 1, sizeof(dns_rbtnode_t),
7829fad4093f2c1985b1efb7cea00287ff015d2bckb CHECK(isc_stdio_write(node_data, 1, datasize, file, NULL));
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt hexdump("node header", (unsigned char*) &temp_node,
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt isc_crc64_update(crc, (const isc_uint8_t *) &temp_node,
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt isc_crc64_update(crc, (const isc_uint8_t *) node_data, datasize);
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox Userserialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
620620df3a74a5a57dc25221aae5033568703eb2Tinderbox User uintptr_t left = 0, right = 0, down = 0, data = 0;
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt /* Reserve space for current node. */
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt offset_adjust = dns_rbt_serialize_align(location + NODE_SIZE(node));
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt * Serialize the rest of the tree.
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt * WARNING: A change in the order (from left, right, down)
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt * will break the way the crc hash is computed.
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt CHECK(serialize_nodes(file, getleft(node, NULL), location,
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt CHECK(serialize_nodes(file, getright(node, NULL), location,
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt CHECK(serialize_nodes(file, getdown(node, NULL), location,
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt /* Seek back to reserved space. */
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt /* Serialize the current node. */
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt CHECK(serialize_node(file, node, left, right, down, parent, data, crc));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Ensure we are always at the end of the file. */
8e6b386ab7e2d1bd8efedecbb8f4efb6b572a866Tinderbox Userdns_rbt_serialize_tree(FILE *file, dns_rbt_t *rbt,
31707708c585c53b61ca1edb2e224e6bb1b985a5Evan Hunt off_t header_position, node_position, end_position;
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Write dummy header */
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Serialize nodes */
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt CHECK(serialize_nodes(file, rbt->root, 0, datawriter,
3911e7610f29dc664cbe8336f35c0652cd74652eMark Andrews hexdump("serializing CRC", (unsigned char *)&crc, sizeof(crc));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Serialize header */
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt CHECK(write_header(file, rbt, HEADER_LENGTH, crc));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Ensure we are always at the end of the file. */
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt if (! (a)) { \
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunttreefix(dns_rbt_t *rbt, void *base, size_t filesize, dns_rbtnode_t *n,
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt size_t datasize, nodemax = filesize - sizeof(dns_rbtnode_t);
127a4a90b0d03ebf55ad44d25f75b30c3a6fb728Evan Hunt CONFIRM((char *) n - (char *) base <= (int) nodemax);
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt CHECK(dns_name_concatenate(&nodename, name, fullname, NULL));
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt /* memorize header contents prior to fixup */
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt /* a change in the order (from left, right, down) will break hashing*/
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt CHECK(treefix(rbt, base, filesize, n->right, name,
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt CHECK(treefix(rbt, base, filesize, n->down, fullname,
b7e40659efd6cf6f5e6b3b1f904f16f74efb0d16Evan Hunt CHECK(datafixer(n, base, filesize, fixer_arg, crc));
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt node_data = (unsigned char *) n + sizeof(dns_rbtnode_t);
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt isc_crc64_update(crc, (const isc_uint8_t *) &header,
e59937c7283216ca22ce6e7937b06eab6d97f4acEvan Hunt isc_crc64_update(crc, (const isc_uint8_t *) node_data,
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Huntdns_rbt_deserialize_tree(void *base_address, size_t filesize,
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt CHECK(dns_rbt_create(mctx, deleter, deleter_arg, &rbt));
7829fad4093f2c1985b1efb7cea00287ff015d2bckb header = (file_header_t *)((char *)base_address + header_offset);
7829fad4093f2c1985b1efb7cea00287ff015d2bckb /* Copy other data items from the header into our rbt. */
1a076410c260ff1d3124ce8b7e22ac111e9cf92aEvan Hunt rbt->root = (dns_rbtnode_t *)((char *)base_address +
127a4a90b0d03ebf55ad44d25f75b30c3a6fb728Evan Hunt if ((header->nodecount * sizeof(dns_rbtnode_t)) > filesize) {
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt CHECK(treefix(rbt, base_address, filesize, rbt->root,
3911e7610f29dc664cbe8336f35c0652cd74652eMark Andrews hexdump("deserializing CRC", (unsigned char *)&crc, sizeof(crc));
d9f0c713fe1d50f1848ca827c5f31db79d904f04Evan Hunt /* Check file hash */
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * Initialize a red/black tree of trees.
b7e40659efd6cf6f5e6b3b1f904f16f74efb0d16Evan Huntdns_rbt_create(isc_mem_t *mctx, dns_rbtdeleter_t deleter,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
df925e6c66d45d960fbac0383169763967d2111cEvan Hunt isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
bd1190c84b08e61a12789c54f083318c36449e5eDavid Lawrence * Deallocate a red/black tree of trees.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
a03848252fa85734ca75beae3d0b01bb503c0a8bMark Andrewsdns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman deletetreeflat(rbt, quantum, ISC_FALSE, &rbt->root);
df925e6c66d45d960fbac0383169763967d2111cEvan Hunt isc_mem_putanddetach(&rbt->mctx, rbt, sizeof(*rbt));
ec80744ad68b97f15657b1fdf5591c30b559b57dDavid Lawrencechain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater if (include_chain_end && chain->end != NULL) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_name_copy(&nodename, name, NULL);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater for (i = (int)chain->level_count - 1; i >= 0; i--) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_name_concatenate(name, &nodename, name, NULL);
ec80744ad68b97f15657b1fdf5591c30b559b57dDavid Lawrencemove_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Go as far right and then down as much as possible,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * as long as the rightmost node has a down pointer.
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * Add 'name' to tree, initializing its data pointer with 'data'.
0f5962ac3e4ef336faff68f1cb838505e64665e5David Lawrencedns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Does this thing have too many variables or what?
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_rbtnode_t **root, *parent, *child, *current, *new_current;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * Dear future BIND developer,
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * After you have tried attempting to optimize this routine by
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * using the hashtable and have realized your folly, please
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * append another cross ("X") below as a warning to the next
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * future BIND developer:
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * Number of victim developers: X
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * I wish the past developer had included such a notice.
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * Long form: Unlike dns_rbt_findnode(), this function does not
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * lend itself to be optimized using the hashtable:
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * 1. In the subtree where the insertion occurs, this function
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * needs to have the insertion point and the order where the
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * lookup terminated (i.e., at the insertion point where left or
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * right child is NULL). This cannot be determined from the
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * hashtable, so at least in that subtree, a BST O(log N) lookup
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * is necessary.
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * 2. Our RBT nodes contain not only single labels but label
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * sequences to optimize space usage. So at every level, we have
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * to look for a match in the hashtable for all superdomains in
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * the rest of the name we're searching. This is an O(N)
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * operation at least, here N being the label size of name, each
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * of which is a hashtable lookup involving dns_name_equal()
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * comparisons.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Create a copy of the name so the original name structure is
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * not modified.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater add_name = dns_fixedname_name(&fixedcopy);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = create_node(rbt->mctx, add_name, &new_current);
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater prefix = dns_fixedname_name(&fixedprefix);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater suffix = dns_fixedname_name(&fixedsuffix);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_init(¤t_name, current_offsets);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater compared = dns_name_fullcompare(add_name, ¤t_name,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater } else if (order > 0) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This name has some suffix in common with the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * name at the current node. If the name at
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the current node is shorter, that means the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * new name should be in a subtree. If the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * name at the current node is longer, that means
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the down pointer to this tree should point
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to a new tree that has the common suffix, and
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the non-common parts of these two names should
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * start a new tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * All of the existing labels are in common,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * so the new name is in a subtree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Whack off the common labels for the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * not-in-common part to be searched for
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * in the next level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Follow the down pointer (possibly NULL).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The number of labels in common is fewer
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * than the number of labels at the current
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node, so the current node must be adjusted
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to have just the common suffix, and a down
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * pointer made to a new tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater INSIST(compared == dns_namereln_commonancestor
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Ensure the number of levels in the tree
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * does not exceed the number of logical
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * levels allowed by DNSSEC.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * XXXDCL need a better error result?
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Split the name into two parts, a prefix
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * which is the not-in-common parts of the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * two names and a suffix that is the common
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * parts of them.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_split(¤t_name, common_labels,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Reproduce the tree attributes of the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * current node.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Fix pointers that were to the current node.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Set up the new root of the next level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * By definition it will not be the top
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman UPPERNODE(new_current) = UPPERNODE(current);
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The name has been added by pushing
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the not-in-common parts down to
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * a new level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The current node has no data,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * because it is just a placeholder.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Its data pointer is already NULL
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * from create_node()), so there's
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * nothing more to do to it.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The not-in-common parts of the new
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * name will be inserted into the new
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * level following this loop (unless
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * result != ISC_R_SUCCESS, which
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * is tested after the loop ends).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = create_node(rbt->mctx, add_name, &new_current);
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
bd1190c84b08e61a12789c54f083318c36449e5eDavid Lawrence * Add a name to the tree of trees, associating it with some data.
0f5962ac3e4ef336faff68f1cb838505e64665e5David Lawrencedns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbt_addnode(rbt, name, &node);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * dns_rbt_addnode will report the node exists even when
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * it does not have data associated with it, but the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * dns_rbt_*name functions all behave depending on whether
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * there is data associated with a node.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater (result == ISC_R_EXISTS && DATA(node) == NULL)) {
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * Find the node for "name" in the tree of trees.
7a00d69909ace5dc11bcff9c1e07c311f92a7f8eWitold Krecickidns_rbt_findnode(dns_rbt_t *rbt, const dns_name_t *name, dns_name_t *foundname,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater unsigned int options, dns_rbtfindcallback_t callback,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_t *search_name, current_name, *callback_name;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_fixedname_t fixedcallbackname, fixedsearchname;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater != (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * If there is a chain it needs to appear to be in a sane state,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * otherwise a chain is still needed to generate foundname and
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * callback_name.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * Appease GCC about variables it incorrectly thinks are
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * possibly used uninitialized.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater callback_name = dns_fixedname_name(&fixedcallbackname);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * search_name is the name segment being sought in each tree level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * By using a fixedname, the search_name will definitely have offsets
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * for use by any splitting.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * By using dns_name_clone, no name data should be copied thanks to
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the lack of bitstring labels.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater search_name = dns_fixedname_name(&fixedsearchname);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater compared = dns_name_fullcompare(search_name, ¤t_name,
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * last_compared is used as a shortcut to start (or
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * continue rather) finding the stop-node of the search
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * when hashing was used (see much below in this
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * Here, current is pointing at a subtree root
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * node. We try to find a matching node using
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * the hashtable. We can get one of 3 results
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * here: (a) we locate the matching node, (b) we
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * find a node to which the current node has a
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * subdomain relation, (c) we fail to find (a)
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * The case of current not being a subtree root,
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * that means a left or right pointer was
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * followed, only happens when the algorithm
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * fell through to the traditional binary search
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * because of a bitstring label. Since we
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * dropped the bitstring support, this should
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * not happen.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater nlabels = dns_name_countlabels(search_name);
614ce1b65ff9ef158aa5a19a9acf2edb99170963Mukund Sivaraman * current is the root of the current level, so
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * its parent is the same as its "up" pointer.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * Compute the hash over the full absolute
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * name. Look for the smallest suffix match at
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * this tree level (hlevel), and then at every
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * iteration, look for the next smallest suffix
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * match (add another subdomain label to the
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * absolute name being hashed).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater hash = dns_name_fullhash(&hash_name, ISC_FALSE);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * Walk all the nodes in the hash bucket pointed
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * by the computed hash value.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater for (hnode = rbt->hashtable[hash % rbt->hashsize];
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * This checks that the hashed label
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * sequence being looked up is at the
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * same tree level, so that we don't
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * match a labelsequence from some other
d1dbf6b20fdcfa95acd75cdb96fcd57067a31144Mukund Sivaraman if (ISC_LIKELY(get_upper_node(hnode) != up_current))
d1dbf6b20fdcfa95acd75cdb96fcd57067a31144Mukund Sivaraman if (ISC_LIKELY(dns_name_equal(&hnode_name, &hash_name)))
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This is an optimization. If hashing found
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the right node, the next call to
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * dns_name_fullcompare() would obviously
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * return _equal or _subdomain. Determine
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * which of those would be the case by
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * checking if the full name was hashed. Then
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * make it look like dns_name_fullcompare
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * was called and jump to the right place.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * All of the labels have been tried against the hash
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * table. Since we dropped the support of bitstring
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * labels, the name isn't in the table.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#else /* DNS_RBT_USEHASH */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Standard binary search tree movement.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman#endif /* DNS_RBT_USEHASH */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The names have some common suffix labels.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * If the number in common are equal in length to
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the current node's name length, then follow the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * down pointer and search in the new tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Whack off the current node's common parts
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * for the name to search in the next level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_split(search_name, common_labels,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This might be the closest enclosing name.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Point the chain to the next level. This
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * needs to be done before 'current' is pointed
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * there because the callback in the next
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * block of code needs the current 'current',
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * but in the event the callback requests that
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the search be stopped then the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * DNS_R_PARTIALMATCH code at the end of this
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * function needs the chain pointed to the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The caller may want to interrupt the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * downward search when certain special nodes
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * are traversed. If this is a special node,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the callback is used to learn what the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * caller wants to do.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Treat this node as if it
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * had no down pointer.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Finally, head to the next tree level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Though there are labels in common, the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * entire name at this node is not common
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * with the search name so the search
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * name does not exist in the tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater INSIST(compared == dns_namereln_commonancestor
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * If current is not NULL, NOEXACT is not disallowing exact matches,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * and either the node has data or an empty node is ok, return
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * ISC_R_SUCCESS to indicate an exact match.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Found an exact match.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater chain->level_matches = chain->level_count;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = chain_name(chain, foundname, ISC_TRUE);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Did not find an exact match (or did not want one).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * ... but found a partially matching superdomain.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Unwind the chain to the partial match node
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to set level_matches to the level above the node,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * and then to derive the name.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * chain->level_count is guaranteed to be at least 1
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * here because by definition of finding a superdomain,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the chain is pointed to at least the first subtree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater chain->level_matches = chain->level_count - 1;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater while (chain->levels[chain->level_matches] != *node) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater unsigned int saved_count = chain->level_count;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater chain->level_count = chain->level_matches + 1;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * There was an exact match but either
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * DNS_RBTFIND_NOEXACT was set, or
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * DNS_RBTFIND_EMPTYDATA was set and the node had no
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * data. A policy decision was made to set the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * chain to the exact match, but this is subject
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to change if it becomes apparent that something
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * else would be more useful. It is important that
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * this case is handled here, because the predecessor
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * setting code below assumes the match was not exact.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Ensure the chain points nowhere.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Since there was no exact match, the chain argument
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * needs to be pointed at the DNSSEC predecessor of
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the search name.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Attempted to follow a down pointer that was
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * NULL, which means the searched for name was
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * a subdomain of a terminal name in the tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Since there are no existing subdomains to
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * order against, the terminal name is the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * predecessor.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Point current to the node that stopped
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * With the hashing modification that has been
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * added to the algorithm, the stop node of a
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * standard binary search is not known. So it
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * has to be found. There is probably a more
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * clever way of doing this.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The assignment of current to NULL when
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the relationship is *not* dns_namereln_none,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * even though it later gets set to the same
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * last_compared anyway, is simply to not push
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the while loop in one more level of
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * indentation.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Standard binary search movement.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Reached a point within a level tree that
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * positively indicates the name is not
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * present, but the stop node could be either
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * less than the desired name (order > 0) or
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * greater than the desired name (order < 0).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * If the stop node is less, it is not
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * necessarily the predecessor. If the stop
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node has a down pointer, then the real
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * predecessor is at the end of a level below
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * (not necessarily the next level).
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Move down levels until the rightmost node
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * does not have a down pointer.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * When the stop node is greater, it is
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the successor. All the logic for finding
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the predecessor is handily encapsulated
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * in dns_rbtnodechain_prev. In the event
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * that the search name is less than anything
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * else in the tree, the chain is reset.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * XXX DCL What is the best way for the caller
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * to know that the search name has
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * no predecessor?
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Ah, the pure and simple
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * case. The stop node is the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * predecessor.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater ; /* Nothing. */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * There is no predecessor.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
bd1190c84b08e61a12789c54f083318c36449e5eDavid Lawrence * Get the data pointer associated with 'name'.
7a00d69909ace5dc11bcff9c1e07c311f92a7f8eWitold Krecickidns_rbt_findname(dns_rbt_t *rbt, const dns_name_t *name, unsigned int options,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrence * Delete a name from the tree of trees.
0f5962ac3e4ef336faff68f1cb838505e64665e5David Lawrencedns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * First, find the node.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * When searching, the name might not have an exact match:
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * elements of a tree, which would make layer 1 a single
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node tree of "b.a.com" and layer 2 a three node tree of
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * a, b, and c. Deleting a.com would find only a partial depth
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * match in the first layer. Should it be a requirement that
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * that the name to be deleted have data? For now, it is.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * ->dirty, ->locknum and ->references are ignored; they are
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * solely the province of rbtdb.c.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbt_deletenode(rbt, node, recurse);
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * Remove a node from the tree of trees.
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * NOTE WELL: deletion is *not* symmetric with addition; that is, reversing
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * a sequence of additions to be deletions will not generally get the
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * tree back to the state it started in. For example, if the addition
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * of "b.c" caused the node "a.b.c" to be split, pushing "a" to its own level,
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * turned out to be a bad idea because it could corrupt an active nodechain
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * that had "b.c" as one of its levels -- and the RBT has no idea what
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * nodechains are in use by callers, so it can't even *try* to helpfully
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * fix them up (which would probably be doomed to failure anyway).
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * Similarly, it is possible to leave the tree in a state where a supposedly
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * deleted node still exists. The first case of this is obvious; take
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * the tree which has "b.c" on one level, pointing to "a". Now deleted "b.c".
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * It was just established in the previous paragraph why we can't pull "a"
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * back up to its parent level. But what happens when "a" then gets deleted?
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * "b.c" is left hanging around without data or children. This condition
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * is actually pretty easy to detect, but ... should it really be removed?
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * Is a chain pointing to it? An iterator? Who knows! (Note that the
b79e66b06d058ef3b9a26b71806ce67971cd3152David Lawrence * references structure member cannot be looked at because it is private to
b79e66b06d058ef3b9a26b71806ce67971cd3152David Lawrence * rbtdb.) This is ugly and makes me unhappy, but after hours of trying to
b79e66b06d058ef3b9a26b71806ce67971cd3152David Lawrence * make it more aesthetically proper and getting nowhere, this is the way it
b79e66b06d058ef3b9a26b71806ce67971cd3152David Lawrence * is going to stay until such time as it proves to be a *real* problem.
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * Finally, for reference, note that the original routine that did node
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * joining was called join_nodes(). It has been excised, living now only
b79e66b06d058ef3b9a26b71806ce67971cd3152David Lawrence * in the CVS history, but comments have been left behind that point to it just
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * in case someone wants to muck with this some more.
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * The one positive aspect of all of this is that joining used to have a
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrence * case where it might fail. Without trying to join, now this function always
a571ebca8b8c472e775d518e82b7335f93ea25c4Andreas Gustafsson * succeeds. It still returns isc_result_t, though, so the API wouldn't change.
510f4bdcb66acbec3f276efaacecbebea891c868David Lawrencedns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman deletetreeflat(rbt, 0, ISC_TRUE, &DOWN(node));
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater if (DATA(node) != NULL && rbt->data_deleter != NULL)
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater rbt->data_deleter(DATA(node), rbt->deleter_arg);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Since there is at least one node below this one and
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * no recursion was requested, the deletion is
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * complete. The down node from this node might be all
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * by itself on a single level, so join_nodes() could
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * be used to collapse the tree (with all the caveats
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * of the comment at the start of this function).
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * But join_nodes() function has now been removed.
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews * Note the node that points to the level of the node
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews * that is being deleted. If the deleted node is the
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews * top level, parent will be set to NULL.
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews * This node now has no down pointer, so now it needs
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews * to be removed from this level.
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews deletefromlevel(node, parent == NULL ? &rbt->root : &DOWN(parent));
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews if (DATA(node) != NULL && rbt->data_deleter != NULL)
558278974eb4a1021943e6bbbc6c7d80dc3707fdMark Andrews rbt->data_deleter(DATA(node), rbt->deleter_arg);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This function never fails.
73d62a89f1493865c33c689b3ee3de91c74ad58eDavid Lawrencedns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrencedns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_name_concatenate(name, ¤t, name, NULL);
a09c545af1ceb8eb6f3aa2bb6fae286208a72141David Lawrencedns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbt_fullnamefromnode(node, name);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater snprintf(printname, size, "<error building name: %s>",
73d62a89f1493865c33c689b3ee3de91c74ad58eDavid Lawrencecreate_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Allocate space for the node structure, the name, and the offsets.
7829fad4093f2c1985b1efb7cea00287ff015d2bckb nodelen = sizeof(dns_rbtnode_t) + region.length + labels + 1;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The following is stored to make reconstructing a name from the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * stored value in the node easy: the length of the name, the number
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * of labels, whether the name is absolute or not, the name itself,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * and the name's offsets table.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The offsets table could be made smaller by eliminating the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * first offset, which is always 0. This requires changes to
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews * Note: OLDOFFSETLEN *must* be assigned *after* OLDNAMELEN is assigned
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews * as it uses OLDNAMELEN.
7704a47aec081144bdb7a0218d5e2dd5296b6b08Mark Andrews OLDNAMELEN(node) = NAMELEN(node) = region.length;
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrencestatic inline void
40e7c805a8f38ad9b20dd6c688496fc09fc971c2Mark Andrewshash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
f2453ece5b6f7c0a5c446b357e3ea26ee5736e02Francis Dupont bytes = (unsigned int)rbt->hashsize * sizeof(dns_rbtnode_t *);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater unsigned int i;
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman INSIST((rbt->hashsize * 2 + 1) > rbt->hashsize);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater for (i = 0; i < oldsize; i++) {
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman for (node = oldtable[i]; node != NULL; node = nextnode) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
7554feaef6057f5ea2926076900ac7634b911456Mark Andrewsstatic inline void
40e7c805a8f38ad9b20dd6c688496fc09fc971c2Mark Andrewshash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrencestatic inline void
b65f2ab14abb4b6ef906d7d02064fba158f07b1eDavid Lawrenceunhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
08e57545c2b1068080f5bf317224160426801406Brian Wellington#endif /* DNS_RBT_USEHASH */
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrencestatic inline void
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencerotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
f389bc2c9e9e434380e10221778b7b548612a67fDavid Lawrencestatic inline void
092b4e5359c5982a438e36ced3dbefc313f7fbfcDavid Lawrencerotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
c4c843edb3f4c609e3552ee77a43400852400467David Lawrence * This is the real workhorse of the insertion code, because it does the
c4c843edb3f4c609e3552ee77a43400852400467David Lawrence * true red/black tree on a single level.
7829fad4093f2c1985b1efb7cea00287ff015d2bckbaddonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_rbtnode_t *child, *root, *parent, *grandparent;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_offsets_t add_offsets, current_offsets;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * First node of a level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_init(¤t_name, current_offsets);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater while (node != root && IS_RED(PARENT(node))) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * XXXDCL could do away with separate parent and grandparent
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * variables. They are vestiges of the days before parent
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * pointers. However, they make the code a little clearer.
0f5962ac3e4ef336faff68f1cb838505e64665e5David Lawrence * This is the real workhorse of the deletion code, because it does the
0f5962ac3e4ef336faff68f1cb838505e64665e5David Lawrence * true red/black tree on a single level.
bfde61d5194a534d800f3b90008d1f52261922c5Mark Andrewsdeletefromlevel(dns_rbtnode_t *item, dns_rbtnode_t **rootp) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Verify that the parent history is (apparently) correct.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This is the only item in the tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This node has one child, on the right.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This node has one child, on the left.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This node has two children, so it cannot be directly
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * deleted. Find its immediate in-order successor and
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * move it to this location, then do the deletion at the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * old site of the successor.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The successor cannot possibly have a left child;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * if there is any child, it is on the right.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Swap the two nodes; it would be simpler to just replace
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the value being deleted with that of the successor,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * but this rigamarole is done so the caller has complete
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * control over the pointers (and memory allocation) of
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * all of nodes. If just the key value were removed from
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the tree, the pointer to the node would be unchanged.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * First, put the successor in the tree location of the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node to be deleted. Save its existing tree pointer
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * information, which will be needed when linking up
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * delete to the successor's old location.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Now relink the node to be deleted into the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * successor's previous tree location. PARENT(tmp)
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * is the successor's original parent.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Node being deleted was successor's parent.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Original location of successor node has no left.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Remove the node by removing the links from its parent.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This is the root being deleted, and at this point
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * it is known to have just one child.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Fix color violations.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater while (child != *rootp && IS_BLACK(child)) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater INSIST(child == NULL || ! IS_ROOT(child));
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Child is parent's right child.
47b7dfffe5d806c6a5e99ef17f07bcde812c2132Francis Dupont * Everything is done the same as above,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * except mirrored.
7829fad4093f2c1985b1efb7cea00287ff015d2bckbstatic void
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaramandeletetreeflat(dns_rbt_t *rbt, unsigned int quantum, isc_boolean_t unhash,
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * If there is a left, right or down node, walk into it
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * and iterate.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * There are no left, right or down nodes, so we
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * can free this one and go back to its parent.
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman if (DATA(node) != NULL && rbt->data_deleter != NULL)
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * Note: we don't call unhash_node() here as we
5d79b60fc5e4dad4f04da39570517d20a2425f8bMukund Sivaraman * are destroying the complete RBT tree.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman down_height = getheight_helper(DOWN(node));
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman return (ISC_MAX(this_height, down_height));
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramancheck_properties_helper(dns_rbtnode_t *node) {
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* Root nodes must be BLACK. */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* Both children of RED nodes must be BLACK. */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman if (IS_RED(LEFT(node)) || IS_RED(RIGHT(node)))
e2047969decfc0c3fc1a946ccade993cab9c9315Mark Andrews if ((DOWN(node) != NULL) && (!IS_ROOT(DOWN(node))))
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* If node is assigned to the down_ pointer of its parent, it is
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * a subtree root and must have the flag set.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* Repeat tests with this node's children. */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman return (check_properties_helper(LEFT(node)) &&
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramancheck_black_distance_helper(dns_rbtnode_t *node, size_t *distance) {
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman if (!check_black_distance_helper(LEFT(node), &dl))
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman if (!check_black_distance_helper(RIGHT(node), &dr))
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman if (!check_black_distance_helper(DOWN(node), &dd))
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* Left and right side black node counts must match. */
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* Path from a given node to all its leaves must contain the
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * same number of BLACK child nodes. This is done separately
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * here instead of inside check_properties_helper() as
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * it would take (n log n) complexity otherwise.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman return (check_black_distance_helper(rbt->root, &dd));
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater for (i = 0; i < depth; i++)
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramandns_rbt_printnodeinfo(dns_rbtnode_t *n, FILE *f) {
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "Relative pointers: %s%s%s%s%s\n",
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "node lock address = %d\n", n->locknum);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramanprintnodename(dns_rbtnode_t *node, isc_boolean_t quoted, FILE *f) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_name_format(&name, buffer, sizeof(buffer));
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramanprint_text_helper(dns_rbtnode_t *root, dns_rbtnode_t *parent,
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman void (*data_printer)(FILE *, void *), FILE *f)
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater if ((! IS_ROOT(root) && PARENT(root) != parent) ||
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "** Red/Red color violation on left\n");
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman print_text_helper(LEFT(root), root, depth, "left",
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "** Red/Red color violation on right\n");
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman print_text_helper(RIGHT(root), root, depth, "right",
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman print_text_helper(DOWN(root), NULL, depth, "down",
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman void (*data_printer)(FILE *, void *), FILE *f)
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman print_text_helper(rbt->root, NULL, 0, "root", data_printer, f);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramanprint_dot_helper(dns_rbtnode_t *node, unsigned int *nodecount,
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman unsigned int l, r, d;
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman l = print_dot_helper(LEFT(node), nodecount, show_pointers, f);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman r = print_dot_helper(RIGHT(node), nodecount, show_pointers, f);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman d = print_dot_helper(DOWN(node), nodecount, show_pointers, f);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "node%u[label = \"<f0> |<f1> ", *nodecount);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "|<f3> n=%p|<f4> p=%p", node, PARENT(node));
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman /* XXXMUKS: verify that IS_ROOT() indicates subtree root and not
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * forest root.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, ",style=filled,fillcolor=lightgrey");
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "\"node%u\":f0 -> \"node%u\":f1;\n", *nodecount, l);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "\"node%u\":f1 -> \"node%u\":f1 [penwidth=5];\n",
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "\"node%u\":f2 -> \"node%u\":f1;\n", *nodecount, r);
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaramandns_rbt_printdot(dns_rbt_t *rbt, isc_boolean_t show_pointers, FILE *f) {
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman fprintf(f, "node [shape = record,height=.1];\n");
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman print_dot_helper(rbt->root, &nodecount, show_pointers, f);
5f50687f61057f7f0acb161d5803f4a48e40b3a8David Lawrence * Chain Functions
5f50687f61057f7f0acb161d5803f4a48e40b3a8David Lawrencedns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
03b5d2689df73fa9a50ff684511fa9d81f317e6cEvan Hunt * Initialize 'chain'.
5497de6931b5ac26f65c2343b0318614f73933baMark Andrews memset(chain->levels, 0, sizeof(chain->levels));
ec80744ad68b97f15657b1fdf5591c30b559b57dDavid Lawrencedns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Names in the top level tree are all absolute.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Always make 'name' relative.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * This is cheaper than dns_name_getlabelsequence().
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = chain_name(chain, origin, ISC_FALSE);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_name_copy(dns_rootname, origin, NULL);
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrencedns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_rbtnode_t *current, *previous, *predecessor;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Moving left one then right as far as possible is the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * previous node, at least for this level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * No left links, so move toward the root. If at any point on
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the way there the link from parent to child is a right
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * link, then the parent is the previous node, at least
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * for this level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Found a predecessor node in this level. It might not
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * really be the predecessor, however.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The predecessor is really down at least one level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Go down and as far right as possible, and repeat
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * as long as the rightmost node has a down pointer.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * XXX DCL Need to do something about origins
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * here. See whether to go down, and if so
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * whether it is truly what Bob calls a
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater /* XXX DCL duplicated from above; clever
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * way to unduplicate? */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater /* XXX DCL probably needs work on the concept */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Dang, didn't find a predecessor in this level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Got to the root of this level without having traversed
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * any right links. Ascend the tree one level; the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node that points to this tree is the predecessor.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater INSIST(chain->level_count > 0 && IS_ROOT(current));
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater predecessor = chain->levels[--chain->level_count];
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater /* XXX DCL probably needs work on the concept */
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Don't declare an origin change when the new origin is "."
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * at the top level tree, because "." is declared as the origin
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * for the second level tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbtnodechain_current(chain, name, origin,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbtnodechain_current(chain, name, NULL,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_rbtnodechain_down(dns_rbtnodechain_t *chain, dns_name_t *name,
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * Don't declare an origin change when the new origin is "."
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * at the second level tree, because "." is already declared
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * as the origin for the top level tree.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * It is not necessary to use dns_rbtnodechain_current like
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * the other functions because this function will never
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * find a node in the topmost level. This is because the
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * root level will never be more than one name, and everything
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * in the megatree is a successor to that node, down at
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews * the second level or below.
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_rbtnodechain_nextflat(dns_rbtnodechain_t *chain, dns_name_t *name) {
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrews REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrencedns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater dns_rbtnode_t *current, *previous, *successor;
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * If there is a level below this node, the next node is the leftmost
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * node of the next level.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Don't declare an origin change when the new origin is "."
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * at the second level tree, because "." is already declared
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * as the origin for the top level tree.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * The successor is up, either in this level or a previous one.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Head back toward the root of the tree, looking for any path
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * that was via a left link; the successor is the node that has
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * that left link. In the event the root of the level is
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * reached without having traversed any left links, ascend one
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * level and look for either a right link off the point of
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * ascent, or search for a left link upward again, repeating
47b7dfffe5d806c6a5e99ef17f07bcde812c2132Francis Dupont * ascends until either case is true.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Reached the root without having traversed
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * any left pointers, so this level is done.
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * If the tree we are iterating over
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * was modified since this chain was
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * initialized in a way that caused
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * node splits to occur, "current" may
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * now be pointing to a root node which
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * appears to be at level 0, but still
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * has a parent. If that happens,
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * abort. Otherwise, we are done
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * looking for a successor as we really
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * reached the root node on level 0.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater current = chain->levels[--chain->level_count];
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater if (successor == NULL && RIGHT(current) != NULL) {
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * If we determine that the current node is the successor to
62f2fefaec754e6a4841ff0e72726e6c0cd89c86Michał Kępień * itself, we will run into an infinite loop, so abort instead.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * It is not necessary to use dns_rbtnodechain_current like
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the other functions because this function will never
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * find a node in the topmost level. This is because the
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * root level will never be more than one name, and everything
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * in the megatree is a successor to that node, down at
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * the second level or below.
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = chain_name(chain, origin, ISC_FALSE);
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrencedns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbtnodechain_current(chain, name, origin, NULL);
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrencedns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = move_chain_to_last(chain, rbt->root);
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater result = dns_rbtnodechain_current(chain, name, origin, NULL);
5f50687f61057f7f0acb161d5803f4a48e40b3a8David Lawrencedns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Free any dynamic storage associated with 'chain', and then
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * reinitialize 'chain'.
33950f0a0262f4d49528c4adcf8be42807fa2576David Lawrencedns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * Free any dynamic storage associated with 'chain', and then
f731b5d665e484c9b9634531c791cee9d87ab7a0Automatic Updater * invalidate 'chain'.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * - worth removing inline as static functions are inlined automatically
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * where suitable by modern compilers.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * - bump the size of dns_rbt.nodecount to size_t.
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * - the dumpfile header also contains a nodecount that is unsigned
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * int. If large files (> 2^32 nodes) are to be supported, the
ce376a81fa674d240197628ceb6113a4fa5a1ab3Mukund Sivaraman * allocation for this field should be increased.