Commit 4fe409c0 authored by Marek Vavruša's avatar Marek Vavruša

journal: implemented apply_changes, moved code around

- deprecated journal functionality was thrown away
- half of the code from zones.c was moved to appropriate places (zone,
  zonefile, journal)
- there are still several functions that should rather be in the
  changesets code, TBD
parent b0b1eb92
......@@ -120,7 +120,7 @@ static int remote_zone_refresh(server_t *server, const zone_t *zone)
return KNOT_EINVAL;
}
zones_schedule_refresh((zone_t *)zone, REFRESH_NOW);
#warning Implement me (schedule zone refresh)
return KNOT_EOK;
}
......@@ -132,7 +132,7 @@ static int remote_zone_flush(server_t *server, const zone_t *zone)
return KNOT_EINVAL;
}
zones_schedule_zonefile_sync((zone_t *)zone, 0);
#warning Implement me (schedule zone file flush)
return KNOT_EOK;
}
......
......@@ -199,7 +199,7 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
AXFR_LOG(LOG_ERR, "Failed to start (%s).", knot_strerror(ret));
return ret;
} else {
AXFR_LOG(LOG_INFO, "Started (serial %u).", knot_zone_serial(qdata->zone->contents));
AXFR_LOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
}
}
......@@ -249,8 +249,8 @@ int axfr_process_answer(knot_ns_xfr_t *xfr)
zone_contents_t *zone = (zone_contents_t *)xfr->data;
assert(zone != NULL);
log_zone_info("%s Serial %u -> %u\n", xfr->msg,
knot_zone_serial(xfr->zone->contents),
knot_zone_serial(zone));
zone_contents_serial(xfr->zone->contents),
zone_contents_serial(zone));
dbg_ns_verb("ns_process_axfrin: adjusting zone.\n");
int rc = zone_contents_adjust_full(zone, NULL, NULL);
......
......@@ -145,8 +145,8 @@ static int ixfr_load_chsets(knot_changesets_t **chgsets, const zone_t *zone,
return KNOT_ENOMEM;
}
/*! \todo This is a candidate for function relocation. */
ret = zones_load_changesets(zone, *chgsets, serial_from, serial_to);
ret = journal_load_changesets(zone->conf->ixfr_db, *chgsets,
serial_from, serial_to);
if (ret != KNOT_EOK) {
knot_changesets_free(chgsets);
}
......
......@@ -158,7 +158,7 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
struct timeval t_start = {0}, t_end = {0};
gettimeofday(&t_start, NULL);
UPDATE_LOG(LOG_INFO, "Started (serial %u).", knot_zone_serial(qdata->zone->contents));
UPDATE_LOG(LOG_INFO, "Started (serial %u).", zone_contents_serial(qdata->zone->contents));
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, tsig_wire_maxsize(qdata->sign.tsig_key));
......@@ -390,9 +390,9 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
}
// Merge changesets
journal_t *transaction = NULL;
journal_t *journal = NULL;
ret = zones_merge_and_store_changesets(zone, chgsets, sec_chs,
&transaction);
&journal);
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to save new entry to journal (%s)\n",
msg, knot_strerror(ret));
......@@ -416,7 +416,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to sign incoming update (%s)"
"\n", msg, knot_strerror(ret));
zones_store_changesets_rollback(transaction);
zones_store_changesets_rollback(journal);
zones_free_merged_changesets(chgsets, sec_chs);
return ret;
}
......@@ -427,7 +427,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to replan zone sign (%s)\n",
msg, knot_strerror(ret));
zones_store_changesets_rollback(transaction);
zones_store_changesets_rollback(journal);
zones_free_merged_changesets(chgsets, sec_chs);
return ret;
}
......@@ -435,7 +435,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
// Set NSEC3 nodes if no new signatures were created (or auto DNSSEC is off)
ret = zone_contents_adjust_nsec3_pointers(new_contents);
if (ret != KNOT_EOK) {
zones_store_changesets_rollback(transaction);
zones_store_changesets_rollback(journal);
zones_free_merged_changesets(chgsets, sec_chs);
xfrin_rollback_update(zone->contents, &new_contents,
chgsets->changes);
......@@ -445,8 +445,8 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
}
// Commit transaction.
if (transaction) {
ret = zones_store_changesets_commit(transaction);
if (journal) {
ret = zones_store_changesets_commit(journal);
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to commit new journal entry "
"(%s).\n", msg, knot_strerror(ret));
......@@ -498,7 +498,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query,
/* Sync zonefile immediately if configured. */
if (zone->conf->dbsync_timeout == 0) {
zones_schedule_zonefile_sync(zone, 0);
#warning Implement me (schedule zone file flush to now)
}
return ret;
......
This diff is collapsed.
......@@ -45,6 +45,7 @@
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include "knot/updates/changesets.h"
/*!
* \brief Journal entry flags.
......@@ -86,8 +87,6 @@ typedef struct journal_node_t
typedef struct journal_t
{
int fd;
struct flock fl; /*!< File lock. */
pthread_mutex_t mutex; /*!< Synchronization mutex. */
char *path; /*!< Path to journal file. */
uint16_t tmark; /*!< Transaction start mark. */
uint16_t max_nodes; /*!< Number of nodes. */
......@@ -100,23 +99,6 @@ typedef struct journal_t
journal_node_t *nodes; /*!< Array of nodes. */
} journal_t;
/*!
* \brief Entry identifier compare function.
*
* \retval -n if k1 < k2
* \retval +n if k1 > k2
* \retval 0 if k1 == k2
*/
typedef int (*journal_cmp_t)(uint64_t k1, uint64_t k2);
/*!
* \brief Function prototype for journal_walk() function.
*
* \param j Associated journal.
* \param n Pointer to target node.
*/
typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n);
/*
* Journal defaults and constants.
*/
......@@ -126,88 +108,16 @@ typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n);
/* HEADER = magic, crc, max_entries, qhead, qtail */
#define JOURNAL_HSIZE (MAGIC_LENGTH + sizeof(crc_t) + sizeof(uint16_t) * 3)
/*!
* \brief Create new journal.
*
* \param fn Journal file name, will be created if not exist.
* \param max_nodes Maximum number of nodes in journal.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_EINVAL if the file with given name cannot be created.
* \retval KNOT_ERROR on I/O error.
*/
int journal_create(const char *fn, uint16_t max_nodes);
/*!
* \brief Open journal.
*
* \warning This doesn't open the file yet, just sets up the structure.
* Call \fn journal_retain before reading/writing the journal.
*
* \param fn Journal file name.
* \param fslimit File size limit (0 for no limit).
* \param bflags Initial flags for each written node.
*
* \retval new journal instance if successful.
* \retval NULL on error.
*/
journal_t* journal_open(const char *fn, size_t fslimit, uint16_t bflags);
/*!
* \brief Fetch entry node for given identifier.
*
* \param journal Associated journal.
* \param id Entry identifier.
* \param cf Compare function (NULL for equality).
* \param dst Destination for journal entry.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_ENOENT if not found.
*/
int journal_fetch(journal_t *journal, uint64_t id,
journal_cmp_t cf, journal_node_t** dst);
/*!
* \brief Read journal entry data.
*
* \param journal Associated journal.
* \param id Entry identifier.
* \param cf Compare function (NULL for equality).
* \param dst Pointer to destination memory.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_ENOENT if the entry cannot be found.
* \retval KNOT_EINVAL if the entry is invalid.
* \retval KNOT_ERROR on I/O error.
*/
int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst);
/*!
* \brief Read journal entry data.
*
* \param journal Associated journal.
* \param n Entry.
* \param dst Pointer to destination memory.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_ENOENT if the entry cannot be found.
* \retval KNOT_EINVAL if the entry is invalid.
* \retval KNOT_ERROR on I/O error.
*/
int journal_read_node(journal_t *journal, journal_node_t *n, char *dst);
/*!
* \brief Write journal entry data.
*
* \param journal Associated journal.
* \param id Entry identifier.
* \param src Pointer to source data.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_EAGAIN if no free node is available, need to remove dirty nodes.
* \retval KNOT_ERROR on I/O error.
*/
int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size);
journal_t* journal_open(const char *path, size_t fslimit);
/*!
* \brief Map journal entry for read/write.
......@@ -217,12 +127,13 @@ int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size)
* \param journal Associated journal.
* \param id Entry identifier.
* \param dst Will contain mapped memory.
* \param rdonly If read only.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_EAGAIN if no free node is available, need to remove dirty nodes.
* \retval KNOT_ERROR on I/O error.
*/
int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size);
int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size, bool rdonly);
/*!
* \brief Finalize mapped journal entry.
......@@ -239,54 +150,6 @@ int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size);
*/
int journal_unmap(journal_t *journal, uint64_t id, void *ptr, int finalize);
/*!
* \brief Return least recent node (journal head).
*
* \param journal Associated journal.
*
* \retval node if successful.
* \retval NULL if empty.
*/
static inline journal_node_t *journal_head(journal_t *journal) {
return journal->nodes + journal->qhead;
}
/*!
* \brief Return node after most recent node (journal tail).
*
* \param journal Associated journal.
*
* \retval node if successful.
* \retval NULL if empty.
*/
static inline journal_node_t *journal_end(journal_t *journal) {
return journal->nodes + journal->qtail;
}
/*!
* \brief Apply function to each node.
*
* \param journal Associated journal.
* \param apply Function to apply to each node.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_EINVAL on invalid parameters.
*/
int journal_walk(journal_t *journal, journal_apply_t apply);
/*!
* \brief Sync node state to permanent storage.
*
* \note May be used for journal_walk().
*
* \param journal Associated journal.
* \param n Pointer to node (must belong to associated journal).
*
* \retval KNOT_EOK on success.
* \retval KNOT_EINVAL on invalid parameters.
*/
int journal_update(journal_t *journal, journal_node_t *n);
/*!
* \brief Begin transaction of multiple entries.
*
......@@ -339,45 +202,22 @@ int journal_close(journal_t *journal);
/*!
* \brief Check if the journal file is used or not.
*
* \param journal Journal.
* \param path Journal file.
*
* \return true or false
*/
bool journal_is_used(journal_t *journal);
bool journal_exists(const char *path);
/*!
* \brief Retain journal for use.
* \brief Load changesets from journal.
*
* \param journal Journal.
*
* \retval KNOT_EOK
* \retval KNOT_EBUSY
* \retval KNOT_EINVAL
* \retval KNOT_ERROR
*/
int journal_retain(journal_t *journal);
/*!
* \brief Release retained journal.
*
* \param journal Retained journal.
* \param changesets Double pointer to changesets structure to be freed.
*/
void journal_release(journal_t *journal);
int journal_load_changesets(const char *path, knot_changesets_t *dst,
uint32_t from, uint32_t to);
/*!
* \brief Recompute journal CRC.
*
* \warning Use only if you altered the journal file somehow
* and need it to pass CRC checks. CRC check normally
* checks file integrity, so you should not touch it unless
* you know what you're doing.
*
* \param fd Open journal file.
*
* \retval KNOT_EOK on success.
* \retval KNOT_EINVAL if not valid fd.
*/
int journal_update_crc(int fd);
/*! \brief Function for unmarking dirty nodes. */
int journal_mark_synced(const char *path);
#endif /* _KNOTD_JOURNAL_H_ */
......
......@@ -339,7 +339,7 @@ static int xfr_task_expire(fdset_t *set, int i, knot_ns_xfr_t *rq)
if ((long)--rq->data > 0) { /* Retries */
rq->send(rq->session, (struct sockaddr *)&rq->addr, rq->wire, rq->wire_size);
log_zone_info("%s Query issued (serial %u).\n",
rq->msg, knot_zone_serial(zone->contents));
rq->msg, zone_contents_serial(zone->contents));
fdset_set_watchdog(set, i, NOTIFY_TIMEOUT);
return KNOT_EOK; /* Keep state. */
}
......@@ -562,7 +562,7 @@ static int xfr_async_finish(fdset_t *set, unsigned id)
/* NOTIFY is special. */
if (rq->type == XFR_TYPE_NOTIFY) {
log_zone_info("%s Query issued (serial %u).\n",
rq->msg, knot_zone_serial(rq->zone->contents));
rq->msg, zone_contents_serial(rq->zone->contents));
} else if (ret == KNOT_EOK) {
log_zone_info("%s %s\n", rq->msg, msg);
} else {
......@@ -723,7 +723,7 @@ static int xfr_task_resp(xfrhandler_t *xfr, knot_ns_xfr_t *rq)
if (ret == KNOT_EUPTODATE) { /* Check up-to-date zone. */
log_zone_info("%s %s (serial %u)\n", rq->msg,
knot_strerror(ret),
knot_zone_serial(rq->zone->contents));
zone_contents_serial(rq->zone->contents));
ret = KNOT_ECONNREFUSED;
} else if (ret == KNOT_EOK) { /* Disconnect if everything went well. */
ret = KNOT_ECONNREFUSED;
......@@ -844,8 +844,7 @@ static int xfr_task_xfer(xfrhandler_t *xfr, knot_ns_xfr_t *rq)
/* Sync zonefile immediately if configured. */
if (rq->type == XFR_TYPE_IIN && zone->conf->dbsync_timeout == 0) {
dbg_zones("%s: syncing zone immediately\n", __func__);
zones_schedule_zonefile_sync(zone, 0);
#warning Implement me (schedule zone file flush to now)
}
/* Update REFRESH/RETRY */
......
This diff is collapsed.
......@@ -49,24 +49,6 @@
#define REFRESH_DEFAULT -1 /* Use time value from zone structure. */
#define REFRESH_NOW (knot_random_uint16_t() % 1000) /* Now, but with jitter. */
/*!
* \brief Sync zone data back to text zonefile.
*
* In case when SOA serial of the zonefile differs from the SOA serial of the
* loaded zone, zonefile needs to be updated.
*
* \note Current implementation rewrites the zone file.
*
* \param zone Evaluated zone.
* \param journal Journal to sync.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_ERANGE if zonefile is in sync with journal.
* \retval KNOT_EINVAL on invalid parameter.
* \retval KNOT_ERROR on unspecified error during processing.
*/
int zones_zonefile_sync(zone_t *zone, journal_t *journal);
/*!
* \brief Processes normal response packet.
*
......@@ -109,7 +91,7 @@ int zones_save_zone(const knot_ns_xfr_t *xfr);
* \todo Expects the xfr structure to be initialized in some way.
* \todo Update documentation!!!
*/
int zones_store_changesets(zone_t *zone, knot_changesets_t *src, journal_t *j);
int zones_store_changesets(knot_changesets_t *src, journal_t *j);
/*!
* \brief Begin changesets storing transaction.
......@@ -137,16 +119,6 @@ int zones_store_changesets_commit(journal_t *j);
*/
int zones_store_changesets_rollback(journal_t *j);
/*! \todo Document me. */
int zones_changesets_from_binary(knot_changesets_t *chgsets);
/*! \todo Document me. */
int zones_changesets_to_binary(knot_changesets_t *chgsets);
int zones_load_changesets(const zone_t *zone,
knot_changesets_t *dst,
uint32_t from, uint32_t to) __attribute__((deprecated));
/*!
* \brief Creates changesets from zones difference.
*
......@@ -212,14 +184,6 @@ int zones_cancel_dnssec(zone_t *zone);
*/
int zones_schedule_dnssec(zone_t *zone, time_t unixtime);
/*!
* \brief Schedule IXFR sync for given zone.
*
* \param zone Zone to scheduler IXFR sync for.
* \param timeout Sync time in seconds.
*/
void zones_schedule_zonefile_sync(zone_t *zone, uint32_t timeout);
/*!
* \brief Verify TSIG in query.
*
......@@ -236,18 +200,6 @@ int zones_verify_tsig_query(const knot_pkt_t *query,
knot_rcode_t *rcode, uint16_t *tsig_rcode,
uint64_t *tsig_prev_time_signed);
/*!
* \brief Apply changesets to zone from journal.
*
* \param zone Specified zone.
*
* \retval KNOT_EOK if successful.
* \retval KNOT_EINVAL on invalid parameters.
* \retval KNOT_ENOENT if zone has no contents.
* \retval KNOT_ERROR on unspecified error.
*/
int zones_journal_apply(zone_t *zone);
/*!
* \brief Creates diff and DNSSEC changesets and stores them to journal.
*
......@@ -269,7 +221,6 @@ int zones_dnssec_sign(zone_t *zone, bool force, uint32_t *expires_at);
int zones_expire_ev(event_t *event);
int zones_refresh_ev(event_t *event);
int zones_flush_ev(event_t *event);
int zones_dnssec_ev(event_t *event);
/*! \note Exported API for UPDATE processing, but this should really be done
......
......@@ -1484,7 +1484,7 @@ void zone_contents_deep_free(zone_contents_t **contents)
/*----------------------------------------------------------------------------*/
uint32_t knot_zone_serial(const zone_contents_t *zone)
uint32_t zone_contents_serial(const zone_contents_t *zone)
{
if (!zone) return 0;
const knot_rrset_t *soa = NULL;
......@@ -1496,3 +1496,8 @@ bool zone_contents_is_signed(const zone_contents_t *zone)
{
return knot_node_rrtype_is_signed(zone->apex, KNOT_RRTYPE_SOA);
}
bool zone_contents_is_empty(const zone_contents_t *zone)
{
return !zone || !knot_node_rrset(zone->apex, KNOT_RRTYPE_SOA);
}
......@@ -437,11 +437,14 @@ void zone_contents_deep_free(zone_contents_t **contents);
*
* \return serial or 0
*/
uint32_t knot_zone_serial(const zone_contents_t *zone);
uint32_t zone_contents_serial(const zone_contents_t *zone);
/*!
* \brief Return true if zone is signed.
*/
bool zone_contents_is_signed(const zone_contents_t *zone);
/*! \brief Return true if zone contents is empty. */
bool zone_contents_is_empty(const zone_contents_t *zone);
/*! @} */
......@@ -39,7 +39,7 @@ static int event_reload(zone_t *zone)
return KNOT_ERROR; // TODO: specific error code
}
int result = apply_journal(content, zone->ixfr_db);
int result = apply_journal(content, zone->conf);
if (result != KNOT_EOK) {
zone_contents_free(&content);
return result;
......@@ -82,6 +82,28 @@ static int event_expire(zone_t *zone)
static int event_flush(zone_t *zone)
{
#warning Implement me.
#if 0
assert(event);
dbg_zones("zone: zonefile SYNC timer event\n");
/* Fetch zone. */
zone_t *zone = (zone_t *)event->data;
if (!zone) {
return KNOT_EINVAL;
}
int ret = zones_zonefile_sync_from_ev(zone);
/* Reschedule. */
rcu_read_lock();
int next_timeout = zone->conf->dbsync_timeout;
if (next_timeout > 0) {
zones_schedule_zonefile_sync(zone, next_timeout * 1000);
}
rcu_read_unlock();
return ret;
#endif
return KNOT_ERROR;
}
......
......@@ -20,6 +20,7 @@
#include "knot/zone/load.h"
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
#include "knot/updates/xfr-in.h"
#include "libknot/rdata.h"
zone_contents_t *zone_load_contents(conf_zone_t *conf)
......@@ -44,8 +45,52 @@ zone_contents_t *zone_load_contents(conf_zone_t *conf)
/*!
* \brief Apply changesets to zone from journal.
*/
int apply_journal(zone_contents_t *contents, journal_t *journal)
int apply_journal(zone_contents_t *contents, conf_zone_t *conf)
{
#warning "Not implemented but returns KNOT_EOK."
return KNOT_EOK;
/* Check if journal is used and zone is not empty. */
if (!journal_exists(conf->ixfr_db) || zone_contents_is_empty(contents)) {
return KNOT_EOK;
}
/* Fetch SOA serial. */
const knot_rrset_t *soa = knot_node_rrset(contents->apex, KNOT_RRTYPE_SOA);
uint32_t serial = knot_rdata_soa_serial(soa);
/* Load all pending changesets. */
knot_changesets_t* chsets = knot_changesets_create();
if (chsets == NULL) {
return KNOT_ERROR;
}
/*! \todo Check what should be the upper bound. */
int ret = journal_load_changesets(conf->ixfr_db, chsets, serial, serial - 1);
if ((ret != KNOT_EOK && ret != KNOT_ERANGE) || EMPTY_LIST(chsets->sets)) {
knot_changesets_free(&chsets);
/* Absence of records is not an error. */
if (ret == KNOT_ENOENT) {
return KNOT_EOK;
} else {
return ret;
}
}
/* Apply changesets. */
log_zone_info("Applying '%zu' changesets from journal to zone '%s'.\n",
chsets->count, conf->name);
ret = xfrin_apply_changesets_directly(contents, chsets->changes, chsets);
if (ret != KNOT_EOK) {
log_zone_error("Failed to apply changesets to '%s' - %s\n",
conf->name, knot_strerror(ret));
knot_changesets_free(&chsets);
return ret;
}
/* Switch zone immediately. */
log_zone_info("Zone '%s' serial %u -> %u.\n",
conf->name,
serial, zone_contents_serial(contents));
/* Free changesets and return. */
xfrin_cleanup_successful_update(chsets->changes);
knot_changesets_free(&chsets);
return ret;
}
......@@ -21,4 +21,4 @@
#include "knot/zone/contents.h"
zone_contents_t *zone_load_contents(conf_zone_t *conf);
int apply_journal(zone_contents_t *contents, journal_t *journal);
int apply_journal(zone_contents_t *contents, conf_zone_t *conf);
......@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
#include "common/descriptor.h"
#include "common/evsched.h"
......@@ -25,6 +26,7 @@
#include "knot/server/zones.h"
#include "knot/zone/node.h"
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
#include "knot/zone/contents.h"
#include "libknot/common.h"
#include "libknot/dname.h"
......@@ -109,17 +111,6 @@ zone_t* zone_new(conf_zone_t *conf)
set_acl(&zone->notify_in, &conf->acl.notify_in);
set_acl(&zone->update_in, &conf->acl.update_in);
// Initialize XFR database
zone->ixfr_db = journal_open(conf->ixfr_db, conf->ixfr_fslimit, JOURNAL_DIRTY);
if (zone->ixfr_db == NULL) {
char ebuf[256] = {0};
if (strerror_r(errno, ebuf, sizeof(ebuf)) == 0) {
log_zone_warning("Couldn't open journal file for "
"zone '%s', disabling incoming "
"IXFR. (%s)\n", conf->name, ebuf);
}
}
// Initialize events
zone_events_init(zone);
......@@ -144,9 +135,6 @@ void zone_free(zone_t **zone_ptr)
pthread_mutex_destroy(&zone->lock);
pthread_mutex_destroy(&zone->ddns_lock);
/* Close IXFR db. */
journal_close(zone->ixfr_db);
/* Free assigned config. */
conf_free_zone(zone->conf);
......@@ -183,3 +171,54 @@ const conf_iface_t *zone_master(const zone_t *zone)
conf_remote_t *master = HEAD(zone->conf->acl.xfr_in);
return master->remote;
}
int zone_flush_journal(zone_t *zone)
{
/*! @note Function expects nobody will change zone contents meanwile. */
if (zone == NULL || zone_contents_is_empty(zone->contents)) {
return KNOT_EINVAL;
}
/* Check for difference against zonefile serial. */
zone_contents_t *contents = zone->contents;
uint32_t serial_to = zone_contents_serial(contents);
if (zone->zonefile_serial == serial_to) {
return KNOT_EOK; /* No differences. */
}
/* Fetch zone source (where it came from). */
const struct sockaddr_storage *from = NULL;
const conf_iface_t *master = zone_master(zone);
if (master != NULL) {
from = &master->addr;
}
/* Synchronize journal. */
conf_zone_t *conf = zone->conf;
int ret = zonefile_write(conf->file, contents, from);
if (ret == KNOT_EOK) {
log_zone_info("Applied differences of '%s' to zonefile.\n", conf->name);
} else {
log_zone_warning("Failed to apply differences of '%s' "
"to zonefile (%s).\n", conf->name, knot_strerror(ret));
return ret;
}
/* Update zone version. */
struct stat st;
if (stat(zone->conf->file, &st) < 0) {
log_zone_warning("Failed to apply differences '%s' to '%s (%s)'\n",
conf->name, conf->file, knot_strerror(KNOT_EACCES));
return KNOT_EACCES;
}
/* Update zone file serial and journal. */
zone->zonefile_mtime = st.st_mtime;
zone->zonefile_serial = serial_to;
journal_mark_synced(zone->conf->ixfr_db);
return ret;
}
......@@ -87,9 +87,6 @@ typedef struct zone_t {
uint32_t refresh_at; /*!< Next refresh time. */
} dnssec;
/*! \brief Zone IXFR history. */
journal_t *ixfr_db;
event_t *ixfr_dbsync; /*!< Syncing IXFR db to zonefile. */
} zone_t;