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:
@@ -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,
|
||||||
|
223
lib/dns/rbt.c
223
lib/dns/rbt.c
@@ -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 *));
|
||||||
|
Reference in New Issue
Block a user