mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-29 23:19:20 +08:00
mdbx-test: redesign fitting internal parameters of "ttl" & "nested" testcases.
Change-Id: I3ade4ba9d78c00ff6911c3e35738f7dcbf63de64
This commit is contained in:
parent
d83a765dbe
commit
bfad1f7086
@ -15,6 +15,25 @@
|
||||
#include "test.h"
|
||||
#include <cmath>
|
||||
|
||||
/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями:
|
||||
* - организуется "скользящее окно", которое каждую транзакцию сдвигается
|
||||
* вперед вдоль числовой оси.
|
||||
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||
* а по заднему удаляются.
|
||||
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||
* от номера транзакции, но с экспоненциальным распределением.
|
||||
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||
* транзакции с "отрицательным" экспоненциальным распределением
|
||||
* MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
|
||||
* край и удаляются записи позади него.
|
||||
* - групповое добавление данных в начало окна и групповое удаление в конце,
|
||||
* преимущественно выполняются во вложенных транзакциях.
|
||||
* - меньшая часть запускаемых вложенных транзакций отменяется, с последующим
|
||||
* продолжением итераций с состояния предыдущиего коммита.
|
||||
*
|
||||
* Таким образом имитируется поведение таблицы с TTL: записи стохастически
|
||||
* добавляются и удаляются, и изредка происходят массивные удаления. */
|
||||
|
||||
bool testcase_nested::setup() {
|
||||
if (!inherited::setup())
|
||||
return false;
|
||||
@ -56,18 +75,6 @@ bool testcase_nested::teardown() {
|
||||
return inherited::teardown() && ok;
|
||||
}
|
||||
|
||||
static unsigned edge2window(uint64_t edge, unsigned window_max) {
|
||||
const double rnd = u64_to_double1(bleach64(edge));
|
||||
const unsigned window = window_max - std::lrint(std::pow(window_max, rnd));
|
||||
return window;
|
||||
}
|
||||
|
||||
static unsigned edge2count(uint64_t edge, unsigned count_max) {
|
||||
const double rnd = u64_to_double1(prng64_map1_white(edge));
|
||||
const unsigned count = std::lrint(std::pow(count_max, rnd));
|
||||
return count;
|
||||
}
|
||||
|
||||
void testcase_nested::push_txn() {
|
||||
MDBX_txn *txn;
|
||||
unsigned flags =
|
||||
@ -172,7 +179,7 @@ bool testcase_nested::trim_tail(unsigned window_width) {
|
||||
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
||||
failure("nested: unexpected key-space overflow on the tail");
|
||||
}
|
||||
report(1);
|
||||
report(tail_count);
|
||||
}
|
||||
} else if (!fifo.empty()) {
|
||||
log_verbose("nested: purge state %" PRIu64 " - %" PRIu64 ", fifo-items %zu",
|
||||
@ -220,39 +227,6 @@ retry:
|
||||
}
|
||||
|
||||
bool testcase_nested::run() {
|
||||
/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями:
|
||||
* - организуется "скользящее окно", которое каждую транзакцию сдвигается
|
||||
* вперед вдоль числовой оси.
|
||||
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||
* а по заднему удаляются.
|
||||
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||
* от номера транзакции, но с экспоненциальным распределением.
|
||||
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||
* транзакции с "отрицательным" экспоненциальным распределением
|
||||
* MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
|
||||
* край и удаляются записи позади него.
|
||||
* - групповое добавление данных в начало окна и групповое уделение в конце,
|
||||
* в половине случаев выполняются во вложенных транзакциях.
|
||||
* - половина запускаемых вложенных транзакций отменяется, последуюим
|
||||
* повтором групповой операции.
|
||||
*
|
||||
* Таким образом имитируется поведение таблицы с TTL: записи стохастически
|
||||
* добавляются и удаляются, но изредка происходят массивные удаления. */
|
||||
|
||||
/* LY: для параметризации используем подходящие параметры, которые не имеют
|
||||
* здесь смысла в первоначальном значении. */
|
||||
const unsigned window_max_lower = 333;
|
||||
const unsigned count_max_lower = 333;
|
||||
|
||||
const unsigned window_max = (config.params.batch_read > window_max_lower)
|
||||
? config.params.batch_read
|
||||
: window_max_lower;
|
||||
const unsigned count_max = (config.params.batch_write > count_max_lower)
|
||||
? config.params.batch_write
|
||||
: count_max_lower;
|
||||
log_verbose("nested: using `batch_read` value %u for window_max", window_max);
|
||||
log_verbose("nested: using `batch_write` value %u for count_max", count_max);
|
||||
|
||||
uint64_t seed =
|
||||
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
||||
|
||||
@ -262,10 +236,9 @@ bool testcase_nested::run() {
|
||||
unsigned loops = 0;
|
||||
while (true) {
|
||||
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
||||
const unsigned window_width = (!should_continue() || flipcoin_x4())
|
||||
? 0
|
||||
: edge2window(salt, window_max);
|
||||
const unsigned head_count = edge2count(salt, count_max);
|
||||
const unsigned window_width =
|
||||
(!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt);
|
||||
const unsigned head_count = edge2count(salt);
|
||||
log_debug("nested: step #%zu (serial %" PRIu64
|
||||
", window %u, count %u) salt %" PRIu64,
|
||||
nops_completed, serial, window_width, head_count, salt);
|
||||
@ -301,7 +274,9 @@ bool testcase_nested::run() {
|
||||
}
|
||||
loops += 1;
|
||||
} else if (fifo.empty()) {
|
||||
log_notice("nested: done %u whole loops", loops);
|
||||
log_notice("nested: done %u whole loops, %" PRIu64 " ops, %" PRIu64
|
||||
" items",
|
||||
loops, nops_completed, serial);
|
||||
break;
|
||||
} else {
|
||||
log_notice("nested: done, wait for empty, skip head-grow");
|
||||
|
@ -394,7 +394,8 @@ bool testcase::should_continue(bool check_timeout_only) const {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!check_timeout_only && nops_target && nops_completed >= nops_target)
|
||||
if (!check_timeout_only && config.params.test_nops &&
|
||||
nops_completed >= config.params.test_nops)
|
||||
result = false;
|
||||
|
||||
if (result)
|
||||
|
34
test/test.h
34
test/test.h
@ -148,7 +148,6 @@ protected:
|
||||
bool signalled{false};
|
||||
bool need_speculum_assign{false};
|
||||
|
||||
unsigned nops_target{config.params.test_nops};
|
||||
size_t nops_completed{0};
|
||||
chrono::time start_timestamp;
|
||||
keygen::buffer key;
|
||||
@ -229,18 +228,7 @@ public:
|
||||
virtual ~testcase() {}
|
||||
};
|
||||
|
||||
class testcase_ttl : public testcase {
|
||||
using inherited = testcase;
|
||||
|
||||
public:
|
||||
testcase_ttl(const actor_config &config, const mdbx_pid_t pid)
|
||||
: testcase(config, pid) {}
|
||||
bool run() override;
|
||||
};
|
||||
|
||||
class testcase_hill : public testcase {
|
||||
using inherited = testcase;
|
||||
|
||||
public:
|
||||
testcase_hill(const actor_config &config, const mdbx_pid_t pid)
|
||||
: testcase(config, pid) {}
|
||||
@ -293,8 +281,26 @@ public:
|
||||
bool run() override;
|
||||
};
|
||||
|
||||
class testcase_nested : public testcase {
|
||||
class testcase_ttl : public testcase {
|
||||
using inherited = testcase;
|
||||
|
||||
protected:
|
||||
struct {
|
||||
unsigned max_window_size{0};
|
||||
unsigned max_step_size{0};
|
||||
} sliding;
|
||||
unsigned edge2window(uint64_t edge);
|
||||
unsigned edge2count(uint64_t edge);
|
||||
|
||||
public:
|
||||
testcase_ttl(const actor_config &config, const mdbx_pid_t pid)
|
||||
: inherited(config, pid) {}
|
||||
bool setup() override;
|
||||
bool run() override;
|
||||
};
|
||||
|
||||
class testcase_nested : public testcase_ttl {
|
||||
using inherited = testcase_ttl;
|
||||
using FIFO = std::deque<std::pair<uint64_t, unsigned>>;
|
||||
|
||||
uint64_t serial{0};
|
||||
@ -317,7 +323,7 @@ class testcase_nested : public testcase {
|
||||
|
||||
public:
|
||||
testcase_nested(const actor_config &config, const mdbx_pid_t pid)
|
||||
: testcase(config, pid) {}
|
||||
: inherited(config, pid) {}
|
||||
bool setup() override;
|
||||
bool run() override;
|
||||
bool teardown() override;
|
||||
|
139
test/ttl.cc
139
test/ttl.cc
@ -16,16 +16,97 @@
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
|
||||
static unsigned edge2window(uint64_t edge, unsigned window_max) {
|
||||
const double rnd = u64_to_double1(bleach64(edge));
|
||||
const unsigned window = window_max - std::lrint(std::pow(window_max, rnd));
|
||||
return window;
|
||||
/* LY: тест "эмуляцией time-to-live":
|
||||
* - организуется "скользящее окно", которое двигается вперед вдоль
|
||||
* числовой оси каждую транзакцию.
|
||||
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||
* а по заднему удаляются.
|
||||
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||
* от номера транзакции, но с экспоненциальным распределением.
|
||||
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||
* транзакции с "отрицательным" экспоненциальным распределением
|
||||
* MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
|
||||
* край и удаляются записи позади него.
|
||||
*
|
||||
* Таким образом имитируется поведение таблицы с TTL: записи стохастически
|
||||
* добавляются и удаляются, но изредка происходит массивное удаление.
|
||||
*/
|
||||
|
||||
unsigned testcase_ttl::edge2count(uint64_t edge) {
|
||||
const double rnd = u64_to_double1(prng64_map1_white(edge));
|
||||
const unsigned count = std::lrint(std::pow(sliding.max_step_size, rnd));
|
||||
// average value: (X - 1) / ln(X), where X = sliding.max_step_size
|
||||
return count;
|
||||
}
|
||||
|
||||
static unsigned edge2count(uint64_t edge, unsigned count_max) {
|
||||
const double rnd = u64_to_double1(prng64_map1_white(edge));
|
||||
const unsigned count = std::lrint(std::pow(count_max, rnd));
|
||||
return count;
|
||||
unsigned testcase_ttl::edge2window(uint64_t edge) {
|
||||
const double rnd = u64_to_double1(bleach64(edge));
|
||||
const unsigned size = sliding.max_window_size -
|
||||
std::lrint(std::pow(sliding.max_window_size, rnd));
|
||||
// average value: Y - (Y - 1) / ln(Y), where Y = sliding.max_window_size
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline double estimate(const double x, const double y) {
|
||||
/* среднее кол-во операций N = X' * Y', где X' и Y' средние значения
|
||||
* размера окна и кол-ва добавляемых за один шаг записей:
|
||||
* X' = (X - 1) / ln(X), где X = sliding.max_step_size
|
||||
* Y' = Y - (Y - 1) / ln(Y), где Y = sliding.max_window_size */
|
||||
return (x - 1) / std::log(x) * (y - (y - 1) / std::log(y));
|
||||
}
|
||||
|
||||
bool testcase_ttl::setup() {
|
||||
const unsigned window_top_lower =
|
||||
7 /* нижний предел для верхней границы диапазона, в котором будет
|
||||
стохастически колебаться размер окна */
|
||||
;
|
||||
const unsigned count_top_lower =
|
||||
7 /* нижний предел для верхней границы диапазона, в котором будет
|
||||
стохастически колебаться кол-во записей добавляемых на одном шаге */
|
||||
;
|
||||
|
||||
/* для параметризации используем подходящие параметры,
|
||||
* которые не имеют здесь смысла в первоначальном значении. */
|
||||
const double ratio =
|
||||
double(config.params.batch_read ? config.params.batch_read : 1) /
|
||||
double(config.params.batch_write ? config.params.batch_write : 1);
|
||||
|
||||
/* проще найти двоичным поиском (вариация метода Ньютона) */
|
||||
double hi = config.params.test_nops, lo = 1;
|
||||
double x = std::sqrt(hi + lo) / ratio;
|
||||
while (hi > lo) {
|
||||
const double n = estimate(x, x * ratio);
|
||||
if (n > config.params.test_nops)
|
||||
hi = x - 1;
|
||||
else
|
||||
lo = x + 1;
|
||||
x = (hi + lo) / 2;
|
||||
}
|
||||
|
||||
sliding.max_step_size = std::lrint(x);
|
||||
if (sliding.max_step_size < count_top_lower)
|
||||
sliding.max_step_size = count_top_lower;
|
||||
sliding.max_window_size = std::lrint(x * ratio);
|
||||
if (sliding.max_window_size < window_top_lower)
|
||||
sliding.max_window_size = window_top_lower;
|
||||
|
||||
while (estimate(sliding.max_step_size, sliding.max_window_size) >
|
||||
config.params.test_nops * 2.0) {
|
||||
if (ratio * sliding.max_step_size > sliding.max_window_size) {
|
||||
if (sliding.max_step_size < count_top_lower)
|
||||
break;
|
||||
sliding.max_step_size = sliding.max_step_size * 7 / 8;
|
||||
} else {
|
||||
if (sliding.max_window_size < window_top_lower)
|
||||
break;
|
||||
sliding.max_window_size = sliding.max_window_size * 7 / 8;
|
||||
}
|
||||
}
|
||||
|
||||
log_verbose("come up window_max %u from `batch_read`",
|
||||
sliding.max_window_size);
|
||||
log_verbose("come up step_max %u from `batch_write`", sliding.max_step_size);
|
||||
return inherited::setup();
|
||||
}
|
||||
|
||||
bool testcase_ttl::run() {
|
||||
@ -35,36 +116,6 @@ bool testcase_ttl::run() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* LY: тест "эмуляцией time-to-live":
|
||||
* - организуется "скользящее окно", которое двигается вперед вдоль
|
||||
* числовой оси каждую транзакцию.
|
||||
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||
* а по заднему удаляются.
|
||||
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||
* от номера транзакции, но с экспоненциальным распределением.
|
||||
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||
* транзакции с "отрицательным" экспоненциальным распределением
|
||||
* MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
|
||||
* край и удаляются записи позади него.
|
||||
*
|
||||
* Таким образом имитируется поведение таблицы с TTL: записи стохастически
|
||||
* добавляются и удаляются, но изредка происходят массивные удаления.
|
||||
*/
|
||||
|
||||
/* LY: для параметризации используем подходящие параметры, которые не имеют
|
||||
* здесь смысла в первоначальном значении. */
|
||||
const unsigned window_max_lower = 333;
|
||||
const unsigned count_max_lower = 333;
|
||||
|
||||
const unsigned window_max = (config.params.batch_read > window_max_lower)
|
||||
? config.params.batch_read
|
||||
: window_max_lower;
|
||||
const unsigned count_max = (config.params.batch_write > count_max_lower)
|
||||
? config.params.batch_write
|
||||
: count_max_lower;
|
||||
log_verbose("ttl: using `batch_read` value %u for window_max", window_max);
|
||||
log_verbose("ttl: using `batch_write` value %u for count_max", count_max);
|
||||
|
||||
uint64_t seed =
|
||||
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
||||
keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
|
||||
@ -85,10 +136,9 @@ bool testcase_ttl::run() {
|
||||
while (true) {
|
||||
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
||||
|
||||
const unsigned window_width = (!should_continue() || flipcoin_x4())
|
||||
? 0
|
||||
: edge2window(salt, window_max);
|
||||
unsigned head_count = edge2count(salt, count_max);
|
||||
const unsigned window_width =
|
||||
(!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt);
|
||||
unsigned head_count = edge2count(salt);
|
||||
log_debug("ttl: step #%zu (serial %" PRIu64
|
||||
", window %u, count %u) salt %" PRIu64,
|
||||
nops_completed, serial, window_width, head_count, salt);
|
||||
@ -115,7 +165,7 @@ bool testcase_ttl::run() {
|
||||
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
||||
failure("ttl: unexpected key-space overflow on the tail");
|
||||
}
|
||||
report(1);
|
||||
report(tail_count);
|
||||
}
|
||||
} else {
|
||||
log_trace("ttl: purge state");
|
||||
@ -185,7 +235,8 @@ bool testcase_ttl::run() {
|
||||
}
|
||||
loops += 1;
|
||||
} else if (fifo.empty()) {
|
||||
log_notice("ttl: done %u whole loops", loops);
|
||||
log_notice("ttl: done %u whole loops, %" PRIu64 " ops, %" PRIu64 " items",
|
||||
loops, nops_completed, serial);
|
||||
rc = true;
|
||||
break;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user