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 {
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)
......
......@@ -19,7 +19,6 @@
#include <stdarg.h>
#include "knot/journal/journal.h"
#include "knot/zone/serial.h"
#include "knot/common/log.h"
#include "contrib/files.h"
#include "contrib/endian.h"
......@@ -534,7 +533,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 +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;
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 +960,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 +1033,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 +1089,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 +1202,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 +1352,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);
......@@ -1388,11 +1387,11 @@ static int store_changesets(journal_t *j, list_t *changesets)
}
} else {
try_flush
}
delete_upto(j, txn, txn->shadow_md.first_serial, serial_to);
txn_restart(txn);
}
}
}
// PART 5: serializing into chunks
WALK_LIST(ch, *changesets) {
......@@ -1796,12 +1795,31 @@ scrape_end:
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.
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;
}
......@@ -1809,13 +1827,37 @@ void journal_metadata_info(journal_t *j, bool *is_empty, uint32_t *serial_from,
txn_begin(txn, false);
txn_check_open(txn);
*is_empty = !md_flag(txn, SERIAL_TO_VALID);
*serial_from = txn->shadow_md.first_serial;
*serial_to = txn->shadow_md.last_serial_to;
if (md_flag(txn, MERGED_SERIAL_VALID)) {
*serial_from = txn->shadow_md.merged_serial;
if (has_bootstrap != NULL) {
*has_bootstrap = has_bootstrap_changeset(j, txn);
}
if (merged_serial != NULL) {
merged_serial->valid = md_flag(txn, MERGED_SERIAL_VALID);
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);
}
......@@ -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);
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 +2054,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 +2064,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 +2088,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 +2114,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);
......
......@@ -22,6 +22,7 @@
#include "contrib/ucw/lists.h"
#include "knot/updates/changesets.h"
#include "knot/journal/serialization.h"
#include "knot/zone/serial.h"
/*! \brief Minimum journal size. */
#define JOURNAL_MIN_FSLIMIT (1 * 1024 * 1024)
......@@ -209,13 +210,10 @@ int journal_flush(journal_t *journal);
int journal_scrape(journal_t *j);
/*! \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.
*
......
......@@ -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;
}
......
......@@ -188,17 +188,24 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo
return ret;
}
bool is_empty;
uint32_t serial_from, serial_to;
journal_metadata_info(j, &is_empty, &serial_from, &serial_to);
bool has_bootstrap;
kserial_t merged_serial, serial_from, last_flushed, 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) {
ret = KNOT_ENOENT;
goto pj_finally;
}
if (has_bootstrap) {
ret = journal_load_bootstrap(j, &db);
if (ret == KNOT_ENOENT) {
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) {
goto pj_finally;
......@@ -221,6 +228,32 @@ int print_journal(char *path, knot_dname_t *name, uint32_t limit, bool color, bo
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:
journal_close(j);
journal_free(&j);
......
......@@ -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