isc_result_t
dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
- dns_name_t *foundname, dns_name_t *predecessor,
- dns_qpchain_t *chain, void **pval_r, uint32_t *ival_r);
+ dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
+ void **pval_r, uint32_t *ival_r);
/*%<
* Look up a leaf in a qp-trie that is equal to, or an ancestor domain of,
* 'name'.
* ISC_R_SUCCESS then it terminates at the name that was requested.
* If the result is ISC_R_NOTFOUND, 'chain' will not be updated.
*
- * If 'predecessor' is not NULL, it will be updated to contain the
- * closest predecessor of the searched-for name that exists in the
- * trie.
+ * If 'iter' is not NULL, it will be updated to point to a QP iterator
+ * which is pointed at the searched-for name if it exists in the trie,
+ * or the closest predecessor if it doesn't.
*
* The leaf data for the node that was found will be assigned to
* whichever of `*pval_r` and `*ival_r` are not NULL, unless the
* \li `qpr` is a pointer to a readable qp-trie
* \li `name` is a pointer to a valid `dns_name_t`
* \li `foundname` is a pointer to a valid `dns_name_t` with
- * buffer and offset space available, or is NULL.
+ * buffer and offset space available, or is NULL
*
* Returns:
* \li ISC_R_SUCCESS if an exact match was found
* \li ISC_R_NOMORE otherwise
*/
+isc_result_t
+dns_qpiter_current(dns_qpiter_t *qpi, dns_name_t *name, void **pval_r,
+ uint32_t *ival_r);
+/*%<
+ * Sets the values of `name`, `pval_r` and `ival_r` to those at the
+ * node currently pointed to by `qpi`, but without moving the iterator
+ * in either direction. If the iterator is not currently pointed at a
+ * leaf node, ISC_R_FAILURE is returned.
+ * Requires:
+ *
+ * \li `qpi` is a pointer to a valid qp iterator
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS if a leaf was found and pval_r and ival_r were set
+ * \li ISC_R_FAILURE if the iterator is not initialized or not pointing
+ * at a leaf node
+ */
+
void
dns_qpchain_init(dns_qpreadable_t qpr, dns_qpchain_t *chain);
/*%<
*
* Requires:
* \li `qpr` is a pointer to a valid qp-trie
- * \li `chain` is not NULL.
+ * \li `chain` is not NULL
*/
unsigned int
* Returns the length of a QP chain.
*
* Requires:
- * \li `chain` is a pointer to an initialized QP chain object.
+ * \li `chain` is a pointer to an initialized QP chain object
*/
void
* are not null.
*
* Requires:
- * \li `chain` is a pointer to an initialized QP chain object.
- * \li `level` is less than `chain->len`.
+ * \li `chain` is a pointer to an initialized QP chain object
+ * \li `level` is less than `chain->len`
*/
/***********************************************************************
return (iterate(false, qpi, name, pval_r, ival_r));
}
+isc_result_t
+dns_qpiter_current(dns_qpiter_t *qpi, dns_name_t *name, void **pval_r,
+ uint32_t *ival_r) {
+ dns_qpnode_t *node = NULL;
+
+ REQUIRE(QPITER_VALID(qpi));
+
+ node = qpi->stack[qpi->sp];
+ if (node == NULL || is_branch(node)) {
+ return (ISC_R_FAILURE);
+ }
+
+ SET_IF_NOT_NULL(pval_r, leaf_pval(node));
+ SET_IF_NOT_NULL(ival_r, leaf_ival(node));
+ maybe_set_name(qpi->qp, node, name);
+ return (ISC_R_SUCCESS);
+}
+
/***********************************************************************
*
* search
isc_result_t
dns_qp_lookup(dns_qpreadable_t qpr, const dns_name_t *name,
- dns_name_t *foundname, dns_name_t *predecessor,
- dns_qpchain_t *chain, void **pval_r, uint32_t *ival_r) {
+ dns_name_t *foundname, dns_qpiter_t *iter, dns_qpchain_t *chain,
+ void **pval_r, uint32_t *ival_r) {
dns_qpreader_t *qp = dns_qpreader(qpr);
dns_qpkey_t search, found;
size_t searchlen, foundlen;
dns_qpchain_t oc;
dns_qpiter_t it;
bool matched = true;
+ bool getpred = true;
REQUIRE(QP_VALID(qp));
REQUIRE(foundname == NULL || ISC_MAGIC_VALID(name, DNS_NAME_MAGIC));
if (chain == NULL) {
chain = &oc;
}
+ if (iter == NULL) {
+ iter = ⁢
+ getpred = false;
+ }
dns_qpchain_init(qp, chain);
- dns_qpiter_init(qp, &it);
+ dns_qpiter_init(qp, iter);
n = get_root(qp);
if (n == NULL) {
return (ISC_R_NOTFOUND);
}
- it.stack[0] = n;
+ iter->stack[0] = n;
/*
* Like `dns_qp_insert()`, we must find a leaf. However, we don't make a
* the loop.
*/
n = branch_twig_ptr(qp, n, bit);
- } else if (predecessor != NULL) {
+ } else if (getpred) {
/*
- * this branch is a dead end, but the caller wants
- * the predecessor to the name we were searching
- * for, so let's go find that.
+ * this branch is a dead end, but the caller
+ * passed us an iterator: position it at the
+ * predecessor node.
*/
dns_qpweight_t pos = branch_twig_pos(n, bit);
if (pos == 0) {
* the key we wanted, so we step back to
* the predecessor using the iterator.
*/
- prevleaf(&it);
- n = it.stack[it.sp];
+ prevleaf(iter);
+ n = iter->stack[iter->sp];
} else {
/*
* the name we want would've been between
n = twigs + pos - 1;
while (is_branch(n)) {
prefetch_twigs(qp, n);
- it.stack[++it.sp] = n;
+ iter->stack[++iter->sp] = n;
pos = branch_twigs_size(n) - 1;
n = ref_ptr(qp,
branch_twigs_ref(n) + pos);
}
}
- it.stack[++it.sp] = n;
+ iter->stack[++iter->sp] = n;
}
/* do the keys differ, and if so, where? */
offset = qpkey_compare(search, searchlen, found, foundlen);
/*
- * if we've been asked to return the predecessor name, we
- * work that out here.
+ * 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, the search ended at a leaf. it's either
- * an exact match or the immediate successor of the searched-for
- * name, and in either case, we can use the qpiter stack we've
- * constructed to step back to the predecessor. if 'matched' is
- * false, then the search failed at a branch node, and we would
- * have already found the predecessor.
+ * if 'matched' is true, then the search ended at a leaf.
+ * if it was not an exact match, then we're now pointing at
+ * the immediate successor of the searched-for name, and can
+ * use the qpiter stack we've constructed to step back to
+ * the predecessor. if 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 (predecessor != NULL && matched) {
- prevleaf(&it);
+ if (getpred && matched) {
+ if (offset != QPKEY_EQUAL) {
+ prevleaf(iter);
+ }
}
- maybe_set_name(qp, it.stack[it.sp], predecessor);
if (offset == QPKEY_EQUAL || offset == foundlen) {
SET_IF_NOT_NULL(pval_r, leaf_pval(n));
int inserted, n;
uint32_t ival;
void *pval = NULL;
+ isc_result_t result;
dns_qp_create(mctx, &qpiter_methods, item, &qp);
for (size_t tests = 0; tests < 1234; tests++) {
while (dns_qpiter_prev(&qpi, NULL, NULL, &ival) ==
ISC_R_SUCCESS)
{
- assert_int_equal(ival, order[--n]);
+ --n;
+
+ assert_int_equal(ival, order[n]);
+
+ /* and check current iterator value as well */
+ result = dns_qpiter_current(&qpi, NULL, NULL, &ival);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(ival, order[n]);
}
+
assert_int_equal(n, 0);
/* ...and forward again */
while (dns_qpiter_next(&qpi, NULL, NULL, &ival) ==
ISC_R_SUCCESS)
{
- assert_int_equal(ival, order[n++]);
+ assert_int_equal(ival, order[n]);
+
+ /* and check current iterator value as well */
+ result = dns_qpiter_current(&qpi, NULL, NULL, &ival);
+ assert_int_equal(result, ISC_R_SUCCESS);
+ assert_int_equal(ival, order[n]);
+
+ n++;
}
assert_int_equal(n, inserted);
dns_name_t *pred = dns_fixedname_initname(&fn2);
for (int i = 0; check[i].query != NULL; i++) {
+ dns_qpiter_t it;
char *predname = NULL;
dns_test_namefromstring(check[i].query, &fn1);
- result = dns_qp_lookup(qp, name, NULL, pred, NULL, NULL, NULL);
+ result = dns_qp_lookup(qp, name, NULL, &it, NULL, NULL, NULL);
#if 0
fprintf(stderr, "%s: expected %s got %s\n", check[i].query,
isc_result_totext(check[i].result),
isc_result_totext(result));
#endif
assert_int_equal(result, check[i].result);
+
+ if (result == ISC_R_SUCCESS) {
+ /*
+ * we found an exact match; iterate to find
+ * the predecessor.
+ */
+ result = dns_qpiter_prev(&it, pred, NULL, NULL);
+ if (result == ISC_R_NOMORE) {
+ result = dns_qpiter_prev(&it, pred, NULL, NULL);
+ }
+ } else {
+ /*
+ * we didn't find a match, so the iterator should
+ * already be pointed at the predecessor node.
+ */
+ result = dns_qpiter_current(&it, pred, NULL, NULL);
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+
result = dns_name_tostring(pred, &predname, mctx);
#if 0
fprintf(stderr, "... expected predecessor %s got %s\n",