}
}
-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);
}
* \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.
#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);
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);
// 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;
}
}
-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;
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);
*/
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.
*
* \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.
#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,
#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;
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;
*/
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.
*
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) {
*/
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.
*
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));
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);