Commit da4d0dc5 authored by Jan Kadlec's avatar Jan Kadlec

changeset: Journal operations with single changeset

parent 77aab373
......@@ -327,16 +327,33 @@ static int ixfrin_answer_init(struct answer_data *data)
static int ixfrin_finalize(struct answer_data *adata)
{
struct ixfr_proc *ixfr = adata->ext;
assert(ixfr->state == IXFR_DONE);
int ret = zone_change_apply_and_store(&ixfr->changesets,
ixfr->zone, "IXFR");
zone_contents_t *new_contents;
int ret = apply_changesets(ixfr->zone, &ixfr->changesets, &new_contents);
if (ret != KNOT_EOK) {
IXFRIN_LOG(LOG_ERR, "Failed to apply changes to zone - %s",
knot_strerror(ret));
return ret;
}
/* Write changes to journal. */
ret = zone_changes_store(ixfr->zone, &ixfr->changesets);
if (ret != KNOT_EOK) {
IXFRIN_LOG(LOG_ERR, "Failed to apply changes to zone - %s",
knot_strerror(ret));
updates_rollback(&ixfr->changesets);
update_free_old_zone(&new_contents);
return ret;
}
/* Switch zone contents. */
zone_contents_t *old_contents = zone_switch_contents(ixfr->zone, new_contents);
synchronize_rcu();
update_free_old_zone(&old_contents);
updates_cleanup(&ixfr->changesets);
struct timeval now = {0};
gettimeofday(&now, NULL);
IXFRIN_LOG(LOG_INFO, "Finished in %.02fs (%u messages, %s%.*f %s).",
......
......@@ -152,7 +152,6 @@ static int process_authenticated(uint16_t *rcode, struct query_data *qdata)
zone_contents_t *new_contents = NULL;
const bool change_made = !changeset_empty(&ddns_ch);
list_t apply;
if (change_made) {
ret = apply_changeset(zone, &ddns_ch, &new_contents);
if (ret != KNOT_EOK) {
......@@ -191,7 +190,7 @@ static int process_authenticated(uint16_t *rcode, struct query_data *qdata)
}
// Write changes to journal if all went well. (DNSSEC merged)
ret = zone_change_store(zone, &apply);
ret = zone_change_store(zone, &ddns_ch);
if (ret != KNOT_EOK) {
update_rollback(&ddns_ch);
update_free_old_zone(&new_contents);
......@@ -216,7 +215,7 @@ static int process_authenticated(uint16_t *rcode, struct query_data *qdata)
// Clear obsolete zone contents
update_free_old_zone(&old_contents);
updates_cleanup(&apply);
update_cleanup(&ddns_ch);
changeset_clear(&ddns_ch);
/* Sync zonefile immediately if configured. */
......
......@@ -1219,17 +1219,32 @@ int journal_store_changesets(list_t *src, const char *path, size_t size_limit)
/* Begin writing to journal. */
changeset_t *chs = NULL;
WALK_LIST(chs, *src) {
/* Make key from serials. */
ret = changeset_pack(chs, journal);
if (ret != KNOT_EOK) {
break;
}
}
/*! @note If the journal is full, this function returns KNOT_EBUSY. */
journal_close(journal);
return ret;
}
int journal_store_changeset(changeset_t *change, const char *path, size_t size_limit)
{
if (change == NULL || path == NULL) {
return KNOT_EINVAL;
}
/* Open journal for reading. */
journal_t *journal = journal_open(path, size_limit);
if (journal == NULL) {
return KNOT_ENOMEM;
}
int ret = changeset_pack(change, journal);
/* Written changesets to journal. */
return journal_close(journal);
journal_close(journal);
return ret;
}
static void mark_synced(journal_t *journal, journal_node_t *node)
......
......@@ -192,6 +192,7 @@ int journal_load_changesets(const struct zone_t *zone, list_t *dst,
* \return < KNOT_EOK on other errors.
*/
int journal_store_changesets(list_t *src, const char *path, size_t size_limit);
int journal_store_changeset(changeset_t *change, const char *path, size_t size_limit);
/*! \brief Function for unmarking dirty nodes. */
/*!
......
......@@ -29,6 +29,7 @@
#include "knot/zone/zone.h"
#include "knot/zone/zone-load.h"
#include "knot/zone/zonefile.h"
#include "knot/updates/apply.h"
#include "libknot/rrtype/soa.h"
#include "libknot/dnssec/random.h"
#include "knot/nameserver/internet.h"
......@@ -525,15 +526,31 @@ static int event_dnssec(zone_t *zone)
}
if (!changeset_empty(&ch)) {
list_t apply;
init_list(&apply);
add_head(&apply, &ch.n);
ret = zone_change_apply_and_store(&apply, zone, "DNSSEC");
/* Apply change. */
zone_contents_t *new_contents;
int ret = apply_changeset(zone, &ch, &new_contents);
if (ret != KNOT_EOK) {
log_zone_error("%s Could not sign zone (%s).\n",
msgpref, knot_strerror(ret));
msgpref, knot_strerror(ret));
goto done;
}
/* Write change to journal. */
ret = zone_change_store(zone, &ch);
if (ret != KNOT_EOK) {
log_zone_error("%s Could not sign zone (%s).\n",
msgpref, knot_strerror(ret));
update_rollback(&ch);
update_free_old_zone(&new_contents);
goto done;
}
/* Switch zone contents. */
zone_contents_t *old_contents = zone_switch_contents(zone, new_contents);
synchronize_rcu();
update_free_old_zone(&old_contents);
update_cleanup(&ch);
}
// Schedule dependent events.
......
......@@ -189,10 +189,7 @@ int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_ref
/* Write changes (DNSSEC, diff, or both) to journal if all went well. */
if (!changeset_empty(&change)) {
list_t apply;
init_list(&apply);
add_head(&apply, &change.n);
ret = zone_change_store(zone, &apply);
ret = zone_change_store(zone, &change);
}
changeset_clear(&change);
......
......@@ -105,14 +105,14 @@ void zone_free(zone_t **zone_ptr)
*zone_ptr = NULL;
}
int zone_change_store(zone_t *zone, list_t *chgs)
int zone_change_store(zone_t *zone, changeset_t *change)
{
assert(zone);
assert(chgs);
assert(change);
conf_zone_t *conf = zone->conf;
int ret = journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
int ret = journal_store_changeset(change, conf->ixfr_db, conf->ixfr_fslimit);
if (ret == KNOT_EBUSY) {
log_zone_notice("Journal for '%s' is full, flushing.\n", conf->name);
......@@ -122,43 +122,33 @@ int zone_change_store(zone_t *zone, list_t *chgs)
return ret;
}
return journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
return journal_store_changeset(change, conf->ixfr_db, conf->ixfr_fslimit);
}
return ret;
}
/*! \note @mvavrusa Moved from zones.c, this needs a common API. */
int zone_change_apply_and_store(list_t *chgs,
zone_t *zone,
const char *msgpref)
int zone_changes_store(zone_t *zone, list_t *chgs)
{
int ret = KNOT_EOK;
assert(zone);
assert(chgs);
zone_contents_t *new_contents;
ret = apply_changesets(zone, chgs, &new_contents);
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to apply changesets.\n", msgpref);
return ret;
}
conf_zone_t *conf = zone->conf;
/* Write changes to journal. */
ret = zone_change_store(zone, chgs);
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to store changesets.\n", msgpref);
updates_rollback(chgs);
update_free_old_zone(&new_contents);
return ret;
}
int ret = journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
if (ret == KNOT_EBUSY) {
log_zone_notice("Journal for '%s' is full, flushing.\n", conf->name);
/* Switch zone contents. */
zone_contents_t *old_contents = zone_switch_contents(zone, new_contents);
synchronize_rcu();
update_free_old_zone(&old_contents);
/* Transaction rolled back, journal released, we may flush. */
ret = zone_flush_journal(zone);
if (ret != KNOT_EOK) {
return ret;
}
updates_cleanup(chgs);
return journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
}
return KNOT_EOK;
return ret;
}
zone_contents_t *zone_switch_contents(zone_t *zone, zone_contents_t *new_contents)
......
......@@ -94,13 +94,8 @@ void zone_free(zone_t **zone_ptr);
* \ref #223 New zone API
* \todo get rid of this
*/
int zone_change_store(zone_t *zone, list_t *chgs);
/*! \note @mvavrusa Moved from zones.c, this needs a common API.
* \todo and this
*/
int zone_change_apply_and_store(list_t *chs,
zone_t *zone,
const char *msgpref);
int zone_changes_store(zone_t *zone, list_t *chgs);
int zone_change_store(zone_t *zone, changeset_t *change);
/*!
* \brief Atomically switch the content of the zone.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment