Commit 5fc62cd4 authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'journal_serials' into 'master'

Journal serials

See merge request !801
parents 7c93631d 97579e3a
...@@ -127,7 +127,7 @@ struct refresh_data { ...@@ -127,7 +127,7 @@ struct refresh_data {
static bool serial_is_current(uint32_t local_serial, uint32_t remote_serial) static bool serial_is_current(uint32_t local_serial, uint32_t remote_serial)
{ {
return serial_compare(local_serial, remote_serial) >= 0; return (serial_compare(local_serial, remote_serial) & SERIAL_MASK_GEQ);
} }
static time_t bootstrap_next(const zone_timers_t *timers) static time_t bootstrap_next(const zone_timers_t *timers)
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <stdarg.h> #include <stdarg.h>
#include "knot/journal/journal.h" #include "knot/journal/journal.h"
#include "knot/zone/serial.h"
#include "knot/common/log.h" #include "knot/common/log.h"
#include "contrib/files.h" #include "contrib/files.h"
#include "contrib/endian.h" #include "contrib/endian.h"
...@@ -534,7 +533,7 @@ static int md_flushed(txn_t *txn) ...@@ -534,7 +533,7 @@ static int md_flushed(txn_t *txn)
{ {
return (!md_flag(txn, SERIAL_TO_VALID) || return (!md_flag(txn, SERIAL_TO_VALID) ||
(md_flag(txn, LAST_FLUSHED_VALID) && (md_flag(txn, LAST_FLUSHED_VALID) &&
serial_compare(txn->shadow_md.last_flushed, txn->shadow_md.last_serial) == 0)); serial_equal(txn->shadow_md.last_flushed, txn->shadow_md.last_serial)));
} }
static void make_header(knot_db_val_t *to, uint32_t serial_to, int chunk_count) static void make_header(knot_db_val_t *to, uint32_t serial_to, int chunk_count)
...@@ -851,7 +850,7 @@ static int load_merged_changeset(journal_t *j, txn_t *_txn, changeset_t **mch, ...@@ -851,7 +850,7 @@ static int load_merged_changeset(journal_t *j, txn_t *_txn, changeset_t **mch,
uint32_t ms = txn->shadow_md.merged_serial, fl = txn->shadow_md.flags; uint32_t ms = txn->shadow_md.merged_serial, fl = txn->shadow_md.flags;
if ((fl & MERGED_SERIAL_VALID) && if ((fl & MERGED_SERIAL_VALID) &&
(only_if_serial == NULL || serial_compare(ms, *only_if_serial) == 0)) { (only_if_serial == NULL || serial_equal(ms, *only_if_serial))) {
load_one(j, txn, ms, mch); load_one(j, txn, ms, mch);
} }
unreuse_txn(txn, _txn); unreuse_txn(txn, _txn);
...@@ -961,17 +960,17 @@ static int del_upto_itercb(iteration_ctx_t *ctx) ...@@ -961,17 +960,17 @@ static int del_upto_itercb(iteration_ctx_t *ctx)
// If it's not merged changeset, point first_serial to next one // If it's not merged changeset, point first_serial to next one
if (ctx->chunk_index == ctx->chunk_count - 1) { if (ctx->chunk_index == ctx->chunk_count - 1) {
if (!md_flag(ctx->txn, MERGED_SERIAL_VALID) || if (!md_flag(ctx->txn, MERGED_SERIAL_VALID) ||
serial_compare(ctx->txn->shadow_md.merged_serial,ctx->serial) != 0) { !serial_equal(ctx->txn->shadow_md.merged_serial,ctx->serial)) {
ctx->txn->shadow_md.first_serial = ctx->serial_to; ctx->txn->shadow_md.first_serial = ctx->serial_to;
ctx->txn->shadow_md.changeset_count--; ctx->txn->shadow_md.changeset_count--;
} }
if (serial_compare(ctx->txn->shadow_md.last_flushed, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID; ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
} }
if (serial_compare(ctx->txn->shadow_md.last_serial, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID; ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
} }
if (serial_compare(ctx->txn->shadow_md.merged_serial,ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.merged_serial,ctx->serial)) {
ctx->txn->shadow_md.flags &= ~MERGED_SERIAL_VALID; ctx->txn->shadow_md.flags &= ~MERGED_SERIAL_VALID;
} }
} }
...@@ -1034,11 +1033,11 @@ static int del_tofree_itercb(iteration_ctx_t *ctx) ...@@ -1034,11 +1033,11 @@ static int del_tofree_itercb(iteration_ctx_t *ctx)
if (ctx->chunk_index == ctx->chunk_count - 1) { if (ctx->chunk_index == ctx->chunk_count - 1) {
ctx->txn->shadow_md.first_serial = ctx->serial_to; ctx->txn->shadow_md.first_serial = ctx->serial_to;
ctx->txn->shadow_md.changeset_count--; ctx->txn->shadow_md.changeset_count--;
if (serial_compare(ctx->txn->shadow_md.last_flushed, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID; ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
ds->to_be_freed = 0; // prevents deleting unflushed changesets ds->to_be_freed = 0; // prevents deleting unflushed changesets
} }
if (serial_compare(ctx->txn->shadow_md.last_serial, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID; ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
} }
if (ds->freed_approx >= ds->to_be_freed) { if (ds->freed_approx >= ds->to_be_freed) {
...@@ -1090,11 +1089,11 @@ static int del_count_itercb(iteration_ctx_t *ctx) ...@@ -1090,11 +1089,11 @@ static int del_count_itercb(iteration_ctx_t *ctx)
if (ctx->chunk_index == ctx->chunk_count - 1) { if (ctx->chunk_index == ctx->chunk_count - 1) {
ctx->txn->shadow_md.first_serial = ctx->serial_to; ctx->txn->shadow_md.first_serial = ctx->serial_to;
ctx->txn->shadow_md.changeset_count--; ctx->txn->shadow_md.changeset_count--;
if (serial_compare(ctx->txn->shadow_md.last_flushed, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_flushed, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID; ctx->txn->shadow_md.flags &= ~LAST_FLUSHED_VALID;
ds->to_be_freed = ds->freed_approx; // prevents deleting unflushed changesets ds->to_be_freed = ds->freed_approx; // prevents deleting unflushed changesets
} }
if (serial_compare(ctx->txn->shadow_md.last_serial, ctx->serial) == 0) { if (serial_equal(ctx->txn->shadow_md.last_serial, ctx->serial)) {
ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID; ctx->txn->shadow_md.flags &= ~SERIAL_TO_VALID;
} }
ds->freed_approx++; ds->freed_approx++;
...@@ -1203,7 +1202,7 @@ static int merge_unflushed_changesets(journal_t *j, txn_t *_txn, changeset_t **m ...@@ -1203,7 +1202,7 @@ static int merge_unflushed_changesets(journal_t *j, txn_t *_txn, changeset_t **m
} }
from = knot_soa_serial(&(*mch)->soa_to->rrs); from = knot_soa_serial(&(*mch)->soa_to->rrs);
if (serial_compare(from, txn->shadow_md.last_serial_to) != 0) { if (!serial_equal(from, txn->shadow_md.last_serial_to)) {
txn->ret = iterate(j, txn, merge_itercb, JOURNAL_ITERATION_CHANGESETS, txn->ret = iterate(j, txn, merge_itercb, JOURNAL_ITERATION_CHANGESETS,
mch, from, txn->shadow_md.last_serial, normal_iterkeycb); mch, from, txn->shadow_md.last_serial, normal_iterkeycb);
} }
...@@ -1353,7 +1352,7 @@ static int store_changesets(journal_t *j, list_t *changesets) ...@@ -1353,7 +1352,7 @@ static int store_changesets(journal_t *j, list_t *changesets)
bool is_first_bootstrap = (chs_head->soa_from == NULL); bool is_first_bootstrap = (chs_head->soa_from == NULL);
uint32_t serial = is_first_bootstrap ? 0 : knot_soa_serial(&chs_head->soa_from->rrs); uint32_t serial = is_first_bootstrap ? 0 : knot_soa_serial(&chs_head->soa_from->rrs);
if (md_flag(txn, SERIAL_TO_VALID) && (is_first_bootstrap || if (md_flag(txn, SERIAL_TO_VALID) && (is_first_bootstrap ||
serial_compare(txn->shadow_md.last_serial_to, serial) != 0) && !serial_equal(txn->shadow_md.last_serial_to, serial)) &&
!inserting_bootstrap /* if inserting bootstrap, drop_journal() was called, so no discontinuity */) { !inserting_bootstrap /* if inserting bootstrap, drop_journal() was called, so no discontinuity */) {
log_zone_warning(j->zone, "journal, discontinuity in changes history (%u -> %u), dropping older changesets", log_zone_warning(j->zone, "journal, discontinuity in changes history (%u -> %u), dropping older changesets",
txn->shadow_md.last_serial_to, serial); txn->shadow_md.last_serial_to, serial);
...@@ -1388,9 +1387,9 @@ static int store_changesets(journal_t *j, list_t *changesets) ...@@ -1388,9 +1387,9 @@ static int store_changesets(journal_t *j, list_t *changesets)
} }
} else { } else {
try_flush try_flush
delete_upto(j, txn, txn->shadow_md.first_serial, serial_to);
txn_restart(txn);
} }
delete_upto(j, txn, txn->shadow_md.first_serial, serial_to);
txn_restart(txn);
} }
} }
...@@ -1796,12 +1795,31 @@ scrape_end: ...@@ -1796,12 +1795,31 @@ scrape_end:
return txn->ret; return txn->ret;
} }
void journal_metadata_info(journal_t *j, bool *is_empty, uint32_t *serial_from, uint32_t *serial_to) void journal_metadata_info(journal_t *j, bool *has_bootstrap, kserial_t *merged_serial,
kserial_t *first_serial, kserial_t *last_flushed, kserial_t *serial_to,
uint64_t *occupied)
{ {
// NOTE: there is NEVER the situation that only merged changeset would be present and no common changeset in db. // NOTE: there is NEVER the situation that only merged changeset would be present and no common changeset in db.
if (j == NULL || j->db == NULL) { if (j == NULL || j->db == NULL) {
*is_empty = true; if (has_bootstrap != NULL) {
*has_bootstrap = false;
}
if (merged_serial != NULL) {
merged_serial->valid = false;
}
if (first_serial != NULL) {
first_serial->valid = false;
}
if (last_flushed != NULL) {
last_flushed->valid = false;
}
if (serial_to != NULL) {
serial_to->valid = false;
}
if (occupied != NULL) {
*occupied = 0;
}
return; return;
} }
...@@ -1809,13 +1827,37 @@ void journal_metadata_info(journal_t *j, bool *is_empty, uint32_t *serial_from, ...@@ -1809,13 +1827,37 @@ void journal_metadata_info(journal_t *j, bool *is_empty, uint32_t *serial_from,
txn_begin(txn, false); txn_begin(txn, false);
txn_check_open(txn); txn_check_open(txn);
*is_empty = !md_flag(txn, SERIAL_TO_VALID); if (has_bootstrap != NULL) {
*serial_from = txn->shadow_md.first_serial; *has_bootstrap = has_bootstrap_changeset(j, txn);
*serial_to = txn->shadow_md.last_serial_to; }
if (merged_serial != NULL) {
if (md_flag(txn, MERGED_SERIAL_VALID)) { merged_serial->valid = md_flag(txn, MERGED_SERIAL_VALID);
*serial_from = txn->shadow_md.merged_serial; merged_serial->serial = txn->shadow_md.merged_serial;
}
if (first_serial != NULL) {
first_serial->valid = !md_flag(txn, FIRST_SERIAL_INVALID);
first_serial->serial = txn->shadow_md.first_serial;
}
if (last_flushed != NULL) {
last_flushed->valid = md_flag(txn, LAST_FLUSHED_VALID);
last_flushed->serial = txn->shadow_md.last_flushed;
} }
if (serial_to != NULL) {
serial_to->valid = md_flag(txn, SERIAL_TO_VALID);
serial_to->serial = txn->shadow_md.last_serial_to;
}
if (occupied != NULL) {
md_get(txn, j->zone, MDKEY_PERZONE_OCCUPIED, occupied);
knot_dname_t *last_inserter = NULL;
md_get_common_last_inserter_zone(txn, &last_inserter);
if (last_inserter != NULL && knot_dname_is_equal(last_inserter, j->zone)) {
size_t lz_occupied;
md_get_common_last_occupied(txn, &lz_occupied);
*occupied += lz_occupied;
}
free(last_inserter);
}
txn_abort(txn); txn_abort(txn);
} }
...@@ -1993,7 +2035,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level) ...@@ -1993,7 +2035,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
} }
sfrom = knot_soa_serial(&ch->soa_from->rrs), sto = knot_soa_serial(&ch->soa_to->rrs); sfrom = knot_soa_serial(&ch->soa_from->rrs), sto = knot_soa_serial(&ch->soa_to->rrs);
if (serial_compare(txn->shadow_md.first_serial, sfrom) != 0) { if (!serial_equal(txn->shadow_md.first_serial, sfrom)) {
jch_warn("first changeset's serial 'from' %u is not ok", sfrom); jch_warn("first changeset's serial 'from' %u is not ok", sfrom);
} }
...@@ -2012,7 +2054,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level) ...@@ -2012,7 +2054,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
changeset_free(ch); changeset_free(ch);
} }
if (serial_compare(txn->shadow_md.last_serial_to, sto) == 0) { if (serial_equal(txn->shadow_md.last_serial_to, sto)) {
jch_info("there is just one changeset in the journal"); jch_info("there is just one changeset in the journal");
goto check_merged; goto check_merged;
} }
...@@ -2022,7 +2064,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level) ...@@ -2022,7 +2064,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
} }
else { else {
sfrom = knot_soa_serial(&ch->soa_from->rrs); sfrom = knot_soa_serial(&ch->soa_from->rrs);
if (serial_compare(sfrom, sto) != 0) { if (!serial_equal(sfrom, sto)) {
jch_warn("second changeset's serial 'from' %u is not ok", sfrom); jch_warn("second changeset's serial 'from' %u is not ok", sfrom);
} }
changeset_free(ch); changeset_free(ch);
...@@ -2046,12 +2088,12 @@ int journal_check(journal_t *j, journal_check_level_t warn_level) ...@@ -2046,12 +2088,12 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
} }
ch = HEAD(l); ch = HEAD(l);
if (serial_compare(sfrom, knot_soa_serial(&ch->soa_from->rrs)) != 0) { if (!serial_equal(sfrom, knot_soa_serial(&ch->soa_from->rrs))) {
jch_warn("first listed changeset's serial 'from' %u is not ok", jch_warn("first listed changeset's serial 'from' %u is not ok",
knot_soa_serial(&ch->soa_from->rrs)); knot_soa_serial(&ch->soa_from->rrs));
} }
ch = TAIL(l); ch = TAIL(l);
if (serial_compare(sto, knot_soa_serial(&ch->soa_to->rrs)) != 0) { if (!serial_equal(sto, knot_soa_serial(&ch->soa_to->rrs))) {
jch_warn("last listed changeset's serial 'to' %u is not ok", jch_warn("last listed changeset's serial 'to' %u is not ok",
knot_soa_serial(&ch->soa_to->rrs)); knot_soa_serial(&ch->soa_to->rrs));
} }
...@@ -2072,10 +2114,10 @@ check_merged: ...@@ -2072,10 +2114,10 @@ check_merged:
sto = knot_soa_serial(&ch->soa_to->rrs); sto = knot_soa_serial(&ch->soa_to->rrs);
jch_info("merged changeset %u -> %u (size %zu)", sfrom, sto, jch_info("merged changeset %u -> %u (size %zu)", sfrom, sto,
changeset_serialized_size(ch)); changeset_serialized_size(ch));
if (serial_compare(sfrom, txn->shadow_md.merged_serial) != 0) { if (!serial_equal(sfrom, txn->shadow_md.merged_serial)) {
jch_warn("merged changeset's serial 'from' is not ok"); jch_warn("merged changeset's serial 'from' is not ok");
} }
if (serial_compare(sto, first_unflushed) != 0) { if (!serial_equal(sto, first_unflushed)) {
jch_warn("merged changeset's serial 'to' is not ok"); jch_warn("merged changeset's serial 'to' is not ok");
} }
changeset_free(ch); changeset_free(ch);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "contrib/ucw/lists.h" #include "contrib/ucw/lists.h"
#include "knot/updates/changesets.h" #include "knot/updates/changesets.h"
#include "knot/journal/serialization.h" #include "knot/journal/serialization.h"
#include "knot/zone/serial.h"
/*! \brief Minimum journal size. */ /*! \brief Minimum journal size. */
#define JOURNAL_MIN_FSLIMIT (1 * 1024 * 1024) #define JOURNAL_MIN_FSLIMIT (1 * 1024 * 1024)
...@@ -209,13 +210,10 @@ int journal_flush(journal_t *journal); ...@@ -209,13 +210,10 @@ int journal_flush(journal_t *journal);
int journal_scrape(journal_t *j); int journal_scrape(journal_t *j);
/*! \brief Obtain public information from journal metadata /*! \brief Obtain public information from journal metadata
*
* \param[in] j Journal
* \param[out] is_empty True if j contains no changesets
* \param[out] serial_from [if !is_empty] starting serial of changesets history
* \param[out] serial_to [if !is_empty] ending serial of changesets history
*/ */
void journal_metadata_info(journal_t *j, bool *is_empty, uint32_t *serial_from, uint32_t *serial_to); void journal_metadata_info(journal_t *j, bool *is_empty, kserial_t *merged_serial,
kserial_t *first_serial, kserial_t *last_flushed, kserial_t *serial_to,
uint64_t *occupied);
/*! \brief Check the journal consistency, errors to stderr. /*! \brief Check the journal consistency, errors to stderr.
* *
......
...@@ -143,12 +143,11 @@ static int ixfr_load_chsets(list_t *chgsets, zone_t *zone, ...@@ -143,12 +143,11 @@ static int ixfr_load_chsets(list_t *chgsets, zone_t *zone,
/* Compare serials. */ /* Compare serials. */
uint32_t serial_to = zone_contents_serial(zone->contents); uint32_t serial_to = zone_contents_serial(zone->contents);
uint32_t serial_from = knot_soa_serial(&their_soa->rrs); uint32_t serial_from = knot_soa_serial(&their_soa->rrs);
int ret = serial_compare(serial_to, serial_from); if (serial_compare(serial_to, serial_from) & SERIAL_MASK_LEQ) { /* We have older/same age zone. */
if (ret <= 0) { /* We have older/same age zone. */
return KNOT_EUPTODATE; return KNOT_EUPTODATE;
} }
ret = zone_changes_load(conf(), zone, chgsets, serial_from); int ret = zone_changes_load(conf(), zone, chgsets, serial_from);
if (ret != KNOT_EOK) { if (ret != KNOT_EOK) {
changesets_free(chgsets); changesets_free(chgsets);
} }
......
...@@ -70,7 +70,7 @@ int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata) ...@@ -70,7 +70,7 @@ int notify_process_query(knot_pkt_t *pkt, knotd_qdata_t *qdata)
uint32_t serial = knot_soa_serial(&soa->rrs); uint32_t serial = knot_soa_serial(&soa->rrs);
uint32_t zone_serial = zone_contents_serial(zone->contents); uint32_t zone_serial = zone_contents_serial(zone->contents);
NOTIFY_LOG(LOG_INFO, qdata, "received, serial %u", serial); NOTIFY_LOG(LOG_INFO, qdata, "received, serial %u", serial);
if (serial_compare(serial, zone_serial) == 0) { if (serial_equal(serial, zone_serial)) {
// NOTIFY serial == zone serial => ignore, keep timers // NOTIFY serial == zone serial => ignore, keep timers
return KNOT_STATE_DONE; return KNOT_STATE_DONE;
} }
......
...@@ -316,7 +316,7 @@ static bool skip_soa(const knot_rrset_t *rr, int64_t sn) ...@@ -316,7 +316,7 @@ static bool skip_soa(const knot_rrset_t *rr, int64_t sn)
{ {
if (rr->type == KNOT_RRTYPE_SOA && if (rr->type == KNOT_RRTYPE_SOA &&
(rr->rclass == KNOT_CLASS_NONE || rr->rclass == KNOT_CLASS_ANY || (rr->rclass == KNOT_CLASS_NONE || rr->rclass == KNOT_CLASS_ANY ||
serial_compare(knot_soa_serial(&rr->rrs), sn) <= 0)) { (serial_compare(knot_soa_serial(&rr->rrs), sn) != SERIAL_GREATER))) {
return true; return true;
} }
......
...@@ -484,7 +484,7 @@ static int set_new_soa(zone_update_t *update, unsigned serial_policy) ...@@ -484,7 +484,7 @@ static int set_new_soa(zone_update_t *update, unsigned serial_policy)
uint32_t old_serial = knot_soa_serial(&soa_cpy->rrs); uint32_t old_serial = knot_soa_serial(&soa_cpy->rrs);
uint32_t new_serial = serial_next(old_serial, serial_policy); uint32_t new_serial = serial_next(old_serial, serial_policy);
if (serial_compare(old_serial, new_serial) >= 0) { if (serial_compare(old_serial, new_serial) != SERIAL_LOWER) {
log_zone_warning(update->zone->name, "updated serial is lower " log_zone_warning(update->zone->name, "updated serial is lower "
"than current, serial %u -> %u", "than current, serial %u -> %u",
old_serial, new_serial); old_serial, new_serial);
......
/* Copyright (C) 2015 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 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 it under the terms of the GNU General Public License as published by
...@@ -20,22 +20,22 @@ ...@@ -20,22 +20,22 @@
#include "knot/conf/conf.h" #include "knot/conf/conf.h"
#include "knot/zone/serial.h" #include "knot/zone/serial.h"
static int32_t serial_difference(uint32_t s1, uint32_t s2) static const serial_cmp_result_t diffbrief2result[4] = {
{ [0] = SERIAL_EQUAL,
return (((int64_t)s1 - s2) % ((int64_t)1 << 32)); [1] = SERIAL_GREATER,
} [2] = SERIAL_INCOMPARABLE,
[3] = SERIAL_LOWER,
};
int serial_compare(uint32_t s1, uint32_t s2) serial_cmp_result_t serial_compare(uint32_t s1, uint32_t s2)
{ {
int32_t diff = serial_difference(s1, s2); uint64_t diff = ((uint64_t)s1 + ((uint64_t)1 << 32) - s2) & 0xffffffff;
return (s1 == s2) /* s1 equal to s2 */ int diffbrief = (diff >> 31 << 1) | ((diff & 0x7fffffff) ? 1 : 0);
? 0 assert(diffbrief > -1 && diffbrief < 4);
:((diff >= 1 && diff < ((uint32_t)1 << 31)) return diffbrief2result[diffbrief];
? 1 /* s1 larger than s2 */
: -1); /* s1 less than s2 */
} }
int serial_next(uint32_t current, int policy) uint32_t serial_next(uint32_t current, int policy)
{ {
switch (policy) { switch (policy) {
case SERIAL_POLICY_INCREMENT: case SERIAL_POLICY_INCREMENT:
...@@ -47,3 +47,8 @@ int serial_next(uint32_t current, int policy) ...@@ -47,3 +47,8 @@ int serial_next(uint32_t current, int policy)
return 0; return 0;
} }
} }
serial_cmp_result_t kserial_cmp(kserial_t a, kserial_t b)
{
return ((a.valid && b.valid) ? serial_compare(a.serial, b.serial) : SERIAL_INCOMPARABLE);
}
/* Copyright (C) 2015 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 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 it under the terms of the GNU General Public License as published by
...@@ -16,16 +16,32 @@ ...@@ -16,16 +16,32 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
/*! /*!
* \brief Compares two zone serials. * \brief result of serial comparison. LOWER means that the first serial is lower that the second.
* *
* \retval < 0 if s1 is less than s2. * Example: (serial_compare(a, b) & SERIAL_MASK_LEQ) means "a <= b".
* \retval > 0 if s1 is larger than s2. */
* \retval == 0 if s1 is equal to s2. typedef enum {
SERIAL_INCOMPARABLE = 0x0,
SERIAL_LOWER = 0x1,
SERIAL_GREATER = 0x2,
SERIAL_EQUAL = 0x3,
SERIAL_MASK_LEQ = SERIAL_LOWER,
SERIAL_MASK_GEQ = SERIAL_GREATER,
} serial_cmp_result_t;
/*!
* \brief Compares two zone serials.
*/ */
int serial_compare(uint32_t s1, uint32_t s2); serial_cmp_result_t serial_compare(uint32_t s1, uint32_t s2);
inline static bool serial_equal(uint32_t a, uint32_t b)
{
return serial_compare(a, b) == SERIAL_EQUAL;
}
/*! /*!
* \brief Get next serial for given serial update policy. * \brief Get next serial for given serial update policy.
...@@ -35,4 +51,21 @@ int serial_compare(uint32_t s1, uint32_t s2); ...@@ -35,4 +51,21 @@ int serial_compare(uint32_t s1, uint32_t s2);
* *
* \return New serial. * \return New serial.
*/ */
int serial_next(uint32_t current, int policy); uint32_t serial_next(uint32_t current, int policy);
typedef struct {
uint32_t serial;
bool valid;
} kserial_t;
/*!
* \brief Compares two kserials.
*
* If any of them is invalid, they are INCOMPARABLE.
*/
serial_cmp_result_t kserial_cmp(kserial_t a, kserial_t b);
inline static bool kserial_equal(kserial_t a, kserial_t b)
{
return kserial_cmp(a, b) == SERIAL_EQUAL;
}
...@@ -54,11 +54,11 @@ static int load_soas(const zone_contents_t *zone1, const zone_contents_t *zone2, ...@@ -54,11 +54,11 @@ static int load_soas(const zone_contents_t *zone1, const zone_contents_t *zone2,
uint32_t soa_serial1 = knot_soa_serial(&soa_rrset1.rrs); uint32_t soa_serial1 = knot_soa_serial(&soa_rrset1.rrs);
uint32_t soa_serial2 = knot_soa_serial(&soa_rrset2.rrs); uint32_t soa_serial2 = knot_soa_serial(&soa_rrset2.rrs);
if (serial_compare(soa_serial1, soa_serial2) == 0) { if (serial_compare(soa_serial1, soa_serial2) == SERIAL_EQUAL) {
return KNOT_ENODIFF; return KNOT_ENODIFF;
} }
if (serial_compare(soa_serial1, soa_serial2) > 0) { if (serial_compare(soa_serial1, soa_serial2) != SERIAL_LOWER) {
return KNOT_ERANGE; return KNOT_ERANGE;
} }
......
...@@ -188,17 +188,24 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo ...@@ -188,17 +188,24 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo
return ret; return ret;
} }
bool is_empty; bool has_bootstrap;
uint32_t serial_from, serial_to; kserial_t merged_serial, serial_from, last_flushed, serial_to;
journal_metadata_info(j, &is_empty, &serial_from, &serial_to); uint64_t occupied;
journal_metadata_info(j, &has_bootstrap, &merged_serial, &serial_from, &last_flushed, &serial_to, &occupied);
bool alternative_from = (has_bootstrap || merged_serial.valid);
bool is_empty = (!alternative_from && !serial_from.valid);
if (is_empty) { if (is_empty) {
ret = KNOT_ENOENT; ret = KNOT_ENOENT;
goto pj_finally; goto pj_finally;
} }
ret = journal_load_bootstrap(j, &db); if (has_bootstrap) {
if (ret == KNOT_ENOENT) { ret = journal_load_bootstrap(j, &db);
ret = journal_load_changesets(j, &db, serial_from); } else if (merged_serial.valid) {
ret = journal_load_changesets(j, &db, merged_serial.serial);
} else {
ret = journal_load_changesets(j, &db, serial_from.serial);
} }
if (ret != KNOT_EOK) { if (ret != KNOT_EOK) {
goto pj_finally; goto pj_finally;
...@@ -221,6 +228,32 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo ...@@ -221,6 +228,32 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo
changesets_free(&db); changesets_free(&db);
if (debugmode) {
if ((alternative_from && serial_from.valid) ||
kserial_equal(serial_from, last_flushed)) {
printf("---- Additional history ----\n");
init_list(&db);
ret = journal_load_changesets(j, &db, serial_from.serial);
if (ret != KNOT_EOK) {
goto pj_finally;
}
WALK_LIST(chs, db) {
print_changeset_debugmode(chs);
if (last_flushed.valid && serial_equal(knot_soa_serial(&chs->soa_from->rrs), last_flushed.serial)) {
break;
}
}
changesets_free(&db);
} else {
printf("---- No additional history ----\n");
}
}
if (debugmode) {
printf("Occupied: %lu KiB\n", occupied / 1024);
}
pj_finally: pj_finally:
journal_close(j); journal_close(j);
journal_free(&j); journal_free(&j);
......
...@@ -43,59 +43,59 @@ int main(int argc, char *argv[]) ...@@ -43,59 +43,59 @@ int main(int argc, char *argv[])
plan(20); plan(20);
/* Serial compare test. */ /* Serial compare test. */
ok(serial_compare(S_LOWEST, S_BELOW_MIDDLE) < 0, ok(serial_compare(S_LOWEST, S_BELOW_MIDDLE) == SERIAL_LOWER,
"serial compare: lowest < below middle"); "serial compare: lowest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) > 0, ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) == SERIAL_GREATER,
"serial compare: below middle > lowest"); "serial compare: below middle > lowest");
/* Corner-case: these serials' distance is exactly 2^31. */ /* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_LOWEST, S_ABOVE_MIDDLE) < 0, ok(serial_compare(S_LOWEST, S_ABOVE_MIDDLE) == SERIAL_INCOMPARABLE,
"serial compare: lowest < above_middle"); "serial compare: lowest < above_middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) < 0, ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) == SERIAL_INCOMPARABLE,
"serial compare: above_middle < lowest"); "serial compare: above_middle < lowest");
ok(serial_compare(S_LOWEST, S_HIGHEST) > 0, ok(serial_compare(S_LOWEST, S_HIGHEST) == SERIAL_GREATER,
"serial compare: lowest > highest"); "serial compare: lowest > highest");
ok(serial_compare(S_HIGHEST, S_LOWEST) < 0, ok(serial_compare(S_HIGHEST, S_LOWEST) == SERIAL_LOWER,
"serial compare: highest < lowest"); "serial compare: highest < lowest");