rbt.c revision bfde61d5194a534d800f3b90008d1f52261922c5
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 1999-2005, 2007-2009, 2011-2016 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/.
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt/* Principal Authors: DCL */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * This define is so dns/name.h (included by dns/fixedname.h) uses more
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * efficient macro calls instead of functions for a few operations.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define VALID_RBT(rbt) ISC_MAGIC_VALID(rbt, RBT_MAGIC)
821350367e2c7313c02eb275e8e05d5193b47cfdJeremy C. Reed * XXXDCL Since parent pointers were added in again, I could remove all of the
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * _lastnode. This would involve pretty major change to the API.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define CHAIN_MAGIC ISC_MAGIC('0', '-', '0', '-')
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define VALID_CHAIN(chain) ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein unsigned int magic;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein void (*data_deleter)(void *, void *);
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein unsigned int nodecount;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * This is the header for map-format RBT images. It is populated,
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * and then written, as the LAST thing done to the file before returning.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Writing this last (with zeros in the header area initially) will ensure
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * that the header is only valid when the RBT image is also valid.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein/* Pad to 32 bytes */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein/* Header length, always the same size regardless of structure size */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein isc_uint64_t first_node_offset; /* usually 1024 */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * information about the system on which the map file was generated
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * will be used to tell if we can load the map file or not
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein unsigned int bigendian:1; /* big or little endian system */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein unsigned int rdataset_fixed:1; /* compiled with --enable-rrset-fixed */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein unsigned int nodecount; /* shadow from rbt structure */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein char version2[32]; /* repeated; must match version1 */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * The following declarations are for the serialization of an RBT:
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * step one: write out a zeroed header of 1024 bytes
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * step two: walk the tree in a depth-first, left-right-down order, writing
30eec077db2bdcb6f2a0dc388a3cdde2ede75ec1Mark Andrews * out the nodes, reserving space as we go, correcting addresses to point
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * at the proper offset in the file, and setting a flag for each pointer to
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * indicate that it is a reference to a location in the file, rather than in
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * step three: write out the header, adding the information that will be
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * needed to re-create the tree object itself.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * The RBTDB object will do this three times, once for each of the three
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * RBT objects it contains.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Note: 'file' must point an actual open file that can be mmapped
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * and fseeked, not to a pipe or stream
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntwrite_header(FILE *file, dns_rbt_t *rbt, isc_uint64_t first_node_offset,
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinserialize_node(FILE *file, dns_rbtnode_t *node, uintptr_t left,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt uintptr_t right, uintptr_t down, uintptr_t parent,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Huntserialize_nodes(FILE *file, dns_rbtnode_t *node, uintptr_t parent,
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein dns_rbtdatawriter_t datawriter, void *writer_arg,
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * The following functions allow you to get the actual address of a pointer
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * without having to use an if statement to check to see if that address is
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * relative or not
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinstatic inline dns_rbtnode_t *
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeingetparent(dns_rbtnode_t *node, file_header_t *header) {
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein char *adjusted_address = (char *)(node->parent);
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein adjusted_address += node->parent_is_relative * (uintptr_t)header;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinstatic inline dns_rbtnode_t *
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeingetleft(dns_rbtnode_t *node, file_header_t *header) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt adjusted_address += node->left_is_relative * (uintptr_t)header;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinstatic inline dns_rbtnode_t *
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeingetright(dns_rbtnode_t *node, file_header_t *header) {
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein adjusted_address += node->right_is_relative * (uintptr_t)header;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinstatic inline dns_rbtnode_t *
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeingetdown(dns_rbtnode_t *node, file_header_t *header) {
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein adjusted_address += node->down_is_relative * (uintptr_t)header;
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeinstatic inline dns_rbtnode_t *
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austeingetdata(dns_rbtnode_t *node, file_header_t *header) {
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein adjusted_address += node->data_is_relative * (uintptr_t)header;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * Elements of the rbtnode structure.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#endif /* DNS_RBT_USEHASH */
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define IS_ROOT(node) ISC_TF((node)->is_root == 1)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define FINDCALLBACK(node) ISC_TF((node)->find_callback == 1)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Structure elements from the rbtdb.c, not
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * used as part of the rbt.c algorithms.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * The variable length stuff stored after the node has the following
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * structure.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * <name_data>{1..255}<oldoffsetlen>{1}<offsets>{1..128}
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * <name_data> contains the name of the node when it was created.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * <oldoffsetlen> contains the length of <offsets> when the node was created.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * <offsets> contains the offets into name for each label when the node was
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define NAME(node) ((unsigned char *)((node) + 1))
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define OFFSETS(node) (NAME(node) + OLDNAMELEN(node) + 1)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein * Color management.
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define IS_RED(node) ((node) != NULL && (node)->color == RED)
268a4475065fe6a8cd7cc707820982cf5e98f430Rob Austein#define IS_BLACK(node) ((node) == NULL || (node)->color == BLACK)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * Chain management.
#ifdef DNS_RBT_USEHASH
static isc_result_t
#ifdef DEBUG
return (name);
isc_buffer_t b;
isc_region_t r;
isc_buffer_putuint8(&b, 0);
} while (size > 0);
#ifdef DNS_RBT_USEHASH
static inline dns_rbtnode_t *
static inline dns_rbtnode_t *
return (node);
static inline dns_rbtnode_t *
nodes++;
return (nodes);
static isc_result_t
#ifdef DNS_RBT_USEHASH
static isc_result_t
static isc_result_t
return (result);
return (result);
return (ISC_R_SUCCESS);
static isc_result_t
#ifdef DNS_RDATASET_FIXED
return (result);
static isc_result_t
unsigned char *node_data;
#ifdef DEBUG
#ifdef DEBUG
sizeof(dns_rbtnode_t));
sizeof(dns_rbtnode_t));
return (result);
static isc_result_t
*where = 0;
return (ISC_R_SUCCESS);
return (result);
if (offset == 0)
return (target);
*offset = 0;
return (ISC_R_SUCCESS);
#ifdef DEBUG
return (result);
#define CONFIRM(a) do { \
goto cleanup; \
static isc_result_t
unsigned char *node_data;
if (n == NULL)
return (ISC_R_SUCCESS);
if (n->left_is_relative) {
n->left_is_relative = 0;
if (n->right_is_relative) {
n->right_is_relative = 0;
if (n->down_is_relative) {
n->down_is_relative = 0;
if (n->parent_is_relative) {
n->parent_is_relative = 0;
if (n->data_is_relative) {
n->data_is_relative = 0;
#ifdef DEBUG
sizeof(dns_rbtnode_t));
sizeof(dns_rbtnode_t));
datasize);
return (result);
#ifdef DNS_RDATASET_FIXED
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
goto cleanup;
#ifdef DEBUG
goto cleanup;
goto cleanup;
#ifdef DNS_RBT_USEHASH
return (result);
#ifdef DNS_RBT_USEHASH
return (ISC_R_NOMEMORY);
#ifdef DNS_RBT_USEHASH
return (result);
return (ISC_R_SUCCESS);
return (ISC_R_QUOTA);
return (ISC_R_SUCCESS);
static inline isc_result_t
return (result);
return (result);
return (result);
static inline isc_result_t
return (ISC_R_SUCCESS);
unsigned int level_count;
unsigned int common_labels;
int order;
#ifdef DNS_RBT_USEHASH
return (result);
level_count = 0;
hlabels = 0;
if (order < 0) {
} else if (order > 0) {
level_count++;
&new_current);
#ifdef DNS_RBT_USEHASH
level_count++;
if (common_labels ==
return (ISC_R_SUCCESS);
#ifdef DNS_RBT_USEHASH
return (result);
return (result);
void *callback_arg)
unsigned int common_labels;
unsigned int hlabels = 0;
int order;
return (ISC_R_NOTFOUND);
order = 0;
#ifdef DNS_RBT_USEHASH
unsigned int nlabels;
unsigned int hash;
&hash_name);
goto subdomain;
goto hashagain;
if (order < 0)
#ifdef DNS_RBT_USEHASH
return (result);
&order,
if (order < 0)
if (order > 0) {
result2 =
NULL,
NULL);
return (result);
return (result);
* node tree of "b.a.com" and layer 2 a three node tree of
* a, b, and c. Deleting a.com would find only a partial depth
* solely the province of rbtdb.c.
return (result);
* then the subsequent deletion of "b.c" will not cause "a" to be pulled up,
* restoring "a.b.c". The RBT *used* to do this kind of rejoining, but it
* that had "b.c" as one of its levels -- and the RBT has no idea what
* "b.c" is left hanging around without data or children. This condition
if (recurse) {
return (ISC_R_SUCCESS);
#if DNS_RBT_USEMAGIC
return (ISC_R_SUCCESS);
return (result);
return (printname);
static isc_result_t
unsigned int labels;
return (ISC_R_NOMEMORY);
#ifdef DNS_RBT_USEHASH
#if DNS_RBT_USEMAGIC
return (ISC_R_SUCCESS);
#ifdef DNS_RBT_USEHASH
unsigned int hash;
static isc_result_t
unsigned int bytes;
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
unsigned int oldsize;
unsigned int hash;
for (i = 0; i < oldsize; i++) {
unsigned int bucket;
if (order < 0) {
if (unhash)
#if DNS_RBT_USEMAGIC
static size_t
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
dl++;
return (ISC_TRUE);
return (ISC_FALSE);
for (i = 0; i < depth; i++)
isc_region_t r;
if (quoted)
depth++;
data_printer, f);
data_printer, f);
data_printer, f);
if (show_pointers)
*nodecount, d);
return (*nodecount);
unsigned int nodecount = 0;
return (ISC_R_NOTFOUND);
return (result);
if (new_origin) {
NULL);
NULL);
return (result);
if (new_origin) {
return (result);
return (result);
if (new_origin) {
return (result);
return (result);
return (result);
return (result);