From 30869e23a183154810b381ea9968ae46814b997c Mon Sep 17 00:00:00 2001 From: Libor Peltan <libor.peltan@nic.cz> Date: Mon, 23 Jan 2017 19:09:36 +0100 Subject: [PATCH] journal support for bootstrap changeset --- src/knot/journal/journal.c | 214 +++++++++++++++++++++++++------ src/knot/journal/journal.h | 16 ++- src/knot/journal/serialization.c | 60 ++++++++- src/knot/journal/serialization.h | 20 ++- src/knot/updates/changesets.h | 2 +- 5 files changed, 266 insertions(+), 46 deletions(-) diff --git a/src/knot/journal/journal.c b/src/knot/journal/journal.c index efcb1b4ec0..79608f43d4 100644 --- a/src/knot/journal/journal.c +++ b/src/knot/journal/journal.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -38,6 +38,7 @@ #define MDKEY_GLOBAL_LAST_INSERTER_ZONE "last_inserter_zone" #define MDKEY_PERZONE_OCCUPIED "occupied" #define MDKEY_PERZONE_FLAGS "flags" +#define KEY_BOOTSTRAP_CHANGESET "bootstrap" /*! \brief The number of unused bytes in DB key. */ #define DB_KEY_UNUSED_ZERO (4) @@ -47,10 +48,11 @@ #define JOURNAL_HEADER_SIZE (32) enum { - LAST_FLUSHED_VALID = 1 << 0, /* "last flush is valid" flag. */ - SERIAL_TO_VALID = 1 << 1, /* "last serial_to is valid" flag. */ - MERGED_SERIAL_VALID = 1 << 2, /* "serial_from" of merged changeset. */ - DIRTY_SERIAL_VALID = 1 << 3, /* "dirty_serial" is present in the DB. */ + LAST_FLUSHED_VALID = 1 << 0, /* "last flush is valid" flag. */ + SERIAL_TO_VALID = 1 << 1, /* "last serial_to is valid" flag. */ + MERGED_SERIAL_VALID = 1 << 2, /* "serial_from" of merged changeset. */ + DIRTY_SERIAL_VALID = 1 << 3, /* "dirty_serial" is present in the DB. */ + FIRST_SERIAL_INVALID = 1 << 4, /* "first_serial" is not valid. */ }; static bool journal_flush_allowed(journal_t *j) { @@ -152,6 +154,8 @@ static void txn_init(txn_t *txn, knot_db_txn_t *db_txn, journal_t *j) * * Changeset: * | zone_name | \0 | unused zero 4B | (be32)serial_from | (be32)chunk_index | + * or + * | zone_name | \0 | unused zero 4B | metadata_key | \0 | (be32)serial_from | * * Structure of the changeset: * | (be32)serial_to | (be32)#of_chunks | unused zero 24B | serialized_changeset... @@ -190,6 +194,23 @@ static void txn_key_2u32(txn_t *txn, const knot_dname_t *zone, uint32_t key1, ui &key_be2, sizeof(uint32_t)); } +static void txn_key_str_u32(txn_t *txn, const knot_dname_t *zone, const char *key1, uint32_t key2) +{ + size_t zone_size = 0; + if (zone != NULL) zone_size = knot_dname_size(zone); + txn->key.len = zone_size + DB_KEY_UNUSED_ZERO + strlen(key1) + 1 + sizeof(uint32_t); + if (txn->key.len > 512) { + txn->ret = KNOT_ERROR; + return; + } + if (zone != NULL) memcpy(txn->key.data, zone, zone_size); + memset(txn->key.data + zone_size, 0, DB_KEY_UNUSED_ZERO); + strcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO, key1); + uint32_t key_be2 = htobe32(key2); + memcpy(txn->key.data + zone_size + DB_KEY_UNUSED_ZERO + strlen(key1) + 1, + &key_be2, sizeof(uint32_t)); +} + static int txn_cmpkey(txn_t *txn, knot_db_val_t *key2) { if (txn->key.len != key2->len) { @@ -462,7 +483,7 @@ static bool md_flag(txn_t *txn, int flag) /*! \brief Marks metadata as flushed */ static void md_flush(txn_t *txn) { - if (md_flag(txn, SERIAL_TO_VALID)) { + if (md_flag(txn, SERIAL_TO_VALID) && !md_flag(txn, FIRST_SERIAL_INVALID)) { txn->shadow_md.last_flushed = txn->shadow_md.last_serial; txn->shadow_md.flags |= LAST_FLUSHED_VALID; } @@ -586,30 +607,31 @@ typedef struct { void *iter_context; // anything to send to the callback by the caller of iterate(), untouched by iterate() } iteration_ctx_t; +typedef int (*iteration_cb_t)(iteration_ctx_t *ctx); + /*! * \brief Move iter to next changeset chunk. * * Try optimisticly fast move to next DB item. But the changeset can be out of order, * so if we don't succeed (different serial or end of DB), we lookup next serial slowly. */ -static void get_iter_next(txn_t *txn, uint32_t expect_serial, int expect_chunk) + +static void get_iter_next(iteration_ctx_t *ctx, iteration_cb_t key_cb) { knot_db_val_t other_key = { 0 }; - txn_check(txn); - txn_iter_next(txn); - txn_iter_key(txn, &other_key); - txn_key_2u32(txn, txn->j->zone, expect_serial, (uint32_t)expect_chunk); - if (txn->ret == KNOT_ENOENT || - (txn->ret == KNOT_EOK && txn_cmpkey(txn, &other_key) != 0)) { - txn_iter_seek(txn); + txn_check(ctx->txn); + txn_iter_next(ctx->txn); + txn_iter_key(ctx->txn, &other_key); + key_cb(ctx); + if (ctx->txn->ret == KNOT_ENOENT || + (ctx->txn->ret == KNOT_EOK && txn_cmpkey(ctx->txn, &other_key) != 0)) { + txn_iter_seek(ctx->txn); } } -typedef int (*iteration_cb_t)(iteration_ctx_t *ctx); - static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method, - void *iter_context, uint32_t first, uint32_t last) + void *iter_context, uint32_t first, uint32_t last, iteration_cb_t key_cb) { reuse_txn(txn, j, _txn, true); @@ -625,7 +647,7 @@ static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method, txn_iter_begin(txn); - txn_key_2u32(txn, j->zone, ctx.serial, ctx.chunk_index); + key_cb(&ctx); txn_iter_seek(txn); ctx.val = &txn->val; @@ -671,7 +693,7 @@ static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method, ctx.chunk_index++; } - get_iter_next(txn, ctx.serial, ctx.chunk_index); + get_iter_next(&ctx, key_cb); } if (vals != NULL) { @@ -684,6 +706,12 @@ static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method, txn_ret(txn); } +static int normal_iterkeycb(iteration_ctx_t *ctx) +{ + txn_key_2u32(ctx->txn, ctx->txn->j->zone, ctx->serial, ctx->chunk_index); + return KNOT_EOK; +} + /* * ***************************** PART IV ****************************** * @@ -694,7 +722,7 @@ static int iterate(journal_t *j, txn_t *_txn, iteration_cb_t cb, int method, /*! \brief Deserialize changeset from chunks (in vals) */ static int vals_to_changeset(knot_db_val_t *vals, int nvals, - const knot_dname_t *zone_name, changeset_t **ch) + const knot_dname_t *zone_name, changeset_t **ch, bool is_bootstrap) { uint8_t *valps[nvals]; size_t vallens[nvals]; @@ -708,7 +736,8 @@ static int vals_to_changeset(knot_db_val_t *vals, int nvals, return KNOT_ENOMEM; } - int ret = changeset_deserialize(t_ch, valps, vallens, nvals); + int ret = is_bootstrap ? changeset_deserialize_bootstrap(t_ch, valps, vallens, nvals) + : changeset_deserialize(t_ch, valps, vallens, nvals); if (ret != KNOT_EOK) { changeset_free(t_ch); @@ -725,7 +754,7 @@ static int load_one_itercb(iteration_ctx_t *ctx) return KNOT_EINVAL; } - int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch); + int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch, false); if (ret == KNOT_EOK) *targ = ch; return ret; } @@ -735,7 +764,7 @@ static int load_list_itercb(iteration_ctx_t *ctx) changeset_t *ch = NULL; list_t *chlist = *(list_t **) ctx->iter_context; - int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch); + int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch, false); if (ret == KNOT_EOK) { add_tail(chlist, &ch->n); @@ -748,7 +777,7 @@ static int load_one(journal_t *j, txn_t *_txn, uint32_t serial, changeset_t **ch { reuse_txn(txn, j, _txn, false); changeset_t *rch = NULL; - iterate(j, txn, load_one_itercb, JOURNAL_ITERATION_CHANGESETS, &rch, serial, serial); + iterate(j, txn, load_one_itercb, JOURNAL_ITERATION_CHANGESETS, &rch, serial, serial, normal_iterkeycb); unreuse_txn(txn, _txn); if (txn_finished_ok(txn)) { if (rch == NULL) txn->ret = KNOT_ENOENT; @@ -775,7 +804,6 @@ static int load_merged_changeset(journal_t *j, txn_t *_txn, changeset_t **mch, txn_ret(txn); } -/*! \brief API: load all changesets since "from" serial into dst. */ int journal_load_changesets(journal_t *j, list_t *dst, uint32_t from) { if (j == NULL || j->db == NULL || dst == NULL) return KNOT_EINVAL; @@ -791,12 +819,72 @@ int journal_load_changesets(journal_t *j, list_t *dst, uint32_t from) } uint32_t ls = txn->shadow_md.last_serial; - iterate(j, txn, load_list_itercb, JOURNAL_ITERATION_CHANGESETS, &dst, from, ls); + iterate(j, txn, load_list_itercb, JOURNAL_ITERATION_CHANGESETS, &dst, from, + ls, normal_iterkeycb); txn_commit(txn); txn_ret(txn); } +int load_bootstrap_iterkeycb(iteration_ctx_t *ctx) +{ + txn_key_str_u32(ctx->txn, ctx->txn->j->zone, KEY_BOOTSTRAP_CHANGESET, ctx->chunk_index); + return KNOT_EOK; +} + +static int load_bootstrap_itercb(iteration_ctx_t *ctx) +{ + changeset_t *ch = NULL, **targ = ctx->iter_context; + if (*targ != NULL) { + return KNOT_EINVAL; + } + + int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch, true); + if (ret == KNOT_EOK) *targ = ch; + return ret; +} + +static int load_bootstrap_changeset(journal_t *j, txn_t *_txn, changeset_t **ch) +{ + reuse_txn(txn, j, _txn, false); + changeset_t *rch = NULL; + iterate(j, txn, load_bootstrap_itercb, JOURNAL_ITERATION_CHANGESETS, &rch, + 0, 0, load_bootstrap_iterkeycb); + unreuse_txn(txn, _txn); + if (txn_finished_ok(txn)) { + if (rch == NULL) txn->ret = KNOT_ENOENT; + else *ch = rch; + } + txn_ret(txn); +} + +int journal_load_bootstrap(journal_t *j, list_t *dst) +{ + if (j == NULL || j->db == NULL || dst == NULL) return KNOT_EINVAL; + + local_txn_t(txn, j); + txn_begin(txn, false); + + changeset_t *bch = NULL; + load_bootstrap_changeset(j, txn, &bch); + if (bch == NULL) { + txn->ret = KNOT_ENOENT; + goto jlb_end; + } + add_tail(dst, &bch->n); + uint32_t from = knot_soa_serial(&bch->soa_to->rrs); + + uint32_t ls = txn->shadow_md.last_serial; + iterate(j, txn, load_list_itercb, JOURNAL_ITERATION_CHANGESETS, &dst, + from, ls, normal_iterkeycb); + if (txn->ret == KNOT_ENOENT) { + txn->ret = KNOT_EOK; + } +jlb_end: + txn_commit(txn); + txn_ret(txn); +} + /* * ***************************** PART V ******************************* * @@ -842,7 +930,8 @@ static int del_upto_itercb(iteration_ctx_t *ctx) * Please ensure (dbfirst == j->metadata.first_serial) */ static int delete_upto(journal_t *j, txn_t *txn, uint32_t dbfirst, uint32_t last) { - return iterate(j, txn, del_upto_itercb, JOURNAL_ITERATION_CHUNKS, NULL, dbfirst, last); + return iterate(j, txn, del_upto_itercb, JOURNAL_ITERATION_CHUNKS, NULL, + dbfirst, last, normal_iterkeycb); } static int delete_merged_changeset(journal_t *j, txn_t *t) @@ -866,7 +955,7 @@ static int drop_journal(journal_t *j, txn_t *_txn) if (md_flag(txn, MERGED_SERIAL_VALID)) { delete_merged_changeset(j, txn); } - if (md_flag(txn, SERIAL_TO_VALID)) { + if (md_flag(txn, SERIAL_TO_VALID) && !md_flag(txn, FIRST_SERIAL_INVALID)) { delete_upto(j, txn, txn->shadow_md.first_serial, txn->shadow_md.last_serial); } unreuse_txn(txn, _txn); @@ -924,7 +1013,7 @@ static int delete_tofree(journal_t *j, txn_t *_txn, size_t to_be_freed, size_t * } delete_status_t ds = { .freed_approx = 0, .to_be_freed = to_be_freed }; iterate(j, txn, del_tofree_itercb, JOURNAL_ITERATION_CHUNKS, &ds, - txn->shadow_md.first_serial, txn->shadow_md.last_serial); + txn->shadow_md.first_serial, txn->shadow_md.last_serial, normal_iterkeycb); unreuse_txn(txn, _txn); if (txn_finished_ok(txn)) *really_freed = ds.freed_approx; @@ -976,7 +1065,7 @@ static int delete_count(journal_t *j, txn_t *_txn, size_t to_be_deleted, size_t } delete_status_t ds = { .freed_approx = 0, .to_be_freed = to_be_deleted }; iterate(j, txn, del_count_itercb, JOURNAL_ITERATION_CHUNKS, &ds, - txn->shadow_md.first_serial, txn->shadow_md.last_serial); + txn->shadow_md.first_serial, txn->shadow_md.last_serial, normal_iterkeycb); unreuse_txn(txn, _txn); if (txn_finished_ok(txn)) *really_deleted = ds.freed_approx; @@ -1016,7 +1105,7 @@ static int merge_itercb(iteration_ctx_t *ctx) { changeset_t *ch = NULL, *mch = *(changeset_t **)ctx->iter_context; - int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch); + int ret = vals_to_changeset(ctx->val, ctx->chunk_count, ctx->txn->j->zone, &ch, false); if (ret == KNOT_EOK) { ret = changeset_merge(mch, ch); changeset_free(ch); @@ -1050,7 +1139,7 @@ static int merge_unflushed_changesets(journal_t *j, txn_t *_txn, changeset_t **m from = knot_soa_serial(&(*mch)->soa_to->rrs); txn->ret = iterate(j, txn, merge_itercb, JOURNAL_ITERATION_CHANGESETS, - mch, from, txn->shadow_md.last_serial); + mch, from, txn->shadow_md.last_serial, normal_iterkeycb); m_u_ch_end: unreuse_txn(txn, _txn); @@ -1158,8 +1247,10 @@ static int store_changesets(journal_t *j, list_t *changesets) // PART 4: continuity and duplicity check changeset_t * chs_head = (HEAD(*changesets)); - uint32_t serial = knot_soa_serial(&chs_head->soa_from->rrs); - if (md_flag(txn, SERIAL_TO_VALID) && serial_compare(txn->shadow_md.last_serial_to, serial) != 0) { + bool is_bootstrap = (chs_head->soa_from == NULL); + uint32_t serial = is_bootstrap ? 0 : knot_soa_serial(&chs_head->soa_from->rrs); + if (!is_bootstrap && md_flag(txn, SERIAL_TO_VALID) && + serial_compare(txn->shadow_md.last_serial_to, serial) != 0) { log_zone_warning(j->zone, "discontinuity in chages history (%u -> %u), dropping older changesets", txn->shadow_md.last_serial_to, serial); try_flush @@ -1168,7 +1259,9 @@ static int store_changesets(journal_t *j, list_t *changesets) } WALK_LIST(ch, *changesets) { uint32_t serial_to = knot_soa_serial(&ch->soa_to->rrs); - if (inserting_merged && ch == TAIL(*changesets)) { + bool is_this_bootstrap = (is_bootstrap && ch == HEAD(*changesets)); + bool is_this_merged = (inserting_merged && ch == TAIL(*changesets)); + if (is_this_bootstrap || is_this_merged) { continue; } txn_key_2u32(txn, j->zone, serial_to, 0); @@ -1206,7 +1299,9 @@ static int store_changesets(journal_t *j, list_t *changesets) break; } - uint32_t serial = knot_soa_serial(&ch->soa_from->rrs); + bool is_this_bootstrap = is_bootstrap && (ch == HEAD(*changesets)); + bool is_this_merged = (inserting_merged && ch == TAIL(*changesets)); + uint32_t serial = is_this_bootstrap ? 0 : knot_soa_serial(&ch->soa_from->rrs); uint32_t serial_to = knot_soa_serial(&ch->soa_to->rrs); for (int i = 0; i < chunks; i++) { @@ -1218,7 +1313,12 @@ static int store_changesets(journal_t *j, list_t *changesets) // PART 6: inserting vals into db for (int i = 0; i < chunks; i++) { if (txn->ret != KNOT_EOK) break; - txn_key_2u32(txn, j->zone, serial, i); + if (is_this_bootstrap) { + txn_key_str_u32(txn, j->zone, KEY_BOOTSTRAP_CHANGESET, i); + } + else { + txn_key_2u32(txn, j->zone, serial, i); + } txn->val = vals[i]; txn_insert(txn); inserted_size += (vals+i)->len; @@ -1236,14 +1336,22 @@ static int store_changesets(journal_t *j, list_t *changesets) if (txn->ret != KNOT_EOK) { break; } - if (inserting_merged && ch == TAIL(*changesets)) { + if (is_this_merged) { txn->shadow_md.flags |= MERGED_SERIAL_VALID; txn->shadow_md.merged_serial = serial; } - else { + else if (is_this_bootstrap) { if (!md_flag(txn, SERIAL_TO_VALID)) { + txn->shadow_md.flags |= FIRST_SERIAL_INVALID; + txn->shadow_md.last_serial_to = serial_to; + } + txn->shadow_md.flags |= SERIAL_TO_VALID; + } + else { + if (!md_flag(txn, SERIAL_TO_VALID) || md_flag(txn, FIRST_SERIAL_INVALID)) { txn->shadow_md.first_serial = serial; } + txn->shadow_md.flags &= ~FIRST_SERIAL_INVALID; txn->shadow_md.flags |= SERIAL_TO_VALID; txn->shadow_md.last_serial = serial; txn->shadow_md.last_serial_to = serial_to; @@ -1716,6 +1824,34 @@ int journal_check(journal_t *j, journal_check_level warn_level) goto check_merged; } + if (md_flag(txn, FIRST_SERIAL_INVALID)) { + jch_info("there is just the bootstrap changeset in journal"); + ret = load_bootstrap_changeset(j, txn, &ch); + if (ret != KNOT_EOK) { + jch_warn("can't read bootstrap changeset (%s)", knot_strerror(ret)); + } + else { + changeset_free(ch); + } + goto check_merged; + } + else { + ret = load_bootstrap_changeset(j, txn, &ch); + switch (ret) { + case KNOT_EOK: + sto = knot_soa_serial(&ch->soa_to->rrs); + jch_info("bootstrap changeset loaded, sto %u", sto); + changeset_free(ch); + break; + case KNOT_ENOENT: + txn->ret = KNOT_EOK; + break; + default: + jch_info("failed to read bootstrap changeset (%s)", knot_strerror(ret)); + break; + } + } + ret = load_one(j, txn, txn->shadow_md.first_serial, &ch); if (ret != KNOT_EOK) { jch_warn("can't read first changeset %u (%s)", diff --git a/src/knot/journal/journal.h b/src/knot/journal/journal.h index e21e6c7307..e7105e2ea9 100644 --- a/src/knot/journal/journal.h +++ b/src/knot/journal/journal.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -111,7 +111,7 @@ int journal_open(journal_t *j, journal_db_t **db, const knot_dname_t *zone_name) void journal_close(journal_t *journal); /*! - * \brief Load changesets from journal. + * \brief Load changesets from journal since "from" serial. * * \param journal Journal to load from. * \param dst Store changesets here. @@ -123,6 +123,18 @@ void journal_close(journal_t *journal); */ int journal_load_changesets(journal_t *journal, list_t *dst, uint32_t from); +/*! + * \brief Load changesets from journal, starting with bootstrap changeset. + * + * \param journal Journal to load from. + * \param dst Store changesets here, starting with bootstrap changeset. + * + * \retval KNOT_EOK on success. + * \retval KNOT_ENOENT when there is no bootstrap changeset. + * \return < KNOT_EOK on other error. + */ +int journal_load_bootstrap(journal_t *j, list_t *dst); + /*! * \brief Store changesets in journal. * diff --git a/src/knot/journal/serialization.c b/src/knot/journal/serialization.c index 38fa302cc5..d9fb37b33c 100644 --- a/src/knot/journal/serialization.c +++ b/src/knot/journal/serialization.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -211,6 +211,11 @@ int changeset_serialize(const changeset_t *ch, uint8_t *dst_chunks[], wire_ctx_t wire = wire_ctx_init(dst_chunks[0], chunk_size); size_t cur_chunk = 0; + if (ch->soa_from == NULL) { + // serializing bootstrap changeset + goto serialize_to; // note: it & ret & rrset are uninitialized here, we don't care + } + // Serialize SOA 'from'. int ret = serialize_rrset_chunks(&wire, ch->soa_from, dst_chunks, chunk_size, chunks_count, chunks_real_sizes, &cur_chunk); @@ -237,6 +242,7 @@ int changeset_serialize(const changeset_t *ch, uint8_t *dst_chunks[], } changeset_iter_clear(&it); +serialize_to: // Serialize SOA 'to'. ret = serialize_rrset_chunks(&wire, ch->soa_to, dst_chunks, chunk_size, chunks_count, chunks_real_sizes, &cur_chunk); @@ -282,7 +288,8 @@ int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[], // Deserialize SOA 'from'. knot_rrset_t rrset; - int ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, chunks_count, &cur_chunk); + int ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, + chunks_count, &cur_chunk); if (ret != KNOT_EOK) { return ret; } @@ -298,7 +305,8 @@ int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[], bool in_remove_section = true; while (cur_chunk < chunks_count - 1 || wire_ctx_available(&wire) > 0) { // Parse next RRSet. - ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, chunks_count, &cur_chunk); + ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, + chunks_count, &cur_chunk); if (ret != KNOT_EOK) { break; } @@ -330,3 +338,49 @@ int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[], return wire.error; } + +int changeset_deserialize_bootstrap(changeset_t *ch, uint8_t *src_chunks[], + const size_t *chunks_sizes, size_t chunks_count) +{ + if (ch == NULL || src_chunks == NULL || chunks_sizes == NULL || + chunks_count == 0) { + return KNOT_EINVAL; + } + + size_t cur_chunk = 0; + wire_ctx_t wire = wire_ctx_init_const(src_chunks[0], chunks_sizes[0]); + + // Deserialize SOA 'to'. + knot_rrset_t rrset; + int ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, + chunks_count, &cur_chunk); + if (ret != KNOT_EOK) { + return ret; + } + assert(rrset.type == KNOT_RRTYPE_SOA); + + ch->soa_from = NULL; + ch->soa_to = knot_rrset_copy(&rrset, NULL); + knot_rrset_clear(&rrset, NULL); + if (ch->soa_to == NULL) { + return KNOT_ENOMEM; + } + + // Read remaining RRSets. + while (cur_chunk < chunks_count - 1 || wire_ctx_available(&wire) > 0) { + // Parse next RRSet. + ret = deserialize_rrset_chunks(&wire, &rrset, src_chunks, chunks_sizes, + chunks_count, &cur_chunk); + if (ret != KNOT_EOK) { + break; + } + assert(rrset.type != KNOT_RRTYPE_SOA); + ret = changeset_add_addition(ch, &rrset, 0); + knot_rrset_clear(&rrset, NULL); + if (ret != KNOT_EOK) { + return ret; + } + } + + return wire.error; +} diff --git a/src/knot/journal/serialization.h b/src/knot/journal/serialization.h index 0558bd72c5..63a2b80928 100644 --- a/src/knot/journal/serialization.h +++ b/src/knot/journal/serialization.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2017 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 @@ -57,3 +57,21 @@ int changeset_serialize(const changeset_t *ch, uint8_t *dst_chunks[], */ int changeset_deserialize(changeset_t *ch, uint8_t *src_chunks[], const size_t *chunks_sizes, size_t chunks_count); + +/*! + * \brief Deserializes bootstrap changeset + * + * This is like changeset_deserialize(), but expects a bootstrap changeset (no soa_from and no + * 'rem' section) in src_chunks. + * + * There is no changeset_serialize_botstrap: simply run changeset_serialize() with ch->soa_from = NULL. + * + * \param[out] ch The changeset. + * \param[in] src_chunks The chunks to deserialize. + * \param[in] chunks_sizes The size of each chunk. + * \param[in] chunks_count The number of chunks. + * + * \retval KNOT_E* + */ +int changeset_deserialize_bootstrap(changeset_t *ch, uint8_t *src_chunks[], + const size_t *chunks_sizes, size_t chunks_count); diff --git a/src/knot/updates/changesets.h b/src/knot/updates/changesets.h index e38e41cc92..2f591af224 100644 --- a/src/knot/updates/changesets.h +++ b/src/knot/updates/changesets.h @@ -41,7 +41,7 @@ typedef struct { knot_rrset_t *soa_to; /*!< Destination SOA. */ zone_contents_t *add; /*!< Change additions. */ zone_contents_t *remove; /*!< Change removals. */ - size_t size; /*!< Size of serialized changeset. */ + size_t size; /*!< Size of serialized changeset. \todo Remove after old_journal removal! */ uint8_t *data; /*!< Serialized changeset. */ } changeset_t; -- GitLab