}
// NOOP if empty changeset/contents.
- if (((zone->control_update->flags & UPDATE_INCREMENTAL) &&
- changeset_empty(&zone->control_update->change)) ||
- ((zone->control_update->flags & UPDATE_FULL) &&
- zone_contents_is_empty(zone->control_update->new_cont))) {
+ if (zone_update_no_change(zone->control_update)) {
zone_control_clear(zone);
return KNOT_EOK;
}
return KNOT_EOK;
}
-static int send_rrset(knot_rrset_t *rrset, send_ctx_t *ctx)
+static int send_rrset(const knot_rrset_t *rrset, send_ctx_t *ctx)
{
if (rrset->type != KNOT_RRTYPE_RRSIG) {
int ret = snprintf(ctx->ttl, sizeof(ctx->ttl), "%u", rrset->ttl);
return KNOT_EOK;
}
+static int send_rrset_callback(const knot_rrset_t *rrset, void *ctx_void)
+{
+ send_ctx_t *ctx = ctx_void;
+ char *owner = knot_dname_to_str(ctx->owner, rrset->owner, sizeof(ctx->owner));
+ if (owner == NULL) {
+ return KNOT_EINVAL;
+ }
+ return send_rrset(rrset, ctx);
+}
+
static int send_node(zone_node_t *node, void *ctx_void)
{
send_ctx_t *ctx = ctx_void;
return ret;
}
-static int send_changeset_part(changeset_t *ch, send_ctx_t *ctx, bool from)
-{
- ctx->data[KNOT_CTL_IDX_FILTERS] = from ? CTL_FILTER_DIFF_REM_R : CTL_FILTER_DIFF_ADD_R;
-
- // Send SOA only if explicitly changed.
- if (ch->soa_to != NULL) {
- knot_rrset_t *soa = from ? ch->soa_from : ch->soa_to;
- assert(soa);
-
- char *owner = knot_dname_to_str(ctx->owner, soa->owner, sizeof(ctx->owner));
- if (owner == NULL) {
- return KNOT_EINVAL;
- }
-
- int ret = send_rrset(soa, ctx);
- if (ret != KNOT_EOK) {
- return ret;
- }
- }
-
- // Send other records.
- changeset_iter_t it;
- int ret = from ? changeset_iter_rem(&it, ch) : changeset_iter_add(&it, ch);
- if (ret != KNOT_EOK) {
- return ret;
- }
-
- knot_rrset_t rrset = changeset_iter_next(&it);
- while (!knot_rrset_empty(&rrset)) {
- char *owner = knot_dname_to_str(ctx->owner, rrset.owner, sizeof(ctx->owner));
- if (owner == NULL) {
- changeset_iter_clear(&it);
- return KNOT_EINVAL;
- }
-
- ret = send_rrset(&rrset, ctx);
- if (ret != KNOT_EOK) {
- changeset_iter_clear(&it);
- return ret;
- }
-
- rrset = changeset_iter_next(&it);
- }
- changeset_iter_clear(&it);
-
- return KNOT_EOK;
-}
-
-static int send_changeset(changeset_t *ch, send_ctx_t *ctx)
-{
- // First send 'from' changeset part.
- int ret = send_changeset_part(ch, ctx, true);
- if (ret != KNOT_EOK) {
- return ret;
- }
-
- // Second send 'to' changeset part.
- return send_changeset_part(ch, ctx, false);
-}
-
static int zone_txn_diff_l(zone_t *zone, ctl_args_t *args)
{
if (zone->control_update == NULL) {
send_ctx_t *ctx = &ctl_globals[args->thread_idx].send_ctx;
int ret = init_send_ctx(ctx, zone->name, args);
- if (ret != KNOT_EOK) {
- return ret;
+ if (ret == KNOT_EOK) {
+ ctx->data[KNOT_CTL_IDX_FILTERS] = CTL_FILTER_DIFF_REM_R;
+ ret = zone_update_foreach(zone->control_update, false, send_rrset_callback, ctx);
+ }
+ if (ret == KNOT_EOK) {
+ ctx->data[KNOT_CTL_IDX_FILTERS] = CTL_FILTER_DIFF_ADD_R;
+ ret = zone_update_foreach(zone->control_update, true, send_rrset_callback, ctx);
}
- return send_changeset(&zone->control_update->change, ctx);
+ return ret;
}
static int zone_txn_diff(zone_t *zone, ctl_args_t *args)
} else if (update->flags & (UPDATE_INCREMENTAL | UPDATE_HYBRID)) {
return changeset_empty(&update->change);
} else {
- /* This branch does not make much sense and FULL update will most likely
- * be a change every time anyway, just return false. */
- return false;
+ return zone_contents_is_empty(update->new_cont);
+ }
+}
+
+static int rrset_foreach(zone_node_t *n, bool subtract_counterpart,
+ int idx, uint16_t rrtype, // two exclusive possibilities how to define which rrset in the node
+ rrset_cb_t cb, void *ctx)
+{
+ knot_rrset_t rr = (rrtype == KNOT_RRTYPE_ANY) ? node_rrset_at(n, idx) : node_rrset(n, rrtype);
+ knot_rrset_t rrc = subtract_counterpart ? node_rrset(binode_counterpart(n), rr.type) : (knot_rrset_t){ 0 };
+ if (rrtype == KNOT_RRTYPE_ANY && rr.type == KNOT_RRTYPE_SOA) {
+ return KNOT_EOK; // ignore SOA if rrset specified by idx
+ } else if (knot_rrset_empty(&rrc)) {
+ return cb(&rr, ctx);
+ } else if (knot_rdataset_subset(&rr.rrs, &rrc.rrs)) {
+ return KNOT_EOK;
+ } else {
+ knot_rdataset_t rd_copy = { 0 };
+ int ret = knot_rdataset_copy(&rd_copy, &rr.rrs, NULL);
+ if (ret == KNOT_EOK) {
+ ret = knot_rdataset_subtract(&rd_copy, &rrc.rrs, NULL);
+ }
+ if (ret == KNOT_EOK) {
+ rr.rrs = rd_copy;
+ ret = cb(&rr, ctx);
+ }
+ knot_rdataset_clear(&rd_copy, NULL);
+ return ret;
+ }
+}
+
+static int trees_foreach(zone_tree_t *nodes, zone_tree_t *nsec3_nodes, bool subtract_counterparts,
+ rrset_cb_t cb, void *ctx)
+{
+ zone_tree_it_t it = { 0 };
+ int ret = zone_tree_it_double_begin(nodes, nsec3_nodes, &it);
+ while (!zone_tree_it_finished(&it) && ret == KNOT_EOK) {
+ zone_node_t *n = zone_tree_it_val(&it);
+ for (int i = 0; i < n->rrset_count && ret == KNOT_EOK; i++) {
+ ret = rrset_foreach(n, subtract_counterparts, i, KNOT_RRTYPE_ANY, cb, ctx);
+ }
+ zone_tree_it_next(&it);
+ }
+ zone_tree_it_free(&it);
+ return ret;
+}
+
+int zone_update_foreach(zone_update_t *update, bool additions, rrset_cb_t cb, void *ctx)
+{
+ if (update == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ if (update->flags & UPDATE_NO_CHSET) {
+ zone_diff_t diff;
+ get_zone_diff(&diff, update);
+ if (!additions) {
+ zone_diff_reverse(&diff);
+ }
+
+ int ret = rrset_foreach(diff.apex, true, 0, KNOT_RRTYPE_SOA, cb, ctx);
+ if (ret == KNOT_EOK) {
+ ret = trees_foreach(&diff.nodes, &diff.nsec3s, true, cb, ctx);
+ }
+ return ret;
+ } else if (update->flags & (UPDATE_INCREMENTAL | UPDATE_HYBRID)) {
+ knot_rrset_t *soa = additions ? update->change.soa_to : update->change.soa_from;
+ zone_contents_t *c = additions ? update->change.add : update->change.remove;
+ int ret = (soa == NULL) ? KNOT_EOK : cb(soa, ctx);
+ if (ret == KNOT_EOK) {
+ ret = trees_foreach(c->nodes, c->nsec3_nodes, false, cb, ctx);
+ }
+ return ret;
+ } else if (additions) {
+ knot_rrset_t soa = node_rrset(update->new_cont->apex, KNOT_RRTYPE_SOA);
+ int ret = knot_rrset_empty(&soa) ? KNOT_EOK : cb(&soa, ctx);
+ if (ret == KNOT_EOK) {
+ ret = trees_foreach(update->new_cont->nodes, update->new_cont->nsec3_nodes, false, cb, ctx);
+ }
+ return ret;
+ } else {
+ return KNOT_EOK;
}
}
*/
bool zone_update_no_change(zone_update_t *update);
+typedef int (*rrset_cb_t)(const knot_rrset_t *, void *);
+/*!
+ * \brief Run callback for every removed/added RRset in this update.
+ *
+ * \param update Zone update in question.
+ * \param additions Apply on addition (removals otherwise).
+ * \param cb Callback to call for each changed RRset.
+ * \param ctx Arbitrary context for the callback.
+ *
+ * \return KNOT_E* emitted by the callback or error in iteration.
+ */
+int zone_update_foreach(zone_update_t *update, bool additions, rrset_cb_t cb, void *ctx);
+
/*!
* \brief Return whether apex DNSKEY, CDNSKEY, or CDS is updated.
*/
resp.check(rcode="SERVFAIL")
resp.check_count(0, "SOA")
+slave.ctl("zone-diff " + ZONE)
slave.ctl("zone-commit " + ZONE)
t.sleep(2)
resp = slave.dig(ZONE, "SOA")
t.sleep(2)
log_count_expect(slave, LOG, 3)
+slave.ctl("zone-diff " + ZONE)
+
slave.ctl("zone-commit " + ZONE)
t.sleep(2)
resp = slave.dig(ZONE, "SOA")
t.sleep(2)
log_count_expect(slave, LOG, 5)
+slave.ctl("zone-diff " + ZONE)
slave.ctl("zone-commit " + ZONE)
t.sleep(2)
resp = slave.dig(ZONE, "SOA")