mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-30 11:29:19 +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 "test.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями:
|
||||||
|
* - организуется "скользящее окно", которое каждую транзакцию сдвигается
|
||||||
|
* вперед вдоль числовой оси.
|
||||||
|
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||||
|
* а по заднему удаляются.
|
||||||
|
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||||
|
* от номера транзакции, но с экспоненциальным распределением.
|
||||||
|
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||||
|
* транзакции с "отрицательным" экспоненциальным распределением
|
||||||
|
* MAX_WIDTH - exp(rnd(N)), при уменьшении окна сдвигается задний
|
||||||
|
* край и удаляются записи позади него.
|
||||||
|
* - групповое добавление данных в начало окна и групповое удаление в конце,
|
||||||
|
* преимущественно выполняются во вложенных транзакциях.
|
||||||
|
* - меньшая часть запускаемых вложенных транзакций отменяется, с последующим
|
||||||
|
* продолжением итераций с состояния предыдущиего коммита.
|
||||||
|
*
|
||||||
|
* Таким образом имитируется поведение таблицы с TTL: записи стохастически
|
||||||
|
* добавляются и удаляются, и изредка происходят массивные удаления. */
|
||||||
|
|
||||||
bool testcase_nested::setup() {
|
bool testcase_nested::setup() {
|
||||||
if (!inherited::setup())
|
if (!inherited::setup())
|
||||||
return false;
|
return false;
|
||||||
@ -56,18 +75,6 @@ bool testcase_nested::teardown() {
|
|||||||
return inherited::teardown() && ok;
|
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() {
|
void testcase_nested::push_txn() {
|
||||||
MDBX_txn *txn;
|
MDBX_txn *txn;
|
||||||
unsigned flags =
|
unsigned flags =
|
||||||
@ -172,7 +179,7 @@ bool testcase_nested::trim_tail(unsigned window_width) {
|
|||||||
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
||||||
failure("nested: unexpected key-space overflow on the tail");
|
failure("nested: unexpected key-space overflow on the tail");
|
||||||
}
|
}
|
||||||
report(1);
|
report(tail_count);
|
||||||
}
|
}
|
||||||
} else if (!fifo.empty()) {
|
} else if (!fifo.empty()) {
|
||||||
log_verbose("nested: purge state %" PRIu64 " - %" PRIu64 ", fifo-items %zu",
|
log_verbose("nested: purge state %" PRIu64 " - %" PRIu64 ", fifo-items %zu",
|
||||||
@ -220,39 +227,6 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool testcase_nested::run() {
|
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 =
|
uint64_t seed =
|
||||||
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
||||||
|
|
||||||
@ -262,10 +236,9 @@ bool testcase_nested::run() {
|
|||||||
unsigned loops = 0;
|
unsigned loops = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
||||||
const unsigned window_width = (!should_continue() || flipcoin_x4())
|
const unsigned window_width =
|
||||||
? 0
|
(!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt);
|
||||||
: edge2window(salt, window_max);
|
const unsigned head_count = edge2count(salt);
|
||||||
const unsigned head_count = edge2count(salt, count_max);
|
|
||||||
log_debug("nested: step #%zu (serial %" PRIu64
|
log_debug("nested: step #%zu (serial %" PRIu64
|
||||||
", window %u, count %u) salt %" PRIu64,
|
", window %u, count %u) salt %" PRIu64,
|
||||||
nops_completed, serial, window_width, head_count, salt);
|
nops_completed, serial, window_width, head_count, salt);
|
||||||
@ -301,7 +274,9 @@ bool testcase_nested::run() {
|
|||||||
}
|
}
|
||||||
loops += 1;
|
loops += 1;
|
||||||
} else if (fifo.empty()) {
|
} 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;
|
break;
|
||||||
} else {
|
} else {
|
||||||
log_notice("nested: done, wait for empty, skip head-grow");
|
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;
|
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;
|
result = false;
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
|
34
test/test.h
34
test/test.h
@ -148,7 +148,6 @@ protected:
|
|||||||
bool signalled{false};
|
bool signalled{false};
|
||||||
bool need_speculum_assign{false};
|
bool need_speculum_assign{false};
|
||||||
|
|
||||||
unsigned nops_target{config.params.test_nops};
|
|
||||||
size_t nops_completed{0};
|
size_t nops_completed{0};
|
||||||
chrono::time start_timestamp;
|
chrono::time start_timestamp;
|
||||||
keygen::buffer key;
|
keygen::buffer key;
|
||||||
@ -229,18 +228,7 @@ public:
|
|||||||
virtual ~testcase() {}
|
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 {
|
class testcase_hill : public testcase {
|
||||||
using inherited = testcase;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
testcase_hill(const actor_config &config, const mdbx_pid_t pid)
|
testcase_hill(const actor_config &config, const mdbx_pid_t pid)
|
||||||
: testcase(config, pid) {}
|
: testcase(config, pid) {}
|
||||||
@ -293,8 +281,26 @@ public:
|
|||||||
bool run() override;
|
bool run() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class testcase_nested : public testcase {
|
class testcase_ttl : public testcase {
|
||||||
using inherited = 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>>;
|
using FIFO = std::deque<std::pair<uint64_t, unsigned>>;
|
||||||
|
|
||||||
uint64_t serial{0};
|
uint64_t serial{0};
|
||||||
@ -317,7 +323,7 @@ class testcase_nested : public testcase {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
testcase_nested(const actor_config &config, const mdbx_pid_t pid)
|
testcase_nested(const actor_config &config, const mdbx_pid_t pid)
|
||||||
: testcase(config, pid) {}
|
: inherited(config, pid) {}
|
||||||
bool setup() override;
|
bool setup() override;
|
||||||
bool run() override;
|
bool run() override;
|
||||||
bool teardown() override;
|
bool teardown() override;
|
||||||
|
139
test/ttl.cc
139
test/ttl.cc
@ -16,16 +16,97 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
static unsigned edge2window(uint64_t edge, unsigned window_max) {
|
/* LY: тест "эмуляцией time-to-live":
|
||||||
const double rnd = u64_to_double1(bleach64(edge));
|
* - организуется "скользящее окно", которое двигается вперед вдоль
|
||||||
const unsigned window = window_max - std::lrint(std::pow(window_max, rnd));
|
* числовой оси каждую транзакцию.
|
||||||
return window;
|
* - по переднему краю "скользящего окна" записи добавляются в таблицу,
|
||||||
|
* а по заднему удаляются.
|
||||||
|
* - количество добавляемых/удаляемых записей псевдослучайно зависит
|
||||||
|
* от номера транзакции, но с экспоненциальным распределением.
|
||||||
|
* - размер "скользящего окна" также псевдослучайно зависит от номера
|
||||||
|
* транзакции с "отрицательным" экспоненциальным распределением
|
||||||
|
* 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) {
|
unsigned testcase_ttl::edge2window(uint64_t edge) {
|
||||||
const double rnd = u64_to_double1(prng64_map1_white(edge));
|
const double rnd = u64_to_double1(bleach64(edge));
|
||||||
const unsigned count = std::lrint(std::pow(count_max, rnd));
|
const unsigned size = sliding.max_window_size -
|
||||||
return count;
|
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() {
|
bool testcase_ttl::run() {
|
||||||
@ -35,36 +116,6 @@ bool testcase_ttl::run() {
|
|||||||
return false;
|
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 =
|
uint64_t seed =
|
||||||
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
prng64_map2_white(config.params.keygen.seed) + config.actor_id;
|
||||||
keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
|
keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
|
||||||
@ -85,10 +136,9 @@ bool testcase_ttl::run() {
|
|||||||
while (true) {
|
while (true) {
|
||||||
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
const uint64_t salt = prng64_white(seed) /* mdbx_txn_id(txn_guard.get()) */;
|
||||||
|
|
||||||
const unsigned window_width = (!should_continue() || flipcoin_x4())
|
const unsigned window_width =
|
||||||
? 0
|
(!should_continue() || flipcoin_x4()) ? 0 : edge2window(salt);
|
||||||
: edge2window(salt, window_max);
|
unsigned head_count = edge2count(salt);
|
||||||
unsigned head_count = edge2count(salt, count_max);
|
|
||||||
log_debug("ttl: step #%zu (serial %" PRIu64
|
log_debug("ttl: step #%zu (serial %" PRIu64
|
||||||
", window %u, count %u) salt %" PRIu64,
|
", window %u, count %u) salt %" PRIu64,
|
||||||
nops_completed, serial, window_width, head_count, salt);
|
nops_completed, serial, window_width, head_count, salt);
|
||||||
@ -115,7 +165,7 @@ bool testcase_ttl::run() {
|
|||||||
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
if (unlikely(!keyvalue_maker.increment(tail_serial, 1)))
|
||||||
failure("ttl: unexpected key-space overflow on the tail");
|
failure("ttl: unexpected key-space overflow on the tail");
|
||||||
}
|
}
|
||||||
report(1);
|
report(tail_count);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_trace("ttl: purge state");
|
log_trace("ttl: purge state");
|
||||||
@ -185,7 +235,8 @@ bool testcase_ttl::run() {
|
|||||||
}
|
}
|
||||||
loops += 1;
|
loops += 1;
|
||||||
} else if (fifo.empty()) {
|
} 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;
|
rc = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user