Commit 475a2e80 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman
Browse files

bi-nodes implemented, used for zone, updates, apply

parent 7b9cc47f
......@@ -291,7 +291,7 @@ static zone_node_t *create_nsec3_node(const knot_dname_t *owner,
assert(apex_node);
assert(rr_types);
zone_node_t *new_node = node_new(owner, NULL);
zone_node_t *new_node = node_new(owner, false, false, NULL);
if (!new_node) {
return NULL;
}
......@@ -508,7 +508,7 @@ static int create_nsec3_nodes(const zone_contents_t *zone,
if (result != KNOT_EOK) {
break;
}
if (node->flags & NODE_FLAGS_NONAUTH || node->flags & NODE_FLAGS_EMPTY) {
if (node->flags & NODE_FLAGS_NONAUTH || node->flags & NODE_FLAGS_EMPTY || node->flags & NODE_FLAGS_DELETED) {
zone_tree_it_next(&it);
continue;
}
......@@ -521,7 +521,7 @@ static int create_nsec3_nodes(const zone_contents_t *zone,
break;
}
result = zone_tree_insert(nsec3_nodes, nsec3_node);
result = zone_tree_insert(nsec3_nodes, &nsec3_node);
if (result != KNOT_EOK) {
break;
}
......@@ -631,6 +631,7 @@ static int fix_nsec3_for_node(zone_update_t *update, const dnssec_nsec3_params_t
ret = changeset_add_addition(chgset, &nsec3, CHANGESET_CHECK | CHANGESET_CHECK_CANCELOUT);
}
}
binode_unify(new_nsec3_n, false, NULL);
node_free_rrsets(new_nsec3_n, NULL);
node_free(new_nsec3_n, NULL);
}
......@@ -749,7 +750,7 @@ int knot_nsec3_create_chain(const zone_contents_t *zone,
int result;
zone_tree_t *nsec3_nodes = zone_tree_create();
zone_tree_t *nsec3_nodes = zone_tree_create(false);
if (!nsec3_nodes) {
return KNOT_ENOMEM;
}
......
......@@ -46,7 +46,7 @@ static int delete_nsec3_chain(const zone_contents_t *zone, changeset_t *changese
return KNOT_EOK;
}
zone_tree_t *empty_tree = zone_tree_create();
zone_tree_t *empty_tree = zone_tree_create(false);
if (!empty_tree) {
return KNOT_ENOMEM;
}
......
......@@ -193,7 +193,7 @@ static void xfr_log_publish(const struct refresh_data *data,
static int axfr_init(struct refresh_data *data)
{
zone_contents_t *new_zone = zone_contents_new(data->zone->name);
zone_contents_t *new_zone = zone_contents_new(data->zone->name, true);
if (new_zone == NULL) {
return KNOT_ENOMEM;
}
......
......@@ -183,7 +183,7 @@ static int add_rr_to_contents(zone_contents_t *z, const knot_rrset_t *rrset)
bool journal_read_changeset(journal_read_t *ctx, changeset_t *ch)
{
zone_contents_t *tree = zone_contents_new(ctx->zone);
zone_contents_t *tree = zone_contents_new(ctx->zone, false);
knot_rrset_t *soa = calloc(1, sizeof(*soa)), rr = { 0 };
if (tree == NULL || soa == NULL) {
ctx->txn.ret = KNOT_ENOMEM;
......@@ -203,7 +203,7 @@ bool journal_read_changeset(journal_read_t *ctx, changeset_t *ch)
ch->soa_from = soa;
ch->remove = tree;
soa = malloc(sizeof(*soa));
tree = zone_contents_new(ctx->zone);
tree = zone_contents_new(ctx->zone, false);
if (tree == NULL || soa == NULL) {
ctx->txn.ret = KNOT_ENOMEM;
goto fail;
......
......@@ -22,43 +22,14 @@
#include "contrib/macros.h"
#include "contrib/mempattern.h"
/* --------------------------- Update cleanup ------------------------------- */
/*!
* \brief Post update cleanup: frees data that are in the tree that will not
* be used (old tree if success, new tree if failure).
* Freed data:
* - actual data inside knot_rrs_t. (the rest is part of the node)
*/
static void rrs_list_clear(list_t *l, knot_mm_t *mm)
{
ptrnode_t *n;
node_t *nxt;
WALK_LIST_DELSAFE(n, nxt, *l) {
mm_free(mm, (void *)n->d);
mm_free(mm, n);
};
}
/*! \brief Frees additional data from single node */
static int free_additional(zone_node_t *node, void *data)
{
UNUSED(data);
for (uint16_t i = 0; i < node->rrset_count; ++i) {
struct rr_data *rrdata = &node->rrs[i];
additional_clear(rrdata->additional);
rrdata->additional = NULL;
}
return KNOT_EOK;
}
/* -------------------- Changeset application helpers ----------------------- */
/*! \brief Replaces rdataset of given type with a copy. */
static int replace_rdataset_with_copy(zone_node_t *node, uint16_t type)
{
int ret = binode_prepare_change(node, NULL);
if (ret != KNOT_EOK) {
return ret;
}
// Find data to copy.
struct rr_data *data = NULL;
for (uint16_t i = 0; i < node->rrset_count; ++i) {
......@@ -67,7 +38,9 @@ static int replace_rdataset_with_copy(zone_node_t *node, uint16_t type)
break;
}
}
assert(data);
if (data == NULL) {
return KNOT_EOK;
}
// Create new data.
knot_rdataset_t *rrs = &data->rrs;
......@@ -93,26 +66,6 @@ static void clear_new_rrs(zone_node_t *node, uint16_t type)
}
}
/*! \brief Stores RR data for update cleanup. */
static int add_old_data(apply_ctx_t *ctx, knot_rdata_t *old_data)
{
if (ptrlist_add(&ctx->old_data, old_data, NULL) == NULL) {
return KNOT_ENOMEM;
}
return KNOT_EOK;
}
/*! \brief Stores RR data for update rollback. */
static int add_new_data(apply_ctx_t *ctx, knot_rdata_t *new_data)
{
if (ptrlist_add(&ctx->new_data, new_data, NULL) == NULL) {
return KNOT_ENOMEM;
}
return KNOT_EOK;
}
/*! \brief Returns true if given RR is present in node and can be removed. */
static bool can_remove(const zone_node_t *node, const knot_rrset_t *rrset)
{
......@@ -226,18 +179,18 @@ int apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags)
ctx->contents = contents;
init_list(&ctx->old_data);
init_list(&ctx->new_data);
ctx->node_ptrs = zone_tree_create();
ctx->node_ptrs = zone_tree_create(true);
if (ctx->node_ptrs == NULL) {
return KNOT_ENOMEM;
}
ctx->nsec3_ptrs = zone_tree_create();
ctx->node_ptrs->flags = contents->nodes->flags;
ctx->nsec3_ptrs = zone_tree_create(true);
if (ctx->nsec3_ptrs == NULL) {
zone_tree_free(&ctx->node_ptrs);
return KNOT_ENOMEM;
}
ctx->nsec3_ptrs->flags = contents->nodes->flags;
ctx->flags = flags;
......@@ -270,67 +223,88 @@ int apply_prepare_zone_copy(zone_contents_t *old_contents,
return KNOT_EOK;
}
static int add_to_changes_cb2(zone_node_t *node, void *ctx)
{
node->flags |= NODE_FLAGS_DELETED;
int ret = zone_tree_insert(ctx, &node);
assert(ret == KNOT_EOK);
return ret;
}
static zone_node_t *find_node_in_changes(const knot_dname_t *owner, void *ctx)
{
zone_tree_t *tree = ctx;
zone_node_t *node = zone_tree_get(tree, owner);
if (node == NULL) {
node = node_new(owner, (tree->flags & ZONE_TREE_USE_BINODES),
(tree->flags & ZONE_TREE_BINO_SECOND), NULL);
(void)zone_tree_insert(tree, &node);
} else {
node->flags &= ~NODE_FLAGS_DELETED;
}
return node;
}
int apply_add_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
{
zone_contents_t *contents = ctx->contents;
bool nsec3rel = knot_rrset_is_nsec3rel(rr);
zone_tree_t *ptrs = nsec3rel ? ctx->nsec3_ptrs : ctx->node_ptrs;
zone_tree_t *tree = zone_contents_tree_for_rr(contents, rr);
if (tree == NULL) {
return KNOT_ENOMEM;
}
// Get or create node with this owner
zone_node_t *node = zone_contents_get_node_for_rr(contents, rr);
// Get or create node with this owner, search changes first
zone_node_t *node = NULL;
int ret = zone_tree_add_node(tree, contents->apex, rr->owner, find_node_in_changes, ptrs, &node);
if (ret != KNOT_EOK) {
return ret;
}
if (node == NULL) {
return KNOT_ENOMEM;
return KNOT_EOUTOFZONE;
}
zone_tree_insert(knot_rrset_is_nsec3rel(rr) ? ctx->nsec3_ptrs : ctx->node_ptrs, node);
// re-inserting makes no harm
knot_rrset_t changed_rrset = node_rrset(node, rr->type);
if (!knot_rrset_empty(&changed_rrset)) {
// Modifying existing RRSet.
knot_rdata_t *old_data = changed_rrset.rrs.rdata;
int ret = replace_rdataset_with_copy(node, rr->type);
if (ret != KNOT_EOK) {
return ret;
}
ret = zone_tree_insert(nsec3rel ? ctx->nsec3_ptrs : ctx->node_ptrs, &node);
if (ret != KNOT_EOK) {
return ret;
}
// Store old RRS for cleanup.
ret = add_old_data(ctx, old_data);
if (binode_rdata_shared(node, rr->type)) {
// Modifying existing RRSet.
ret = replace_rdataset_with_copy(node, rr->type);
if (ret != KNOT_EOK) {
clear_new_rrs(node, rr->type);
return ret;
}
}
// Insert new RR to RRSet, data will be copied.
int ret = node_add_rrset(node, rr, NULL);
if (ret == KNOT_EOK || ret == KNOT_ETTL) {
// RR added, store for possible rollback.
knot_rdataset_t *rrs = node_rdataset(node, rr->type);
int data_ret = add_new_data(ctx, rrs->rdata);
if (data_ret != KNOT_EOK) {
knot_rdataset_clear(rrs, NULL);
return data_ret;
}
if (ret == KNOT_ETTL) {
char buff[KNOT_DNAME_TXT_MAXLEN + 1];
char *owner = knot_dname_to_str(buff, rr->owner, sizeof(buff));
if (owner == NULL) {
owner = "";
}
char type[16] = { '\0' };
knot_rrtype_to_string(rr->type, type, sizeof(type));
log_zone_notice(contents->apex->owner,
"TTL mismatch, owner %s, type %s, "
"TTL set to %u", owner, type, rr->ttl);
return KNOT_EOK;
ret = node_add_rrset(node, rr, NULL);
if (ret == KNOT_ETTL) {
char buff[KNOT_DNAME_TXT_MAXLEN + 1];
char *owner = knot_dname_to_str(buff, rr->owner, sizeof(buff));
if (owner == NULL) {
owner = "";
}
char type[16] = { '\0' };
knot_rrtype_to_string(rr->type, type, sizeof(type));
log_zone_notice(contents->apex->owner,
"TTL mismatch, owner %s, type %s, "
"TTL set to %u", owner, type, rr->ttl);
return KNOT_EOK;
}
return ret;
}
int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
{
zone_contents_t *contents = ctx->contents;
bool nsec3rel = knot_rrset_is_nsec3rel(rr);
zone_tree_t *ptrs = nsec3rel ? ctx->nsec3_ptrs : ctx->node_ptrs;
zone_tree_t *tree = zone_contents_tree_for_rr(contents, rr);
if (tree == NULL) {
return KNOT_ENOMEM;
}
// Find node for this owner
zone_node_t *node = zone_contents_find_node_for_rr(contents, rr);
......@@ -343,22 +317,16 @@ int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
return KNOT_EOK;
}
bool nsec3 = knot_rrset_is_nsec3rel(rr);
zone_tree_insert(nsec3 ? ctx->nsec3_ptrs : ctx->node_ptrs, node);
zone_tree_t *tree = nsec3 ? contents->nsec3_nodes : contents->nodes;
knot_rrset_t removed_rrset = node_rrset(node, rr->type);
knot_rdata_t *old_data = removed_rrset.rrs.rdata;
int ret = replace_rdataset_with_copy(node, rr->type);
int ret = zone_tree_insert(ptrs, &node);
if (ret != KNOT_EOK) {
return ret;
}
// Store old data for cleanup.
ret = add_old_data(ctx, old_data);
if (ret != KNOT_EOK) {
clear_new_rrs(node, rr->type);
return ret;
if (binode_rdata_shared(node, rr->type)) {
ret = replace_rdataset_with_copy(node, rr->type);
if (ret != KNOT_EOK) {
return ret;
}
}
knot_rdataset_t *changed_rrs = node_rdataset(node, rr->type);
......@@ -369,20 +337,12 @@ int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr)
return ret;
}
if (changed_rrs->count > 0) {
// Subtraction left some data in RRSet, store it for rollback.
ret = add_new_data(ctx, changed_rrs->rdata);
if (ret != KNOT_EOK) {
knot_rdataset_clear(changed_rrs, NULL);
return ret;
}
} else {
if (changed_rrs->count == 0) {
// RRSet is empty now, remove it from node, all data freed, except additionals.
node_remove_rdataset(node, rr->type);
// If node is empty now, delete it from zone tree.
if (node->rrset_count == 0 && node != contents->apex) {
zone_tree_remove_node(nsec3 ? ctx->nsec3_ptrs: ctx->node_ptrs, node->owner);
zone_tree_delete_empty(tree, node);
if (node->rrset_count == 0 && node->children == 0 && node != contents->apex) {
zone_tree_del_node(tree, node, add_to_changes_cb2, ptrs);
}
}
......@@ -436,7 +396,6 @@ int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch)
int ret = apply_single(ctx, ch);
if (ret != KNOT_EOK) {
update_rollback(ctx);
return ret;
}
......@@ -449,15 +408,16 @@ void update_cleanup(apply_ctx_t *ctx)
return;
}
zone_trees_unify_binodes(ctx->node_ptrs, ctx->nsec3_ptrs);
zone_tree_free(&ctx->node_ptrs);
zone_tree_free(&ctx->nsec3_ptrs);
// Delete old RR data
rrs_list_clear(&ctx->old_data, NULL);
init_list(&ctx->old_data);
// Keep new RR data
ptrlist_free(&ctx->new_data, NULL);
init_list(&ctx->new_data);
// this is important not only for full update
// but also for incremental because during adjusting
// also the nodes not being affected by the update itself
// might be affected
zone_trees_unify_binodes(ctx->contents->nodes, ctx->contents->nsec3_nodes);
}
void update_rollback(apply_ctx_t *ctx)
......@@ -466,15 +426,16 @@ void update_rollback(apply_ctx_t *ctx)
return;
}
if (ctx->node_ptrs != NULL) {
ctx->node_ptrs->flags ^= ZONE_TREE_BINO_SECOND;
}
if (ctx->nsec3_ptrs != NULL) {
ctx->nsec3_ptrs->flags ^= ZONE_TREE_BINO_SECOND;
}
zone_trees_unify_binodes(ctx->node_ptrs, ctx->nsec3_ptrs);
zone_tree_free(&ctx->node_ptrs);
zone_tree_free(&ctx->nsec3_ptrs);
// Delete new RR data
rrs_list_clear(&ctx->new_data, NULL);
init_list(&ctx->new_data);
// Keep old RR data
ptrlist_free(&ctx->old_data, NULL);
init_list(&ctx->old_data);
}
void update_free_zone(zone_contents_t *contents)
......@@ -483,9 +444,8 @@ void update_free_zone(zone_contents_t *contents)
return;
}
(void)zone_tree_apply(contents->nodes, free_additional, NULL);
zone_tree_deep_free(&contents->nodes);
zone_tree_deep_free(&contents->nsec3_nodes);
zone_tree_free(&contents->nodes);
zone_tree_free(&contents->nsec3_nodes);
dnssec_nsec3_params_free(&contents->nsec3_params);
......
......@@ -26,8 +26,6 @@ enum {
struct apply_ctx {
zone_contents_t *contents;
list_t old_data; /*!< Old data, to be freed after successful update. */
list_t new_data; /*!< New data, to be freed after failed update. */
zone_tree_t *node_ptrs; /*!< Just pointers to the affected nodes in contents. */
zone_tree_t *nsec3_ptrs; /*!< The same for NSEC3 nodes. */
uint32_t flags;
......
......@@ -122,7 +122,7 @@ static void check_redundancy(zone_contents_t *counterpart, const knot_rrset_t *r
// Remove empty node.
zone_tree_t *t = knot_rrset_is_nsec3rel(rr) ?
counterpart->nsec3_nodes : counterpart->nodes;
zone_tree_delete_empty(t, node);
zone_tree_del_node(t, node, (zone_tree_del_node_cb_t)node_free, NULL);
}
}
......@@ -134,11 +134,11 @@ int changeset_init(changeset_t *ch, const knot_dname_t *apex)
memset(ch, 0, sizeof(changeset_t));
// Init local changes
ch->add = zone_contents_new(apex);
ch->add = zone_contents_new(apex, false);
if (ch->add == NULL) {
return KNOT_ENOMEM;
}
ch->remove = zone_contents_new(apex);
ch->remove = zone_contents_new(apex, false);
if (ch->remove == NULL) {
zone_contents_free(ch->add);
return KNOT_ENOMEM;
......
......@@ -71,7 +71,7 @@ static int init_incremental(zone_update_t *update, zone_t *zone, zone_contents_t
static int init_full(zone_update_t *update, zone_t *zone)
{
update->new_cont = zone_contents_new(zone->name);
update->new_cont = zone_contents_new(zone->name, true);
if (update->new_cont == NULL) {
return KNOT_ENOMEM;
}
......@@ -681,6 +681,16 @@ static int commit_full(conf_t *conf, zone_update_t *update)
return ret;
}
static int check_unified(zone_node_t *node, void *data)
{
(void)data;
zone_node_t *counter = binode_counterpart(node);
assert((node->flags ^ counter->flags) == NODE_FLAGS_SECOND);
assert(node->rrset_count == counter->rrset_count);
assert(node->rrs == counter->rrs);
return KNOT_EOK;
}
int zone_update_commit(conf_t *conf, zone_update_t *update)
{
if (conf == NULL || update == NULL) {
......@@ -748,6 +758,9 @@ int zone_update_commit(conf_t *conf, zone_update_t *update)
update->a_ctx = NULL;
update->new_cont = NULL;
zone_contents_apply(update->zone->contents, check_unified, NULL);
zone_contents_nsec3_apply(update->zone->contents, check_unified, NULL);
/* Sync zonefile immediately if configured. */
val = conf_zone_get(conf, C_ZONEFILE_SYNC, update->zone->name);
if (conf_int(&val) == 0) {
......
......@@ -25,10 +25,7 @@ int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone)
{
zone_node_t *parent = node_parent(node);
// check if this node is not a wildcard child of its parent
if (knot_dname_is_wildcard(node->owner)) {
parent->flags |= NODE_FLAGS_WILDCARD_CHILD;
}
assert(!(node->flags & NODE_FLAGS_DELETED));
// set flags (delegation point, non-authoritative)
if (parent && (parent->flags & NODE_FLAGS_DELEG || parent->flags & NODE_FLAGS_NONAUTH)) {
......@@ -37,7 +34,7 @@ int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone)
node->flags |= NODE_FLAGS_DELEG;
} else {
// Default.
node->flags = NODE_FLAGS_AUTH | (node->flags & NODE_FLAGS_APEX);
node->flags &= ~(NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH);
}
return KNOT_EOK; // always returns this value :)
......@@ -75,7 +72,13 @@ int unadjust_cb_point_to_nsec3(zone_node_t *node, const zone_contents_t *zone)
int adjust_cb_wildcard_nsec3(zone_node_t *node, const zone_contents_t *zone)
{
free(node->nsec3_wildcard_name);
zone_node_t *counter = binode_counterpart(node);
assert(counter != NULL);
if (counter->nsec3_wildcard_name != node->nsec3_wildcard_name) {
// FIXME this should never happen, but it does
free(node->nsec3_wildcard_name);
}
node->nsec3_wildcard_name = NULL;
if (!knot_is_nsec3_enabled(zone)) {
return KNOT_EOK;
......@@ -118,6 +121,7 @@ static bool nsec3_params_match(const knot_rdataset_t *rrs,
int adjust_cb_nsec3_flags(zone_node_t *node, const zone_contents_t *zone)
{
// check if this node belongs to correct chain
node->flags &= ~NODE_FLAGS_IN_NSEC3_CHAIN;
const knot_rdataset_t *nsec3_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC3);
for (uint16_t i = 0; nsec3_rrs != NULL && i < nsec3_rrs->count; i++) {
if (nsec3_params_match(nsec3_rrs, &zone->nsec3_params, i)) {
......@@ -128,15 +132,12 @@ int adjust_cb_nsec3_flags(zone_node_t *node, const zone_contents_t *zone)
}
/*! \brief Link pointers to additional nodes for this RRSet. */
static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_data,
static int discover_additionals(zone_node_t *adjn, uint16_t rr_at,
const zone_contents_t *zone)
{
struct rr_data *rr_data = &adjn->rrs[rr_at];
assert(rr_data != NULL);
/* Drop possible previous additional nodes. */
additional_clear(rr_data->additional);
rr_data->additional = NULL;
const knot_rdataset_t *rrs = &rr_data->rrs;
uint16_t rdcount = rrs->count;
......@@ -158,7 +159,7 @@ static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_da
glue_t *glue;
if ((node->flags & (NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH)) &&
rr_data->type == KNOT_RRTYPE_NS &&
knot_dname_in_bailiwick(node->owner, owner) >= 0) {
knot_dname_in_bailiwick(node->owner, adjn->owner) >= 0) {
glue = &mandatory[mandatory_count++];
glue->optional = false;
} else {
......@@ -171,26 +172,45 @@ static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_da
/* Store sorted additionals by the type, mandatory first. */
size_t total_count = mandatory_count + others_count;
additional_t *new_addit = NULL;
if (total_count > 0) {
rr_data->additional = malloc(sizeof(additional_t));
if (rr_data->additional == NULL) {
new_addit = malloc(sizeof(additional_t));
if (new_addit == NULL) {
return KNOT_ENOMEM;
}
rr_data->additional->count = total_count;
new_addit->count = total_count;
size_t size = total_count * sizeof(glue_t);
rr_data->additional->glues = malloc(size);
if (rr_data->additional->glues == NULL) {
free(rr_data->additional);
new_addit->glues = malloc(size);
if (new_addit->glues == NULL) {
free(new_addit);
return KNOT_ENOMEM;
}
size_t mandatory_size = mandatory_count * sizeof(glue_t);
memcpy(rr_data->additional->glues, mandatory, mandatory_size);
memcpy(rr_data->additional->glues + mandatory_count, others,
memcpy(new_addit->glues, mandatory, mandatory_size);
memcpy(new_addit->glues + mandatory_count, others,
size - mandatory_size);
}
/* If the result differs, shallow copy node and store additionals. */
if (!additional_equal(rr_data->additional, new_addit)) {