From: Libor Peltan Date: Mon, 11 Feb 2019 11:33:57 +0000 (+0100) Subject: zone tree: api for tree iteration, avoid iterating trie X-Git-Tag: v2.9.0~286^2~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32df9283d6b6dd1817d14a64c386168e8b3cd3cf;p=thirdparty%2Fknot-dns.git zone tree: api for tree iteration, avoid iterating trie --- diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c index 4bcb6bcb1d..952b7d28fa 100644 --- a/src/knot/dnssec/nsec-chain.c +++ b/src/knot/dnssec/nsec-chain.c @@ -157,25 +157,25 @@ int knot_nsec_chain_iterate_create(zone_tree_t *nodes, assert(nodes); assert(callback); - trie_it_t *it = trie_it_begin(nodes); - if (!it) { - return KNOT_ENOMEM; + zone_tree_it_t it = { 0 }; + int result = zone_tree_it_begin(nodes, &it); + if (result != KNOT_EOK) { + return result; } - if (trie_it_finished(it)) { - trie_it_free(it); + if (zone_tree_it_finished(&it)) { + zone_tree_it_free(&it); return KNOT_EINVAL; } - zone_node_t *first = (zone_node_t *)*trie_it_val(it); + zone_node_t *first = zone_tree_it_val(&it); zone_node_t *previous = first; zone_node_t *current = first; - trie_it_next(it); + zone_tree_it_next(&it); - int result = KNOT_EOK; - while (!trie_it_finished(it)) { - current = (zone_node_t *)*trie_it_val(it); + while (!zone_tree_it_finished(&it)) { + current = zone_tree_it_val(&it); result = callback(previous, current, data); if (result == NSEC_NODE_SKIP) { @@ -184,30 +184,25 @@ int knot_nsec_chain_iterate_create(zone_tree_t *nodes, } else if (result == KNOT_EOK) { previous = current; } else { - trie_it_free(it); + zone_tree_it_free(&it); return result; } - trie_it_next(it); + zone_tree_it_next(&it); } - trie_it_free(it); + zone_tree_it_free(&it); return result == NSEC_NODE_SKIP ? callback(previous, first, data) : callback(current, first, data); } -inline static zone_node_t *it_val(trie_it_t *it) -{ - return (zone_node_t *)*trie_it_val(it); -} - -inline static zone_node_t *it_next0(trie_it_t *it, zone_node_t *first) +inline static zone_node_t *it_next0(zone_tree_it_t *it, zone_node_t *first) { - trie_it_next(it); - return (trie_it_finished(it) ? first : it_val(it)); + zone_tree_it_next(it); + return (zone_tree_it_finished(it) ? first : zone_tree_it_val(it)); } -static zone_node_t *it_next1(trie_it_t *it, zone_node_t *first) +static zone_node_t *it_next1(zone_tree_it_t *it, zone_node_t *first) { zone_node_t *res; do { @@ -216,7 +211,7 @@ static zone_node_t *it_next1(trie_it_t *it, zone_node_t *first) return res; } -static zone_node_t *it_next2(trie_it_t *it, zone_node_t *first, changeset_t *ch) +static zone_node_t *it_next2(zone_tree_it_t *it, zone_node_t *first, changeset_t *ch) { zone_node_t *res = it_next0(it, first); while (knot_nsec_empty_nsec_and_rrsigs_in_node(res) || (res->flags & NODE_FLAGS_NONAUTH)) { @@ -245,24 +240,25 @@ int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes, assert(new_nodes); assert(callback); - int ret = KNOT_EOK; - - trie_it_t *old_it = trie_it_begin(old_nodes), *new_it = trie_it_begin(new_nodes); - if (old_it == NULL || new_it == NULL) { - ret = KNOT_ENOMEM; + zone_tree_it_t old_it = { 0 }, new_it = { 0 }; + int ret = zone_tree_it_begin(old_nodes, &old_it); + if (ret == KNOT_EOK) { + ret = zone_tree_it_begin(new_nodes, &new_it); + } + if (ret != KNOT_EOK) { goto cleanup; } - if (trie_it_finished(new_it)) { + if (zone_tree_it_finished(&new_it)) { ret = KNOT_ENORECORD; goto cleanup; } - if (trie_it_finished(old_it)) { + if (zone_tree_it_finished(&old_it)) { ret = KNOT_ENORECORD; goto cleanup; } - zone_node_t *old_first = it_val(old_it), *new_first = it_val(new_it); + zone_node_t *old_first = zone_tree_it_val(&old_it), *new_first = zone_tree_it_val(&new_it); if (!knot_dname_is_equal(old_first->owner, new_first->owner)) { // this may happen with NSEC3 (on NSEC, it will be apex) @@ -280,8 +276,8 @@ int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes, } zone_node_t *old_prev = old_first, *new_prev = new_first; - zone_node_t *old_curr = it_next1(old_it, old_first); - zone_node_t *new_curr = it_next2(new_it, new_first, data->changeset); + zone_node_t *old_curr = it_next1(&old_it, old_first); + zone_node_t *new_curr = it_next2(&new_it, new_first, data->changeset); while (1) { bool bitmap_change = !node_bitmap_equal(old_prev, new_prev); @@ -305,7 +301,7 @@ int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes, ret = knot_nsec_changeset_remove(old_curr, data->changeset); CHECK_RET; old_prev = old_curr; - old_curr = it_next1(old_it, old_first); + old_curr = it_next1(&old_it, old_first); ret = callback(new_prev, new_curr, data); CHECK_RET; } else { @@ -315,7 +311,7 @@ int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes, ret = callback(new_prev, new_curr, data); CHECK_RET; new_prev = new_curr; - new_curr = it_next2(new_it, new_first, data->changeset); + new_curr = it_next2(&new_it, new_first, data->changeset); ret = callback(new_prev, new_curr, data); CHECK_RET; } @@ -328,13 +324,13 @@ int knot_nsec_chain_iterate_fix(zone_tree_t *old_nodes, zone_tree_t *new_nodes, old_prev = old_curr; new_prev = new_curr; - old_curr = it_next1(old_it, old_first); - new_curr = it_next2(new_it, new_first, data->changeset); + old_curr = it_next1(&old_it, old_first); + new_curr = it_next2(&new_it, new_first, data->changeset); } cleanup: - trie_it_free(old_it); - trie_it_free(new_it); + zone_tree_it_free(&old_it); + zone_tree_it_free(&new_it); return ret; } diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c index b70a8faf21..fe706af0c3 100644 --- a/src/knot/dnssec/nsec3-chain.c +++ b/src/knot/dnssec/nsec3-chain.c @@ -126,10 +126,9 @@ static int copy_signatures(zone_tree_t *from, zone_tree_t *to) assert(to); - trie_it_t *it = trie_it_begin(from); - - for (/* NOP */; !trie_it_finished(it); trie_it_next(it)) { - zone_node_t *node_from = (zone_node_t *)*trie_it_val(it); + zone_tree_it_t it = { 0 }; + for ((void)zone_tree_it_begin(from, &it); !zone_tree_it_finished(&it); zone_tree_it_next(&it)) { + zone_node_t *node_from = zone_tree_it_val(&it); zone_node_t *node_to = zone_tree_get(to, node_from->owner); if (node_to == NULL) { @@ -142,12 +141,12 @@ static int copy_signatures(zone_tree_t *from, zone_tree_t *to) int ret = shallow_copy_signature(node_from, node_to); if (ret != KNOT_EOK) { - trie_it_free(it); + zone_tree_it_free(&it); return ret; } } - trie_it_free(it); + zone_tree_it_free(&it); return KNOT_EOK; } @@ -159,9 +158,9 @@ static void free_nsec3_tree(zone_tree_t *nodes) { assert(nodes); - trie_it_t *it = trie_it_begin(nodes); - for (/* NOP */; !trie_it_finished(it); trie_it_next(it)) { - zone_node_t *node = (zone_node_t *)*trie_it_val(it); + zone_tree_it_t it = { 0 }; + for ((void)zone_tree_it_begin(nodes, &it); !zone_tree_it_finished(&it); zone_tree_it_next(&it)) { + zone_node_t *node = zone_tree_it_val(&it); // newly allocated NSEC3 nodes knot_rdataset_t *nsec3 = node_rdataset(node, KNOT_RRTYPE_NSEC3); knot_rdataset_t *rrsig = node_rdataset(node, KNOT_RRTYPE_RRSIG); @@ -170,7 +169,7 @@ static void free_nsec3_tree(zone_tree_t *nodes) node_free(node, NULL); } - trie_it_free(it); + zone_tree_it_free(&it); zone_tree_free(&nodes); } @@ -495,11 +494,11 @@ static int create_nsec3_nodes(const zone_contents_t *zone, assert(nsec3_nodes); assert(chgset); - int result = KNOT_EOK; + zone_tree_it_t it = { 0 }; + int result = zone_tree_it_begin(zone->nodes, &it); - trie_it_t *it = trie_it_begin(zone->nodes); - while (!trie_it_finished(it)) { - zone_node_t *node = (zone_node_t *)*trie_it_val(it); + while (!zone_tree_it_finished(&it)) { + zone_node_t *node = zone_tree_it_val(&it); /*! * Remove possible NSEC from the node. (Do not allow both NSEC @@ -510,7 +509,7 @@ static int create_nsec3_nodes(const zone_contents_t *zone, break; } if (node->flags & NODE_FLAGS_NONAUTH || node->flags & NODE_FLAGS_EMPTY) { - trie_it_next(it); + zone_tree_it_next(&it); continue; } @@ -527,10 +526,10 @@ static int create_nsec3_nodes(const zone_contents_t *zone, break; } - trie_it_next(it); + zone_tree_it_next(&it); } - trie_it_free(it); + zone_tree_it_free(&it); return result; } @@ -644,23 +643,26 @@ static int fix_nsec3_nodes(zone_update_t *update, const dnssec_nsec3_params_t *p { assert(update); - int ret = KNOT_EOK; + zone_tree_it_t it = { 0 }; + int ret = zone_tree_it_begin(update->change.remove->nodes, &it); - trie_it_t *rem_it = trie_it_begin(update->change.remove->nodes); - while (!trie_it_finished(rem_it) && ret == KNOT_EOK) { - zone_node_t *n = (zone_node_t *)*trie_it_val(rem_it); + while (!zone_tree_it_finished(&it) && ret == KNOT_EOK) { + zone_node_t *n = zone_tree_it_val(&it); ret = fix_nsec3_for_node(update, params, ttl, opt_out, chgset, n->owner); - trie_it_next(rem_it); + zone_tree_it_next(&it); + } + + if (ret == KNOT_EOK) { + zone_tree_it_free(&it); + ret = zone_tree_it_begin(update->change.add->nodes, &it); } - trie_it_free(rem_it); - trie_it_t *add_it = trie_it_begin(update->change.add->nodes); - while (!trie_it_finished(add_it) && ret == KNOT_EOK) { - zone_node_t *n = (zone_node_t *)*trie_it_val(add_it); + while (!zone_tree_it_finished(&it) && ret == KNOT_EOK) { + zone_node_t *n = zone_tree_it_val(&it); ret = fix_nsec3_for_node(update, params, ttl, opt_out, chgset, n->owner); - trie_it_next(add_it); + zone_tree_it_next(&it); } - trie_it_free(add_it); + zone_tree_it_free(&it); return ret; } diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c index 0bd9611e3a..4b55f8b956 100644 --- a/src/knot/nameserver/axfr.c +++ b/src/knot/nameserver/axfr.c @@ -35,6 +35,7 @@ struct axfr_proc { struct xfr_proc proc; trie_it_t *i; + zone_tree_it_t it; unsigned cur_rrset; }; @@ -70,25 +71,20 @@ static int axfr_process_node_tree(knot_pkt_t *pkt, const void *item, struct axfr_proc *axfr = (struct axfr_proc*)state; - if (axfr->i == NULL) { - axfr->i = trie_it_begin((trie_t *)item); - } + int ret = zone_tree_it_begin((zone_tree_t *)item, &axfr->it); // does nothing if already itearating /* Put responses. */ - int ret = KNOT_EOK; - while (!trie_it_finished(axfr->i)) { - zone_node_t *node = (zone_node_t *)*trie_it_val(axfr->i); + while (ret == KNOT_EOK && !zone_tree_it_finished(&axfr->it)) { + zone_node_t *node = zone_tree_it_val(&axfr->it); ret = axfr_put_rrsets(pkt, node, axfr); - if (ret != KNOT_EOK) { - break; + if (ret == KNOT_EOK) { + zone_tree_it_next(&axfr->it); } - trie_it_next(axfr->i); } /* Finished all nodes. */ if (ret == KNOT_EOK) { - trie_it_free(axfr->i); - axfr->i = NULL; + zone_tree_it_free(&axfr->it); } return ret; } @@ -97,7 +93,7 @@ static void axfr_query_cleanup(knotd_qdata_t *qdata) { struct axfr_proc *axfr = (struct axfr_proc *)qdata->extra->ext; - trie_it_free(axfr->i); + zone_tree_it_free(&axfr->it); ptrlist_free(&axfr->proc.nodes, qdata->mm); mm_free(qdata->mm, axfr); diff --git a/src/knot/updates/changesets.c b/src/knot/updates/changesets.c index 79c341128d..ff393578a8 100644 --- a/src/knot/updates/changesets.c +++ b/src/knot/updates/changesets.c @@ -53,96 +53,28 @@ static int add_rr_to_contents(zone_contents_t *z, const knot_rrset_t *rrset) return ret == KNOT_ETTL ? KNOT_EOK : ret; } -/*! \brief Cleans up trie iterations. */ -static void cleanup_iter_list(list_t *l) -{ - ptrnode_t *n, *nxt; - WALK_LIST_DELSAFE(n, nxt, *l) { - trie_it_t *it = (trie_it_t *)n->d; - trie_it_free(it); - rem_node(&n->n); - free(n); - } - init_list(l); -} - /*! \brief Inits changeset iterator with given tries. */ static int changeset_iter_init(changeset_iter_t *ch_it, size_t tries, ...) { memset(ch_it, 0, sizeof(*ch_it)); - init_list(&ch_it->iters); va_list args; va_start(args, tries); + assert(tries <= sizeof(ch_it->trees) / sizeof(*ch_it->trees)); for (size_t i = 0; i < tries; ++i) { - trie_t *t = va_arg(args, trie_t *); + zone_tree_t *t = va_arg(args, zone_tree_t *); if (t == NULL) { continue; } - trie_it_t *it = trie_it_begin(t); - if (it == NULL) { - cleanup_iter_list(&ch_it->iters); - va_end(args); - return KNOT_ENOMEM; - } - - if (ptrlist_add(&ch_it->iters, it, NULL) == NULL) { - cleanup_iter_list(&ch_it->iters); - va_end(args); - return KNOT_ENOMEM; - } + ch_it->trees[ch_it->n_trees++] = t; } va_end(args); - return KNOT_EOK; -} - -/*! \brief Gets next node from trie iterators. */ -static void iter_next_node(changeset_iter_t *ch_it, trie_it_t *t_it) -{ - assert(!trie_it_finished(t_it)); - // Get next node, but not for the very first call. - if (ch_it->node) { - trie_it_next(t_it); - } - if (trie_it_finished(t_it)) { - ch_it->node = NULL; - return; - } - - ch_it->node = (zone_node_t *)*trie_it_val(t_it); - assert(ch_it->node); - while (ch_it->node && ch_it->node->rrset_count == 0) { - // Skip empty non-terminals. - trie_it_next(t_it); - if (trie_it_finished(t_it)) { - ch_it->node = NULL; - } else { - ch_it->node = (zone_node_t *)*trie_it_val(t_it); - assert(ch_it->node); - } - } - - ch_it->node_pos = 0; -} - -/*! \brief Gets next RRSet from trie iterators. */ -static knot_rrset_t get_next_rr(changeset_iter_t *ch_it, trie_it_t *t_it) -{ - if (ch_it->node == NULL || ch_it->node_pos == ch_it->node->rrset_count) { - iter_next_node(ch_it, t_it); - if (ch_it->node == NULL) { - assert(trie_it_finished(t_it)); - knot_rrset_t rr; - knot_rrset_init_empty(&rr); - return rr; - } - } - - return node_rrset_at(ch_it->node, ch_it->node_pos++); + assert(ch_it->n_trees); + return zone_tree_it_begin(ch_it->trees[0], &ch_it->it); } // removes from counterpart what is in rr. @@ -737,29 +669,36 @@ int changeset_iter_all(changeset_iter_t *itt, const changeset_t *ch) knot_rrset_t changeset_iter_next(changeset_iter_t *it) { assert(it); - ptrnode_t *n = NULL; + knot_rrset_t rr; - knot_rrset_init_empty(&rr); - WALK_LIST(n, it->iters) { - trie_it_t *t_it = (trie_it_t *)n->d; - if (trie_it_finished(t_it)) { - continue; + while (it->node == NULL || it->node_pos >= it->node->rrset_count) { + if (it->node != NULL) { + zone_tree_it_next(&it->it); } - - rr = get_next_rr(it, t_it); - if (!knot_rrset_empty(&rr)) { - // Got valid RRSet. - return rr; + while (zone_tree_it_finished(&it->it)) { + zone_tree_it_free(&it->it); + if (--it->n_trees > 0) { + for (size_t i = 0; i < it->n_trees; i++) { + it->trees[i] = it->trees[i + 1]; + } + (void)zone_tree_it_begin(it->trees[0], &it->it); + } else { + knot_rrset_init_empty(&rr); + return rr; + } } + it->node = zone_tree_it_val(&it->it); + it->node_pos = 0; } - + rr = node_rrset_at(it->node, it->node_pos++); + assert(!knot_rrset_empty(&rr)); return rr; } void changeset_iter_clear(changeset_iter_t *it) { if (it) { - cleanup_iter_list(&it->iters); + zone_tree_it_free(&it->it); it->node = NULL; it->node_pos = 0; } diff --git a/src/knot/updates/changesets.h b/src/knot/updates/changesets.h index 2cbd1bb9c1..f64264d2ed 100644 --- a/src/knot/updates/changesets.h +++ b/src/knot/updates/changesets.h @@ -43,6 +43,9 @@ typedef struct { /*! \brief Changeset iteration structure. */ typedef struct { list_t iters; /*!< List of pending zone iterators. */ + zone_tree_t *trees[4]; /*!< Poiters to zone trees to iterate over. */ + size_t n_trees; /*!< Their count. */ + zone_tree_it_t it; /*!< Zone tree iterator. */ const zone_node_t *node; /*!< Current zone node. */ uint16_t node_pos; /*!< Position in node. */ } changeset_iter_t; diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c index f55a1b023f..b9564d8954 100644 --- a/src/knot/updates/zone-update.c +++ b/src/knot/updates/zone-update.c @@ -799,27 +799,25 @@ static int iter_init_tree_iters(zone_update_iter_t *it, zone_update_t *update, /* Begin iteration. We can safely assume _contents is a valid pointer. */ zone_tree_t *tree = nsec3 ? _contents->nsec3_nodes : _contents->nodes; - it->tree_it = trie_it_begin(tree); - if (it->tree_it == NULL) { + if (zone_tree_it_begin(tree, &it->tree_it) != KNOT_EOK) { return KNOT_ENOMEM; } - it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it)); + it->cur_node = zone_tree_it_val(&it->tree_it); return KNOT_EOK; } static int iter_get_next_node(zone_update_iter_t *it) { - trie_it_next(it->tree_it); - if (trie_it_finished(it->tree_it)) { - trie_it_free(it->tree_it); - it->tree_it = NULL; + zone_tree_it_next(&it->tree_it); + if (zone_tree_it_finished(&it->tree_it)) { + zone_tree_it_free(&it->tree_it); it->cur_node = NULL; return KNOT_ENOENT; } - it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it)); + it->cur_node = zone_tree_it_val(&it->tree_it); return KNOT_EOK; } @@ -835,7 +833,7 @@ static int iter_init(zone_update_iter_t *it, zone_update_t *update, const bool n return ret; } - it->cur_node = (zone_node_t *)(*trie_it_val(it->tree_it)); + it->cur_node = zone_tree_it_val(&it->tree_it); return KNOT_EOK; } @@ -877,7 +875,7 @@ int zone_update_iter_next(zone_update_iter_t *it) return KNOT_EINVAL; } - if (it->tree_it != NULL) { + if (it->tree_it.it != NULL) { int ret = iter_get_next_node(it); if (ret != KNOT_EOK && ret != KNOT_ENOENT) { return ret; @@ -902,7 +900,7 @@ void zone_update_iter_finish(zone_update_iter_t *it) return; } - trie_it_free(it->tree_it); + zone_tree_it_free(&it->tree_it); } bool zone_update_no_change(zone_update_t *update) diff --git a/src/knot/updates/zone-update.h b/src/knot/updates/zone-update.h index 59eb3b9f11..27dd83a022 100644 --- a/src/knot/updates/zone-update.h +++ b/src/knot/updates/zone-update.h @@ -36,7 +36,7 @@ typedef struct zone_update { typedef struct { zone_update_t *update; /*!< The update we're iterating over. */ - trie_it_t *tree_it; /*!< Iterator for the new zone. */ + zone_tree_it_t tree_it; /*!< Iterator for the new zone. */ const zone_node_t *cur_node; /*!< Current node in the new zone. */ bool nsec3; /*!< Set when we're using the NSEC3 node tree. */ } zone_update_iter_t; diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c index 2bf6b47f66..48eea2f387 100644 --- a/src/knot/zone/contents.c +++ b/src/knot/zone/contents.c @@ -375,12 +375,12 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out) // everything done, now just update "parent" and "apex" pointers out->apex = NULL; - trie_it_t *itt = trie_it_begin(out->nodes); - if (itt == NULL) { + zone_tree_it_t it = { 0 }; + if (zone_tree_it_begin(out->nodes, &it) != KNOT_EOK) { return KNOT_ENOMEM; } - while (!trie_it_finished(itt)) { - zone_node_t *to_fix = (zone_node_t *)*trie_it_val(itt); + while (!zone_tree_it_finished(&it)) { + zone_node_t *to_fix = zone_tree_it_val(&it); if (out->apex == NULL && knot_dname_cmp(to_fix->owner, z->apex->owner) == 0) { out->apex = to_fix; } else { @@ -389,9 +389,9 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out) assert(parent != NULL); node_set_parent(to_fix, parent); } - trie_it_next(itt); + zone_tree_it_next(&it); } - trie_it_free(itt); + zone_tree_it_free(&it); assert(out->apex != NULL); return KNOT_EOK; @@ -404,16 +404,16 @@ static int recreate_nsec3_tree(const zone_contents_t *z, zone_contents_t *out) return KNOT_ENOMEM; } - trie_it_t *itt = trie_it_begin(z->nsec3_nodes); - if (itt == NULL) { + zone_tree_it_t it = { 0 }; + if (zone_tree_it_begin(z->nsec3_nodes, &it) != KNOT_EOK) { return KNOT_ENOMEM; } - while (!trie_it_finished(itt)) { - zone_node_t *to_fix = (zone_node_t *)*trie_it_val(itt); + while (!zone_tree_it_finished(&it)) { + zone_node_t *to_fix = zone_tree_it_val(&it); to_fix->parent = out->apex; - trie_it_next(itt); + zone_tree_it_next(&it); } - trie_it_free(itt); + zone_tree_it_free(&it); return KNOT_EOK; } diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c index 0cfed7f0b2..486853bfb4 100644 --- a/src/knot/zone/zone-tree.c +++ b/src/knot/zone/zone-tree.c @@ -103,11 +103,15 @@ int zone_tree_get_less_or_equal(zone_tree_t *tree, * cases like NSEC3, there is no such sort of thing (name wise). */ /*! \todo We could store rightmost node in zonetree probably. */ - trie_it_t *i = trie_it_begin(tree); - *previous = *(zone_node_t **)trie_it_val(i); /* leftmost */ + zone_tree_it_t it = { 0 }; + ret = zone_tree_it_begin(tree, &it); + if (ret != KNOT_EOK) { + return ret; + } + *previous = zone_tree_it_val(&it); /* leftmost */ *previous = (*previous)->prev; /* rightmost */ *found = NULL; - trie_it_free(i); + zone_tree_it_free(&it); } return exact_match; @@ -175,6 +179,39 @@ int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data return trie_apply(tree, (int (*)(trie_val_t *, void *))function, data); } +int zone_tree_it_begin(zone_tree_t *tree, zone_tree_it_t *it) +{ + if (it->tree == NULL) { + it->it = trie_it_begin((trie_t *)tree); + if (it->it == NULL) { + return KNOT_ENOMEM; + } + it->tree = tree; + } + return KNOT_EOK; +} + +bool zone_tree_it_finished(zone_tree_it_t *it) +{ + return it->it == NULL || trie_it_finished(it->it); +} + +zone_node_t *zone_tree_it_val(zone_tree_it_t *it) +{ + return (zone_node_t *)*trie_it_val(it->it); +} + +void zone_tree_it_next(zone_tree_it_t *it) +{ + trie_it_next(it->it); +} + +void zone_tree_it_free(zone_tree_it_t *it) +{ + trie_it_free(it->it); + memset(it, 0, sizeof(*it)); +} + void zone_tree_free(zone_tree_t **tree) { if (tree == NULL || *tree == NULL) { diff --git a/src/knot/zone/zone-tree.h b/src/knot/zone/zone-tree.h index e31ae2c22d..62091a7046 100644 --- a/src/knot/zone/zone-tree.h +++ b/src/knot/zone/zone-tree.h @@ -26,6 +26,14 @@ typedef trie_t zone_tree_t; */ typedef int (*zone_tree_apply_cb_t)(zone_node_t **node, void *data); +/*! + * \brief Zone tree iteration context. + */ +typedef struct { + zone_tree_t *tree; + trie_it_t *it; +} zone_tree_it_t; + /*! * \brief Creates the zone tree. * @@ -135,6 +143,40 @@ void zone_tree_delete_empty(zone_tree_t *tree, zone_node_t *node); */ int zone_tree_apply(zone_tree_t *tree, zone_tree_apply_cb_t function, void *data); +/*! + * \brief Start zone tree iteration. + * + * \param tree Zone tree to iterate over. + * \param it Out: iteration context. It shall be zeroed before. + * + * \return KNOT_OK, KNOT_ENOMEM + */ +int zone_tree_it_begin(zone_tree_t *tree, zone_tree_it_t *it); + +/*! + * \brief Return true iff iteration is finished. + * + * \note The iteration context needs to be freed afterwards nevertheless. + */ +bool zone_tree_it_finished(zone_tree_it_t *it); + +/*! + * \brief Return the node, zone iteration is currently pointing at. + * + * \note Don't call this when zone_tree_it_finished. + */ +zone_node_t *zone_tree_it_val(zone_tree_it_t *it); + +/*! + * \brief Move the iteration to next node. + */ +void zone_tree_it_next(zone_tree_it_t *it); + +/*! + * \brief Free zone iteration context. + */ +void zone_tree_it_free(zone_tree_it_t *it); + /*! * \brief Destroys the zone tree, not touching the saved data. *