From aa779124dc8969762b9f9fcc922bf39a92eccc9c Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek.vavrusa@nic.cz> Date: Wed, 19 Jun 2013 16:28:57 +0200 Subject: [PATCH] Fixed a problem with too many differences (>1k) in one IXFR. --- src/knot/server/journal.c | 2 +- src/knot/server/xfr-handler.c | 66 ++++++++++++++++-------- src/knot/server/zones.c | 75 +++++++--------------------- src/libknot/nameserver/name-server.c | 1 - src/libknot/updates/xfr-in.c | 11 +++- 5 files changed, 71 insertions(+), 84 deletions(-) diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index 2fe9f317ec..b725083a20 100644 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -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. */ diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index 114fc714ec..0402fe482b 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -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); diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index e5ecf5455c..46ba65ea38 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -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); diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 00ec5c966b..4a95240181 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -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"); diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index 04d75eaed0..7aa95dbfa5 100644 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -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; -- GitLab