]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
zone-in-journal: serialize zone contents directly
authorLibor Peltan <libor.peltan@nic.cz>
Wed, 13 Feb 2019 14:20:21 +0000 (15:20 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Fri, 26 Apr 2019 12:39:58 +0000 (14:39 +0200)
src/knot/journal/journal_basic.c
src/knot/journal/journal_basic.h
src/knot/journal/journal_write.c
src/knot/journal/journal_write.h
src/knot/journal/serialization.c
src/knot/journal/serialization.h
src/knot/updates/changesets.c
src/knot/updates/changesets.h
src/knot/zone/zone.c
tests/knot/test_journal.c

index d0aff1bdf4b8c4df2f8400861c04d5e081980a89..be138f6d21cc55a3f2c4f3e68a85e9814f077a2d 100644 (file)
@@ -38,9 +38,9 @@ MDB_val journal_changeset_to_chunk_key(const changeset_t *ch, uint32_t chunk_id)
        }
 }
 
-void journal_make_header(void *chunk, const changeset_t *ch)
+void journal_make_header(void *chunk, uint32_t ch_serial_to)
 {
-       knot_lmdb_make_key_part(chunk, JOURNAL_HEADER_SIZE, "IILLL", changeset_to(ch),
+       knot_lmdb_make_key_part(chunk, JOURNAL_HEADER_SIZE, "IILLL", ch_serial_to,
                                (uint32_t)0 /* we no longer care for # of chunks */,
                                (uint64_t)0, (uint64_t)0, (uint64_t)0);
 }
index f9637a995d5c0cfa01e48dcc90aa57c902a44443..10e29fd18cce0e23d64d019b99ad5810e80e1831 100644 (file)
@@ -60,9 +60,9 @@ MDB_val journal_changeset_to_chunk_key(const changeset_t *ch, uint32_t chunk_id)
  * \brief Initialise chunk header.
  *
  * \param chunk   Pointer to the changeset chunk. It must be at least JOURNAL_HEADER_SIZE, perhaps more.
- * \param ch      Changeset to be serialized into the chunk.
+ * \param ch      Serial-to of the changeset being serialized.
  */
-void journal_make_header(void *chunk, const changeset_t *ch);
+void journal_make_header(void *chunk, uint32_t ch_serial_to);
 
 /*!
  * \brief Obtain serial-to of the serialized changeset.
index 2cbd51b1f71b2370f7f09b27bdef4b1eb3841f88..6e9d30e0c8d837c42539e5cc4de62ca5f8ad7f5f 100644 (file)
 #include "knot/journal/serialization.h"
 #include "libknot/error.h"
 
-void journal_write_changeset(knot_lmdb_txn_t *txn, const changeset_t *ch)
+static void journal_write_serialize(knot_lmdb_txn_t *txn, serialize_ctx_t *ser, const changeset_t *ch, uint32_t ch_serial_to)
 {
        MDB_val chunk;
-       serialize_ctx_t *ser = serialize_init(ch);
-       if (ser == NULL) {
-               txn->ret = KNOT_ENOMEM;
-               return;
-       }
        uint32_t i = 0;
        while (serialize_unfinished(ser) && txn->ret == KNOT_EOK) {
                serialize_prepare(ser, JOURNAL_CHUNK_MAX - JOURNAL_HEADER_SIZE, &chunk.mv_size);
@@ -40,7 +35,7 @@ void journal_write_changeset(knot_lmdb_txn_t *txn, const changeset_t *ch)
                chunk.mv_data = NULL;
                MDB_val key = journal_changeset_to_chunk_key(ch, i);
                if (knot_lmdb_insert(txn, &key, &chunk)) {
-                       journal_make_header(chunk.mv_data, ch);
+                       journal_make_header(chunk.mv_data, ch_serial_to);
                        serialize_chunk(ser, chunk.mv_data + JOURNAL_HEADER_SIZE, chunk.mv_size - JOURNAL_HEADER_SIZE);
                }
                free(key.mv_data);
@@ -50,6 +45,29 @@ void journal_write_changeset(knot_lmdb_txn_t *txn, const changeset_t *ch)
        // return value is in the txn
 }
 
+void journal_write_changeset(knot_lmdb_txn_t *txn, const changeset_t *ch)
+{
+       serialize_ctx_t *ser = serialize_init(ch);
+       if (ser == NULL) {
+               txn->ret = KNOT_ENOMEM;
+               return;
+       }
+       journal_write_serialize(txn, ser, ch, changeset_to(ch));
+}
+
+void journal_write_zone(knot_lmdb_txn_t *txn, const zone_contents_t *z)
+{
+       serialize_ctx_t *ser = serialize_zone_init(z);
+       if (ser == NULL) {
+               txn->ret = KNOT_ENOMEM;
+               return;
+       }
+       changeset_t fake_ch;
+       fake_ch.soa_from = NULL;
+       fake_ch.add = (zone_contents_t *)z;
+       journal_write_serialize(txn, ser, &fake_ch, zone_contents_serial(z));
+}
+
 static int merge_cb(bool remove, const knot_rrset_t *rr, void *ctx)
 {
        changeset_t *ch = ctx;
@@ -171,11 +189,8 @@ void journal_fix_occupation(zone_journal_t j, knot_lmdb_txn_t *txn, journal_meta
        }
 }
 
-int journal_insert_zone(zone_journal_t j, const changeset_t *ch)
+int journal_insert_zone(zone_journal_t j, const zone_contents_t *z)
 {
-       if (ch->remove != NULL) {
-               return KNOT_EINVAL;
-       }
        int ret = knot_lmdb_open(j.db);
        if (ret != KNOT_EOK) {
                return ret;
@@ -187,11 +202,11 @@ int journal_insert_zone(zone_journal_t j, const changeset_t *ch)
        MDB_val prefix = { knot_dname_size(j.zone), (void *)j.zone };
        knot_lmdb_del_prefix(&txn, &prefix);
 
-       journal_write_changeset(&txn, ch);
+       journal_write_zone(&txn, z);
 
        journal_metadata_t md = { 0 };
        md.flags = JOURNAL_SERIAL_TO_VALID;
-       md.serial_to = changeset_to(ch);
+       md.serial_to = zone_contents_serial(z);
        md.first_serial = md.serial_to;
        journal_store_metadata(&txn, j.zone, &md);
 
index 2aa9d1548d9697507cccc49caa3238d309f7ac7b..20fa6f944fe5fb97b1ea66a93fc6e7fea03efcbd 100644 (file)
  */
 void journal_write_changeset(knot_lmdb_txn_t *txn, const changeset_t *ch);
 
+/*!
+ * \brief Serialize zone contents aka "bootstrap" changeset into journal, no checks.
+ *
+ * \param txn   Journal DB transaction.
+ * \param z     Zone contents to be written.
+ */
+void journal_write_zone(knot_lmdb_txn_t *txn, const zone_contents_t *z);
+
 /*!
  * \brief Merge all following changeset into one of journal changeset.
  *
@@ -87,11 +95,11 @@ void journal_fix_occupation(zone_journal_t j, knot_lmdb_txn_t *txn, journal_meta
  * \brief Store zone-in-journal into the journal, update metadata.
  *
  * \param j    Zone journal.
- * \param ch   Changeset containing zone-in-journal.
+ * \param z    Zone contents to be stored.
  *
  * \return KNOT_E*
  */
-int journal_insert_zone(zone_journal_t j, const changeset_t *ch);
+int journal_insert_zone(zone_journal_t j, const zone_contents_t *z);
 
 /*!
  * \brief Store changeset into journal, fulfilling quotas and updating metadata.
index 6483b2735c6895d9f2ab6f53cfc81433c9025bc5..51cef81e7cc61a0028f7e539110b557d43306b93 100644 (file)
 #include <assert.h>
 
 #include "knot/journal/serialization.h"
+#include "knot/zone/zone-tree.h"
 #include "libknot/libknot.h"
 
 #define SERIALIZE_RRSET_INIT (-1)
 #define SERIALIZE_RRSET_DONE ((1L<<16)+1)
 
 typedef enum {
+       PHASE_ZONE_SOA,
+       PHASE_ZONE_NODES,
+       PHASE_ZONE_NSEC3,
        PHASE_SOA_1,
        PHASE_REM,
        PHASE_SOA_2,
@@ -33,6 +37,11 @@ typedef enum {
 #define RRSET_BUF_MAXSIZE 256
 
 struct serialize_ctx {
+       const zone_contents_t *z;
+       zone_tree_it_t zit;
+       zone_node_t *n;
+       uint16_t node_pos;
+
        const changeset_t *ch;
        changeset_iter_t it;
        serialize_phase_t changeset_phase;
@@ -56,11 +65,52 @@ serialize_ctx_t *serialize_init(const changeset_t *ch)
        return ctx;
 }
 
+serialize_ctx_t *serialize_zone_init(const zone_contents_t *z)
+{
+       serialize_ctx_t *ctx = calloc(1, sizeof(*ctx));
+       if (ctx == NULL) {
+               return NULL;
+       }
+
+       ctx->z = z;
+       ctx->changeset_phase = PHASE_ZONE_SOA;
+       ctx->rrset_phase = SERIALIZE_RRSET_INIT;
+       ctx->rrset_buf_size = 0;
+
+       return ctx;
+}
+
 static knot_rrset_t get_next_rrset(serialize_ctx_t *ctx)
 {
        knot_rrset_t res;
        knot_rrset_init_empty(&res);
        switch (ctx->changeset_phase) {
+       case PHASE_ZONE_SOA:
+               zone_tree_it_begin(ctx->z->nodes, &ctx->zit);
+               ctx->changeset_phase = PHASE_ZONE_NODES;
+               return node_rrset(ctx->z->apex, KNOT_RRTYPE_SOA);
+       case PHASE_ZONE_NODES:
+       case PHASE_ZONE_NSEC3:
+               while (ctx->n == NULL || ctx->node_pos >= ctx->n->rrset_count) {
+                       if (zone_tree_it_finished(&ctx->zit)) {
+                               zone_tree_it_free(&ctx->zit);
+                               if (ctx->changeset_phase == PHASE_ZONE_NSEC3 || zone_tree_is_empty(ctx->z->nsec3_nodes)) {
+                                       ctx->changeset_phase = PHASE_END;
+                                       return res;
+                               } else {
+                                       zone_tree_it_begin(ctx->z->nsec3_nodes, &ctx->zit);
+                                       ctx->changeset_phase = PHASE_ZONE_NSEC3;
+                               }
+                       }
+                       ctx->n = zone_tree_it_val(&ctx->zit);
+                       zone_tree_it_next(&ctx->zit);
+                       ctx->node_pos = 0;
+               }
+               res = node_rrset_at(ctx->n, ctx->node_pos++);
+               if (ctx->n == ctx->z->apex && res.type == KNOT_RRTYPE_SOA) {
+                       return get_next_rrset(ctx);
+               }
+               return res;
        case PHASE_SOA_1:
                changeset_iter_rem(&ctx->it, ctx->ch);
                ctx->changeset_phase = PHASE_REM;
index 9d4c40bf3e8e8b05efe3f950238127e58f39bede..8be2ebc2a23a90e0a96a8d8a51ea4f5617107981 100644 (file)
@@ -32,6 +32,15 @@ typedef struct serialize_ctx serialize_ctx_t;
  */
 serialize_ctx_t *serialize_init(const changeset_t *ch);
 
+/*!
+ * \brief Init serialization context.
+ *
+ * \param z   Zone to be serialized like zone-in-journal changeset.
+ *
+ * \return Context.
+ */
+serialize_ctx_t *serialize_zone_init(const zone_contents_t *z);
+
 /*!
  * \brief Pre-check and space computation before serializing a chunk.
  *
index 3ca827e74aa651f9b44f5230980afefa86a5f4da..3098ac82ff3a9cafd6c5db45118ac31ffb0a9e0f 100644 (file)
@@ -503,42 +503,6 @@ bool changeset_differs_just_serial(const changeset_t *ch)
        return ret;
 }
 
-changeset_t *changeset_from_contents(const zone_contents_t *contents)
-{
-       zone_contents_t *copy = NULL;
-       if (zone_contents_shallow_copy(contents, &copy) != KNOT_EOK) {
-               return NULL;
-       }
-
-       changeset_t *res = changeset_new(copy->apex->owner);
-
-       knot_rrset_t soa_rr = node_rrset(copy->apex, KNOT_RRTYPE_SOA);;
-       res->soa_to = knot_rrset_copy(&soa_rr, NULL);
-
-       node_remove_rdataset(copy->apex, KNOT_RRTYPE_SOA);
-
-       zone_contents_deep_free(res->add);
-       res->add = copy;
-       zone_contents_deep_free(res->remove);
-       res->remove = NULL;
-       return res;
-}
-
-void changeset_from_contents_free(changeset_t *ch)
-{
-       assert(ch);
-       assert(ch->soa_from == NULL);
-       assert(ch->remove == NULL);
-
-       update_free_zone(ch->add);
-
-       zone_contents_deep_free(ch->remove);
-       knot_rrset_free(ch->soa_from, NULL);
-       knot_rrset_free(ch->soa_to, NULL);
-       free(ch->data);
-       free(ch);
-}
-
 void changesets_clear(list_t *chgs)
 {
        if (chgs) {
index 5f053c1b7f8c495fde25eb2aa7fd26c0b4e7688d..f941b875d16ca1b575de7b7c855d1280b965318e 100644 (file)
@@ -192,22 +192,6 @@ int changeset_cancelout(changeset_t *ch);
  */
 bool changeset_differs_just_serial(const changeset_t *ch);
 
-/*!
- * \brief Creates a bootstrap changeset from zone.
- *
- * \param contents  Contents to include, will be freed!
- *
- * \return Changeset, which shall be freed with changeset_from_contents_free()
- */
-changeset_t *changeset_from_contents(const zone_contents_t *contents);
-
-/*!
- * \brief Frees single changeset.
- *
- * \param ch  Changeset from changeset_from_contents() to free.
- */
-void changeset_from_contents_free(changeset_t *ch);
-
 /*!
  * \brief Clears changesets in list. Changesets are not free'd. Legacy.
  *
index 239fa8c07e3788379fd586ce884461072193c276..bc75c338cbb5ee268d09541f447549cee0d527cf 100644 (file)
@@ -264,10 +264,7 @@ int zone_in_journal_store(conf_t *conf, zone_t *zone, zone_contents_t *new_conte
                return KNOT_EINVAL;
        }
 
-       changeset_t *co_ch = changeset_from_contents(new_contents);
-       int ret = co_ch ? journal_insert_zone(zone_journal(zone), co_ch) : KNOT_ENOMEM;
-       changeset_from_contents_free(co_ch);
-
+       int ret = journal_insert_zone(zone_journal(zone), new_contents);
        if (ret == KNOT_EOK) {
                log_zone_info(zone->name, "zone stored to journal, serial %u",
                              zone_contents_serial(new_contents));
index 933436230a9a1667413c2a7a66e4080646743821..c1d9a10d8693a415d083ddd30a9f0f76e62b2a00 100644 (file)
@@ -431,7 +431,10 @@ static void test_store_load(const knot_dname_t *apex)
 
        changeset_init(&e_ch, apex);
        init_random_changeset(&e_ch, 0, 1, 200, apex, true);
-       ret = journal_insert_zone(jj, &e_ch);
+       zone_node_t *n = NULL;
+       zone_contents_add_rr(e_ch.add, e_ch.soa_to, &n);
+       ret = journal_insert_zone(jj, e_ch.add);
+       zone_contents_remove_rr(e_ch.add, e_ch.soa_to, &n);
        is_int(KNOT_EOK, ret, "journal: insert zone-in-journal (%s)", knot_strerror(ret));
        changeset_init(&r_ch, apex);
        init_random_changeset(&r_ch, 1, 2, 200, apex, false);