From: Libor Peltan Date: Thu, 23 May 2019 15:28:33 +0000 (+0200) Subject: adjust: refactored measurement of zone size and max TTL X-Git-Tag: v2.9.0~259^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=90e4a8c75764ea511c4274cc64ed986e8a4ef9ce;p=thirdparty%2Fknot-dns.git adjust: refactored measurement of zone size and max TTL --- diff --git a/Knot.files b/Knot.files index 353c15aa79..3790b8f95d 100644 --- a/Knot.files +++ b/Knot.files @@ -227,6 +227,8 @@ src/knot/zone/adjust.c src/knot/zone/adjust.h src/knot/zone/contents.c src/knot/zone/contents.h +src/knot/zone/measure.c +src/knot/zone/measure.h src/knot/zone/node.c src/knot/zone/node.h src/knot/zone/semantic-check.c diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc index dc916af28d..f9a5f4d2db 100644 --- a/src/knot/Makefile.inc +++ b/src/knot/Makefile.inc @@ -159,6 +159,8 @@ libknotd_la_SOURCES = \ knot/zone/adjust.h \ knot/zone/contents.c \ knot/zone/contents.h \ + knot/zone/measure.h \ + knot/zone/measure.c \ knot/zone/node.c \ knot/zone/node.h \ knot/zone/semantic-check.c \ diff --git a/src/knot/zone/adjust.c b/src/knot/zone/adjust.c index 273fae61e8..0ef31582d3 100644 --- a/src/knot/zone/adjust.c +++ b/src/knot/zone/adjust.c @@ -21,12 +21,7 @@ #include "knot/common/log.h" #include "knot/dnssec/zone-nsec.h" #include "knot/zone/adds_tree.h" - -typedef enum { - ADJUST_MEASURE_SIZE_NONE = 0, - ADJUST_MEASURE_SIZE_NORM = 1, - ADJUST_MEASURE_SIZE_DIFF = -1, -} adjust_measure_size_t; +#include "knot/zone/measure.h" int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone) { @@ -276,12 +271,9 @@ typedef struct { zone_node_t *first_node; const zone_contents_t *zone; zone_node_t *previous_node; - size_t zone_size; - size_t counter_size; - uint32_t zone_max_ttl; adjust_cb_t adjust_cb; bool adjust_prevs; - adjust_measure_size_t measure_size; + measure_t *m; } zone_adjust_arg_t; static int adjust_single(zone_node_t *node, void *data) @@ -290,9 +282,8 @@ static int adjust_single(zone_node_t *node, void *data) assert(data != NULL); zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; - if (args->measure_size == ADJUST_MEASURE_SIZE_DIFF) { - node_size(binode_counterpart(node), &args->counter_size); - } + + knot_measure_node(node, args->m); if ((node->flags & NODE_FLAGS_DELETED)) { return KNOT_EOK; @@ -313,18 +304,11 @@ static int adjust_single(zone_node_t *node, void *data) args->previous_node = node; } - if (args->measure_size) { - node_size(node, &args->zone_size); - } - - node_max_ttl(node, &args->zone_max_ttl); - return args->adjust_cb(node, args->zone); } static int zone_adjust_tree(zone_tree_t *tree, const zone_contents_t *zone, adjust_cb_t adjust_cb, - ssize_t *tree_size, uint32_t *tree_max_ttl, bool adjust_prevs, - adjust_measure_size_t measure_size) + bool adjust_prevs, measure_t *measure_ctx) { if (zone_tree_is_empty(tree)) { return KNOT_EOK; @@ -332,15 +316,9 @@ static int zone_adjust_tree(zone_tree_t *tree, const zone_contents_t *zone, adju zone_adjust_arg_t arg = { 0 }; arg.zone = zone; - if (tree_size != NULL) { - arg.zone_size = *tree_size; - } - if (tree_max_ttl != NULL) { - arg.zone_max_ttl = *tree_max_ttl; - } arg.adjust_cb = adjust_cb; arg.adjust_prevs = adjust_prevs; - arg.measure_size = measure_size; + arg.m = measure_ctx; int ret = zone_tree_apply(tree, adjust_single, &arg); if (ret != KNOT_EOK) { @@ -351,16 +329,10 @@ static int zone_adjust_tree(zone_tree_t *tree, const zone_contents_t *zone, adju arg.first_node->prev = arg.previous_node; } - if (tree_size != NULL) { - *tree_size = arg.zone_size - arg.counter_size; - } - if (tree_max_ttl != NULL) { - *tree_max_ttl = arg.zone_max_ttl; - } return KNOT_EOK; } -int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_size) +int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_zone) { int ret = zone_contents_load_nsec3param(zone); if (ret != KNOT_EOK) { @@ -371,39 +343,33 @@ int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_ } zone->dnssec = node_rrtype_is_signed(zone->apex, KNOT_RRTYPE_SOA); - ssize_t nodes_size = 0; - uint32_t nodes_max_ttl = 0; - adjust_measure_size_t ms = (measure_size && nodes_cb != NULL && nsec3_cb != NULL ? ADJUST_MEASURE_SIZE_NORM : ADJUST_MEASURE_SIZE_NONE); + measure_t m = knot_measure_init(measure_zone, false); if (nsec3_cb != NULL) { - ret = zone_adjust_tree(zone->nsec3_nodes, zone, nsec3_cb, &nodes_size, &nodes_max_ttl, true, ms); + ret = zone_adjust_tree(zone->nsec3_nodes, zone, nsec3_cb, true, &m); } if (ret == KNOT_EOK && nodes_cb != NULL) { - ret = zone_adjust_tree(zone->nodes, zone, nodes_cb, &nodes_size, &nodes_max_ttl, true, ms); + ret = zone_adjust_tree(zone->nodes, zone, nodes_cb, true, &m); } - if (ret == KNOT_EOK && nodes_cb != NULL && nsec3_cb != NULL) { - if (measure_size) { - zone->size = nodes_size; - } - zone->max_ttl = nodes_max_ttl; + if (ret == KNOT_EOK && measure_zone && nodes_cb != NULL && nsec3_cb != NULL) { + knot_measure_finish_zone(&m, zone); } return ret; } -int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_size) +int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_diff) { int ret = KNOT_EOK; - adjust_measure_size_t ms = (measure_size && nsec3_cb != NULL ? ADJUST_MEASURE_SIZE_DIFF : ADJUST_MEASURE_SIZE_NONE); - ssize_t nodes_size = 0, nsec3_size = 0; + measure_t m = knot_measure_init(false, measure_diff); if (nsec3_cb != NULL) { - ret = zone_adjust_tree(update->a_ctx->nsec3_ptrs, update->new_cont, nsec3_cb, &nsec3_size, NULL, false, ms); + ret = zone_adjust_tree(update->a_ctx->nsec3_ptrs, update->new_cont, nsec3_cb, false, &m); } if (ret == KNOT_EOK && nodes_cb != NULL) { - ret = zone_adjust_tree(update->a_ctx->node_ptrs, update->new_cont, nodes_cb, &nodes_size, NULL, false, ms); + ret = zone_adjust_tree(update->a_ctx->node_ptrs, update->new_cont, nodes_cb, false, &m); } - if (ret == KNOT_EOK && measure_size && nodes_cb != NULL && nsec3_cb != NULL) { - update->new_cont->size += nodes_size + nsec3_size; + if (ret == KNOT_EOK && measure_diff && nodes_cb != NULL && nsec3_cb != NULL) { + knot_measure_finish_update(&m, update); } return ret; } diff --git a/src/knot/zone/adjust.h b/src/knot/zone/adjust.h index eea15bf4f7..e93a01142b 100644 --- a/src/knot/zone/adjust.h +++ b/src/knot/zone/adjust.h @@ -66,11 +66,11 @@ int adjust_cb_void(zone_node_t *node, const zone_contents_t *zone); * \param zone Zone to be adjusted. * \param nodes_cb Callback for NORMAL nodes. * \param nsec3_cb Callback for NSEC3 nodes. - * \param measure_size While adjusting, count the size of the zone and store it to contents. + * \param measure_zone While adjusting, count the size and max TTL of the zone. * * \return KNOT_E* */ -int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_size); +int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_zone); /*! * \brief Apply callback to nodes affected by the zone update. @@ -82,11 +82,11 @@ int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_ * \param update Zone update being finalized. * \param nodes_cb Callback for NORMAL nodes. * \param nsec3_cb Callback for NSEC3 nodes. - * \param measure_size While adjusting, count the size of the zone and store it to contents. + * \param measure_diff While adjusting, count the size difference and max TTL change. * * \return KNOT_E* */ -int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_size); +int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb, bool measure_diff); /*! * \brief Do a general-purpose full update. diff --git a/src/knot/zone/measure.c b/src/knot/zone/measure.c new file mode 100644 index 0000000000..4c3ab5e762 --- /dev/null +++ b/src/knot/zone/measure.c @@ -0,0 +1,133 @@ +/* Copyright (C) 2019 CZ.NIC, z.s.p.o. + + 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 . + */ + +#include "knot/zone/measure.h" + +measure_t knot_measure_init(bool measure_whole, bool measure_diff) +{ + assert(!measure_whole || !measure_diff); + measure_t m = { 0 }; + if (measure_whole) { + m.how_size = MEASURE_SIZE_WHOLE; + m.how_ttl = MEASURE_TTL_WHOLE; + } + if (measure_diff) { + m.how_size = MEASURE_SIZE_DIFF; + m.how_ttl = MEASURE_TTL_DIFF; + } + return m; +} + +bool knot_measure_node(zone_node_t *node, measure_t *m) +{ + if (m->how_size == MEASURE_SIZE_NONE && (m->how_ttl == MEASURE_TTL_NONE || + (m->how_ttl == MEASURE_TTL_LIMIT && m->max_ttl >= m->limit_max_ttl))) { + return false; + } + + int rrset_count = node->rrset_count; + for (int i = 0; i < rrset_count; i++) { + if (m->how_size != MEASURE_SIZE_NONE) { + knot_rrset_t rrset = node_rrset_at(node, i); + m->zone_size += knot_rrset_size(&rrset); + } + if (m->how_ttl != MEASURE_TTL_NONE) { + m->max_ttl = MAX(m->max_ttl, node->rrs[i].ttl); + } + } + + if (m->how_size != MEASURE_SIZE_DIFF && m->how_ttl != MEASURE_TTL_DIFF) { + return true; + } + + node = binode_counterpart(node); + rrset_count = node->rrset_count; + for (int i = 0; i < rrset_count; i++) { + if (m->how_size == MEASURE_SIZE_DIFF) { + knot_rrset_t rrset = node_rrset_at(node, i); + m->zone_size -= knot_rrset_size(&rrset); + } + if (m->how_ttl == MEASURE_TTL_DIFF) { + m->rem_max_ttl = MAX(m->rem_max_ttl, node->rrs[i].ttl); + } + } + + return true; +} + +static uint32_t re_measure_max_ttl(zone_contents_t *zone, uint32_t limit) +{ + measure_t m = {0 }; + m.how_ttl = MEASURE_TTL_LIMIT; + m.limit_max_ttl = limit; + + zone_tree_it_t it = { 0 }; + int ret = zone_tree_it_double_begin(zone->nodes, zone->nsec3_nodes, &it); + if (ret != KNOT_EOK) { + return limit; + } + + while (!zone_tree_it_finished(&it) && knot_measure_node(zone_tree_it_val(&it), &m)) { + zone_tree_it_next(&it); + } + zone_tree_it_free(&it); + + return m.max_ttl; +} + +void knot_measure_finish_zone(measure_t *m, zone_contents_t *zone) +{ + assert(m->how_size == MEASURE_SIZE_WHOLE || m->how_size == MEASURE_SIZE_NONE); + assert(m->how_ttl == MEASURE_TTL_WHOLE || m->how_ttl == MEASURE_TTL_NONE); + if (m->how_size == MEASURE_SIZE_WHOLE) { + zone->size = m->zone_size; + } + if (m->how_ttl == MEASURE_TTL_WHOLE) { + zone->max_ttl = m->max_ttl; + } +} + +void knot_measure_finish_update(measure_t *m, zone_update_t *update) +{ + switch (m->how_size) { + case MEASURE_SIZE_NONE: + break; + case MEASURE_SIZE_WHOLE: + update->new_cont->size = m->zone_size; + break; + case MEASURE_SIZE_DIFF: + update->new_cont->size = update->zone->contents->size + m->zone_size; + break; + } + + switch (m->how_ttl) { + case MEASURE_TTL_NONE: + break; + case MEASURE_TTL_WHOLE: + case MEASURE_TTL_LIMIT: + update->new_cont->max_ttl = m->max_ttl; + break; + case MEASURE_TTL_DIFF: + if (m->max_ttl >= update->zone->contents->max_ttl) { + update->new_cont->max_ttl = m->max_ttl; + } else if (update->zone->contents->max_ttl > m->rem_max_ttl) { + update->new_cont->max_ttl = update->zone->contents->max_ttl; + } else { + update->new_cont->max_ttl = re_measure_max_ttl(update->new_cont, update->zone->contents->max_ttl); + } + break; + } +} diff --git a/src/knot/zone/measure.h b/src/knot/zone/measure.h new file mode 100644 index 0000000000..5c73c91f57 --- /dev/null +++ b/src/knot/zone/measure.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2019 CZ.NIC, z.s.p.o. + + 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 . + */ + +#pragma once + +#include "knot/updates/zone-update.h" + +typedef enum { + MEASURE_SIZE_NONE = 0, // don't measure size of zone + MEASURE_SIZE_WHOLE, // measure complete size of zone nodes + MEASURE_SIZE_DIFF, // measure difference in size for bi-nodes in zone update +} measure_size_t; + +typedef enum { + MEASURE_TTL_NONE = 0, // don't measure max TTL of zone records + MEASURE_TTL_WHOLE, // measure max TTL among all zone records + MEASURE_TTL_DIFF, // check out zone update (bi-nodes) if the max TTL is affected + MEASURE_TTL_LIMIT, // measure max TTL whole; stop if a specific value is reached +} measure_ttl_t; + +typedef struct { + measure_size_t how_size; + measure_ttl_t how_ttl; + ssize_t zone_size; + uint32_t max_ttl; + uint32_t rem_max_ttl; + uint32_t limit_max_ttl; +} measure_t; + +/*! \brief Initialize measure struct. */ +measure_t knot_measure_init(bool measure_whole, bool measure_diff); + +/*! + * \brief Measure one node's size and max TTL, collecting into measure struct. + * + * \param node Node to be measured. + * \param m Measure context with instructions and results. + * + * \return False if no more measure is needed. + * \note You will probably ignore the return value. + */ +bool knot_measure_node(zone_node_t *node, measure_t *m); + +/*! + * \brief Collect the measured results and update the new zone with measured properties. + * + * \param zone Zone. + * \param m Measured results. + */ +void knot_measure_finish_zone(measure_t *m, zone_contents_t *zone); + +/*! + * \brief Collect the measured results and update the new zone with measured properties. + * + * \param update Zone update with the zone. + * \param m Measured results. + */ +void knot_measure_finish_update(measure_t *m, zone_update_t *update); diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c index 9ad65f59e1..bf73e33de0 100644 --- a/src/knot/zone/node.c +++ b/src/knot/zone/node.c @@ -390,22 +390,3 @@ bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b) } return true; } - -void node_size(const zone_node_t *node, size_t *size) -{ - if (node != NULL) { - int rrset_count = node->rrset_count; - for (int i = 0; i < rrset_count; i++) { - knot_rrset_t rrset = node_rrset_at(node, i); - *size += knot_rrset_size(&rrset); - } - } -} - -void node_max_ttl(const zone_node_t *node, uint32_t *max) -{ - int rrset_count = node->rrset_count; - for (int i = 0; i < rrset_count; i++) { - *max = MAX(*max, node->rrs[i].ttl); - } -} diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h index 4ca4f1933c..d0b671ce60 100644 --- a/src/knot/zone/node.h +++ b/src/knot/zone/node.h @@ -355,19 +355,3 @@ static inline knot_rrset_t node_rrset_at(const zone_node_t *node, size_t pos) rrset.additional = rr_data->additional; return rrset; } - -/*! - * \brief Compute node size. - * - * \param node Node in question. - * \param size In/out: node size will be added to this value. - */ -void node_size(const zone_node_t *node, size_t *size); - -/*! - * \brief Compute node maximum TTL. - * - * \param node Node in question. - * \param size In/out: this value will be maximalized with max TTL of node rrsets. - */ -void node_max_ttl(const zone_node_t *node, uint32_t *max); diff --git a/tests/knot/test_zone-update.c b/tests/knot/test_zone-update.c index 28781cd8dd..c5c9ef488b 100644 --- a/tests/knot/test_zone-update.c +++ b/tests/knot/test_zone-update.c @@ -30,11 +30,11 @@ #include "knot/server/server.h" static const char *zone_str1 = "test. 600 IN SOA ns.test. m.test. 1 900 300 4800 900 \n"; -static const char *zone_str2 = "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 const char *node_str1 = "node.test. IN TXT \"abc\"\n"; -static const char *node_str2 = "node.test. IN TXT \"def\"\n"; +static const char *zone_str2 = "test. 600 IN TXT \"test\"\n"; +static const char *add_str = "test. 600 IN TXT \"test2\"\n"; +static const char *del_str = "test. 600 IN TXT \"test\"\n"; +static const char *node_str1 = "node.test. 601 IN TXT \"abc\"\n"; +static const char *node_str2 = "node.test. 601 IN TXT \"def\"\n"; knot_rrset_t rrset; @@ -225,7 +225,7 @@ void test_full(zone_t *zone, zs_scanner_t *sc) ret = zone_update_commit(conf(), &update); node = zone_contents_find_node_for_rr(zone->contents, &rrset); rrset_present = node_contains_rr(node, &rrset); - ok(ret == KNOT_EOK && rrset_present, "full zone update: commit"); + ok(ret == KNOT_EOK && rrset_present, "full zone update: commit (max TTL: %u)", zone->contents->max_ttl); test_zone_unified(zone); @@ -334,10 +334,13 @@ void test_incremental(zone_t *zone, zs_scanner_t *sc) knot_rdataset_clear(&rrset.rrs, NULL); size_t zone_size1 = zone->contents->size; + uint32_t zone_max_ttl1 = zone->contents->max_ttl; ret = zone_adjust_full(zone->contents); ok(ret == KNOT_EOK, "zone adjust full shall work"); size_t zone_size2 = zone->contents->size; - ok(zone_size1 == zone_size2, "zone size measured the same by incremental and full way (%zu, %zu)", zone_size1, zone_size2); + uint32_t zone_max_ttl2 = zone->contents->max_ttl; + ok(zone_size1 == zone_size2, "zone size measured the same incremental vs full (%zu, %zu)", zone_size1, zone_size2); + ok(zone_max_ttl1 == zone_max_ttl2, "zone max TTL measured the same incremental vs full (%u, %u)", zone_max_ttl1, zone_max_ttl2); // TODO test more things after re-adjust, search for non-unified bi-nodes }