mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
Add tests for hash function, and comment dns_rbt_addnode() (#41179)
No CHANGES entry necessary.
This commit is contained in:
@@ -1128,6 +1128,37 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
|
|||||||
REQUIRE(dns_name_isabsolute(name));
|
REQUIRE(dns_name_isabsolute(name));
|
||||||
REQUIRE(nodep != NULL && *nodep == NULL);
|
REQUIRE(nodep != NULL && *nodep == NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dear future BIND developer,
|
||||||
|
*
|
||||||
|
* After you have tried attempting to optimize this routine by
|
||||||
|
* using the hashtable and have realized your folly, please
|
||||||
|
* append another cross ("X") below as a warning to the next
|
||||||
|
* future BIND developer:
|
||||||
|
*
|
||||||
|
* Number of victim developers: X
|
||||||
|
*
|
||||||
|
* I wish the past developer had included such a notice.
|
||||||
|
*
|
||||||
|
* Long form: Unlike dns_rbt_findnode(), this function does not
|
||||||
|
* lend itself to be optimized using the hashtable:
|
||||||
|
*
|
||||||
|
* 1. In the subtree where the insertion occurs, this function
|
||||||
|
* needs to have the insertion point and the order where the
|
||||||
|
* lookup terminated (i.e., at the insertion point where left or
|
||||||
|
* right child is NULL). This cannot be determined from the
|
||||||
|
* hashtable, so at least in that subtree, a BST O(log N) lookup
|
||||||
|
* is necessary.
|
||||||
|
*
|
||||||
|
* 2. Our RBT nodes contain not only single labels but label
|
||||||
|
* sequences to optimize space usage. So at every level, we have
|
||||||
|
* to look for a match in the hashtable for all superdomains in
|
||||||
|
* the rest of the name we're searching. This is an O(N)
|
||||||
|
* operation at least, here N being the label size of name, each
|
||||||
|
* of which is a hashtable lookup involving dns_name_equal()
|
||||||
|
* comparisons.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a copy of the name so the original name structure is
|
* Create a copy of the name so the original name structure is
|
||||||
* not modified.
|
* not modified.
|
||||||
@@ -1437,7 +1468,7 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
|||||||
unsigned int options, dns_rbtfindcallback_t callback,
|
unsigned int options, dns_rbtfindcallback_t callback,
|
||||||
void *callback_arg)
|
void *callback_arg)
|
||||||
{
|
{
|
||||||
dns_rbtnode_t *current, *last_compared, *current_root;
|
dns_rbtnode_t *current, *last_compared;
|
||||||
dns_rbtnodechain_t localchain;
|
dns_rbtnodechain_t localchain;
|
||||||
dns_name_t *search_name, current_name, *callback_name;
|
dns_name_t *search_name, current_name, *callback_name;
|
||||||
dns_fixedname_t fixedcallbackname, fixedsearchname;
|
dns_fixedname_t fixedcallbackname, fixedsearchname;
|
||||||
@@ -1494,7 +1525,6 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
|||||||
|
|
||||||
saved_result = ISC_R_SUCCESS;
|
saved_result = ISC_R_SUCCESS;
|
||||||
current = rbt->root;
|
current = rbt->root;
|
||||||
current_root = rbt->root;
|
|
||||||
|
|
||||||
while (ISC_LIKELY(current != NULL)) {
|
while (ISC_LIKELY(current != NULL)) {
|
||||||
NODENAME(current, ¤t_name);
|
NODENAME(current, ¤t_name);
|
||||||
@@ -1531,22 +1561,23 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
|||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The case of current != current_root, that
|
* The case of current not being a subtree root,
|
||||||
* means a left or right pointer was followed,
|
* that means a left or right pointer was
|
||||||
* only happens when the algorithm fell through to
|
* followed, only happens when the algorithm
|
||||||
* the traditional binary search because of a
|
* fell through to the traditional binary search
|
||||||
* bitstring label. Since we dropped the bitstring
|
* because of a bitstring label. Since we
|
||||||
* support, this should not happen.
|
* dropped the bitstring support, this should
|
||||||
|
* not happen.
|
||||||
*/
|
*/
|
||||||
INSIST(current == current_root);
|
INSIST(IS_ROOT(current));
|
||||||
|
|
||||||
nlabels = dns_name_countlabels(search_name);
|
nlabels = dns_name_countlabels(search_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current_root is the root of the current level, so
|
* current is the root of the current level, so
|
||||||
* its parent is the same as its "up" pointer.
|
* its parent is the same as its "up" pointer.
|
||||||
*/
|
*/
|
||||||
up_current = PARENT(current_root);
|
up_current = PARENT(current);
|
||||||
dns_name_init(&hash_name, NULL);
|
dns_name_init(&hash_name, NULL);
|
||||||
|
|
||||||
hashagain:
|
hashagain:
|
||||||
@@ -1714,8 +1745,6 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
|
|||||||
* Finally, head to the next tree level.
|
* Finally, head to the next tree level.
|
||||||
*/
|
*/
|
||||||
current = DOWN(current);
|
current = DOWN(current);
|
||||||
current_root = current;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Though there are labels in common, the
|
* Though there are labels in common, the
|
||||||
|
@@ -428,10 +428,14 @@ isc_hash_function(const void *data, size_t length,
|
|||||||
const unsigned char *bp;
|
const unsigned char *bp;
|
||||||
const unsigned char *be;
|
const unsigned char *be;
|
||||||
|
|
||||||
|
INSIST(data == NULL || length > 0);
|
||||||
RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
|
RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
|
||||||
|
|
||||||
hval = previous_hashp != NULL ? *previous_hashp : fnv_offset_basis;
|
hval = previous_hashp != NULL ? *previous_hashp : fnv_offset_basis;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
return (hval);
|
||||||
|
|
||||||
bp = (const unsigned char *) data;
|
bp = (const unsigned char *) data;
|
||||||
be = bp + length;
|
be = bp + length;
|
||||||
|
|
||||||
@@ -490,10 +494,14 @@ isc_hash_function_reverse(const void *data, size_t length,
|
|||||||
const unsigned char *bp;
|
const unsigned char *bp;
|
||||||
const unsigned char *be;
|
const unsigned char *be;
|
||||||
|
|
||||||
|
INSIST(data == NULL || length > 0);
|
||||||
RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
|
RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
|
||||||
|
|
||||||
hval = ISC_UNLIKELY(previous_hashp != NULL) ? *previous_hashp : fnv_offset_basis;
|
hval = ISC_UNLIKELY(previous_hashp != NULL) ? *previous_hashp : fnv_offset_basis;
|
||||||
|
|
||||||
|
if (length == 0)
|
||||||
|
return (hval);
|
||||||
|
|
||||||
bp = (const unsigned char *) data;
|
bp = (const unsigned char *) data;
|
||||||
be = bp + length;
|
be = bp + length;
|
||||||
|
|
||||||
|
@@ -14,8 +14,6 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id$ */
|
|
||||||
|
|
||||||
/* ! \file */
|
/* ! \file */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@@ -25,6 +23,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <isc/hash.h>
|
||||||
|
|
||||||
#include <isc/crc64.h>
|
#include <isc/crc64.h>
|
||||||
#include <isc/hmacmd5.h>
|
#include <isc/hmacmd5.h>
|
||||||
#include <isc/hmacsha.h>
|
#include <isc/hmacsha.h>
|
||||||
@@ -1848,10 +1848,111 @@ ATF_TC_BODY(isc_crc64, tc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ATF_TC(isc_hash_function);
|
||||||
|
ATF_TC_HEAD(isc_hash_function, tc) {
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Hash function test");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(isc_hash_function, tc) {
|
||||||
|
unsigned int h1;
|
||||||
|
unsigned int h2;
|
||||||
|
|
||||||
|
UNUSED(tc);
|
||||||
|
|
||||||
|
/* Incremental hashing */
|
||||||
|
|
||||||
|
h1 = isc_hash_function(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
h1 = isc_hash_function("This ", 5, ISC_TRUE, &h1);
|
||||||
|
h1 = isc_hash_function("is ", 3, ISC_TRUE, &h1);
|
||||||
|
h1 = isc_hash_function("a long test", 12, ISC_TRUE, &h1);
|
||||||
|
|
||||||
|
h2 = isc_hash_function("This is a long test", 20,
|
||||||
|
ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Immutability of hash function */
|
||||||
|
h1 = isc_hash_function(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Hash function characteristics */
|
||||||
|
h1 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Case */
|
||||||
|
h1 = isc_hash_function("Hello world", 12, ISC_FALSE, NULL);
|
||||||
|
h2 = isc_hash_function("heLLo WorLd", 12, ISC_FALSE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Unequal */
|
||||||
|
h1 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function("heLLo WorLd", 12, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK(h1 != h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATF_TC(isc_hash_function_reverse);
|
||||||
|
ATF_TC_HEAD(isc_hash_function_reverse, tc) {
|
||||||
|
atf_tc_set_md_var(tc, "descr", "Reverse hash function test");
|
||||||
|
}
|
||||||
|
ATF_TC_BODY(isc_hash_function_reverse, tc) {
|
||||||
|
unsigned int h1;
|
||||||
|
unsigned int h2;
|
||||||
|
|
||||||
|
UNUSED(tc);
|
||||||
|
|
||||||
|
/* Incremental hashing */
|
||||||
|
|
||||||
|
h1 = isc_hash_function_reverse(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
h1 = isc_hash_function_reverse("\000", 1, ISC_TRUE, &h1);
|
||||||
|
h1 = isc_hash_function_reverse("\003org", 4, ISC_TRUE, &h1);
|
||||||
|
h1 = isc_hash_function_reverse("\007example", 8, ISC_TRUE, &h1);
|
||||||
|
|
||||||
|
h2 = isc_hash_function_reverse("\007example\003org\000", 13,
|
||||||
|
ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Immutability of hash function */
|
||||||
|
h1 = isc_hash_function_reverse(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function_reverse(NULL, 0, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Hash function characteristics */
|
||||||
|
h1 = isc_hash_function_reverse("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function_reverse("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Case */
|
||||||
|
h1 = isc_hash_function_reverse("Hello world", 12, ISC_FALSE, NULL);
|
||||||
|
h2 = isc_hash_function_reverse("heLLo WorLd", 12, ISC_FALSE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK_EQ(h1, h2);
|
||||||
|
|
||||||
|
/* Unequal */
|
||||||
|
h1 = isc_hash_function_reverse("Hello world", 12, ISC_TRUE, NULL);
|
||||||
|
h2 = isc_hash_function_reverse("heLLo WorLd", 12, ISC_TRUE, NULL);
|
||||||
|
|
||||||
|
ATF_CHECK(h1 != h2);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main
|
* Main
|
||||||
*/
|
*/
|
||||||
ATF_TP_ADD_TCS(tp) {
|
ATF_TP_ADD_TCS(tp) {
|
||||||
|
/*
|
||||||
|
* Tests of hash functions, including isc_hash and the
|
||||||
|
* various cryptographic hashes.
|
||||||
|
*/
|
||||||
|
ATF_TP_ADD_TC(tp, isc_hash_function);
|
||||||
|
ATF_TP_ADD_TC(tp, isc_hash_function_reverse);
|
||||||
ATF_TP_ADD_TC(tp, isc_hmacmd5);
|
ATF_TP_ADD_TC(tp, isc_hmacmd5);
|
||||||
ATF_TP_ADD_TC(tp, isc_hmacsha1);
|
ATF_TP_ADD_TC(tp, isc_hmacsha1);
|
||||||
ATF_TP_ADD_TC(tp, isc_hmacsha224);
|
ATF_TP_ADD_TC(tp, isc_hmacsha224);
|
||||||
@@ -1865,6 +1966,6 @@ ATF_TP_ADD_TCS(tp) {
|
|||||||
ATF_TP_ADD_TC(tp, isc_sha384);
|
ATF_TP_ADD_TC(tp, isc_sha384);
|
||||||
ATF_TP_ADD_TC(tp, isc_sha512);
|
ATF_TP_ADD_TC(tp, isc_sha512);
|
||||||
ATF_TP_ADD_TC(tp, isc_crc64);
|
ATF_TP_ADD_TC(tp, isc_crc64);
|
||||||
|
|
||||||
return (atf_no_error());
|
return (atf_no_error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user