bool new_origin;
isc_rwlocktype_t tree_locked;
isc_result_t result;
- dns_fixedname_t name;
dns_fixedname_t origin;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
dns_qpiter_t iter;
dns_qpiter_t nsec3iter;
dns_qpiter_t *current;
qpdbiter->paused = true;
qpdbiter->tree_locked = isc_rwlocktype_none;
qpdbiter->result = ISC_R_SUCCESS;
- dns_fixedname_init(&qpdbiter->name);
dns_fixedname_init(&qpdbiter->origin);
+ dns_fixedname_init(&qpdbiter->fixed);
+ qpdbiter->name = dns_fixedname_initname(&qpdbiter->fixed);
qpdbiter->node = NULL;
if ((options & DNS_DB_NSEC3ONLY) != 0) {
}
static void
-resume_iteration(qpdb_dbiterator_t *qpdbiter) {
+resume_iteration(qpdb_dbiterator_t *qpdbiter, bool continuing) {
dns_qpdb_t *qpdb = (dns_qpdb_t *)qpdbiter->common.db;
REQUIRE(qpdbiter->paused);
TREE_RDLOCK(&qpdb->tree_lock, &qpdbiter->tree_locked);
+ /*
+ * If we're being called from dbiterator_next or _prev,
+ * then we may need to reinitialize the iterator to the current
+ * name. The tree could have changed while it was unlocked,
+ * would make the iterator traversal inconsistent.
+ *
+ * As long as the iterator is holding a reference to
+ * qpdbiter->node, the node won't be removed from the tree,
+ * so the lookup should always succeed.
+ */
+ if (continuing && qpdbiter->node != NULL) {
+ isc_result_t result;
+ dns_qp_t *tree = qpdb->tree;
+
+ if (qpdbiter->current == &qpdbiter->nsec3iter) {
+ tree = qpdb->nsec3;
+ }
+ result = dns_qp_lookup(tree, qpdbiter->name, NULL,
+ qpdbiter->current, NULL, NULL, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+ }
+
qpdbiter->paused = false;
}
}
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, false);
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
case nsec3only:
qpdbiter->current = &qpdbiter->nsec3iter;
dns_qpiter_init(qpdb->nsec3, qpdbiter->current);
- result = dns_qpiter_next(qpdbiter->current, NULL,
+ result = dns_qpiter_next(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
/* If we're in the NSEC3 tree, skip the origin */
if (QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter)) {
result = dns_qpiter_next(
- qpdbiter->current, NULL,
+ qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
}
}
case nonsec3:
qpdbiter->current = &qpdbiter->iter;
dns_qpiter_init(qpdb->tree, qpdbiter->current);
- result = dns_qpiter_next(qpdbiter->current, NULL,
+ result = dns_qpiter_next(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
break;
case full:
qpdbiter->current = &qpdbiter->iter;
dns_qpiter_init(qpdb->tree, qpdbiter->current);
- result = dns_qpiter_next(qpdbiter->current, NULL,
+ result = dns_qpiter_next(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if (result == ISC_R_NOMORE) {
qpdbiter->current = &qpdbiter->nsec3iter;
dns_qpiter_init(qpdb->nsec3, qpdbiter->current);
- result = dns_qpiter_next(qpdbiter->current, NULL,
- (void **)&qpdbiter->node,
- NULL);
+ result = dns_qpiter_next(
+ qpdbiter->current, qpdbiter->name,
+ (void **)&qpdbiter->node, NULL);
}
break;
default:
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
} else {
INSIST(result == ISC_R_NOMORE); /* The tree is empty. */
+ qpdbiter->node = NULL;
}
qpdbiter->result = result;
}
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, false);
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
case nsec3only:
qpdbiter->current = &qpdbiter->nsec3iter;
dns_qpiter_init(qpdb->nsec3, qpdbiter->current);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
+ result = dns_qpiter_prev(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if ((result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) &&
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
case nonsec3:
qpdbiter->current = &qpdbiter->iter;
dns_qpiter_init(qpdb->tree, qpdbiter->current);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
+ result = dns_qpiter_prev(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
break;
case full:
qpdbiter->current = &qpdbiter->nsec3iter;
dns_qpiter_init(qpdb->nsec3, qpdbiter->current);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
+ result = dns_qpiter_prev(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if ((result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) &&
QPDBITER_NSEC3_ORIGIN_NODE(qpdb, qpdbiter))
if (result == ISC_R_NOMORE) {
qpdbiter->current = &qpdbiter->iter;
dns_qpiter_init(qpdb->tree, qpdbiter->current);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
- (void **)&qpdbiter->node,
- NULL);
+ result = dns_qpiter_prev(
+ qpdbiter->current, qpdbiter->name,
+ (void **)&qpdbiter->node, NULL);
}
break;
default:
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
} else {
INSIST(result == ISC_R_NOMORE); /* The tree is empty. */
+ qpdbiter->node = NULL;
}
qpdbiter->result = result;
}
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, false);
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
qpdbiter->new_origin = true;
+ dns_name_copy(qpdbiter->node->name, qpdbiter->name);
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
} else {
qpdbiter->node = NULL;
}
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, true);
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
+ result = dns_qpiter_prev(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if (qpdbiter->current == &qpdbiter->nsec3iter) {
if (result == ISC_R_NOMORE && qpdbiter->nsec3mode == full) {
qpdbiter->current = &qpdbiter->iter;
dns_qpiter_init(qpdb->tree, qpdbiter->current);
- result = dns_qpiter_prev(qpdbiter->current, NULL,
- (void **)&qpdbiter->node,
- NULL);
+ result = dns_qpiter_prev(
+ qpdbiter->current, qpdbiter->name,
+ (void **)&qpdbiter->node, NULL);
}
}
if (result == ISC_R_SUCCESS) {
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
+ } else {
+ INSIST(result == ISC_R_NOMORE);
+ qpdbiter->node = NULL;
}
qpdbiter->result = result;
}
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, true);
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
- result = dns_qpiter_next(qpdbiter->current, NULL,
+ result = dns_qpiter_next(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
if (result == ISC_R_NOMORE && qpdbiter->nsec3mode == full &&
{
qpdbiter->current = &qpdbiter->nsec3iter;
dns_qpiter_init(qpdb->nsec3, qpdbiter->current);
- result = dns_qpiter_next(qpdbiter->current, NULL,
+ result = dns_qpiter_next(qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
}
case nsec3only:
case full:
result = dns_qpiter_next(
- qpdbiter->current, NULL,
+ qpdbiter->current, qpdbiter->name,
(void **)&qpdbiter->node, NULL);
break;
case nonsec3:
if (result == ISC_R_SUCCESS) {
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
+ } else {
+ INSIST(result == ISC_R_NOMORE);
+ qpdbiter->node = NULL;
}
qpdbiter->result = result;
REQUIRE(qpdbiter->node != NULL);
if (qpdbiter->paused) {
- resume_iteration(qpdbiter);
+ resume_iteration(qpdbiter, false);
}
if (name != NULL) {