Commit f78a209c authored by Jan Kadlec's avatar Jan Kadlec

zone API: initial commit of zone+changeset hybrid

parent fa7cf958
......@@ -338,3 +338,6 @@ tests/worker_queue.c
tests/zone_events.c
tests/zonedb.c
tests/ztree.c
src/knot/updates/zone-update.c
src/knot/updates/zone-update.h
tests/zone-update.c
......@@ -281,6 +281,8 @@ libknotd_la_SOURCES = \
knot/updates/ddns.h \
knot/updates/apply.c \
knot/updates/apply.h \
knot/updates/zone-update.c \
knot/updates/zone-update.h \
knot/worker/pool.c \
knot/worker/pool.h \
knot/worker/queue.c \
......
......@@ -121,7 +121,7 @@ static int shallow_copy_signature(const zone_node_t *from, zone_node_t *to)
if (knot_rrset_empty(&from_sig)) {
return KNOT_EOK;
}
return node_add_rrset(to, &from_sig);
return node_add_rrset(to, &from_sig, NULL);
}
/*!
......@@ -179,7 +179,7 @@ static void free_nsec3_tree(zone_tree_t *nodes)
knot_rdataset_t *rrsig = node_rdataset(node, KNOT_RRTYPE_RRSIG);
knot_rdataset_clear(nsec3, NULL);
knot_rdataset_clear(rrsig, NULL);
node_free(&node);
node_free(&node, NULL);
}
hattrie_iter_free(it);
......@@ -283,7 +283,7 @@ static zone_node_t *create_nsec3_node(knot_dname_t *owner,
assert(apex_node);
assert(rr_types);
zone_node_t *new_node = node_new(owner);
zone_node_t *new_node = node_new(owner, NULL);
if (!new_node) {
return NULL;
}
......@@ -294,14 +294,14 @@ static zone_node_t *create_nsec3_node(knot_dname_t *owner,
int ret = create_nsec3_rrset(&nsec3_rrset, owner, nsec3_params,
rr_types, NULL, ttl);
if (ret != KNOT_EOK) {
node_free(&new_node);
node_free(&new_node, NULL);
return NULL;
}
ret = node_add_rrset(new_node, &nsec3_rrset);
ret = node_add_rrset(new_node, &nsec3_rrset, NULL);
knot_rrset_clear(&nsec3_rrset, NULL);
if (ret != KNOT_EOK) {
node_free(&new_node);
node_free(&new_node, NULL);
return NULL;
}
......
......@@ -240,7 +240,7 @@ static int add_rr(zone_node_t *node, const knot_rrset_t *rr,
}
// Insert new RR to RRSet, data will be copied.
int ret = node_add_rrset(node, rr);
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);
......@@ -385,7 +385,7 @@ static int remove_empty_tree_nodes(zone_tree_t *tree)
if (ret != KNOT_EOK) {
return ret;
}
node_free(&node);
node_free(&node, NULL);
free(n);
}
......
......@@ -449,7 +449,7 @@ static bool skip_record_addition(changeset_t *changeset,
// Replace singleton RR.
knot_rdataset_clear(rrs, NULL);
node_remove_rdataset(n, rr->type);
node_add_rrset(n, rr);
node_add_rrset(n, rr, NULL);
return true;
}
......
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "knot/updates/zone-update.h"
#include "common/lists.h"
#include "common/mempool.h"
static bool node_empty(const zone_node_t *node)
{
return node == NULL || node->rrset_count == 0;
}
static int add_to_node(zone_node_t *old_node, const zone_node_t *add_node,
mm_ctx_t *mm)
{
for (uint16_t i = 0; i < add_node->rrset_count; ++i) {
knot_rrset_t rr = node_rrset_at(add_node, i);
if (!knot_rrset_empty(&rr)) {
int ret = node_add_rrset(old_node, &rr, mm);
if (ret != KNOT_EOK) {
return ret;
}
}
}
return KNOT_EOK;
}
static int rem_from_node(zone_node_t *old_node, const zone_node_t *rem_node,
mm_ctx_t *mm)
{
for (uint16_t i = 0; i < rem_node->rrset_count; ++i) {
knot_rrset_t rem_rrset = node_rrset_at(rem_node, i);
knot_rrset_t to_change = node_rrset(old_node, rem_rrset.type);
if (!knot_rrset_empty(&to_change) &&
!(knot_rrset_empty(&rem_rrset))) {
// Remove data from synthesized node
int ret = knot_rdataset_subtract(&to_change.rrs,
&rem_rrset.rrs,
mm);
if (ret != KNOT_EOK) {
return ret;
}
}
}
return KNOT_EOK;
}
static int apply_changes_to_node(zone_node_t *synth_node, const zone_node_t *add_node,
const zone_node_t *rem_node, mm_ctx_t *mm)
{
// Add changes to node
if (!node_empty(add_node)) {
int ret = add_to_node(synth_node, add_node, mm);
if (ret != KNOT_EOK) {
node_free(&synth_node, mm);
return ret;
}
}
// Remove changes from node
if (!node_empty(rem_node)) {
int ret = rem_from_node(synth_node, rem_node, mm);
if (ret != KNOT_EOK) {
node_free(&synth_node, mm);
return ret;
}
}
return KNOT_EOK;
}
static int deep_copy_node_data(zone_node_t *node_copy, const zone_node_t *old_node,
mm_ctx_t *mm)
{
for (uint16_t i = 0; i < old_node->rrset_count; ++i) {
int ret = knot_rdataset_copy(&node_copy->rrs[i].rrs,
&old_node->rrs[i].rrs, mm);
if (ret != KNOT_EOK) {
#warning leak
return ret;
}
}
return KNOT_EOK;
}
void zone_update_init(zone_update_t *update, const zone_contents_t *zone, changeset_t *change)
{
update->zone = zone;
update->change = change;
mm_ctx_mempool(&update->mm, 4096);
}
/* Node is either zone original or synthesized, cannot free nor modify. */
const zone_node_t *zone_update_get_node(zone_update_t *update, const knot_dname_t *dname)
{
if (update == NULL || dname == NULL) {
return NULL;
}
const zone_node_t *old_node = zone_contents_find_node(update->zone, dname);
const zone_node_t *add_node = zone_contents_find_node(update->change->add, dname);
const zone_node_t *rem_node = zone_contents_find_node(update->change->remove, dname);
const bool have_change = !node_empty(add_node) || !node_empty(rem_node);
if (!have_change) {
return old_node;
}
zone_node_t *synth_node = NULL;
if (old_node) {
synth_node = node_shallow_copy(old_node, &update->mm);
if (synth_node == NULL) {
return NULL;
}
// Deep copy data inside node copy
int ret = deep_copy_node_data(synth_node, old_node, &update->mm);
if (ret != KNOT_EOK) {
node_free(&synth_node, &update->mm);
return NULL;
}
// Apply changes to node
ret = apply_changes_to_node(synth_node, add_node, rem_node, &update->mm);
if (ret != KNOT_EOK) {
node_free(&synth_node, &update->mm);
return NULL;
}
return synth_node;
} else {
if (add_node && node_empty(rem_node)) {
// Just addition
return add_node;
} else {
// Addition and deletion
#warning do not allow this
return NULL;
}
}
}
void zone_update_clear(zone_update_t *update)
{
mp_delete(update->mm.ctx);
update->zone = NULL;
update->change = NULL;
}
/*!
* \file zone_update.h
*
* \author Jan Kadlec <jan.kadlec@nic.cz>
*
* \brief API for quering zone that is being updated.
*
* \addtogroup server
* @{
*/
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "knot/updates/changesets.h"
#include "knot/zone/contents.h"
#include "common/mempattern.h"
typedef struct {
const zone_contents_t *zone;
const changeset_t *change;
mm_ctx_t mm;
} zone_update_t;
struct zone_node;
void zone_update_init(zone_update_t *update, const zone_contents_t *zone, changeset_t *change);
/* Node is either zone original or synthesized, cannot free or modify. */
const zone_node_t *zone_update_get_node(zone_update_t *update, const knot_dname_t *dname);
void zone_update_clear(zone_update_t *update);
......@@ -107,7 +107,7 @@ static int zone_contents_destroy_node_rrsets_from_tree(
assert(tnode != NULL);
if (*tnode != NULL) {
node_free_rrsets(*tnode);
node_free(tnode);
node_free(tnode, NULL);
}
return KNOT_EOK;
......@@ -411,7 +411,7 @@ zone_contents_t *zone_contents_new(const knot_dname_t *apex_name)
}
memset(contents, 0, sizeof(zone_contents_t));
contents->apex = node_new(apex_name);
contents->apex = node_new(apex_name, NULL);
if (contents->apex == NULL) {
goto cleanup;
}
......@@ -502,7 +502,7 @@ static int zone_contents_add_node(zone_contents_t *zone, zone_node_t *node,
/* Create a new node. */
dbg_zone_detail("Creating new node.\n");
next_node = node_new(parent);
next_node = node_new(parent, NULL);
if (next_node == NULL) {
return KNOT_ENOMEM;
}
......@@ -511,7 +511,7 @@ static int zone_contents_add_node(zone_contents_t *zone, zone_node_t *node,
dbg_zone_detail("Inserting new node to zone tree.\n");
ret = zone_tree_insert(zone->nodes, next_node);
if (ret != KNOT_EOK) {
node_free(&next_node);
node_free(&next_node, NULL);
return ret;
}
......@@ -614,19 +614,19 @@ static int insert_rr(zone_contents_t *z,
zone_contents_get_node(z, rr->owner);
if (*n == NULL) {
// Create new, insert
*n = node_new(rr->owner);
*n = node_new(rr->owner, NULL);
if (*n == NULL) {
return KNOT_ENOMEM;
}
ret = nsec3 ? zone_contents_add_nsec3_node(z, *n) :
zone_contents_add_node(z, *n, true);
if (ret != KNOT_EOK) {
node_free(n);
node_free(n, NULL);
}
}
}
return node_add_rrset(*n, rr);
return node_add_rrset(*n, rr, NULL);
}
static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
......@@ -637,7 +637,7 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
}
// Insert APEX first.
zone_node_t *apex_cpy = node_shallow_copy(z->apex);
zone_node_t *apex_cpy = node_shallow_copy(z->apex, NULL);
if (apex_cpy == NULL) {
return KNOT_ENOMEM;
}
......@@ -645,7 +645,7 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
// Normal additions need apex ... so we need to insert directly.
int ret = zone_tree_insert(out->nodes, apex_cpy);
if (ret != KNOT_EOK) {
node_free(&apex_cpy);
node_free(&apex_cpy, NULL);
return ret;
}
......@@ -662,7 +662,7 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
hattrie_iter_next(itt);
continue;
}
zone_node_t *to_add = node_shallow_copy(to_cpy);
zone_node_t *to_add = node_shallow_copy(to_cpy, NULL);
if (to_add == NULL) {
hattrie_iter_free(itt);
return KNOT_ENOMEM;
......@@ -670,7 +670,7 @@ static int recreate_normal_tree(const zone_contents_t *z, zone_contents_t *out)
int ret = zone_contents_add_node(out, to_add, true);
if (ret != KNOT_EOK) {
node_free(&to_add);
node_free(&to_add, NULL);
hattrie_iter_free(itt);
return ret;
}
......@@ -696,7 +696,7 @@ static int recreate_nsec3_tree(const zone_contents_t *z, zone_contents_t *out)
}
while (!hattrie_iter_finished(itt)) {
const zone_node_t *to_cpy = (zone_node_t *)*hattrie_iter_val(itt);
zone_node_t *to_add = node_shallow_copy(to_cpy);
zone_node_t *to_add = node_shallow_copy(to_cpy, NULL);
if (to_add == NULL) {
hattrie_iter_free(itt);
return KNOT_ENOMEM;
......@@ -704,7 +704,7 @@ static int recreate_nsec3_tree(const zone_contents_t *z, zone_contents_t *out)
int ret = zone_contents_add_nsec3_node(out, to_add);
if (ret != KNOT_EOK) {
hattrie_iter_free(itt);
node_free(&to_add);
node_free(&to_add, NULL);
return ret;
}
hattrie_iter_next(itt);
......@@ -1397,14 +1397,14 @@ zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrs
if (node == NULL) {
int ret = KNOT_EOK;
node = node_new(rrset->owner);
node = node_new(rrset->owner, NULL);
if (!nsec3) {
ret = zone_contents_add_node(zone, node, 1);
} else {
ret = zone_contents_add_nsec3_node(zone, node);
}
if (ret != KNOT_EOK) {
node_free(&node);
node_free(&node, NULL);
return NULL;
}
......
......@@ -82,9 +82,9 @@ static bool ttl_error(struct rr_data *node_data, const knot_rrset_t *rrset)
return inserted_ttl != node_ttl;
}
zone_node_t *node_new(const knot_dname_t *owner)
zone_node_t *node_new(const knot_dname_t *owner, mm_ctx_t *mm)
{
zone_node_t *ret = malloc(sizeof(zone_node_t));
zone_node_t *ret = mm_alloc(mm, sizeof(zone_node_t));
if (ret == NULL) {
ERR_ALLOC_FAILED;
return NULL;
......@@ -92,7 +92,7 @@ zone_node_t *node_new(const knot_dname_t *owner)
memset(ret, 0, sizeof(*ret));
if (owner) {
ret->owner = knot_dname_copy(owner, NULL);
ret->owner = knot_dname_copy(owner, mm);
if (ret->owner == NULL) {
free(ret);
return NULL;
......@@ -118,30 +118,30 @@ void node_free_rrsets(zone_node_t *node)
node->rrset_count = 0;
}
void node_free(zone_node_t **node)
void node_free(zone_node_t **node, mm_ctx_t *mm)
{
if (node == NULL || *node == NULL) {
return;
}
if ((*node)->rrs != NULL) {
free((*node)->rrs);
mm_free(mm, (*node)->rrs);
}
knot_dname_free(&(*node)->owner, NULL);
knot_dname_free(&(*node)->owner, mm);
free(*node);
mm_free(mm, *node);
*node = NULL;
}
zone_node_t *node_shallow_copy(const zone_node_t *src)
zone_node_t *node_shallow_copy(const zone_node_t *src, mm_ctx_t *mm)
{
if (src == NULL) {
return NULL;
}
// create new node
zone_node_t *dst = node_new(src->owner);
zone_node_t *dst = node_new(src->owner, mm);
if (dst == NULL) {
return NULL;
}
......@@ -151,9 +151,9 @@ zone_node_t *node_shallow_copy(const zone_node_t *src)
// copy RRSets
dst->rrset_count = src->rrset_count;
size_t rrlen = sizeof(struct rr_data) * src->rrset_count;
dst->rrs = malloc(rrlen);
dst->rrs = mm_alloc(mm, rrlen);
if (dst->rrs == NULL) {
node_free(&dst);
node_free(&dst, mm);
return NULL;
}
memcpy(dst->rrs, src->rrs, rrlen);
......@@ -166,7 +166,7 @@ zone_node_t *node_shallow_copy(const zone_node_t *src)
return dst;
}
int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset)
int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, mm_ctx_t *mm)
{
if (node == NULL || rrset == NULL) {
return KNOT_EINVAL;
......@@ -177,7 +177,7 @@ int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset)
struct rr_data *node_data = &node->rrs[i];
const bool ttl_err = ttl_error(node_data, rrset);
int ret = knot_rdataset_merge(&node_data->rrs,
&rrset->rrs, NULL);
&rrset->rrs, mm);
if (ret != KNOT_EOK) {
return ret;
} else {
......
......@@ -89,7 +89,7 @@ enum node_flags {
*
* \return Newly created node or NULL if an error occured.
*/
zone_node_t *node_new(const knot_dname_t *owner);
zone_node_t *node_new(const knot_dname_t *owner, mm_ctx_t *mm);
/*!
* \brief Destroys allocated data within the node
......@@ -107,7 +107,7 @@ void node_free_rrsets(zone_node_t *node);
*
* \param node Node to be destroyed.
*/
void node_free(zone_node_t **node);
void node_free(zone_node_t **node, mm_ctx_t *mm);
/*!
* \brief Creates a shallow copy of node structure, RR data are shared.
......@@ -116,7 +116,7 @@ void node_free(zone_node_t **node);
*
* \return Copied node if success, NULL otherwise.
*/
zone_node_t *node_shallow_copy(const zone_node_t *src);
zone_node_t *node_shallow_copy(const zone_node_t *src, mm_ctx_t *mm);
/* ----------------------- Data addition/removal -----------------------------*/
......@@ -129,7 +129,7 @@ zone_node_t *node_shallow_copy(const zone_node_t *src);
*
* \return KNOT_E*
*/
int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset);
int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, mm_ctx_t *mm);
/*!
* \brief Removes data for given RR type from node.
......
......@@ -282,7 +282,7 @@ static int zone_tree_free_node(zone_node_t **node, void *data)
{
UNUSED(data);
if (node) {
node_free(node);
node_free(node, NULL);
}
return KNOT_EOK;
}
......
......@@ -27,6 +27,7 @@ check_PROGRAMS = \
ztree \
zonedb \
changeset \
zone-update \
dnssec_keys \
dnssec_nsec3 \
dnssec_sign \
......
......@@ -63,7 +63,7 @@ int main(int argc, char *argv[])
node_set_parent(node, parent);
ok(node->parent == parent && parent->children == 1, "Node: set parent.");
node_free(&parent);
node_free(&parent, NULL);
// Test RRSet addition
knot_rrset_t *dummy_rrset = create_dummy_rrset(dummy_owner, KNOT_RRTYPE_TXT);
......@@ -83,7 +83,7 @@ int main(int argc, char *argv[])
copy->flags == node->flags;
ok(copy_ok, "Node: shallow copy - set fields.");
node_free(&copy);
node_free(&copy, NULL);
// Test RRSet getters
knot_rrset_t *n_rrset = node_create_rrset(node, KNOT_RRTYPE_TXT);
......@@ -149,7 +149,7 @@ int main(int argc, char *argv[])
node_free_rrsets(node);
ok(node->rrset_count == 0, "Node: free RRSets.");
node_free(&node);
node_free(&node, NULL);
ok(node == NULL, "Node: free.");
knot_dname_free(&dummy_owner, NULL);
......
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <assert.h>
#include <tap/basic.h>
#include "knot/updates/zone-update.h"
#include "zscanner/zscanner.h"
#include "common/getline.h"
static const char *zone_str =
"test. 3600 IN SOA a.ns.test. hostmaster.nic.cz. 1406641065 900 300 604800 900 \n"
"test. IN TXT \"test\"\n";
static const char *add_str =
"test. IN TXT \"test2\"\n";
static const char *del_str =
"test. IN TXT \"test\"\n";
static void process_rr(zs_scanner_t *scanner)
{
// get zone to insert into
zone_contents_t *zone = scanner->data;
// create data
knot_rrset_t *rr = knot_rrset_new(scanner->r_owner,
scanner->r_type,
scanner->r_class, NULL);
assert(rr);
int ret = knot_rrset_add_rdata(rr, scanner->r_data,
scanner->r_data_length,
scanner->r_ttl, NULL);
assert(ret == KNOT_EOK);
// add to zone
zone_node_t *n = NULL;
ret = zone_contents_add_rr(zone, rr, &n);
knot_rrset_free(&rr, NULL);
UNUSED(n);
assert(ret == KNOT_EOK);
}
int main(int argc, char *argv[])
{
plan(4);
zone_contents_t *zone = zone_contents_new(knot_dname_from_str("test."));
assert(zone);
changeset_t ch;
int ret = changeset_init(&ch, zone->apex->owner);
assert(ret == KNOT_EOK);
zone_update_t update;
zone_update_init(&update, zone, &ch);
ok(update.zone == zone && update.change == &ch && update.mm.alloc,
"zone update: init");
// Fill zone
zs_scanner_t *sc = zs_scanner_create(NULL, "test.", KNOT_CLASS_IN, 3600, process_rr,
NULL, zone);
assert(sc);
ret = zs_scanner_process(zone_str, zone_str + strlen(zone_str), true, sc);
assert(ret == 0);
// Check that old node is returned without changes
ok(zone->apex == zone_update_get_node(&update, zone->apex->owner),
"zone update: no change");
// Add RRs to add section
sc->data = ch.add;
ret = zs_scanner_process(add_str, add_str + strlen(add_str), true, sc);
assert(ret == 0);
// Check that apex TXT has two RRs now
const zone_node_t *synth_node = zone_update_get_node(&update, zone->apex->owner);
ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->rr_count == 2,
"zone update: add change");
// Add RRs to remove section
sc->data = ch.remove;
ret = zs_scanner_process(del_str, del_str + strlen(del_str), true, sc);
assert(ret == 0);
// Check that apex TXT has one RR again
synth_node = zone_update_get_node(&update, zone->apex->owner);
ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->rr_count == 1,
"zone update: del change");
return 0;
}
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