Refactor getpred code
Move the code to find the predecessor into one function, as it is shares quite some similarities: In both cases we first need to find the immediate predecessor/successor, then we need to find the immediate predecessor if the iterator is not already pointing at it.
This commit is contained in:
committed by
Evan Hunt
parent
ab8a0c4b5a
commit
21867f200a
286
lib/dns/qp.c
286
lib/dns/qp.c
@@ -2049,6 +2049,141 @@ greatest_leaf(dns_qpreadable_t qpr, dns_qpnode_t *n, dns_qpiter_t *iter) {
|
||||
return (n);
|
||||
}
|
||||
|
||||
static inline dns_qpnode_t *
|
||||
anyleaf(dns_qpreader_t *qp, dns_qpnode_t *n) {
|
||||
while (is_branch(n)) {
|
||||
n = branch_twigs(qp, n);
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
/*
|
||||
* If dns_qp_lookup() was passed an iterator, we want it to point at the
|
||||
* matching name in the case of an exact match, or at the predecessor name
|
||||
* for a non-exact match.
|
||||
*
|
||||
* If the search ended at a leaf, and it was an exact match, the iterator is
|
||||
* already pointing to the correct node (the compare results in QPKEY_EQUAL),
|
||||
* and we don't need to do anything else. Otherwise, we have found a leaf node
|
||||
* that is close by. There are a couple of scenarios:
|
||||
* - If the search key differs from the found key before the offset point...
|
||||
* - and the search key at that point is smaller then the found key, the
|
||||
* predecessor of the searched-for name is somewhere in the left twig of
|
||||
* the parent node (but not necessarily the direct parent node).
|
||||
* - and the search key at that point is equal or greater then the found key,
|
||||
* the found key is the predecessor of the searched-for name.
|
||||
* - If the search key differs at or after the offset point...
|
||||
* - and the search key is smaller than the found key, then the iterator
|
||||
* points to the immediate successor of the search key and we can use the
|
||||
* qpiter stack to step back one leaf to the predecessor.
|
||||
* - and the search key is greater than the found key, the found key is the
|
||||
* the predecessor, and the iterator already points to the correct node
|
||||
* (so we don't need to do anything anymore).
|
||||
*
|
||||
* If the search ended on a branch, we first continue down to the left-most
|
||||
* (least) leaf node to compare the search key against.
|
||||
* - If the search key differs from the found key before the offset point...
|
||||
* - and the search key at that point is smaller then the found key, the
|
||||
* predecessor of the searched-for name is somewhere in the left twig of
|
||||
* the parent node (but not necessarily the direct parent node).
|
||||
* - and the search key at that point is equal or greater then the found key,
|
||||
* the greatest leaf of the branch is the predecessor of the searched-for
|
||||
* name.
|
||||
* - If the search key differs at or after the offset point...
|
||||
* - and there is a twig for the key at the offset point, the predecessor
|
||||
* is the greatest leaf node in the twig left of the found twig.
|
||||
* - and there is no twig for the key at the offset point, the search key
|
||||
* is smaller than all the leaves on this branch and the predecessor for the
|
||||
* searched-for name is in the most-right (greatest) leaf in left twig of
|
||||
* the parent branch. We can use the qpiter stack to step back one leaf to
|
||||
* the predecessor.
|
||||
*/
|
||||
static dns_qpnode_t *
|
||||
fix_iterator(dns_qpreader_t *qp, dns_qpiter_t *iter, dns_qpnode_t *start,
|
||||
dns_qpkey_t search, size_t searchlen, dns_qpshift_t bit,
|
||||
size_t offset) {
|
||||
dns_qpkey_t found;
|
||||
size_t foundlen, to;
|
||||
dns_qpnode_t *n = start;
|
||||
dns_qpnode_t *leaf = anyleaf(qp, n);
|
||||
|
||||
foundlen = leaf_qpkey(qp, leaf, found);
|
||||
to = qpkey_compare(search, searchlen, found, foundlen);
|
||||
if (to == QPKEY_EQUAL) {
|
||||
return (leaf);
|
||||
}
|
||||
|
||||
/*
|
||||
* As long as the branch offset point is after the point where the
|
||||
* search key differs, we need to branch up and find a better leaf
|
||||
* node.
|
||||
*/
|
||||
while (to < offset) {
|
||||
if (to <= searchlen && to <= foundlen && search[to] < found[to])
|
||||
{
|
||||
/*
|
||||
* Every leaf is greater than the one we wanted, so
|
||||
* go to the parent branch and iterate back to the
|
||||
* predecessor from that point.
|
||||
*/
|
||||
iter->sp--;
|
||||
prevleaf(iter);
|
||||
n = iter->stack[iter->sp];
|
||||
leaf = n;
|
||||
} else {
|
||||
if (is_branch(n)) {
|
||||
n = greatest_leaf(qp, n, iter);
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
foundlen = leaf_qpkey(qp, leaf, found);
|
||||
to = qpkey_compare(search, searchlen, found, foundlen);
|
||||
}
|
||||
|
||||
if (is_branch(n)) {
|
||||
/*
|
||||
* We're on the right branch, so find the best match.
|
||||
*/
|
||||
prefetch_twigs(qp, n);
|
||||
dns_qpnode_t *twigs = branch_twigs(qp, n);
|
||||
dns_qpweight_t pos = branch_twig_pos(n, bit);
|
||||
|
||||
if (pos == 0) {
|
||||
/*
|
||||
* Every leaf in the branch is greater than the one we
|
||||
* wanted; use the iterator to walk back to the
|
||||
* predecessor.
|
||||
*/
|
||||
prevleaf(iter);
|
||||
n = iter->stack[iter->sp--];
|
||||
} else {
|
||||
/*
|
||||
* The name we want would've been after some twig in
|
||||
* this branch. point n to that twig, then walk down
|
||||
* to the highest leaf in that subtree to get
|
||||
* the predecessor.
|
||||
*/
|
||||
n = greatest_leaf(qp, twigs + pos - 1, iter);
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* We're on the right leaf, either the iterator already points
|
||||
* to the rightful predecessor, or it points to an immediate
|
||||
* successor. If the latter, we can now use the qpiter stack
|
||||
* we've constructed to step back to the predecessor. Otherwise,
|
||||
* we don't have to do anything anymore.
|
||||
*/
|
||||
if (to <= searchlen && to <= foundlen && search[to] < found[to])
|
||||
{
|
||||
prevleaf(iter);
|
||||
}
|
||||
}
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
|
||||
@@ -2057,12 +2192,12 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
dns_qpkey_t search, found;
|
||||
size_t searchlen, foundlen;
|
||||
size_t offset = 0;
|
||||
size_t difpos = 0;
|
||||
dns_qpnode_t *n = NULL;
|
||||
dns_qpshift_t bit = SHIFT_NOBYTE;
|
||||
dns_qpchain_t oc;
|
||||
dns_qpiter_t it;
|
||||
bool matched = true;
|
||||
bool getpred = true;
|
||||
bool matched = false;
|
||||
bool setiter = true;
|
||||
|
||||
REQUIRE(QP_VALID(qp));
|
||||
REQUIRE(foundname == NULL || ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
|
||||
@@ -2074,7 +2209,7 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
}
|
||||
if (iter == NULL) {
|
||||
iter = ⁢
|
||||
getpred = false;
|
||||
setiter = false;
|
||||
}
|
||||
dns_qpchain_init(qp, chain);
|
||||
dns_qpiter_init(qp, iter);
|
||||
@@ -2096,7 +2231,7 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
prefetch_twigs(qp, n);
|
||||
|
||||
offset = branch_key_offset(n);
|
||||
dns_qpshift_t bit = qpkey_bit(search, searchlen, offset);
|
||||
bit = qpkey_bit(search, searchlen, offset);
|
||||
dns_qpnode_t *twigs = branch_twigs(qp, n);
|
||||
|
||||
/*
|
||||
@@ -2111,7 +2246,7 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
* want when `off == 0`.
|
||||
*
|
||||
* Note 2: If SHIFT_NOBYTE twig is present, it will always
|
||||
* be in position 0, the first localtion in 'twigs'.
|
||||
* be in position 0, the first location in 'twigs'.
|
||||
*/
|
||||
if (bit != SHIFT_NOBYTE && branch_has_twig(n, SHIFT_NOBYTE) &&
|
||||
qpkey_bit(search, searchlen, offset - 1) == SHIFT_NOBYTE &&
|
||||
@@ -2128,144 +2263,53 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
* the loop.
|
||||
*/
|
||||
n = branch_twig_ptr(qp, n, bit);
|
||||
} else if (getpred) {
|
||||
} else if (setiter) {
|
||||
/*
|
||||
* this branch is a dead end. however, the caller
|
||||
* passed us an iterator, so we need to find the
|
||||
* predecessor of the searched-for-name.
|
||||
* first step: find out if we've overshot
|
||||
* the search key; we do that by finding an
|
||||
* arbitrary leaf to compare against.
|
||||
* passed us an iterator, so we'll need to look
|
||||
* for the predecessor of the searched-for-name;
|
||||
* that will break the loop.
|
||||
*/
|
||||
size_t to;
|
||||
dns_qpnode_t *least = n;
|
||||
|
||||
least:
|
||||
while (is_branch(least)) {
|
||||
least = branch_twigs(qp, least);
|
||||
}
|
||||
foundlen = leaf_qpkey(qp, least, found);
|
||||
to = qpkey_compare(search, searchlen, found, foundlen);
|
||||
if (to >= offset) {
|
||||
/*
|
||||
* we're on the right branch, so find
|
||||
* the best match.
|
||||
*/
|
||||
|
||||
dns_qpweight_t pos = branch_twig_pos(n, bit);
|
||||
if (pos == 0) {
|
||||
/*
|
||||
* every leaf in the branch is greater
|
||||
* than the one we wanted; use the
|
||||
* iterator to walk back to the
|
||||
* predecessor.
|
||||
*/
|
||||
prevleaf(iter);
|
||||
n = iter->stack[iter->sp--];
|
||||
} else {
|
||||
/*
|
||||
* the name we want would've been
|
||||
* after some twig in this
|
||||
* branch. point n to that twig,
|
||||
* then walk down to the highest
|
||||
* leaf in that subtree to get the
|
||||
* predecessor.
|
||||
*/
|
||||
n = greatest_leaf(qp, twigs + pos - 1,
|
||||
iter);
|
||||
}
|
||||
} else if (to <= searchlen && to <= foundlen &&
|
||||
search[to] < found[to])
|
||||
{
|
||||
/*
|
||||
* every leaf is greater than the one
|
||||
* we wanted, so iterate back to the
|
||||
* predecessor.
|
||||
*/
|
||||
iter->sp--;
|
||||
prevleaf(iter);
|
||||
n = iter->stack[iter->sp];
|
||||
least = n;
|
||||
goto least;
|
||||
} else if (is_branch(n)) {
|
||||
/*
|
||||
* every leaf is less than the one we
|
||||
* wanted, so get the highest.
|
||||
*/
|
||||
n = greatest_leaf(qp, n, iter);
|
||||
}
|
||||
n = fix_iterator(qp, iter, n, search, searchlen, bit,
|
||||
offset);
|
||||
} else {
|
||||
/*
|
||||
* this branch is a dead end, and the predecessor
|
||||
* doesn't matter. now we just need to find a leaf
|
||||
* to end on so qpkey_leaf() will work below.
|
||||
* to end on so that qpkey_leaf() will work below.
|
||||
*/
|
||||
if (chain->len > 0) {
|
||||
/* we saved an ancestor leaf: use that */
|
||||
n = chain->chain[chain->len - 1].node;
|
||||
} else {
|
||||
/* walk down to find the leftmost leaf */
|
||||
while (is_branch(twigs)) {
|
||||
twigs = branch_twigs(qp, twigs);
|
||||
}
|
||||
n = twigs;
|
||||
n = anyleaf(qp, twigs);
|
||||
}
|
||||
}
|
||||
|
||||
iter->stack[++iter->sp] = n;
|
||||
}
|
||||
|
||||
/* do the keys differ, and if so, where? */
|
||||
foundlen = leaf_qpkey(qp, n, found);
|
||||
difpos = qpkey_compare(search, searchlen, found, foundlen);
|
||||
|
||||
/*
|
||||
* if we've been passed an iterator, we want it to point
|
||||
* at the matching name in the case of an exact match, or at
|
||||
* the predecessor name for a non-exact match.
|
||||
*
|
||||
* if 'matched' is true, then the search ended at a leaf.
|
||||
* if it was not an exact match, then we're now pointing
|
||||
* at either the immediate predecessor or the immediate
|
||||
* successor of the searched-for name; if successor, we can
|
||||
* now use the qpiter stack we've constructed to step back to
|
||||
* the predecessor. if we're pointed at the predecessor
|
||||
* or it was an exact match, we don't need to do anything.
|
||||
*
|
||||
* if 'matched' is false, then the search failed at a branch
|
||||
* node, and we would already have positioned the iterator
|
||||
* at the predecessor.
|
||||
*/
|
||||
if (getpred && matched && difpos != QPKEY_EQUAL) {
|
||||
while (difpos < offset) {
|
||||
if (difpos <= searchlen && difpos <= foundlen &&
|
||||
search[difpos] < found[difpos])
|
||||
{
|
||||
iter->sp--;
|
||||
prevleaf(iter);
|
||||
n = iter->stack[iter->sp];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
foundlen = leaf_qpkey(qp, n, found);
|
||||
difpos = qpkey_compare(search, searchlen, found,
|
||||
foundlen);
|
||||
}
|
||||
|
||||
if (difpos <= searchlen && difpos <= foundlen &&
|
||||
search[difpos] < found[difpos])
|
||||
{
|
||||
prevleaf(iter);
|
||||
}
|
||||
if (matched && setiter) {
|
||||
/*
|
||||
* we found a leaf on a matching twig, but it
|
||||
* might not be the leaf we wanted. if it isn't,
|
||||
* and if the caller passed us an iterator,
|
||||
* then we might need to reposition it.
|
||||
*/
|
||||
n = fix_iterator(qp, iter, n, search, searchlen, bit, offset);
|
||||
}
|
||||
|
||||
if (difpos == QPKEY_EQUAL || difpos == foundlen) {
|
||||
/* do the keys differ, and if so, where? */
|
||||
foundlen = leaf_qpkey(qp, n, found);
|
||||
offset = qpkey_compare(search, searchlen, found, foundlen);
|
||||
|
||||
if (offset == QPKEY_EQUAL || offset == foundlen) {
|
||||
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
||||
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
||||
maybe_set_name(qp, n, foundname);
|
||||
add_link(chain, n, difpos);
|
||||
if (difpos == QPKEY_EQUAL) {
|
||||
add_link(chain, n, offset);
|
||||
if (offset == QPKEY_EQUAL) {
|
||||
return (ISC_R_SUCCESS);
|
||||
} else {
|
||||
return (DNS_R_PARTIALMATCH);
|
||||
@@ -2278,7 +2322,7 @@ dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
|
||||
*/
|
||||
int len = chain->len;
|
||||
while (len-- > 0) {
|
||||
if (difpos >= chain->chain[len].offset) {
|
||||
if (offset >= chain->chain[len].offset) {
|
||||
n = chain->chain[len].node;
|
||||
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
|
||||
SET_IF_NOT_NULL(ival_r, leaf_ival(n));
|
||||
|
||||
Reference in New Issue
Block a user