2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00

New parameter to dns_rbt_find{name,node} will return the full dns_name_t

of the node that is found.

Avoids doing any memory allocation when building ancestor chain in 99%
of the cases.
This commit is contained in:
David Lawrence
1999-03-16 16:10:36 +00:00
parent bf668d0017
commit 194f54f4da
2 changed files with 169 additions and 64 deletions

View File

@@ -177,7 +177,8 @@ dns_result_t dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name,
* DNS_R_NOMEMORY Resource Limit: Out of Memory * DNS_R_NOMEMORY Resource Limit: Out of Memory
*/ */
dns_result_t dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, void **data); dns_result_t dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name,
dns_name_t *foundname, void **data);
/* /*
* Get the data pointer associated with 'name'. * Get the data pointer associated with 'name'.
* *
@@ -206,11 +207,13 @@ dns_result_t dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, void **data);
* DNS_R_SUCCESS Success * DNS_R_SUCCESS Success
* DNS_R_PARTIALMATCH Superdomain found with data * DNS_R_PARTIALMATCH Superdomain found with data
* DNS_R_NOTFOUND No match * DNS_R_NOTFOUND No match
* DNS_R_NOSPACE Concatenating nodes to form foundname failed
*/ */
dns_result_t dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_result_t dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name,
dns_rbtnode_t **node, dns_name_t *foundname,
dns_rbtnodechain_t *chain); dns_rbtnode_t **node,
dns_rbtnodechain_t *chain);
/* /*
* Find the node for 'name'. * Find the node for 'name'.
* *
@@ -274,6 +277,7 @@ dns_result_t dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name,
* DNS_R_PARTIALMATCH Superdomain found with data * DNS_R_PARTIALMATCH Superdomain found with data
* DNS_R_NOTFOUND No match, or superdomain with no data * DNS_R_NOTFOUND No match, or superdomain with no data
* DNS_R_NOMEMORY Resource Limit: Out of Memory building chain * DNS_R_NOMEMORY Resource Limit: Out of Memory building chain
* DNS_R_NOSPACE Concatenating nodes to form foundname failed
*/ */
dns_result_t dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, dns_result_t dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name,

View File

@@ -29,6 +29,7 @@
#include <dns/rbt.h> #include <dns/rbt.h>
#include <dns/result.h> #include <dns/result.h>
#include <dns/fixedname.h>
#define RBT_MAGIC 0x5242542BU /* RBT+. */ #define RBT_MAGIC 0x5242542BU /* RBT+. */
#define VALID_RBT(rbt) ((rbt) != NULL && (rbt)->magic == RBT_MAGIC) #define VALID_RBT(rbt) ((rbt) != NULL && (rbt)->magic == RBT_MAGIC)
@@ -41,8 +42,27 @@ struct dns_rbt {
void * deleter_arg; void * deleter_arg;
}; };
/*
* For use in allocating space for the chain of ancestor nodes.
*
* The maximum number of ancestors is theoretically not limited by the
* data tree. This initial value of 24 ancestors would be able to scan
* the full height of a single level of 16,777,216 nodes, more than double
* the current size of .com.
*/
#ifndef ISC_MEM_DEBUG
#define ANCESTOR_BLOCK 24
#else
#define ANCESTOR_BLOCK 1 /* To give the reallocation code a workout. */
#endif
struct dns_rbtnodechain { struct dns_rbtnodechain {
dns_rbtnode_t ** ancestors; dns_rbtnode_t ** ancestors;
/*
* ancestor_buffer avoids doing any memory allocation (a MP
* bottleneck) in 99%+ of the real-world cases.
*/
dns_rbtnode_t * ancestor_buffer[ANCESTOR_BLOCK];
int ancestor_count; int ancestor_count;
int ancestor_maxitems; int ancestor_maxitems;
/* /*
@@ -121,20 +141,6 @@ do { \
#define FAST_COUNTLABELS(name) \ #define FAST_COUNTLABELS(name) \
((name)->labels) ((name)->labels)
/*
* For use in allocating space for the chain of ancestor nodes.
*
* The maximum number of ancestors is theoretically not limited by the
* data tree. This initial value of 24 ancestors would be able to scan
* the full height of a single level of 16,777,216 nodes, more than double
* the current size of .com.
*/
#ifndef ISC_MEM_DEBUG
#define ANCESTOR_BLOCK 24
#else
#define ANCESTOR_BLOCK 1 /* To give the reallocation code a workout. */
#endif
#ifdef DEBUG #ifdef DEBUG
#define inline #define inline
/* /*
@@ -576,17 +582,19 @@ dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
* the down pointer for the found node. * the down pointer for the found node.
*/ */
dns_result_t dns_result_t
dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node, dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
dns_rbtnodechain_t *chain) dns_rbtnode_t **node, dns_rbtnodechain_t *chain)
{ {
dns_rbtnode_t *current; dns_rbtnode_t *current;
dns_name_t *search_name, *new_search_name, *current_name; dns_name_t *search_name, *current_name, *tmp_name;
dns_name_t holder1, holder2; dns_name_t name1, name2, *current_foundname, *new_foundname;
dns_fixedname_t foundname1, foundname2;
dns_offsets_t name1_offsets, name2_offsets;
dns_namereln_t compared; dns_namereln_t compared;
dns_result_t result; dns_result_t result;
dns_offsets_t holder1_offsets, holder2_offsets;
isc_region_t r; isc_region_t r;
unsigned int current_labels, keep_labels, common_labels, common_bits; unsigned int current_labels, common_labels, common_bits;
unsigned int first_common_label, foundname_labels;
int order; int order;
/* @@@ optimize skipping the root node? */ /* @@@ optimize skipping the root node? */
@@ -595,22 +603,37 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
REQUIRE(FAST_ISABSOLUTE(name)); REQUIRE(FAST_ISABSOLUTE(name));
REQUIRE(node != NULL && *node == NULL); REQUIRE(node != NULL && *node == NULL);
dns_name_init(&holder1, holder1_offsets); dns_name_init(&name1, name1_offsets);
dns_name_init(&holder2, holder2_offsets); dns_name_init(&name2, name2_offsets);
/* /*
* search_name is the name segment being sought in each tree level. * search_name is the name segment being sought in each tree level.
* Ensure that it has offsets by making a copy into a structure * Ensure that it has offsets by making a copy into a structure
* that has offsets. * that has offsets.
*/ */
search_name = &holder1; if (name->offsets == NULL) {
dns_name_toregion(name, &r); search_name = &name1;
dns_name_fromregion(search_name, &r); dns_name_toregion(name, &r);
dns_name_fromregion(search_name, &r);
} else
search_name = name;
current = rbt->root; current_name = &name2;
current_name = &holder2; /*
* Initialize the building of the name of the returned node.
* This is not wrapped in "if (foundname != NULL)" because gcc
* gives spurious warnings otherwise.
*/
dns_fixedname_init(&foundname1);
dns_fixedname_init(&foundname2);
current_foundname = dns_fixedname_name(&foundname1);
new_foundname = dns_fixedname_name(&foundname2);
foundname_labels = 0;
/*
* Initialize the chain.
*/
if (chain != NULL) { if (chain != NULL) {
chain->ancestor_maxitems = 0; chain->ancestor_maxitems = 0;
chain->ancestor_count = 0; chain->ancestor_count = 0;
@@ -621,7 +644,8 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
ADD_ANCESTOR(chain, NULL); ADD_ANCESTOR(chain, NULL);
} }
current = rbt->root;
while (current != NULL) { while (current != NULL) {
NODENAME(current, current_name); NODENAME(current, current_name);
compared = dns_name_fullcompare(search_name, current_name, compared = dns_name_fullcompare(search_name, current_name,
@@ -666,31 +690,69 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
current_labels = FAST_COUNTLABELS(current_name); current_labels = FAST_COUNTLABELS(current_name);
if (common_labels == current_labels) { if (common_labels == current_labels) {
/* /*
* Set up new name to search for as * Set up new name to search for as
* the not-in-common part. * the not-in-common part, and build foundname.
*/ */
if (search_name == &holder2) { if (search_name == &name2) {
current_name = &holder2; current_name = &name2;
new_search_name = &holder1; tmp_name = &name1;
dns_name_init(new_search_name, dns_name_init(tmp_name, name1_offsets);
holder1_offsets);
if (foundname != NULL) {
current_foundname =
dns_fixedname_name(&foundname1);
new_foundname =
dns_fixedname_name(&foundname2);
dns_fixedname_init(&foundname2);
}
} else { } else {
current_name = &holder1; current_name = &name1;
new_search_name = &holder2; tmp_name = &name2;
dns_name_init(new_search_name, dns_name_init(tmp_name, name2_offsets);
holder2_offsets);
if (foundname != NULL) {
current_foundname =
dns_fixedname_name(&foundname2);
new_foundname =
dns_fixedname_name(&foundname1);
dns_fixedname_init(&foundname1);
}
} }
keep_labels = FAST_COUNTLABELS(search_name) first_common_label =
FAST_COUNTLABELS(search_name)
- common_labels; - common_labels;
dns_name_getlabelsequence(search_name, if (foundname != NULL) {
0, /*
keep_labels, * Build foundname by getting the common
new_search_name); * labels and prefixing them to the
* current foundname.
*/
dns_name_getlabelsequence(search_name,
first_common_label,
current_labels,
tmp_name);
result = dns_name_concatenate(tmp_name,
current_foundname,
new_foundname,
NULL);
if (result != DNS_R_SUCCESS)
return (result);
}
/*
* Whack off the common labels of the current
* node for the name to search in the next level.
*/
dns_name_getlabelsequence(search_name, 0,
first_common_label,
tmp_name);
search_name = new_search_name; search_name = tmp_name;
if (chain != NULL) { if (chain != NULL) {
ADD_ANCESTOR(chain, NULL); ADD_ANCESTOR(chain, NULL);
@@ -703,8 +765,11 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
* match node that has no data, another * match node that has no data, another
* parameter would be needed for this function. * parameter would be needed for this function.
*/ */
if (DATA(current) != NULL) if (DATA(current) != NULL) {
*node = current; *node = current;
foundname_labels =
FAST_COUNTLABELS(new_foundname);
}
/* /*
* Search in the next tree level. * Search in the next tree level.
@@ -723,11 +788,40 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
} }
if (current != NULL) { if (current != NULL) {
*node = current; if (foundname != NULL)
result = DNS_R_SUCCESS; result = dns_name_concatenate(current_name,
} else if (*node != NULL) new_foundname, foundname,
result = DNS_R_PARTIALMATCH; NULL);
else else
result = DNS_R_SUCCESS;
*node = result == DNS_R_SUCCESS ? current : NULL;
} else if (*node != NULL) {
if (foundname != NULL) {
current_labels = FAST_COUNTLABELS(new_foundname);
if (current_labels != foundname_labels) {
dns_name_init(&name1, name1_offsets);
dns_name_getlabelsequence(new_foundname,
current_labels -
foundname_labels,
foundname_labels,
&name1);
result = dns_name_concatenate(&name1, NULL,
foundname, NULL);
printf("HEY!\n");
} else
result = dns_name_concatenate(new_foundname,
NULL,
foundname, NULL);
} else
result = DNS_R_SUCCESS;
if (result == DNS_R_SUCCESS)
result = DNS_R_PARTIALMATCH;
} else
result = DNS_R_NOTFOUND; result = DNS_R_NOTFOUND;
return (result); return (result);
@@ -737,14 +831,15 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **node,
* Get the data pointer associated with 'name'. * Get the data pointer associated with 'name'.
*/ */
dns_result_t dns_result_t
dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, void **data) { dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name,
dns_name_t *foundname, void **data) {
dns_rbtnode_t *node = NULL; dns_rbtnode_t *node = NULL;
dns_result_t result; dns_result_t result;
REQUIRE(VALID_RBT(rbt)); REQUIRE(VALID_RBT(rbt));
REQUIRE(data != NULL && *data == NULL); REQUIRE(data != NULL && *data == NULL);
result = dns_rbt_findnode(rbt, name, &node, NULL); result = dns_rbt_findnode(rbt, name, foundname, &node, NULL);
if (node != NULL && DATA(node) != NULL) if (node != NULL && DATA(node) != NULL)
*data = DATA(node); *data = DATA(node);
@@ -779,7 +874,7 @@ dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
* *
* @@@ how to ->dirty, ->locknum and ->references figure in? * @@@ how to ->dirty, ->locknum and ->references figure in?
*/ */
result = dns_rbt_findnode(rbt, name, &node, &chain); result = dns_rbt_findnode(rbt, name, NULL, &node, &chain);
/* /*
* The guts of this routine are in a separate function (which * The guts of this routine are in a separate function (which
@@ -1063,17 +1158,23 @@ get_ancestor_mem(isc_mem_t *mctx, dns_rbtnodechain_t *chain) {
oldsize = chain->ancestor_maxitems * sizeof(dns_rbtnode_t *); oldsize = chain->ancestor_maxitems * sizeof(dns_rbtnode_t *);
newsize = oldsize + ANCESTOR_BLOCK * sizeof(dns_rbtnode_t *); newsize = oldsize + ANCESTOR_BLOCK * sizeof(dns_rbtnode_t *);
ancestor_mem = isc_mem_get(mctx, newsize); if (oldsize == 0) {
chain->ancestors = chain->ancestor_buffer;
if (ancestor_mem == NULL) } else {
return (DNS_R_NOMEMORY); ancestor_mem = isc_mem_get(mctx, newsize);
if (ancestor_mem == NULL)
return (DNS_R_NOMEMORY);
if (oldsize > 0) {
memcpy(ancestor_mem, chain->ancestors, oldsize); memcpy(ancestor_mem, chain->ancestors, oldsize);
isc_mem_put(mctx, chain->ancestors, oldsize);
if (chain->ancestor_maxitems > ANCESTOR_BLOCK)
isc_mem_put(mctx, chain->ancestors, oldsize);
chain->ancestors = ancestor_mem;
} }
chain->ancestors = ancestor_mem;
chain->ancestor_maxitems += ANCESTOR_BLOCK; chain->ancestor_maxitems += ANCESTOR_BLOCK;
return (DNS_R_SUCCESS); return (DNS_R_SUCCESS);
@@ -1081,7 +1182,7 @@ get_ancestor_mem(isc_mem_t *mctx, dns_rbtnodechain_t *chain) {
static void static void
put_ancestor_mem(isc_mem_t *mctx, dns_rbtnodechain_t *chain) { put_ancestor_mem(isc_mem_t *mctx, dns_rbtnodechain_t *chain) {
if (chain->ancestor_maxitems > 0) if (chain->ancestor_maxitems > ANCESTOR_BLOCK)
isc_mem_put(mctx, chain->ancestors, isc_mem_put(mctx, chain->ancestors,
chain->ancestor_maxitems chain->ancestor_maxitems
* sizeof(dns_rbtnode_t *)); * sizeof(dns_rbtnode_t *));