From: Libor Peltan Date: Wed, 13 Feb 2019 14:20:21 +0000 (+0100) Subject: zone-in-journal: serialize zone contents directly X-Git-Tag: v2.9.0~286^2~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=25b571de7b41002db1eecc8fb57db7f40b93114a;p=thirdparty%2Fknot-dns.git zone-in-journal: serialize zone contents directly --- diff --git a/src/knot/journal/journal_basic.c b/src/knot/journal/journal_basic.c index d0aff1bdf4..be138f6d21 100644 --- a/src/knot/journal/journal_basic.c +++ b/src/knot/journal/journal_basic.c @@ -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); } diff --git a/src/knot/journal/journal_basic.h b/src/knot/journal/journal_basic.h index f9637a995d..10e29fd18c 100644 --- a/src/knot/journal/journal_basic.h +++ b/src/knot/journal/journal_basic.h @@ -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. diff --git a/src/knot/journal/journal_write.c b/src/knot/journal/journal_write.c index 2cbd51b1f7..6e9d30e0c8 100644 --- a/src/knot/journal/journal_write.c +++ b/src/knot/journal/journal_write.c @@ -22,14 +22,9 @@ #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); diff --git a/src/knot/journal/journal_write.h b/src/knot/journal/journal_write.h index 2aa9d1548d..20fa6f944f 100644 --- a/src/knot/journal/journal_write.h +++ b/src/knot/journal/journal_write.h @@ -27,6 +27,14 @@ */ 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. diff --git a/src/knot/journal/serialization.c b/src/knot/journal/serialization.c index 6483b2735c..51cef81e7c 100644 --- a/src/knot/journal/serialization.c +++ b/src/knot/journal/serialization.c @@ -17,12 +17,16 @@ #include #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; diff --git a/src/knot/journal/serialization.h b/src/knot/journal/serialization.h index 9d4c40bf3e..8be2ebc2a2 100644 --- a/src/knot/journal/serialization.h +++ b/src/knot/journal/serialization.h @@ -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. * diff --git a/src/knot/updates/changesets.c b/src/knot/updates/changesets.c index 3ca827e74a..3098ac82ff 100644 --- a/src/knot/updates/changesets.c +++ b/src/knot/updates/changesets.c @@ -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, ©) != 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) { diff --git a/src/knot/updates/changesets.h b/src/knot/updates/changesets.h index 5f053c1b7f..f941b875d1 100644 --- a/src/knot/updates/changesets.h +++ b/src/knot/updates/changesets.h @@ -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. * diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index 239fa8c07e..bc75c338cb 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -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)); diff --git a/tests/knot/test_journal.c b/tests/knot/test_journal.c index 933436230a..c1d9a10d86 100644 --- a/tests/knot/test_journal.c +++ b/tests/knot/test_journal.c @@ -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);