]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
adjust: refactored measurement of zone size and max TTL
authorLibor Peltan <libor.peltan@nic.cz>
Thu, 23 May 2019 15:28:33 +0000 (17:28 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 24 May 2019 12:08:42 +0000 (14:08 +0200)
Knot.files
src/knot/Makefile.inc
src/knot/zone/adjust.c
src/knot/zone/adjust.h
src/knot/zone/measure.c [new file with mode: 0644]
src/knot/zone/measure.h [new file with mode: 0644]
src/knot/zone/node.c
src/knot/zone/node.h
tests/knot/test_zone-update.c

index 353c15aa79c6f73974eab1f953fde137563e1408..3790b8f95d2886be1f8a600312401c4283d1126c 100644 (file)
@@ -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
index dc916af28d65de3854434e226e758e2a47933451..f9a5f4d2dbc643fc025a35242bb7bc45a3fb8c74 100644 (file)
@@ -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              \
index 273fae61e814bff991771bd13cf6d9ba5ff76e28..0ef31582d36ef3211637c5e7c6165b076e05dd12 100644 (file)
 #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;
 }
index eea15bf4f7f69b09c389311c1705c559e9264767..e93a01142b48f934cd551cd0fa5cd369a3ca3482 100644 (file)
@@ -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 (file)
index 0000000..4c3ab5e
--- /dev/null
@@ -0,0 +1,133 @@
+/*  Copyright (C) 2019 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 <https://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..5c73c91
--- /dev/null
@@ -0,0 +1,71 @@
+/*  Copyright (C) 2019 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 <https://www.gnu.org/licenses/>.
+ */
+
+#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);
index 9ad65f59e1e187da978d39b295086ff75ac1a2cc..bf73e33de0c6c1408ddc516c0a581da273a1eb81 100644 (file)
@@ -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);
-       }
-}
index 4ca4f1933cd7b294d63001ecaf75c34d4c3b6a13..d0b671ce6043fde817e77a636ebc544d4bc89965 100644 (file)
@@ -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);
index 28781cd8dd87d055a4baa721e088934251b9809a..c5c9ef488bc1f145ceab28bd728fd5d9e92e0231 100644 (file)
 #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
 }