Commit aa779124 authored by Marek Vavrusa's avatar Marek Vavrusa

Fixed a problem with too many differences (>1k) in one IXFR.

parent 94a96f86
......@@ -189,7 +189,7 @@ int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len)
/* Check if it has been synced to disk. */
if (head->flags & JOURNAL_DIRTY) {
return KNOT_EAGAIN;
return KNOT_EBUSY;
}
/* Write back evicted node. */
......
......@@ -296,6 +296,7 @@ static void xfr_task_cleanup(knot_ns_xfr_t *rq)
/* Cleanup other data - so that the structure may be reused. */
rq->packet_nr = 0;
rq->tsig_data_size = 0;
hattrie_clear(rq->lookup_tree);
}
/*! \brief Close and free task. */
......@@ -642,6 +643,28 @@ static int xfr_task_resp(xfrworker_t *w, knot_ns_xfr_t *rq)
return ret;
}
static int xfr_fallback_axfr(knot_ns_xfr_t *rq)
{
log_server_notice("%s Retrying with AXFR.\n", rq->msg);
rq->wire_size = rq->wire_maxlen; /* Reset maximum bufsize */
int ret = xfrin_create_axfr_query(rq->zone->name, rq, &rq->wire_size, 1);
/* Send AXFR/IN query. */
if (ret == KNOT_EOK) {
ret = rq->send(rq->session, &rq->addr,
rq->wire, rq->wire_size);
/* Switch to AXFR and return. */
if (ret == rq->wire_size) {
xfr_task_cleanup(rq);
rq->type = XFR_TYPE_AIN;
rq->msg[XFR_MSG_DLTTR] = 'A';
ret = KNOT_EOK;
} else {
ret = KNOT_ERROR;
}
}
return ret;
}
static int xfr_task_xfer(xfrworker_t *w, knot_ns_xfr_t *rq)
{
......@@ -675,25 +698,16 @@ static int xfr_task_xfer(xfrworker_t *w, knot_ns_xfr_t *rq)
dbg_xfr_verb("xfr: processed XFR pkt (%s)\n", knot_strerror(ret));
/* IXFR refused, try again with AXFR. */
if (rq->type == XFR_TYPE_IIN && ret == KNOT_EXFRREFUSED) {
log_server_notice("%s Transfer failed, fallback to AXFR.\n", rq->msg);
rq->wire_size = rq->wire_maxlen; /* Reset maximum bufsize */
ret = xfrin_create_axfr_query(rq->zone->name, rq, &rq->wire_size, 1);
/* Send AXFR/IN query. */
if (ret == KNOT_EOK) {
ret = rq->send(rq->session, &rq->addr,
rq->wire, rq->wire_size);
/* Switch to AXFR and return. */
if (ret == rq->wire_size) {
xfr_task_cleanup(rq);
rq->type = XFR_TYPE_AIN;
rq->msg[XFR_MSG_DLTTR] = 'A';
return KNOT_EOK;
} else {
ret = KNOT_ERROR;
}
if (rq->type == XFR_TYPE_IIN) {
switch(ret) {
case KNOT_ESPACE: /* Fallthrough */
log_server_notice("%s Exceeded journal size limit.\n",
rq->msg);
case KNOT_EXFRREFUSED:
return xfr_fallback_axfr(rq);
default:
break;
}
return ret; /* Something failed in fallback. */
}
/* Handle errors. */
......@@ -706,19 +720,26 @@ static int xfr_task_xfer(xfrworker_t *w, knot_ns_xfr_t *rq)
/* Only for successful xfers. */
if (ret > 0) {
ret = xfr_task_finalize(w, rq);
/* AXFR bootstrap timeout. */
if (ret != KNOT_EOK && !knot_zone_contents(rq->zone)) {
/* AXFR bootstrap timeout. */
zonedata_t *zd = (zonedata_t *)knot_zone_data(rq->zone);
int tmr_s = AXFR_BOOTSTRAP_RETRY * tls_rand();
zd->xfr_in.bootstrap_retry = tmr_s;
log_zone_info("%s Next attempt to bootstrap "
"in %d seconds.\n",
rq->msg, tmr_s / 1000);
} else if (ret == KNOT_EBUSY && rq->type == XFR_TYPE_IIN) {
/* Attempt to retry with AXFR. */
ret = xfr_fallback_axfr(rq);
if (ret == KNOT_EOK)
return ret;
} else {
zones_schedule_notify(rq->zone); /* NOTIFY */
}
/* Passed, schedule NOTIFYs. */
zones_schedule_notify(rq->zone);
}
/* Update REFRESH/RETRY */
zones_schedule_refresh(rq->zone);
......@@ -1264,6 +1285,7 @@ int xfr_task_free(knot_ns_xfr_t *rq)
/* Free DNAME trie. */
hattrie_free(rq->lookup_tree);
rq->lookup_tree = NULL;
/* Free TSIG buffers. */
free(rq->digest);
......
......@@ -2836,48 +2836,6 @@ static int zones_store_changeset(const knot_changeset_t *chs, journal_t *j,
/* Reserve space for the journal entry. */
char *journal_entry = NULL;
ret = journal_map(j, k, &journal_entry, entry_size);
/* Sync to zonefile may be needed. */
while (ret == KNOT_EAGAIN) {
/* Cancel sync timer. */
event_t *tmr = zd->ixfr_dbsync;
if (tmr) {
dbg_xfr_verb("xfr: cancelling zonefile "
"SYNC timer of '%s'\n",
zd->conf->name);
evsched_cancel(tmr->parent, tmr);
}
/* Synchronize. */
dbg_xfr_verb("xfr: forcing zonefile SYNC "
"of '%s'\n",
zd->conf->name);
ret = zones_zonefile_sync(zone, j);
if (ret != KNOT_EOK && ret != KNOT_ERANGE) {
continue;
}
/* Reschedule sync timer. */
if (tmr) {
/* Fetch sync timeout. */
rcu_read_lock();
int timeout = zd->conf->dbsync_timeout;
timeout *= 1000; /* Convert to ms. */
rcu_read_unlock();
/* Reschedule. */
dbg_xfr_verb("xfr: resuming SYNC "
"of '%s'\n",
zd->conf->name);
evsched_schedule(tmr->parent, tmr,
timeout);
}
/* Attempt to map again. */
ret = journal_map(j, k, &journal_entry, entry_size);
}
if (ret != KNOT_EOK) {
dbg_xfr("Failed to map space for journal entry: %s.\n",
knot_strerror(ret));
......@@ -2960,8 +2918,7 @@ int zones_store_changesets(knot_zone_t *zone, knot_changesets_t *src)
return KNOT_EINVAL;
}
// knot_zone_t *zone = xfr->zone;
// knot_changesets_t *src = (knot_changesets_t *)xfr->data;
int ret = KNOT_EOK;
/* Fetch zone-specific data. */
zonedata_t *zd = (zonedata_t *)zone->data;
......@@ -2974,7 +2931,6 @@ int zones_store_changesets(knot_zone_t *zone, knot_changesets_t *src)
if (j == NULL) {
return KNOT_EBUSY;
}
int ret = 0;
/* Begin writing to journal. */
for (unsigned i = 0; i < src->count; ++i) {
......@@ -2982,17 +2938,24 @@ int zones_store_changesets(knot_zone_t *zone, knot_changesets_t *src)
knot_changeset_t* chs = src->sets + i;
ret = zones_store_changeset(chs, j, zone, zd);
if (ret != KNOT_EOK) {
journal_release(j);
return ret;
}
if (ret != KNOT_EOK)
break;
}
/* Release journal. */
journal_release(j);
/* Flush if the journal is full. */
event_t *tmr = zd->ixfr_dbsync;
if (ret == KNOT_EBUSY && tmr) {
log_server_notice("Journal for '%s' is full, flushing.\n",
zd->conf->name);
evsched_cancel(tmr->parent, tmr);
evsched_schedule(tmr->parent, tmr, 0);
}
/* Written changesets to journal. */
return KNOT_EOK;
return ret;
}
/*----------------------------------------------------------------------------*/
......@@ -3125,8 +3088,7 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs,
}
if (ret != KNOT_EOK) {
log_zone_error("%s Failed to serialize and store "
"changesets - %s\n", msgpref,
knot_strerror(ret));
"changesets.\n", msgpref);
/* Free changesets, but not the data. */
zones_store_changesets_rollback(transaction);
knot_free_changesets(&chs);
......@@ -3137,8 +3099,7 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs,
apply_ret = xfrin_apply_changesets(zone, chs, new_contents);
if (apply_ret != KNOT_EOK) {
log_zone_error("%s Failed to apply changesets - %s\n",
msgpref, knot_strerror(apply_ret));
log_zone_error("%s Failed to apply changesets.\n", msgpref);
/* Free changesets, but not the data. */
zones_store_changesets_rollback(transaction);
......@@ -3150,8 +3111,7 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs,
ret = zones_store_changesets_commit(transaction);
if (ret != KNOT_EOK) {
/*! \todo THIS WILL LEAK!! xfrin_rollback_update() needed. */
log_zone_error("%s Failed to commit stored changesets "
"- %s\n", msgpref, knot_strerror(apply_ret));
log_zone_error("%s Failed to commit stored changesets.\n", msgpref);
knot_free_changesets(&chs);
return ret;
}
......@@ -3160,8 +3120,7 @@ int zones_store_and_apply_chgsets(knot_changesets_t *chs,
switch_ret = xfrin_switch_zone(zone, *new_contents, type);
if (switch_ret != KNOT_EOK) {
log_zone_error("%s Failed to replace current zone - %s\n",
msgpref, knot_strerror(switch_ret));
log_zone_error("%s Failed to replace current zone.\n", msgpref);
// Cleanup old and new contents
xfrin_rollback_update(zone->contents, new_contents,
&chs->changes);
......
......@@ -4176,7 +4176,6 @@ int knot_ns_process_ixfrin(knot_nameserver_t *nameserver,
if (ret < 0) {
knot_packet_free(&xfr->query);
hattrie_clear(xfr->lookup_tree);
return ret;
} else if (ret > 0) {
dbg_ns("ns_process_ixfrin: IXFR finished\n");
......
......@@ -18,6 +18,8 @@
#include <assert.h>
#include <urcu.h>
#include "knot/server/journal.h"
#include "updates/xfr-in.h"
#include "nameserver/name-server.h"
......@@ -1159,8 +1161,13 @@ dbg_xfrin_exec_verb(
} else {
// normal SOA, start new changeset
(*chs)->count++;
if ((ret = knot_changesets_check_size(*chs))
!= KNOT_EOK) {
ret = knot_changesets_check_size(*chs);
/* Check changesets for maximum count (so they fit into journal). */
if ((*chs)->count > JOURNAL_NCOUNT)
ret = KNOT_ESPACE;
if (ret != KNOT_EOK) {
(*chs)->count--;
knot_rrset_deep_free(&rr, 1, 1);
goto cleanup;
......
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