Commit ad730712 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

zone SOA serial: refactored

parent 692bc018
......@@ -127,7 +127,7 @@ struct refresh_data {
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)
......
......@@ -534,7 +534,7 @@ static int md_flushed(txn_t *txn)
{
return (!md_flag(txn, SERIAL_TO_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)
......@@ -851,7 +851,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;
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);
}
unreuse_txn(txn, _txn);
......@@ -961,17 +961,17 @@ static int del_upto_itercb(iteration_ctx_t *ctx)
// If it's not merged changeset, point first_serial to next one
if (ctx->chunk_index == ctx->chunk_count - 1) {
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.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;
}
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;
}
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;
}
}
......@@ -1034,11 +1034,11 @@ static int del_tofree_itercb(iteration_ctx_t *ctx)
if (ctx->chunk_index == ctx->chunk_count - 1) {
ctx->txn->shadow_md.first_serial = ctx->serial_to;
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;
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;
}
if (ds->freed_approx >= ds->to_be_freed) {
......@@ -1090,11 +1090,11 @@ static int del_count_itercb(iteration_ctx_t *ctx)
if (ctx->chunk_index == ctx->chunk_count - 1) {
ctx->txn->shadow_md.first_serial = ctx->serial_to;
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;
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;
}
ds->freed_approx++;
......@@ -1203,7 +1203,7 @@ static int merge_unflushed_changesets(journal_t *j, txn_t *_txn, changeset_t **m
}
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,
mch, from, txn->shadow_md.last_serial, normal_iterkeycb);
}
......@@ -1353,7 +1353,7 @@ static int store_changesets(journal_t *j, list_t *changesets)
bool is_first_bootstrap = (chs_head->soa_from == NULL);
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 ||
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 */) {
log_zone_warning(j->zone, "journal, discontinuity in changes history (%u -> %u), dropping older changesets",
txn->shadow_md.last_serial_to, serial);
......@@ -1993,7 +1993,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);
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);
}
......@@ -2012,7 +2012,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
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");
goto check_merged;
}
......@@ -2022,7 +2022,7 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
}
else {
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);
}
changeset_free(ch);
......@@ -2046,12 +2046,12 @@ int journal_check(journal_t *j, journal_check_level_t warn_level)
}
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",
knot_soa_serial(&ch->soa_from->rrs));
}
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",
knot_soa_serial(&ch->soa_to->rrs));
}
......@@ -2072,10 +2072,10 @@ check_merged:
sto = knot_soa_serial(&ch->soa_to->rrs);
jch_info("merged changeset %u -> %u (size %zu)", sfrom, sto,
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");
}
if (serial_compare(sto, first_unflushed) != 0) {
if (!serial_equal(sto, first_unflushed)) {
jch_warn("merged changeset's serial 'to' is not ok");
}
changeset_free(ch);
......
......@@ -143,12 +143,11 @@ static int ixfr_load_chsets(list_t *chgsets, zone_t *zone,
/* Compare serials. */
uint32_t serial_to = zone_contents_serial(zone->contents);
uint32_t serial_from = knot_soa_serial(&their_soa->rrs);
int ret = serial_compare(serial_to, serial_from);
if (ret <= 0) { /* We have older/same age zone. */
if (serial_compare(serial_to, serial_from) & SERIAL_MASK_LEQ) { /* We have older/same age zone. */
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) {
changesets_free(chgsets);
}
......
......@@ -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 zone_serial = zone_contents_serial(zone->contents);
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
return KNOT_STATE_DONE;
}
......
......@@ -316,7 +316,7 @@ static bool skip_soa(const knot_rrset_t *rr, int64_t sn)
{
if (rr->type == KNOT_RRTYPE_SOA &&
(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;
}
......
......@@ -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 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 "
"than current, serial %u -> %u",
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
it under the terms of the GNU General Public License as published by
......@@ -20,22 +20,22 @@
#include "knot/conf/conf.h"
#include "knot/zone/serial.h"
static int32_t serial_difference(uint32_t s1, uint32_t s2)
{
return (((int64_t)s1 - s2) % ((int64_t)1 << 32));
}
static const serial_cmp_result_t diffbrief2result[4] = {
[0] = SERIAL_EQUAL,
[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);
return (s1 == s2) /* s1 equal to s2 */
? 0
:((diff >= 1 && diff < ((uint32_t)1 << 31))
? 1 /* s1 larger than s2 */
: -1); /* s1 less than s2 */
uint64_t diff = ((uint64_t)s1 + ((uint64_t)1 << 32) - s2) & 0xffffffff;
int diffbrief = (diff >> 31 << 1) | ((diff & 0x7fffffff) ? 1 : 0);
assert(diffbrief > -1 && diffbrief < 4);
return diffbrief2result[diffbrief];
}
int serial_next(uint32_t current, int policy)
uint32_t serial_next(uint32_t current, int policy)
{
switch (policy) {
case SERIAL_POLICY_INCREMENT:
......@@ -47,3 +47,8 @@ int serial_next(uint32_t current, int policy)
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
it under the terms of the GNU General Public License as published by
......@@ -16,16 +16,32 @@
#pragma once
#include <stdbool.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.
* \retval > 0 if s1 is larger than s2.
* \retval == 0 if s1 is equal to s2.
* Example: (serial_compare(a, b) & SERIAL_MASK_LEQ) means "a <= b".
*/
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.
......@@ -35,4 +51,21 @@ int serial_compare(uint32_t s1, uint32_t s2);
*
* \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,
uint32_t soa_serial1 = knot_soa_serial(&soa_rrset1.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;
}
if (serial_compare(soa_serial1, soa_serial2) > 0) {
if (serial_compare(soa_serial1, soa_serial2) != SERIAL_LOWER) {
return KNOT_ERANGE;
}
......
......@@ -43,59 +43,59 @@ int main(int argc, char *argv[])
plan(20);
/* 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");
ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) > 0,
ok(serial_compare(S_BELOW_MIDDLE, S_LOWEST) == SERIAL_GREATER,
"serial compare: below middle > lowest");
/* 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");
ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) < 0,
ok(serial_compare(S_ABOVE_MIDDLE, S_LOWEST) == SERIAL_INCOMPARABLE,
"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");
ok(serial_compare(S_HIGHEST, S_LOWEST) < 0,
ok(serial_compare(S_HIGHEST, S_LOWEST) == SERIAL_LOWER,
"serial compare: highest < lowest");
ok(serial_compare(S_2LOWEST, S_ABOVE_MIDDLE) < 0,
ok(serial_compare(S_2LOWEST, S_ABOVE_MIDDLE) == SERIAL_LOWER,
"serial compare: 2nd lowest < above middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_2LOWEST) > 0,
ok(serial_compare(S_ABOVE_MIDDLE, S_2LOWEST) == SERIAL_GREATER,
"serial compare: above middle > 2nd lowest");
/* Corner-case: these serials' distance is exactly 2^31. */
ok(serial_compare(S_BELOW_MIDDLE, S_HIGHEST) < 0,
ok(serial_compare(S_BELOW_MIDDLE, S_HIGHEST) == SERIAL_INCOMPARABLE,
"serial compare: below middle < highest");
ok(serial_compare(S_HIGHEST, S_BELOW_MIDDLE) < 0,
ok(serial_compare(S_HIGHEST, S_BELOW_MIDDLE) == SERIAL_INCOMPARABLE,
"serial compare: highest < below middle");
ok(serial_compare(S_BELOW_MIDDLE, S_2HIGHEST) < 0,
ok(serial_compare(S_BELOW_MIDDLE, S_2HIGHEST) == SERIAL_LOWER,
"serial compare: below middle < 2nd highest");
ok(serial_compare(S_2HIGHEST, S_BELOW_MIDDLE) > 0,
ok(serial_compare(S_2HIGHEST, S_BELOW_MIDDLE) == SERIAL_GREATER,
"serial compare: 2nd highest > below middle");
ok(serial_compare(S_ABOVE_MIDDLE, S_HIGHEST) < 0,
ok(serial_compare(S_ABOVE_MIDDLE, S_HIGHEST) == SERIAL_LOWER,
"serial compare: above middle < highest");
ok(serial_compare(S_HIGHEST, S_ABOVE_MIDDLE) > 0,
ok(serial_compare(S_HIGHEST, S_ABOVE_MIDDLE) == SERIAL_GREATER,
"serial compare: highest > above middle");
ok(serial_compare(S_LOWEST, S_LOWEST) == 0,
ok(serial_compare(S_LOWEST, S_LOWEST) == SERIAL_EQUAL,
"serial compare: lowest == lowest");
ok(serial_compare(S_HIGHEST, S_HIGHEST) == 0,
ok(serial_compare(S_HIGHEST, S_HIGHEST) == SERIAL_EQUAL,
"serial compare: highest == highest");
ok(serial_compare(S_LOWEST - 1, S_HIGHEST) == 0,
ok(serial_compare(S_LOWEST - 1, S_HIGHEST) == SERIAL_EQUAL,
"serial compare: lowest - 1 == highest");
ok(serial_compare(S_LOWEST, S_HIGHEST + 1) == 0,
ok(serial_compare(S_LOWEST, S_HIGHEST + 1) == SERIAL_EQUAL,
"serial compare: lowest== highest + 1");
/* Corner-case: these serials' distance is exactly 2^31. */
uint32_t s1 = random_serial();
uint32_t s2 = s1 + S_ABOVE_MIDDLE; // exactly the 'opposite' number
ok(serial_compare(s1, s2) < 0,
ok(serial_compare(s1, s2) == SERIAL_INCOMPARABLE,
"serial compare: random opposites (s1 < s2)");
ok(serial_compare(s2, s1) < 0,
ok(serial_compare(s2, s1) == SERIAL_INCOMPARABLE,
"serial compare: random opposites (s2 < s1)");
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment