Commit fe3ecd05 authored by Dominik Taborsky's avatar Dominik Taborsky

apply: move rollback/update lists from changeset to a apply context structure

parent 6148338b
......@@ -380,8 +380,11 @@ static int ixfrin_finalize(struct answer_data *adata)
struct ixfr_proc *ixfr = adata->ext;
assert(ixfr->state == IXFR_DONE);
apply_ctx_t a_ctx;
apply_init_ctx(&a_ctx);
zone_contents_t *new_contents;
int ret = apply_changesets(ixfr->zone, &ixfr->changesets, &new_contents);
int ret = apply_changesets(&a_ctx, ixfr->zone, &ixfr->changesets, &new_contents);
if (ret != KNOT_EOK) {
IXFRIN_LOG(LOG_WARNING, "failed to apply changes to zone (%s)",
knot_strerror(ret));
......@@ -393,7 +396,7 @@ static int ixfrin_finalize(struct answer_data *adata)
if (ret != KNOT_EOK) {
IXFRIN_LOG(LOG_WARNING, "failed to write changes to journal (%s)",
knot_strerror(ret));
updates_rollback(&ixfr->changesets);
update_rollback(&a_ctx);
update_free_zone(&new_contents);
return ret;
}
......@@ -404,7 +407,7 @@ static int ixfrin_finalize(struct answer_data *adata)
synchronize_rcu();
update_free_zone(&old_contents);
updates_cleanup(&ixfr->changesets);
update_cleanup(&a_ctx);
struct timeval now = {0};
gettimeofday(&now, NULL);
......
......@@ -135,9 +135,9 @@ static void clear_new_rrs(zone_node_t *node, uint16_t type)
}
/*! \brief Stores RR data for update cleanup. */
static int add_old_data(changeset_t *chset, knot_rdata_t *old_data)
static int add_old_data(apply_ctx_t *ctx, knot_rdata_t *old_data)
{
if (ptrlist_add(&chset->old_data, old_data, NULL) == NULL) {
if (ptrlist_add(&ctx->old_data, old_data, NULL) == NULL) {
return KNOT_ENOMEM;
}
......@@ -145,9 +145,9 @@ static int add_old_data(changeset_t *chset, knot_rdata_t *old_data)
}
/*! \brief Stores RR data for update rollback. */
static int add_new_data(changeset_t *chset, knot_rdata_t *new_data)
static int add_new_data(apply_ctx_t *ctx, knot_rdata_t *new_data)
{
if (ptrlist_add(&chset->new_data, new_data, NULL) == NULL) {
if (ptrlist_add(&ctx->new_data, new_data, NULL) == NULL) {
return KNOT_ENOMEM;
}
......@@ -195,7 +195,7 @@ static bool rrset_is_nsec3rel(const knot_rrset_t *rr)
}
/*! \brief Removes single RR from zone contents. */
static int remove_rr(zone_tree_t *tree, zone_node_t *node,
static int remove_rr(apply_ctx_t *ctx, zone_tree_t *tree, zone_node_t *node,
const knot_rrset_t *rr, changeset_t *chset)
{
knot_rrset_t removed_rrset = node_rrset(node, rr->type);
......@@ -206,7 +206,7 @@ static int remove_rr(zone_tree_t *tree, zone_node_t *node,
}
// Store old data for cleanup.
ret = add_old_data(chset, old_data);
ret = add_old_data(ctx, old_data);
if (ret != KNOT_EOK) {
clear_new_rrs(node, rr->type);
return ret;
......@@ -222,7 +222,7 @@ static int remove_rr(zone_tree_t *tree, zone_node_t *node,
if (changed_rrs->rr_count > 0) {
// Subtraction left some data in RRSet, store it for rollback.
ret = add_new_data(chset, changed_rrs->data);
ret = add_new_data(ctx, changed_rrs->data);
if (ret != KNOT_EOK) {
knot_rdataset_clear(changed_rrs, NULL);
return ret;
......@@ -240,7 +240,7 @@ static int remove_rr(zone_tree_t *tree, zone_node_t *node,
}
/*! \brief Removes all RRs from changeset from zone contents. */
static int apply_remove(zone_contents_t *contents, changeset_t *chset)
static int apply_remove(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *chset)
{
changeset_iter_t itt;
changeset_iter_rem(&itt, chset, false);
......@@ -257,7 +257,7 @@ static int apply_remove(zone_contents_t *contents, changeset_t *chset)
zone_tree_t *tree = rrset_is_nsec3rel(&rr) ?
contents->nsec3_nodes : contents->nodes;
int ret = remove_rr(tree, node, &rr, chset);
int ret = remove_rr(ctx, tree, node, &rr, chset);
if (ret != KNOT_EOK) {
changeset_iter_clear(&itt);
return ret;
......@@ -271,7 +271,7 @@ static int apply_remove(zone_contents_t *contents, changeset_t *chset)
}
/*! \brief Adds a single RR into zone contents. */
static int add_rr(const zone_contents_t *zone, zone_node_t *node,
static int add_rr(apply_ctx_t *ctx, const zone_contents_t *zone, zone_node_t *node,
const knot_rrset_t *rr, changeset_t *chset)
{
knot_rrset_t changed_rrset = node_rrset(node, rr->type);
......@@ -284,7 +284,7 @@ static int add_rr(const zone_contents_t *zone, zone_node_t *node,
}
// Store old RRS for cleanup.
ret = add_old_data(chset, old_data);
ret = add_old_data(ctx, old_data);
if (ret != KNOT_EOK) {
clear_new_rrs(node, rr->type);
return ret;
......@@ -296,7 +296,7 @@ static int add_rr(const zone_contents_t *zone, zone_node_t *node,
if (ret == KNOT_EOK || ret == KNOT_ETTL) {
// RR added, store for possible rollback.
knot_rdataset_t *rrs = node_rdataset(node, rr->type);
int data_ret = add_new_data(chset, rrs->data);
int data_ret = add_new_data(ctx, rrs->data);
if (data_ret != KNOT_EOK) {
knot_rdataset_clear(rrs, NULL);
return data_ret;
......@@ -314,7 +314,7 @@ static int add_rr(const zone_contents_t *zone, zone_node_t *node,
}
/*! \brief Adds all RRs from changeset into zone contents. */
static int apply_add(zone_contents_t *contents, changeset_t *chset)
static int apply_add(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *chset)
{
changeset_iter_t itt;
changeset_iter_add(&itt, chset, false);
......@@ -328,7 +328,7 @@ static int apply_add(zone_contents_t *contents, changeset_t *chset)
return KNOT_ENOMEM;
}
int ret = add_rr(contents, node, &rr, chset);
int ret = add_rr(ctx, contents, node, &rr, chset);
if (ret != KNOT_EOK) {
changeset_iter_clear(&itt);
return ret;
......@@ -341,21 +341,21 @@ static int apply_add(zone_contents_t *contents, changeset_t *chset)
}
/*! \brief Replace old SOA with a new one. */
static int apply_replace_soa(zone_contents_t *contents, changeset_t *chset)
static int apply_replace_soa(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *chset)
{
assert(chset->soa_from && chset->soa_to);
int ret = remove_rr(contents->nodes, contents->apex, chset->soa_from, chset);
int ret = remove_rr(ctx, contents->nodes, contents->apex, chset->soa_from, chset);
if (ret != KNOT_EOK) {
return ret;
}
assert(!node_rrtype_exists(contents->apex, KNOT_RRTYPE_SOA));
return add_rr(contents, contents->apex, chset->soa_to, chset);
return add_rr(ctx, contents, contents->apex, chset->soa_to, chset);
}
/*! \brief Apply single change to zone contents structure. */
static int apply_single(zone_contents_t *contents, changeset_t *chset)
static int apply_single(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *chset)
{
/*
* Applies one changeset to the zone. Checks if the changeset may be
......@@ -369,17 +369,17 @@ static int apply_single(zone_contents_t *contents, changeset_t *chset)
return KNOT_EINVAL;
}
int ret = apply_remove(contents, chset);
int ret = apply_remove(ctx, contents, chset);
if (ret != KNOT_EOK) {
return ret;
}
ret = apply_add(contents, chset);
ret = apply_add(ctx, contents, chset);
if (ret != KNOT_EOK) {
return ret;
}
return apply_replace_soa(contents, chset);
return apply_replace_soa(ctx, contents, chset);
}
/* --------------------- Zone copy and finalization ------------------------- */
......@@ -428,9 +428,15 @@ static int finalize_updated_zone(zone_contents_t *contents_copy,
/* ------------------------------- API -------------------------------------- */
int apply_changesets(zone_t *zone, list_t *chsets, zone_contents_t **new_contents)
void apply_init_ctx(apply_ctx_t *ctx)
{
if (zone == NULL || chsets == NULL || EMPTY_LIST(*chsets) || new_contents == NULL) {
init_list(&ctx->old_data);
init_list(&ctx->new_data);
}
int apply_changesets(apply_ctx_t *ctx, zone_t *zone, list_t *chsets, zone_contents_t **new_contents)
{
if (ctx == NULL || zone == NULL || chsets == NULL || EMPTY_LIST(*chsets) || new_contents == NULL) {
return KNOT_EINVAL;
}
......@@ -450,9 +456,9 @@ int apply_changesets(zone_t *zone, list_t *chsets, zone_contents_t **new_content
*/
changeset_t *set = NULL;
WALK_LIST(set, *chsets) {
ret = apply_single(contents_copy, set);
ret = apply_single(ctx, contents_copy, set);
if (ret != KNOT_EOK) {
updates_rollback(chsets);
update_rollback(ctx);
update_free_zone(&contents_copy);
return ret;
}
......@@ -462,7 +468,7 @@ int apply_changesets(zone_t *zone, list_t *chsets, zone_contents_t **new_content
ret = finalize_updated_zone(contents_copy, true);
if (ret != KNOT_EOK) {
updates_rollback(chsets);
update_rollback(ctx);
update_free_zone(&contents_copy);
return ret;
}
......@@ -472,9 +478,9 @@ int apply_changesets(zone_t *zone, list_t *chsets, zone_contents_t **new_content
return KNOT_EOK;
}
int apply_changeset(zone_t *zone, changeset_t *change, zone_contents_t **new_contents)
int apply_changeset(apply_ctx_t *ctx, zone_t *zone, changeset_t *change, zone_contents_t **new_contents)
{
if (zone == NULL || change == NULL || new_contents == NULL) {
if (ctx == NULL || zone == NULL || change == NULL || new_contents == NULL) {
return KNOT_EINVAL;
}
......@@ -489,16 +495,16 @@ int apply_changeset(zone_t *zone, changeset_t *change, zone_contents_t **new_con
return ret;
}
ret = apply_single(contents_copy, change);
ret = apply_single(ctx, contents_copy, change);
if (ret != KNOT_EOK) {
update_rollback(change);
update_rollback(ctx);
update_free_zone(&contents_copy);
return ret;
}
ret = finalize_updated_zone(contents_copy, true);
if (ret != KNOT_EOK) {
update_rollback(change);
update_rollback(ctx);
update_free_zone(&contents_copy);
return ret;
}
......@@ -508,93 +514,71 @@ int apply_changeset(zone_t *zone, changeset_t *change, zone_contents_t **new_con
return KNOT_EOK;
}
int apply_changesets_directly(zone_contents_t *contents, list_t *chsets)
int apply_changesets_directly(apply_ctx_t *ctx, zone_contents_t *contents, list_t *chsets)
{
if (contents == NULL || chsets == NULL) {
if (ctx == NULL || contents == NULL || chsets == NULL) {
return KNOT_EINVAL;
}
changeset_t *set = NULL;
WALK_LIST(set, *chsets) {
int ret = apply_single(contents, set);
int ret = apply_single(ctx, contents, set);
if (ret != KNOT_EOK) {
updates_cleanup(chsets);
update_cleanup(ctx);
return ret;
}
}
int ret = finalize_updated_zone(contents, true);
if (ret != KNOT_EOK) {
updates_cleanup(chsets);
update_cleanup(ctx);
}
return ret;
}
int apply_changeset_directly(zone_contents_t *contents, changeset_t *ch)
int apply_changeset_directly(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *ch)
{
if (contents == NULL || ch == NULL) {
if (ctx == NULL || contents == NULL || ch == NULL) {
return KNOT_EINVAL;
}
int ret = apply_single(contents, ch);
int ret = apply_single(ctx, contents, ch);
if (ret != KNOT_EOK) {
update_cleanup(ch);
update_cleanup(ctx);
return ret;
}
ret = finalize_updated_zone(contents, true);
if (ret != KNOT_EOK) {
update_cleanup(ch);
update_cleanup(ctx);
return ret;
}
return KNOT_EOK;
}
void update_cleanup(changeset_t *change)
void update_cleanup(apply_ctx_t *ctx)
{
if (change) {
if (ctx) {
// Delete old RR data
rrs_list_clear(&change->old_data, NULL);
init_list(&change->old_data);
rrs_list_clear(&ctx->old_data, NULL);
init_list(&ctx->old_data);
// Keep new RR data
ptrlist_free(&change->new_data, NULL);
init_list(&change->new_data);
}
}
void updates_cleanup(list_t *chgs)
{
if (chgs == NULL || EMPTY_LIST(*chgs)) {
return;
ptrlist_free(&ctx->new_data, NULL);
init_list(&ctx->new_data);
}
changeset_t *change = NULL;
WALK_LIST(change, *chgs) {
update_cleanup(change);
};
}
void update_rollback(changeset_t *change)
void update_rollback(apply_ctx_t *ctx)
{
if (change) {
if (ctx) {
// Delete new RR data
rrs_list_clear(&change->new_data, NULL);
init_list(&change->new_data);
rrs_list_clear(&ctx->new_data, NULL);
init_list(&ctx->new_data);
// Keep old RR data
ptrlist_free(&change->old_data, NULL);
init_list(&change->old_data);
}
}
void updates_rollback(list_t *chgs)
{
if (chgs != NULL && !EMPTY_LIST(*chgs)) {
changeset_t *change = NULL;
WALK_LIST(change, *chgs) {
update_rollback(change);
}
ptrlist_free(&ctx->old_data, NULL);
init_list(&ctx->old_data);
}
}
......
......@@ -34,6 +34,20 @@
#include "knot/zone/zone.h"
#include "knot/updates/changesets.h"
struct apply_ctx {
list_t old_data; /*!< Old data, to be freed after successful update. */
list_t new_data; /*!< New data, to be freed after failed update. */
};
typedef struct apply_ctx apply_ctx_t;
/*!
* \brief Initialize a new context structure.
*
* \param ctx Context to be initialized.
*/
void apply_init_ctx(apply_ctx_t *ctx);
/*!
* \brief Applies changesets *with* zone shallow copy.
*
......@@ -43,7 +57,7 @@
*
* \return KNOT_E*
*/
int apply_changesets(zone_t *zone, list_t *chsets,
int apply_changesets(apply_ctx_t *ctx, zone_t *zone, list_t *chsets,
zone_contents_t **new_contents);
/*!
......@@ -55,7 +69,7 @@ int apply_changesets(zone_t *zone, list_t *chsets,
*
* \return KNOT_E*
*/
int apply_changeset(zone_t *zone, changeset_t *ch,
int apply_changeset(apply_ctx_t *ctx, zone_t *zone, changeset_t *ch,
zone_contents_t **new_contents);
/*!
......@@ -66,7 +80,7 @@ int apply_changeset(zone_t *zone, changeset_t *ch,
*
* \return KNOT_E*
*/
int apply_changesets_directly(zone_contents_t *contents, list_t *chsets);
int apply_changesets_directly(apply_ctx_t *ctx, zone_contents_t *contents, list_t *chsets);
/*!
* \brief Applies changeset directly to the zone, without copying it.
......@@ -76,35 +90,21 @@ int apply_changesets_directly(zone_contents_t *contents, list_t *chsets);
*
* \return KNOT_E*
*/
int apply_changeset_directly(zone_contents_t *contents, changeset_t *ch);
/*!
* \brief Cleanups successful zone updates.
* \param chgs Changesets used to create the update.
*/
void updates_cleanup(list_t *chgs);
int apply_changeset_directly(apply_ctx_t *ctx, zone_contents_t *contents, changeset_t *ch);
/*!
* \brief Cleanups successful zone update.
* \param chgs Changeset used to create the update.
*/
void update_cleanup(changeset_t *change);
/*!
* \brief Rollbacks failed zone updates.
*
* \param chgs Changesets used to create the update.
*/
void updates_rollback(list_t *chgs);
void update_cleanup(apply_ctx_t *ctx);
/*!
* \brief Rollbacks failed zone update.
*
* \param chgs Changeset. used to create the update.
*/
void update_rollback(changeset_t *change);
void update_rollback(apply_ctx_t *ctx);
/*!
* \brief Shallow frees zone contents - either shallow copy after failed update
......
......@@ -203,10 +203,6 @@ int changeset_init(changeset_t *ch, const knot_dname_t *apex)
return KNOT_ENOMEM;
}
// Init change lists
init_list(&ch->new_data);
init_list(&ch->old_data);
return KNOT_EOK;
}
......@@ -329,14 +325,6 @@ int changeset_merge(changeset_t *ch1, const changeset_t *ch2)
knot_rrset_free(&ch1->soa_to, NULL);
ch1->soa_to = soa_copy;
ptrnode_t *n;
WALK_LIST(n, ch2->old_data) {
ptrlist_add(&ch1->old_data, (void *)n->d, NULL);
};
WALK_LIST(n, ch2->new_data) {
ptrlist_add(&ch1->new_data, (void *)n->d, NULL);
};
return KNOT_EOK;
}
......@@ -377,14 +365,6 @@ void changeset_clear(changeset_t *ch)
knot_rrset_free(&ch->soa_from, NULL);
knot_rrset_free(&ch->soa_to, NULL);
node_t *n, *nxt;
WALK_LIST_DELSAFE(n, nxt, ch->old_data) {
mm_free(NULL, n);
};
WALK_LIST_DELSAFE(n, nxt, ch->new_data) {
mm_free(NULL, n);
};
// Delete binary data
free(ch->data);
}
......
......@@ -37,8 +37,6 @@ typedef struct {
knot_rrset_t *soa_to; /*!< Destination SOA. */
zone_contents_t *add; /*!< Change additions. */
zone_contents_t *remove; /*!< Change removals. */
list_t old_data; /*!< Old data, to be freed after successful update. */
list_t new_data; /*!< New data, to be freed after failed update. */
size_t size; /*!< Size of serialized changeset. */
uint8_t *data; /*!< Serialized changeset. */
} changeset_t;
......
......@@ -279,28 +279,6 @@ static void remove_rr_from_changeset(zone_contents_t *z, const knot_rrset_t *rr)
}
}
/*!< \brief Removes RR from list, owner and type check. */
static void remove_header_from_changeset(zone_contents_t *z, const knot_rrset_t *rr)
{
zone_node_t *n = zone_contents_find_node_for_rr(z, rr);
if (n == NULL) {
return;
}
knot_rdataset_t *rrs = node_rdataset(n, rr->type);
if (rrs) {
knot_rdataset_clear(rrs, NULL);
node_remove_rdataset(n, rr->type);
}
}
/*!< \brief Removes RR from list, owner check. */
static void remove_owner_from_changeset(zone_contents_t *z, const knot_dname_t *owner)
{
zone_node_t *n = (zone_node_t *)zone_contents_find_node(z, owner);
node_free_rrsets(n, NULL);
}
/* --------------------- true/false helper functions ------------------------ */
static inline bool is_addition(const knot_rrset_t *rr)
......
......@@ -18,7 +18,6 @@
#include "knot/common/log.h"
#include "knot/dnssec/zone-events.h"
#include "knot/updates/apply.h"
#include "knot/zone/serial.h"
#include "libknot/internal/lists.h"
......@@ -121,11 +120,14 @@ static zone_node_t *node_deep_copy(const zone_node_t *node, mm_ctx_t *mm)
static int init_incremental(zone_update_t *update, zone_t *zone)
{
assert(zone->contents);
int ret = changeset_init(&update->change, zone->name);
if (ret != KNOT_EOK) {
return ret;
}
assert(zone->contents);
apply_init_ctx(&update->a_ctx);
// Copy base SOA RR.
update->change.soa_from =
......@@ -253,7 +255,7 @@ const knot_rdataset_t *zone_update_to(zone_update_t *update)
void zone_update_clear(zone_update_t *update)
{
if (update) {
update_cleanup(&update->change);
update_cleanup(&update->a_ctx);
changeset_clear(&update->change);
mp_delete(update->mm.ctx);
memset(update, 0, sizeof(*update));
......@@ -335,7 +337,7 @@ static int sign_update(zone_update_t *update,
}
// Apply DNSSEC changeset
ret = apply_changeset_directly(new_contents, &sec_ch);
ret = apply_changeset_directly(&update->a_ctx, new_contents, &sec_ch);
if (ret != KNOT_EOK) {
changeset_clear(&sec_ch);
return ret;
......@@ -344,7 +346,7 @@ static int sign_update(zone_update_t *update,
// Merge changesets
ret = changeset_merge(&update->change, &sec_ch);
if (ret != KNOT_EOK) {
update_rollback(&sec_ch);
update_rollback(&update->a_ctx);
changeset_clear(&sec_ch);
return ret;
}
......@@ -408,7 +410,7 @@ static int commit_incremental(zone_update_t *update, zone_contents_t **contents_
// Apply changes.
zone_contents_t *new_contents = NULL;
ret = apply_changeset(update->zone, &update->change, &new_contents);
ret = apply_changeset(&update->a_ctx, update->zone, &update->change, &new_contents);
if (ret != KNOT_EOK) {
changeset_clear(&update->change);
return ret;
......@@ -423,7 +425,7 @@ static int commit_incremental(zone_update_t *update, zone_contents_t **contents_
if (dnssec_enable) {
ret = sign_update(update, new_contents);
if (ret != KNOT_EOK) {
update_rollback(&update->change);
update_rollback(&update->a_ctx);
update_free_zone(&new_contents);
changeset_clear(&update->change);
return ret;
......@@ -433,7 +435,7 @@ static int commit_incremental(zone_update_t *update, zone_contents_t **contents_
// Write changes to journal if all went well. (DNSSEC merged)
ret = zone_change_store(update->zone, &update->change);
if (ret != KNOT_EOK) {
update_rollback(&update->change);
update_rollback(&update->a_ctx);
update_free_zone(&new_contents);
return ret;
}
......
......@@ -26,6 +26,7 @@
#pragma once
#include "knot/updates/apply.h"
#include "knot/updates/changesets.h"
#include "knot/zone/contents.h"
#include "knot/zone/zone.h"
......@@ -37,6 +38,7 @@ typedef struct {
zone_t *zone; /*!< Zone being updated. */
zone_contents_t *new_cont; /*!< New zone contents for full updates. */
changeset_t change; /*!< Changes we want to apply. */
apply_ctx_t a_ctx; /*!< Context for applying changesets. */
uint8_t flags; /*!< Zone update flags. */
mm_ctx_t mm; /*!< Memory context used for intermediate nodes. */
} zone_update_t;
......
......@@ -628,8 +628,11 @@ int event_dnssec(zone_t *zone)
bool zone_changed = !changeset_empty(&ch);
if (zone_changed) {
/* Apply change. */
apply_ctx_t a_ctx;
apply_init_ctx(&a_ctx);
zone_contents_t *new_contents = NULL;
int ret = apply_changeset(zone, &ch, &new_contents);
int ret = apply_changeset(&a_ctx, zone, &ch, &new_contents);
if (ret != KNOT_EOK) {
log_zone_error(zone->name, "DNSSEC, failed to sign zone (%s)",
knot_strerror(ret));
......@@ -641,7 +644,7 @@ int event_dnssec(zone_t *zone)
if (ret != KNOT_EOK) {
log_zone_error(zone->name, "DNSSEC, failed to sign zone (%s)",