mdbx-tests: добавление extra/details-rkl.

This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2025-01-30 18:56:25 +03:00
parent de968541cc
commit 2a3764a3de
2 changed files with 249 additions and 0 deletions

View File

@ -298,6 +298,7 @@ else()
add_extra_test(upsert_alldups SOURCE extra/upsert_alldups.c) add_extra_test(upsert_alldups SOURCE extra/upsert_alldups.c)
add_extra_test(dupfix_addodd SOURCE extra/dupfix_addodd.c) add_extra_test(dupfix_addodd SOURCE extra/dupfix_addodd.c)
endif() endif()
add_extra_test(details_rkl SOURCE extra/details_rkl.c)
if(MDBX_BUILD_CXX) if(MDBX_BUILD_CXX)
if(NOT WIN32 OR NOT MDBX_CXX_STANDARD LESS 17) if(NOT WIN32 OR NOT MDBX_CXX_STANDARD LESS 17)
add_extra_test(cursor_closing) add_extra_test(cursor_closing)

248
test/extra/details_rkl.c Normal file
View File

@ -0,0 +1,248 @@
/// \copyright SPDX-License-Identifier: Apache-2.0
/// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2025
#define debug_log debug_log_sub
#include "../../src/rkl.c"
#include "../../src/txl.c"
MDBX_MAYBE_UNUSED __cold void debug_log_sub(int level, const char *function, int line, const char *fmt, ...) {
(void)level;
(void)function;
(void)line;
(void)fmt;
}
/*-----------------------------------------------------------------------------*/
static size_t tst_failed, tst_ok, tst_iterations, tst_cases;
#ifndef NDEBUG
static size_t tst_target;
#endif
static bool check_bool(bool v, bool expect, const char *fn, unsigned line) {
if (unlikely(v != expect)) {
++tst_failed;
fprintf(stderr, "iteration %zi: got %s, expected %s, at %s:%u\n", tst_iterations, v ? "true" : "false",
expect ? "true" : "false", fn, line);
fflush(nullptr);
return false;
}
++tst_ok;
return true;
}
static bool check_eq(uint64_t v, uint64_t expect, const char *fn, unsigned line) {
if (unlikely(v != expect)) {
++tst_failed;
fprintf(stderr, "iteration %zi: %" PRIu64 " (got) != %" PRIu64 " (expected), at %s:%u\n", tst_iterations, v, expect,
fn, line);
fflush(nullptr);
return false;
}
++tst_ok;
return true;
}
#define CHECK_BOOL(T, EXPECT) check_bool((T), (EXPECT), __func__, __LINE__)
#define CHECK_TRUE(T) CHECK_BOOL(T, true)
#define CHECK_FALSE(T) CHECK_BOOL(T, false)
#define CHECK_EQ(T, EXPECT) check_eq((T), (EXPECT), __func__, __LINE__)
void trivia(void) {
rkl_t x, y;
rkl_init(&x);
rkl_init(&y);
CHECK_TRUE(rkl_check(&x));
CHECK_TRUE(rkl_empty(&x));
CHECK_EQ(rkl_len(&x), 0);
rkl_iterator_t f, r;
rkl_iterator_init(&f, &x, false);
rkl_iterator_init(&r, &x, true);
CHECK_EQ(rkl_iterator_left(&f, &x, false), 0);
CHECK_EQ(rkl_iterator_left(&f, &x, true), 0);
CHECK_EQ(rkl_iterator_left(&r, &x, false), 0);
CHECK_EQ(rkl_iterator_left(&r, &x, true), 0);
CHECK_EQ(rkl_iterator_turn(&f, &x, false), 0);
CHECK_EQ(rkl_iterator_turn(&f, &x, true), 0);
CHECK_EQ(rkl_iterator_turn(&r, &x, false), 0);
CHECK_EQ(rkl_iterator_turn(&r, &x, true), 0);
CHECK_TRUE(rkl_check(&x));
CHECK_EQ(rkl_push(&x, 42, false), MDBX_SUCCESS);
CHECK_TRUE(rkl_check(&x));
CHECK_FALSE(rkl_empty(&x));
CHECK_EQ(rkl_len(&x), 1);
CHECK_TRUE(rkl_push(&x, 42, true) == MDBX_RESULT_TRUE);
CHECK_TRUE(rkl_check(&x));
rkl_iterator_init(&f, &x, false);
rkl_iterator_init(&r, &x, true);
CHECK_EQ(rkl_iterator_left(&f, &x, false), 1);
CHECK_EQ(rkl_iterator_left(&f, &x, true), 0);
CHECK_EQ(rkl_iterator_left(&r, &x, false), 0);
CHECK_EQ(rkl_iterator_left(&r, &x, true), 1);
CHECK_EQ(rkl_iterator_turn(&f, &x, true), 0);
CHECK_EQ(rkl_iterator_turn(&f, &x, false), 42);
CHECK_EQ(rkl_iterator_turn(&f, &x, false), 0);
CHECK_EQ(rkl_iterator_turn(&f, &x, true), 42);
CHECK_EQ(rkl_iterator_turn(&f, &x, true), 0);
CHECK_EQ(rkl_iterator_turn(&r, &x, false), 0);
CHECK_EQ(rkl_iterator_turn(&r, &x, true), 42);
CHECK_EQ(rkl_iterator_turn(&r, &x, true), 0);
CHECK_EQ(rkl_iterator_turn(&r, &x, false), 42);
CHECK_EQ(rkl_iterator_turn(&r, &x, false), 0);
rkl_resize(&x, 222);
CHECK_FALSE(rkl_empty(&x));
CHECK_TRUE(rkl_check(&x));
rkl_destructive_move(&x, &y);
CHECK_TRUE(rkl_check(&x));
CHECK_TRUE(rkl_check(&y));
rkl_destroy(&x);
rkl_destroy(&y);
}
/*-----------------------------------------------------------------------------*/
uint64_t prng;
static bool stochastic_pass(const unsigned start, const unsigned width, const unsigned n) {
rkl_t k, c;
txl_t l = txl_alloc();
if (!CHECK_TRUE(l))
return false;
rkl_init(&k);
rkl_init(&c);
const size_t errors = tst_failed;
rkl_iterator_t f, r;
rkl_iterator_init(&f, &k, false);
rkl_iterator_init(&r, &k, true);
txnid_t lowest = UINT_MAX;
txnid_t highest = 0;
while (MDBX_PNL_GETSIZE(l) < n) {
prng = prng * UINT64_C(6364136223846793005) + 1;
txnid_t id = (txnid_t)(prng % width + start);
if (id < MIN_TXNID || id >= INVALID_TXNID)
continue;
if (txl_contain(l, id)) {
if (!CHECK_TRUE(rkl_contain(&k, id)) || !CHECK_TRUE(rkl_push(&k, id, false) == MDBX_RESULT_TRUE))
break;
continue;
}
if (!CHECK_FALSE(rkl_contain(&k, id)))
break;
if (tst_iterations % (1u << 24) == 0 && tst_iterations) {
printf("done %.3fM iteration, %zu cases\n", tst_iterations / 1000000.0, tst_cases);
fflush(nullptr);
}
tst_iterations += 1;
#ifndef NDEBUG
if (tst_iterations == tst_target) {
printf("reach %zu iteration\n", tst_iterations);
fflush(nullptr);
}
#endif
if (!CHECK_EQ(rkl_push(&k, id, false), MDBX_SUCCESS))
break;
if (!CHECK_TRUE(rkl_check(&k)))
break;
if (!CHECK_EQ(txl_append(&l, id), MDBX_SUCCESS))
break;
if (!CHECK_TRUE(rkl_contain(&k, id)))
break;
lowest = (lowest < id) ? lowest : id;
highest = (highest > id) ? highest : id;
if (!CHECK_EQ(rkl_lowest(&k), lowest))
break;
if (!CHECK_EQ(rkl_highest(&k), highest))
break;
}
txl_sort(l);
CHECK_EQ(rkl_len(&k), n);
CHECK_EQ(MDBX_PNL_GETSIZE(l), n);
rkl_iterator_init(&f, &k, false);
rkl_iterator_init(&r, &k, true);
CHECK_EQ(rkl_iterator_left(&f, &k, false), n);
CHECK_EQ(rkl_iterator_left(&f, &k, true), 0);
CHECK_EQ(rkl_iterator_left(&r, &k, false), 0);
CHECK_EQ(rkl_iterator_left(&r, &k, true), n);
for (size_t i = 0; i < n; ++i) {
CHECK_EQ(rkl_iterator_turn(&f, &k, false), l[n - i]);
CHECK_EQ(rkl_iterator_left(&f, &k, false), n - i - 1);
CHECK_EQ(rkl_iterator_left(&f, &k, true), i + 1);
CHECK_EQ(rkl_iterator_turn(&r, &k, true), l[i + 1]);
r.pos += 1;
CHECK_EQ(rkl_iterator_turn(&r, &k, true), l[i + 1]);
CHECK_EQ(rkl_iterator_left(&r, &k, true), n - i - 1);
CHECK_EQ(rkl_iterator_left(&r, &k, false), i + 1);
}
if (CHECK_EQ(rkl_copy(&k, &c), MDBX_SUCCESS)) {
for (size_t i = 1; i <= n; ++i) {
if (!CHECK_FALSE(rkl_empty(&k)))
break;
if (!CHECK_FALSE(rkl_empty(&c)))
break;
CHECK_EQ(rkl_pop(&k, true), l[i]);
CHECK_EQ(rkl_pop(&c, false), l[1 + n - i]);
}
}
CHECK_TRUE(rkl_empty(&k));
CHECK_TRUE(rkl_empty(&c));
rkl_destroy(&k);
rkl_destroy(&c);
txl_free(l);
++tst_cases;
return errors == tst_failed;
}
static bool stochastic(const size_t limit_cases, const size_t limit_loops) {
for (unsigned loop = 0; tst_cases < limit_cases || loop < limit_loops; ++loop)
for (unsigned width = 2; width < 10; ++width)
for (unsigned n = 1; n < width; ++n)
for (unsigned prev = 1, start = 0, t; start < 4242; t = start + prev, prev = start, start = t)
if (!stochastic_pass(start, 1u << width, 1u << n) || tst_failed > 42) {
puts("bailout\n");
return false;
}
return true;
}
int main(int argc, const char *argv[]) {
(void)argc;
(void)argv;
#ifndef NDEBUG
// tst_target = 281870;
#endif
prng = (uint64_t)time(nullptr);
printf("prng-seed %" PRIu64 "\n", prng);
fflush(nullptr);
trivia();
stochastic(42 * 42 * 42, 42);
printf("done: %zu cases, %zu iterations, %zu checks ok, %zu checks failed\n", tst_cases, tst_iterations, tst_ok,
tst_failed);
fflush(nullptr);
return tst_failed ? EXIT_FAILURE : EXIT_SUCCESS;
}