Commit c0a1304e authored by Lubos Slovak's avatar Lubos Slovak

Separated changeset applying from zone switching.

And unified with processing of AXFR/IN.

refs #1668 @1h45m
parent c9df02b7
......@@ -235,7 +235,7 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data)
if (data->data) {
if (data->flags & XFR_FLAG_AXFR_FINISHED) {
knot_zone_contents_deep_free(
(knot_zone_contents_t **)&data->data, 0);
&data->new_contents, 0);
} else {
xfrin_constructed_zone_t *constr_zone =
(xfrin_constructed_zone_t *)data->data;
......@@ -252,6 +252,10 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data)
chs = (knot_changesets_t *)data->data;
knot_free_changesets(&chs);
}
// this function is called before new contents are created
assert(data->new_contents == NULL);
break;
}
......@@ -310,25 +314,46 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data)
ret == KNOTD_EOK ? "finished" : "failed");
break;
case XFR_TYPE_IIN:
/* Save changesets. */
dbg_xfr("xfr: IXFR/IN saving changesets\n");
ret = zones_store_changesets(data);
if (ret != KNOTD_EOK) {
log_zone_error("IXFR failed to save "
"transferred changesets "
"for zone '%s/IN' - %s\n",
zorigin, knotd_strerror(ret));
/* First, try to apply the changesets to the zone. */
/* Update zone. */
ret = xfrin_apply_changesets(data->zone,
(knot_changesets_t *)data->data,
&data->new_contents);
if (ret != KNOT_EOK) {
log_zone_error("IXFR failed to "
"apply changesets to "
"zone '%s/IN' - %s\n",
zorigin,
knot_strerror(ret));
} else {
/* Update zone. */
ret = zones_apply_changesets(data);
if (ret != KNOT_EOK) {
log_zone_error("IXFR failed to "
"apply changesets to "
"zone '%s/IN' - %s\n",
zorigin,
knot_strerror(ret));
/* Save changesets. */
dbg_xfr("xfr: IXFR/IN saving changesets\n");
ret = zones_store_changesets(data);
if (ret != KNOTD_EOK) {
log_zone_error("IXFR failed to save "
"transferred changesets "
"for zone '%s/IN' - %s\n",
zorigin, knotd_strerror(ret));
// Cleanup old and new contents
xfrin_cleanup_failed_update(
data->zone->contents,
&data->new_contents);
} else {
/* Switch zone contents. */
ret = xfrin_switch_zone(data->zone,
data->new_contents,
data->type);
if (ret != KNOT_EOK) {
// Cleanup old and new contents
xfrin_cleanup_failed_update(
data->zone->contents,
&data->new_contents);
}
}
}
/* Free changesets, but not the data. */
chs = (knot_changesets_t *)data->data;
knot_free_changesets(&chs);
......
......@@ -1180,13 +1180,34 @@ static int zones_journal_apply(knot_zone_t *zone)
log_server_info("Applying '%zu' changesets from journal "
"to zone '%s'.\n",
chsets->count, zd->conf->name);
int apply_ret = xfrin_apply_changesets(zone, chsets);
knot_zone_contents_t *contents = NULL;
int apply_ret = xfrin_apply_changesets(zone, chsets,
&contents);
if (apply_ret != KNOT_EOK) {
log_server_error("Failed to apply changesets to "
"'%s' - %s\n",
log_server_error("Failed to apply changesets to"
"'%s' - Apply failed: %s\n",
zd->conf->name,
knot_strerror(apply_ret));
ret = KNOTD_ERROR;
// Cleanup old and new contents
xfrin_cleanup_failed_update(zone->contents,
&contents);
}
/* Switch zone immediately. */
apply_ret = xfrin_switch_zone(zone, contents,
XFR_TYPE_IIN);
if (apply_ret != KNOT_EOK) {
log_server_error("Failed to apply changesets to"
" '%s' - Switch failed: %s\n",
zd->conf->name,
knot_strerror(apply_ret));
ret = KNOTD_ERROR;
// Cleanup old and new contents
xfrin_cleanup_failed_update(zone->contents,
&contents);
}
}
} else {
......@@ -2398,8 +2419,7 @@ int zones_save_zone(const knot_ns_xfr_t *xfr)
return KNOTD_EINVAL;
}
knot_zone_contents_t *zone =
(knot_zone_contents_t *)xfr->data;
knot_zone_contents_t *zone = xfr->new_contents;
const char *zonefile = NULL;
const char *zonedb = NULL;
......@@ -2729,18 +2749,6 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from,
/*----------------------------------------------------------------------------*/
int zones_apply_changesets(knot_ns_xfr_t *xfr)
{
if (xfr == NULL || xfr->zone == NULL || xfr->data == NULL) {
return KNOT_EBADARG;
}
return xfrin_apply_changesets(xfr->zone,
(knot_changesets_t *)xfr->data);
}
/*----------------------------------------------------------------------------*/
int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch)
{
if (!sch || !zone) {
......
......@@ -236,20 +236,6 @@ int zones_store_changesets(knot_ns_xfr_t *xfr);
int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from,
uint32_t serial_to);
/*!
* \brief Apply changesets to zone.
*
* Applies a list of XFR-style changesets to the given zone. Also checks if the
* changesets are applicable (i.e. zone is right and has the right serial).
*
* \param zone Zone to which the changesets should be applied.
* \param chsets Changesets to be applied to the zone.
*
* \retval KNOTD_EOK
* \retval KNOTD_EINVAL
*/
int zones_apply_changesets(knot_ns_xfr_t *xfr);
/*!
* \brief Update zone timers.
*
......
......@@ -3335,7 +3335,7 @@ int knot_ns_process_axfrin(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
}
// save the zone contents to the xfr->data
xfr->data = zone;
xfr->new_contents = zone;
xfr->flags |= XFR_FLAG_AXFR_FINISHED;
assert(zone->nsec3_nodes != NULL);
......@@ -3371,7 +3371,7 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver,
return KNOT_EBADARG;
}
knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->data;
knot_zone_contents_t *zone = (knot_zone_contents_t *)xfr->new_contents;
dbg_ns("Replacing zone by new one: %p\n", zone);
......@@ -3388,28 +3388,11 @@ int knot_ns_switch_zone(knot_nameserver_t *nameserver,
zone->zone = z;
}
knot_zone_contents_t *old = rcu_xchg_pointer(&z->contents, zone);
// knot_zone_t *old = knot_zonedb_replace_zone(nameserver->zone_db,
// zone);
dbg_ns("Old zone: %p\n", old);
// if (old == NULL) {
// char *name = knot_dname_to_str(
// knot_node_owner(knot_zone_apex(zone)));
// dbg_ns("Failed to replace zone %s\n", name);
// free(name);
// }
// wait for readers to finish
dbg_ns("Waiting for readers to finish...\n");
synchronize_rcu();
// destroy the old zone
dbg_ns("Freeing old zone: %p\n", old);
knot_zone_contents_deep_free(&old, 0);
int ret = xfrin_switch_zone(z, zone, xfr->type);
dbg_ns_exec(
dbg_ns("Zone db contents: (zone count: %zu)\n",
nameserver->zone_db->zone_count);
nameserver->zone_db->zone_count);
const knot_zone_t **zones = knot_zonedb_zones(nameserver->zone_db);
for (int i = 0; i < knot_zonedb_zone_count
......@@ -3422,7 +3405,7 @@ dbg_ns_exec(
free(zones);
);
return KNOT_EOK;
return ret;
}
/*----------------------------------------------------------------------------*/
......
......@@ -103,6 +103,8 @@ typedef struct knot_ns_xfr {
knot_zone_t *zone;
char* zname;
void *owner;
knot_zone_contents_t *new_contents;
/*! \note [TSIG] TSIG fields */
/*! \brief Message(s) to sign in wireformat.
......
......@@ -2345,7 +2345,7 @@ static void xfrin_cleanup_old_nodes(knot_node_t *node, void *data)
/*----------------------------------------------------------------------------*/
static void xfrin_rollback_update2(knot_zone_contents_t *old_contents,
knot_zone_contents_t *new_contents,
knot_zone_contents_t **new_contents,
xfrin_changes_t *changes)
{
// discard new RRSets
......@@ -2383,16 +2383,7 @@ static void xfrin_rollback_update2(knot_zone_contents_t *old_contents,
free(changes->old_rdata);
free(changes->old_rdata_types);
// destroy the shallow copy of zone
xfrin_zone_contents_free2(&new_contents);
// cleanup old zone tree - reset pointers to new node to NULL
// also set pointers from dnames to old nodes
knot_zone_contents_tree_apply_inorder(old_contents,
xfrin_cleanup_old_nodes, NULL);
knot_zone_contents_nsec3_apply_inorder(old_contents,
xfrin_cleanup_old_nodes, NULL);
xfrin_cleanup_failed_update(old_contents, new_contents);
}
/*----------------------------------------------------------------------------*/
......@@ -2995,9 +2986,11 @@ static int xfrin_check_contents_copy(knot_zone_contents_t *old_contents)
/*----------------------------------------------------------------------------*/
int xfrin_apply_changesets(knot_zone_t *zone,
knot_changesets_t *chsets)
knot_changesets_t *chsets,
knot_zone_contents_t **new_contents)
{
if (zone == NULL || chsets == NULL || chsets->count == 0) {
if (zone == NULL || chsets == NULL || chsets->count == 0
|| new_contents == NULL) {
return KNOT_EBADARG;
}
......@@ -3050,7 +3043,7 @@ int xfrin_apply_changesets(knot_zone_t *zone,
ret = xfrin_check_contents_copy(old_contents);
if (ret != KNOT_EOK) {
dbg_xfrin("Contents copy check failed!\n");
xfrin_rollback_update2(old_contents, contents_copy, &changes);
xfrin_rollback_update2(old_contents, &contents_copy, &changes);
return ret;
}
......@@ -3075,7 +3068,7 @@ int xfrin_apply_changesets(knot_zone_t *zone,
&chsets->sets[i]))
!= KNOT_EOK) {
xfrin_rollback_update2(old_contents,
contents_copy, &changes);
&contents_copy, &changes);
dbg_xfrin("Failed to apply changesets to zone: "
"%s\n", knot_strerror(ret));
return ret;
......@@ -3102,7 +3095,7 @@ int xfrin_apply_changesets(knot_zone_t *zone,
if (ret != KNOT_EOK) {
dbg_xfrin("Failed to remove empty nodes: %s\n",
knot_strerror(ret));
xfrin_rollback_update2(old_contents, contents_copy, &changes);
xfrin_rollback_update2(old_contents, &contents_copy, &changes);
return ret;
}
......@@ -3115,7 +3108,7 @@ int xfrin_apply_changesets(knot_zone_t *zone,
if (ret != KNOT_EOK) {
dbg_xfrin("Failed to finalize zone contents: %s\n",
knot_strerror(ret));
xfrin_rollback_update2(old_contents, contents_copy, &changes);
xfrin_rollback_update2(old_contents, &contents_copy, &changes);
return ret;
}
assert(knot_zone_contents_apex(contents_copy) != NULL);
......@@ -3124,35 +3117,77 @@ int xfrin_apply_changesets(knot_zone_t *zone,
ret = knot_zone_contents_check_loops(contents_copy);
if (ret != KNOT_EOK) {
dbg_xfrin("CNAME loop check failed: %s\n", knot_strerror(ret));
xfrin_rollback_update2(old_contents, contents_copy, &changes);
xfrin_rollback_update2(old_contents, &contents_copy, &changes);
return ret;
}
/*!
* \todo Maybe check also all mandatory semantic checks, e.g. CNAME
* and DNAME children.
*/
xfrin_cleanup_update(&changes);
*new_contents = contents_copy;
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
int xfrin_switch_zone(knot_zone_t *zone,
knot_zone_contents_t *new_contents,
int transfer_type)
{
if (zone == NULL || new_contents == NULL || zone->contents == NULL) {
return KNOT_EBADARG;
}
dbg_xfrin("Switching zone contents.\n");
dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n",
old_contents->apex, contents_copy->apex);
zone->contents->apex, new_contents->apex);
knot_zone_contents_t *old =
knot_zone_switch_contents(zone, contents_copy);
assert(old == old_contents);
knot_zone_switch_contents(zone, new_contents);
assert(old != NULL);
dbg_xfrin_verb("Old contents apex: %p, new apex: %p\n",
old_contents->apex, contents_copy->apex);
/*
* Wait until all readers finish reading
*/
old->apex, new_contents->apex);
dbg_xfrin_verb("Old zone: %p\n", old);
// wait for readers to finish
dbg_xfrin_verb("Waiting for readers to finish...\n");
synchronize_rcu();
// destroy the old zone
dbg_xfrin_verb("Freeing old zone: %p\n", old);
/*
* Delete all old and unused data.
*/
dbg_xfrin("Cleaning up.\n");
xfrin_zone_contents_free(&old_contents);
xfrin_cleanup_update(&changes);
if (transfer_type == XFR_TYPE_AIN) {
knot_zone_contents_deep_free(&old, 0);
} else {
xfrin_zone_contents_free(&old);
}
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents)
{
if (old_contents == NULL && new_contents == NULL) {
return;
}
if (*new_contents != NULL) {
// destroy the shallow copy of zone
xfrin_zone_contents_free2(new_contents);
}
if (old_contents != NULL) {
// cleanup old zone tree - reset pointers to new node to NULL
// also set pointers from dnames to old nodes
knot_zone_contents_tree_apply_inorder(old_contents,
xfrin_cleanup_old_nodes,
NULL);
knot_zone_contents_nsec3_apply_inorder(old_contents,
xfrin_cleanup_old_nodes,
NULL);
}
}
......@@ -182,7 +182,15 @@ int xfrin_apply_changesets_to_zone(knot_zone_t *zone,
knot_changesets_t *chsets);
int xfrin_apply_changesets(knot_zone_t *zone,
knot_changesets_t *chsets);
knot_changesets_t *chsets,
knot_zone_contents_t **new_contents);
int xfrin_switch_zone(knot_zone_t *zone,
knot_zone_contents_t *new_contents,
int deep_free);
void xfrin_cleanup_failed_update(knot_zone_contents_t *old_contents,
knot_zone_contents_t **new_contents);
#endif /* _KNOTXFR_IN_H_ */
......
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