mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-10 03:14:13 +08:00
mdbx-test: backport - update test (squashed).
- add support for 'default' options values. - add min/max cases for option values. - add support for db-geometry params. - fix int-types for 32-bit builds (minor). - fix key/value generation for long-length cases. - fix update_flags for non-MDBX_DUPSORT. - 'none' for config-verbs. - check commandline length under Windows. - workaround for QueryFullProcessImageNameA() bug. - add setloglevel(). - workaroung for MSVC bug. - avoid extra 'jitter' testcase loops. - cleanup DUPSORT flags. - refine key/value min/max handling. - dump keygen params. - fix/refine keygen. - alter keygen defaults (rotate 3, offset 41). - default test-db size 4mb or 256mb. - fix/refine keygen for non-MDBX_DUPSORT. - seeding keygen with actor_id for better spreading.
This commit is contained in:
parent
6da477d37f
commit
b51d92d449
115
test/config.cc
115
test/config.cc
@ -43,6 +43,11 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
if (narg + 1 < argc && strncmp("--", argv[narg + 1], 2) != 0) {
|
||||
*value = argv[narg + 1];
|
||||
if (strcmp(*value, "default") == 0) {
|
||||
if (!default_value)
|
||||
failure("Option '--%s' doen't accept default value\n", option);
|
||||
*value = default_value;
|
||||
}
|
||||
++narg;
|
||||
return true;
|
||||
}
|
||||
@ -57,9 +62,15 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
std::string &value, bool allow_empty) {
|
||||
return parse_option(argc, argv, narg, option, value, allow_empty,
|
||||
allow_empty ? "" : nullptr);
|
||||
}
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
std::string &value, bool allow_empty,
|
||||
const char *default_value) {
|
||||
const char *value_cstr;
|
||||
if (!parse_option(argc, argv, narg, option, &value_cstr,
|
||||
allow_empty ? "" : nullptr))
|
||||
if (!parse_option(argc, argv, narg, option, &value_cstr, default_value))
|
||||
return false;
|
||||
|
||||
if (!allow_empty && strlen(value_cstr) == 0)
|
||||
@ -110,12 +121,28 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
uint64_t &value, const scale_mode scale,
|
||||
const uint64_t minval, const uint64_t maxval) {
|
||||
const uint64_t minval, const uint64_t maxval,
|
||||
const uint64_t default_value) {
|
||||
|
||||
const char *value_cstr;
|
||||
if (!parse_option(argc, argv, narg, option, &value_cstr))
|
||||
return false;
|
||||
|
||||
if (default_value && strcmp(value_cstr, "default") == 0) {
|
||||
value = default_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp(value_cstr, "min") == 0 || strcmp(value_cstr, "minimal") == 0) {
|
||||
value = minval;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcmp(value_cstr, "max") == 0 || strcmp(value_cstr, "maximal") == 0) {
|
||||
value = maxval;
|
||||
return true;
|
||||
}
|
||||
|
||||
char *suffix = nullptr;
|
||||
errno = 0;
|
||||
unsigned long long raw = strtoull(value_cstr, &suffix, 0);
|
||||
@ -179,28 +206,58 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
unsigned &value, const scale_mode scale,
|
||||
const unsigned minval, const unsigned maxval) {
|
||||
const unsigned minval, const unsigned maxval,
|
||||
const unsigned default_value) {
|
||||
|
||||
uint64_t huge;
|
||||
if (!parse_option(argc, argv, narg, option, huge, scale, minval, maxval))
|
||||
if (!parse_option(argc, argv, narg, option, huge, scale, minval, maxval,
|
||||
default_value))
|
||||
return false;
|
||||
value = (unsigned)huge;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
uint8_t &value, const uint8_t minval, const uint8_t maxval) {
|
||||
uint8_t &value, const uint8_t minval, const uint8_t maxval,
|
||||
const uint8_t default_value) {
|
||||
|
||||
uint64_t huge;
|
||||
if (!parse_option(argc, argv, narg, option, huge, no_scale, minval, maxval))
|
||||
if (!parse_option(argc, argv, narg, option, huge, no_scale, minval, maxval,
|
||||
default_value))
|
||||
return false;
|
||||
value = (uint8_t)huge;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
int64_t &value, const int64_t minval, const int64_t maxval,
|
||||
const int64_t default_value) {
|
||||
uint64_t proxy = (uint64_t)value;
|
||||
if (parse_option(argc, argv, narg, option, proxy, config::binary,
|
||||
(uint64_t)minval, (uint64_t)maxval,
|
||||
(uint64_t)default_value)) {
|
||||
value = (int64_t)proxy;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
int32_t &value, const int32_t minval, const int32_t maxval,
|
||||
const int32_t default_value) {
|
||||
uint64_t proxy = (uint64_t)value;
|
||||
if (parse_option(argc, argv, narg, option, proxy, config::binary,
|
||||
(uint64_t)minval, (uint64_t)maxval,
|
||||
(uint64_t)default_value)) {
|
||||
value = (int32_t)proxy;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
bool &value) {
|
||||
const char *value_cstr = NULL;
|
||||
const char *value_cstr = nullptr;
|
||||
if (!parse_option(argc, argv, narg, option, &value_cstr, "yes")) {
|
||||
const char *current = argv[narg];
|
||||
if (strncmp(current, "--no-", 5) == 0 && strcmp(current + 5, option) == 0) {
|
||||
@ -269,7 +326,7 @@ static void dump_verbs(const char *caption, size_t bits,
|
||||
++verbs;
|
||||
}
|
||||
|
||||
logging::feed("\n");
|
||||
logging::feed("%s\n", (*comma == '\0') ? "none" : "");
|
||||
}
|
||||
|
||||
static void dump_duration(const char *caption, unsigned duration) {
|
||||
@ -300,8 +357,12 @@ void dump(const char *title) {
|
||||
: i->params.pathname_log.c_str());
|
||||
}
|
||||
|
||||
log_info("database: %s, size %" PRIu64 "\n", i->params.pathname_db.c_str(),
|
||||
i->params.size);
|
||||
log_info("database: %s, size %" PRIuPTR "[%" PRIiPTR "..%" PRIiPTR
|
||||
", %i %i, %i]\n",
|
||||
i->params.pathname_db.c_str(), i->params.size_now,
|
||||
i->params.size_lower, i->params.size_upper,
|
||||
i->params.shrink_threshold, i->params.growth_step,
|
||||
i->params.pagesize);
|
||||
|
||||
dump_verbs("mode", i->params.mode_flags, mode_bits);
|
||||
dump_verbs("table", i->params.table_flags, table_bits);
|
||||
@ -318,7 +379,13 @@ void dump(const char *title) {
|
||||
|
||||
log_info("threads %u\n", i->params.nthreads);
|
||||
|
||||
log_info("keygen.case: %s\n", keygencase2str(i->params.keygen.keycase));
|
||||
log_info(
|
||||
"keygen.params: case %s, width %u, mesh %u, rotate %u, offset %" PRIu64
|
||||
", split %u/%u\n",
|
||||
keygencase2str(i->params.keygen.keycase), i->params.keygen.width,
|
||||
i->params.keygen.mesh, i->params.keygen.rotate, i->params.keygen.offset,
|
||||
i->params.keygen.split,
|
||||
i->params.keygen.width - i->params.keygen.split);
|
||||
log_info("keygen.seed: %u\n", i->params.keygen.seed);
|
||||
log_info("key: minlen %u, maxlen %u\n", i->params.keylen_min,
|
||||
i->params.keylen_max);
|
||||
@ -481,3 +548,27 @@ bool actor_config::deserialize(const char *str, actor_config &config) {
|
||||
TRACE("<< actor_config::deserialize: OK\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned actor_params::mdbx_keylen_min() const {
|
||||
return (table_flags & MDBX_INTEGERKEY) ? 4 : 0;
|
||||
}
|
||||
|
||||
unsigned actor_params::mdbx_keylen_max() const {
|
||||
return (table_flags & MDBX_INTEGERKEY)
|
||||
? 8
|
||||
: std::min((unsigned)mdbx_get_maxkeysize(pagesize),
|
||||
(unsigned)UINT16_MAX);
|
||||
}
|
||||
|
||||
unsigned actor_params::mdbx_datalen_min() const {
|
||||
return (table_flags & MDBX_INTEGERDUP) ? 4 : 0;
|
||||
}
|
||||
|
||||
unsigned actor_params::mdbx_datalen_max() const {
|
||||
return (table_flags & MDBX_INTEGERDUP)
|
||||
? 8
|
||||
: std::min((table_flags & MDBX_DUPSORT)
|
||||
? (unsigned)mdbx_get_maxkeysize(pagesize)
|
||||
: (unsigned)MDBX_MAXDATASIZE,
|
||||
(unsigned)UINT16_MAX);
|
||||
}
|
||||
|
@ -62,6 +62,10 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
std::string &value, bool allow_empty = false);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
std::string &value, bool allow_empty,
|
||||
const char *default_value);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
bool &value);
|
||||
|
||||
@ -75,16 +79,25 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
uint64_t &value, const scale_mode scale,
|
||||
const uint64_t minval = 0, const uint64_t maxval = INT64_MAX);
|
||||
const uint64_t minval = 0, const uint64_t maxval = INT64_MAX,
|
||||
const uint64_t default_value = 0);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
unsigned &value, const scale_mode scale,
|
||||
const unsigned minval = 0, const unsigned maxval = INT32_MAX);
|
||||
const unsigned minval = 0, const unsigned maxval = INT32_MAX,
|
||||
const unsigned default_value = 0);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
uint8_t &value, const uint8_t minval = 0,
|
||||
const uint8_t maxval = 255);
|
||||
const uint8_t maxval = 255, const uint8_t default_value = 0);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
int64_t &value, const int64_t minval, const int64_t maxval,
|
||||
const int64_t default_value = -1);
|
||||
|
||||
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||
int32_t &value, const int32_t minval, const int32_t maxval,
|
||||
const int32_t default_value = -1);
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -121,6 +134,8 @@ struct keygen_params_pod {
|
||||
* Иначе говоря, нет смысла в со-координации генерации паттернов для
|
||||
* ключей и значений. Более того, генерацию значений всегда необходимо
|
||||
* рассматривать в контексте связки с одним значением ключа.
|
||||
* - Тем не менее, во всех случаях достаточно важным является равномерная
|
||||
* всех возможных сочетаний длин ключей и данных.
|
||||
*
|
||||
* width:
|
||||
* Большинство тестов предполагают создание или итерирование некоторого
|
||||
@ -156,7 +171,7 @@ struct keygen_params_pod {
|
||||
* псевдо-случайные значений ключей без псевдо-случайности в значениях.
|
||||
*
|
||||
* Такое ограничение соответствуют внутренней алгоритмике libmdbx. Проще
|
||||
* говоря мы можем проверить движок псевдо-случайной последовательностью
|
||||
* говоря, мы можем проверить движок псевдо-случайной последовательностью
|
||||
* ключей на таблицах без дубликатов (без multi-value), а затем проверить
|
||||
* корректность работу псевдо-случайной последовательностью значений на
|
||||
* таблицах с дубликатами (с multi-value), опционально добавляя
|
||||
@ -203,7 +218,12 @@ struct actor_params_pod {
|
||||
|
||||
unsigned mode_flags;
|
||||
unsigned table_flags;
|
||||
uint64_t size;
|
||||
intptr_t size_lower;
|
||||
intptr_t size_now;
|
||||
intptr_t size_upper;
|
||||
int shrink_threshold;
|
||||
int growth_step;
|
||||
int pagesize;
|
||||
|
||||
unsigned test_duration;
|
||||
unsigned test_nops;
|
||||
@ -246,6 +266,11 @@ struct actor_params : public config::actor_params_pod {
|
||||
std::string pathname_log;
|
||||
std::string pathname_db;
|
||||
void set_defaults(const std::string &tmpdir);
|
||||
|
||||
unsigned mdbx_keylen_min() const;
|
||||
unsigned mdbx_keylen_max() const;
|
||||
unsigned mdbx_datalen_min() const;
|
||||
unsigned mdbx_datalen_max() const;
|
||||
};
|
||||
|
||||
struct actor_config : public config::actor_config_pod {
|
||||
|
@ -53,7 +53,7 @@ bool testcase_hill::run() {
|
||||
*/
|
||||
|
||||
/* TODO: работа в несколько потоков */
|
||||
keyvalue_maker.setup(config.params, 0 /* thread_number */);
|
||||
keyvalue_maker.setup(config.params, config.actor_id, 0 /* thread_number */);
|
||||
|
||||
keygen::buffer a_key = keygen::alloc(config.params.keylen_max);
|
||||
keygen::buffer a_data_0 = keygen::alloc(config.params.datalen_max);
|
||||
@ -65,7 +65,9 @@ bool testcase_hill::run() {
|
||||
? MDBX_NODUPDATA
|
||||
: MDBX_NODUPDATA | MDBX_NOOVERWRITE;
|
||||
const unsigned update_flags =
|
||||
MDBX_CURRENT | MDBX_NODUPDATA | MDBX_NOOVERWRITE;
|
||||
(config.params.table_flags & MDBX_DUPSORT)
|
||||
? MDBX_CURRENT | MDBX_NODUPDATA | MDBX_NOOVERWRITE
|
||||
: MDBX_NODUPDATA;
|
||||
|
||||
uint64_t serial_count = 0;
|
||||
unsigned txn_nops = 0;
|
||||
@ -115,7 +117,7 @@ bool testcase_hill::run() {
|
||||
rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_0->value,
|
||||
&a_data_1->value, update_flags);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_put(update-a: 1->0)", rc);
|
||||
failure_perror("mdbx_replace(update-a: 1->0)", rc);
|
||||
|
||||
if (++txn_nops >= config.params.batch_write) {
|
||||
txn_restart(false, false);
|
||||
|
@ -58,7 +58,11 @@ bool testcase_jitter::run() {
|
||||
|
||||
jitter_delay();
|
||||
db_close();
|
||||
report(1);
|
||||
|
||||
/* just 'align' nops with other tests with batching */
|
||||
const auto batching =
|
||||
std::max(config.params.batch_read, config.params.batch_write);
|
||||
report(std::max(1u, batching / 2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ serial_t injective(const serial_t serial,
|
||||
/* LY: All these "magic" prime numbers were found
|
||||
* and verified with a bit of brute force. */
|
||||
|
||||
static const uint64_t m[64 - serial_minwith] = {
|
||||
static const uint64_t m[64 - serial_minwith + 1] = {
|
||||
/* 8 - 24 */
|
||||
113, 157, 397, 653, 1753, 5641, 9697, 23873, 25693, 80833, 105953, 316937,
|
||||
309277, 834497, 1499933, 4373441, 10184137,
|
||||
@ -43,26 +43,31 @@ serial_t injective(const serial_t serial,
|
||||
2420886491930041, 3601632139991929, 11984491914483833, 21805846439714153,
|
||||
23171543400565993, 53353226456762893, 155627817337932409,
|
||||
227827205384840249, 816509268558278821, 576933057762605689,
|
||||
2623957345935638441, 5048241705479929949, 4634245581946485653};
|
||||
static const uint8_t s[64 - serial_minwith] = {
|
||||
2623957345935638441, 5048241705479929949, 4634245581946485653,
|
||||
4613509448041658233, 4952535426879925961};
|
||||
static const uint8_t s[64 - serial_minwith + 1] = {
|
||||
/* 8 - 24 */
|
||||
2, 3, 4, 4, 2, 4, 3, 3, 7, 3, 3, 4, 8, 3, 10, 3, 11,
|
||||
/* 25 - 64 */
|
||||
11, 9, 9, 9, 11, 10, 5, 14, 11, 16, 14, 12, 13, 16, 19, 10, 10, 21, 7, 20,
|
||||
10, 14, 22, 19, 3, 21, 18, 19, 26, 24, 2, 21, 25, 29, 24, 10, 11, 14};
|
||||
10, 14, 22, 19, 3, 21, 18, 19, 26, 24, 2, 21, 25, 29, 24, 10, 11, 14, 20,
|
||||
19};
|
||||
|
||||
serial_t result = serial * m[bits - 8];
|
||||
const auto mult = m[bits - 8];
|
||||
const auto shift = s[bits - 8];
|
||||
serial_t result = serial * mult;
|
||||
if (salt) {
|
||||
const unsigned left = bits / 2;
|
||||
const unsigned right = bits - left;
|
||||
result = (result << left) | ((result & mask(bits)) >> right);
|
||||
result = (result ^ salt) * m[bits - 8];
|
||||
result = (result ^ salt) * mult;
|
||||
}
|
||||
|
||||
result ^= result << s[bits - 8];
|
||||
result ^= result << shift;
|
||||
result &= mask(bits);
|
||||
log_trace("keygen-injective: serial %" PRIu64 " into %" PRIu64, serial,
|
||||
result);
|
||||
log_trace("keygen-injective: serial %" PRIu64 "/%u @%" PRIx64 ",%u,%" PRIu64
|
||||
" => %" PRIu64 "/%u",
|
||||
serial, bits, mult, shift, salt, result, bits);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -73,8 +78,9 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
|
||||
assert(mapping.mesh <= mapping.width);
|
||||
assert(mapping.rotate <= mapping.width);
|
||||
assert(mapping.offset <= mask(mapping.width));
|
||||
assert(!(key_essentials.flags & (MDBX_INTEGERDUP | MDBX_REVERSEDUP)));
|
||||
assert(!(value_essentials.flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY)));
|
||||
assert(!(key_essentials.flags &
|
||||
~(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT)));
|
||||
assert(!(value_essentials.flags & ~(MDBX_INTEGERDUP | MDBX_REVERSEDUP)));
|
||||
|
||||
log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial,
|
||||
value_age);
|
||||
@ -82,31 +88,49 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
|
||||
if (mapping.mesh >= serial_minwith) {
|
||||
serial =
|
||||
(serial & ~mask(mapping.mesh)) | injective(serial, mapping.mesh, salt);
|
||||
log_trace("keygen-pair: mesh %" PRIu64, serial);
|
||||
log_trace("keygen-pair: mesh@%u => %" PRIu64, mapping.mesh, serial);
|
||||
}
|
||||
|
||||
if (mapping.rotate) {
|
||||
const unsigned right = mapping.rotate;
|
||||
const unsigned left = mapping.width - right;
|
||||
serial = (serial << left) | ((serial & mask(mapping.width)) >> right);
|
||||
log_trace("keygen-pair: rotate %" PRIu64 ", 0x%" PRIx64, serial, serial);
|
||||
log_trace("keygen-pair: rotate@%u => %" PRIu64 ", 0x%" PRIx64,
|
||||
mapping.rotate, serial, serial);
|
||||
}
|
||||
|
||||
serial = (serial + mapping.offset) & mask(mapping.width);
|
||||
log_trace("keygen-pair: offset %" PRIu64, serial);
|
||||
serial += base;
|
||||
if (mapping.offset) {
|
||||
serial = (serial + mapping.offset) & mask(mapping.width);
|
||||
log_trace("keygen-pair: offset@%" PRIu64 " => %" PRIu64, mapping.offset,
|
||||
serial);
|
||||
}
|
||||
if (base) {
|
||||
serial += base;
|
||||
log_trace("keygen-pair: base@%" PRIu64 " => %" PRIu64, base, serial);
|
||||
}
|
||||
|
||||
serial_t key_serial = serial;
|
||||
serial_t value_serial = value_age;
|
||||
serial_t value_serial = value_age << mapping.split;
|
||||
if (mapping.split) {
|
||||
key_serial = serial >> mapping.split;
|
||||
value_serial =
|
||||
(serial & mask(mapping.split)) | (value_age << mapping.split);
|
||||
if (key_essentials.flags & MDBX_DUPSORT) {
|
||||
key_serial >>= mapping.split;
|
||||
value_serial += serial & mask(mapping.split);
|
||||
} else {
|
||||
/* Без MDBX_DUPSORT требуется уникальность ключей, а для этого нельзя
|
||||
* отбрасывать какие-либо биты serial после инъективного преобразования.
|
||||
* Поэтому key_serial не трогаем, а в value_serial нелинейно вмешиваем
|
||||
* запрошенное количество бит из serial */
|
||||
value_serial +=
|
||||
(serial ^ (serial >> mapping.split)) & mask(mapping.split);
|
||||
}
|
||||
|
||||
value_serial |= value_age << mapping.split;
|
||||
log_trace("keygen-pair: split@%u => k%" PRIu64 ", v%" PRIu64, mapping.split,
|
||||
key_serial, value_serial);
|
||||
}
|
||||
|
||||
log_trace("keygen-pair: key %" PRIu64 ", value %" PRIu64, key_serial,
|
||||
value_serial);
|
||||
|
||||
mk(key_serial, key_essentials, *key);
|
||||
mk(value_serial, value_essentials, *value);
|
||||
|
||||
@ -118,10 +142,10 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
|
||||
}
|
||||
}
|
||||
|
||||
void maker::setup(const config::actor_params_pod &actor,
|
||||
void maker::setup(const config::actor_params_pod &actor, unsigned actor_id,
|
||||
unsigned thread_number) {
|
||||
key_essentials.flags =
|
||||
actor.table_flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY);
|
||||
actor.table_flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT);
|
||||
assert(actor.keylen_min <= UINT8_MAX);
|
||||
key_essentials.minlen = (uint8_t)actor.keylen_min;
|
||||
assert(actor.keylen_max <= UINT16_MAX);
|
||||
@ -137,7 +161,7 @@ void maker::setup(const config::actor_params_pod &actor,
|
||||
assert(thread_number < 2);
|
||||
(void)thread_number;
|
||||
mapping = actor.keygen;
|
||||
salt = actor.keygen.seed * UINT64_C(14653293970879851569);
|
||||
salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569);
|
||||
|
||||
// FIXME: TODO
|
||||
base = 0;
|
||||
@ -165,7 +189,7 @@ bool maker::increment(serial_t &serial, int delta) {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
size_t length(serial_t serial) {
|
||||
static size_t length(serial_t serial) {
|
||||
size_t n = 0;
|
||||
if (serial > UINT32_MAX) {
|
||||
n = 4;
|
||||
@ -199,7 +223,10 @@ void __hot maker::mk(const serial_t serial, const essentials ¶ms,
|
||||
assert(params.maxlen >= length(serial));
|
||||
|
||||
out.value.iov_base = out.bytes;
|
||||
out.value.iov_len = params.minlen;
|
||||
out.value.iov_len =
|
||||
(params.maxlen > params.minlen)
|
||||
? params.minlen + serial % (params.maxlen - params.minlen)
|
||||
: params.minlen;
|
||||
|
||||
if (params.flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) {
|
||||
assert(params.maxlen == params.minlen);
|
||||
|
@ -44,7 +44,7 @@ namespace keygen {
|
||||
* - абсолютное значение ключей или разность между отдельными значениями;
|
||||
*
|
||||
* Соответственно, в общих чертах, схема генерации следующая:
|
||||
* - вводится плоская одномерная "координата" uint64_t;
|
||||
* - вводится плоская одномерная "координата" serial (uint64_t);
|
||||
* - генерация специфических паттернов (последовательностей)
|
||||
* реализуется посредством соответствующих преобразований "координат", при
|
||||
* этом все подобные преобразования выполняются только над "координатой";
|
||||
@ -74,7 +74,7 @@ typedef uint64_t serial_t;
|
||||
enum : serial_t {
|
||||
serial_minwith = 8,
|
||||
serial_maxwith = sizeof(serial_t) * 8,
|
||||
serial_allones = ~(serial_t)0
|
||||
serial_allones = ~(serial_t)0u
|
||||
};
|
||||
|
||||
struct result {
|
||||
@ -85,6 +85,10 @@ struct result {
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
};
|
||||
|
||||
std::string as_string() const {
|
||||
return std::string((const char *)value.iov_base, value.iov_len);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -115,11 +119,10 @@ public:
|
||||
|
||||
void pair(serial_t serial, const buffer &key, buffer &value,
|
||||
serial_t value_age);
|
||||
void setup(const config::actor_params_pod &actor, unsigned thread_number);
|
||||
void setup(const config::actor_params_pod &actor, unsigned actor_id,
|
||||
unsigned thread_number);
|
||||
|
||||
bool increment(serial_t &serial, int delta);
|
||||
};
|
||||
|
||||
size_t length(serial_t serial);
|
||||
|
||||
} /* namespace keygen */
|
||||
|
42
test/log.cc
42
test/log.cc
@ -37,6 +37,31 @@ void __noreturn failure_perror(const char *what, int errnum) {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void mdbx_logger(int type, const char *function, int line,
|
||||
const char *msg, va_list args) {
|
||||
logging::loglevel level = logging::info;
|
||||
if (type & MDBX_DBG_EXTRA)
|
||||
level = logging::extra;
|
||||
if (type & MDBX_DBG_TRACE)
|
||||
level = logging::trace;
|
||||
if (type & MDBX_DBG_PRINT)
|
||||
level = logging::verbose;
|
||||
|
||||
if (!function)
|
||||
function = "unknown";
|
||||
if (type & MDBX_DBG_ASSERT) {
|
||||
log_error("mdbx: assertion failure: %s, %d", function, line);
|
||||
level = logging::failure;
|
||||
}
|
||||
|
||||
if (logging::output(
|
||||
level,
|
||||
strncmp(function, "mdbx_", 5) == 0 ? "%s: " : "mdbx: %s: ", function))
|
||||
logging::feed_ap(msg, args);
|
||||
if (type & MDBX_DBG_ASSERT)
|
||||
abort();
|
||||
}
|
||||
|
||||
namespace logging {
|
||||
|
||||
static std::string prefix;
|
||||
@ -44,8 +69,19 @@ static std::string suffix;
|
||||
static loglevel level;
|
||||
static FILE *last;
|
||||
|
||||
void setup(loglevel _level, const std::string &_prefix) {
|
||||
void setlevel(loglevel _level) {
|
||||
level = (_level > error) ? failure : _level;
|
||||
int mdbx_dbg_opts = MDBX_DBG_ASSERT | MDBX_DBG_JITTER | MDBX_DBG_DUMP;
|
||||
if (level <= trace)
|
||||
mdbx_dbg_opts |= MDBX_DBG_TRACE;
|
||||
if (level <= verbose)
|
||||
mdbx_dbg_opts |= MDBX_DBG_PRINT;
|
||||
int rc = mdbx_setup_debug(mdbx_dbg_opts, mdbx_logger);
|
||||
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
||||
}
|
||||
|
||||
void setup(loglevel _level, const std::string &_prefix) {
|
||||
setlevel(_level);
|
||||
prefix = _prefix;
|
||||
}
|
||||
|
||||
@ -157,7 +193,7 @@ bool output(const logging::loglevel priority, const char *format, va_list ap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool feed(const char *format, va_list ap) {
|
||||
bool feed_ap(const char *format, va_list ap) {
|
||||
if (!last)
|
||||
return false;
|
||||
|
||||
@ -176,7 +212,7 @@ bool feed(const char *format, ...) {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
feed(format, ap);
|
||||
feed_ap(format, ap);
|
||||
va_end(ap);
|
||||
return true;
|
||||
}
|
||||
|
@ -46,11 +46,12 @@ enum loglevel {
|
||||
const char *level2str(const loglevel level);
|
||||
void setup(loglevel level, const std::string &prefix);
|
||||
void setup(const std::string &prefix);
|
||||
void setlevel(loglevel level);
|
||||
|
||||
bool output(const loglevel priority, const char *format, va_list ap);
|
||||
bool __printf_args(2, 3)
|
||||
output(const loglevel priority, const char *format, ...);
|
||||
bool feed(const char *format, va_list ap);
|
||||
bool feed_ap(const char *format, va_list ap);
|
||||
bool __printf_args(1, 2) feed(const char *format, ...);
|
||||
|
||||
class local_suffix {
|
||||
|
105
test/main.cc
105
test/main.cc
@ -35,25 +35,31 @@ void actor_params::set_defaults(const std::string &tmpdir) {
|
||||
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NORDAHEAD |
|
||||
MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_LIFORECLAIM;
|
||||
table_flags = MDBX_DUPSORT;
|
||||
size = 1024 * 1024 * 4;
|
||||
|
||||
size_lower = -1;
|
||||
size_now = 1024 * 1024 * ((table_flags & MDBX_DUPSORT) ? 4 : 256);
|
||||
size_upper = -1;
|
||||
shrink_threshold = -1;
|
||||
growth_step = -1;
|
||||
pagesize = -1;
|
||||
|
||||
keygen.seed = 1;
|
||||
keygen.keycase = kc_random;
|
||||
keygen.width = 32;
|
||||
keygen.mesh = 32;
|
||||
keygen.width = (table_flags & MDBX_DUPSORT) ? 32 : 64;
|
||||
keygen.mesh = keygen.width;
|
||||
keygen.split = keygen.width / 2;
|
||||
keygen.rotate = 0;
|
||||
keygen.offset = 0;
|
||||
keygen.rotate = 3;
|
||||
keygen.offset = 41;
|
||||
|
||||
test_duration = 0;
|
||||
test_nops = 1000;
|
||||
nrepeat = 1;
|
||||
nthreads = 1;
|
||||
|
||||
keylen_min = 0;
|
||||
keylen_max = 42;
|
||||
datalen_min = 0;
|
||||
datalen_max = 256;
|
||||
keylen_min = mdbx_keylen_min();
|
||||
keylen_max = mdbx_keylen_max();
|
||||
datalen_min = mdbx_datalen_min();
|
||||
datalen_max = std::min(mdbx_datalen_max(), 256u * 1024 + 42);
|
||||
|
||||
batch_read = 4;
|
||||
batch_write = 4;
|
||||
@ -148,10 +154,53 @@ int main(int argc, char *const argv[]) {
|
||||
config::mode_bits))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "table", params.table_flags,
|
||||
config::table_bits))
|
||||
config::table_bits)) {
|
||||
if ((params.table_flags & MDBX_DUPFIXED) == 0)
|
||||
params.table_flags &= ~MDBX_INTEGERDUP;
|
||||
if ((params.table_flags & MDBX_DUPSORT) == 0)
|
||||
params.table_flags &=
|
||||
~(MDBX_DUPFIXED | MDBX_REVERSEDUP | MDBX_INTEGERDUP);
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "size", params.size,
|
||||
config::binary, 4096 * 4))
|
||||
}
|
||||
|
||||
if (config::parse_option(argc, argv, narg, "pagesize", params.pagesize,
|
||||
mdbx_limits_pgsize_min(),
|
||||
mdbx_limits_pgsize_max())) {
|
||||
const unsigned keylen_max = params.mdbx_keylen_max();
|
||||
if (params.keylen_min > keylen_max)
|
||||
params.keylen_min = keylen_max;
|
||||
if (params.keylen_max > keylen_max)
|
||||
params.keylen_max = keylen_max;
|
||||
const unsigned datalen_max = params.mdbx_datalen_max();
|
||||
if (params.datalen_min > datalen_max)
|
||||
params.datalen_min = datalen_max;
|
||||
if (params.datalen_max > datalen_max)
|
||||
params.datalen_max = datalen_max;
|
||||
continue;
|
||||
}
|
||||
if (config::parse_option(argc, argv, narg, "size-lower", params.size_lower,
|
||||
mdbx_limits_dbsize_min(params.pagesize),
|
||||
mdbx_limits_dbsize_max(params.pagesize)))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "size", params.size_now,
|
||||
mdbx_limits_dbsize_min(params.pagesize),
|
||||
mdbx_limits_dbsize_max(params.pagesize)))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "size-upper", params.size_upper,
|
||||
mdbx_limits_dbsize_min(params.pagesize),
|
||||
mdbx_limits_dbsize_max(params.pagesize)))
|
||||
continue;
|
||||
if (config::parse_option(
|
||||
argc, argv, narg, "shrink-threshold", params.shrink_threshold, 0,
|
||||
(int)std::min((intptr_t)INT_MAX,
|
||||
mdbx_limits_dbsize_max(params.pagesize) -
|
||||
mdbx_limits_dbsize_min(params.pagesize))))
|
||||
continue;
|
||||
if (config::parse_option(
|
||||
argc, argv, narg, "growth-step", params.growth_step, 0,
|
||||
(int)std::min((intptr_t)INT_MAX,
|
||||
mdbx_limits_dbsize_max(params.pagesize) -
|
||||
mdbx_limits_dbsize_min(params.pagesize))))
|
||||
continue;
|
||||
|
||||
if (config::parse_option(argc, argv, narg, "keygen.width",
|
||||
@ -188,30 +237,36 @@ int main(int argc, char *const argv[]) {
|
||||
config::duration, 1))
|
||||
continue;
|
||||
if (config::parse_option(argc, argv, narg, "keylen.min", params.keylen_min,
|
||||
config::no_scale, 0, UINT8_MAX)) {
|
||||
if (params.keylen_max < params.keylen_min)
|
||||
config::no_scale, params.mdbx_keylen_min(),
|
||||
params.mdbx_keylen_max())) {
|
||||
if ((params.table_flags & MDBX_INTEGERKEY) ||
|
||||
params.keylen_max < params.keylen_min)
|
||||
params.keylen_max = params.keylen_min;
|
||||
continue;
|
||||
}
|
||||
if (config::parse_option(
|
||||
argc, argv, narg, "keylen.max", params.keylen_max, config::no_scale,
|
||||
0,
|
||||
std::min((unsigned)mdbx_get_maxkeysize(0), (unsigned)UINT16_MAX))) {
|
||||
if (params.keylen_min > params.keylen_max)
|
||||
if (config::parse_option(argc, argv, narg, "keylen.max", params.keylen_max,
|
||||
config::no_scale, params.mdbx_keylen_min(),
|
||||
params.mdbx_keylen_max())) {
|
||||
if ((params.table_flags & MDBX_INTEGERKEY) ||
|
||||
params.keylen_min > params.keylen_max)
|
||||
params.keylen_min = params.keylen_max;
|
||||
continue;
|
||||
}
|
||||
if (config::parse_option(argc, argv, narg, "datalen.min",
|
||||
params.datalen_min, config::no_scale, 0,
|
||||
UINT8_MAX)) {
|
||||
if (params.datalen_max < params.datalen_min)
|
||||
params.datalen_min, config::no_scale,
|
||||
params.mdbx_datalen_min(),
|
||||
params.mdbx_datalen_max())) {
|
||||
if ((params.table_flags & MDBX_DUPFIXED) ||
|
||||
params.datalen_max < params.datalen_min)
|
||||
params.datalen_max = params.datalen_min;
|
||||
continue;
|
||||
}
|
||||
if (config::parse_option(argc, argv, narg, "datalen.max",
|
||||
params.datalen_max, config::no_scale, 0,
|
||||
std::min((int)UINT16_MAX, MDBX_MAXDATASIZE))) {
|
||||
if (params.datalen_min > params.datalen_max)
|
||||
params.datalen_max, config::no_scale,
|
||||
params.mdbx_datalen_min(),
|
||||
params.mdbx_datalen_max())) {
|
||||
if ((params.table_flags & MDBX_DUPFIXED) ||
|
||||
params.datalen_min > params.datalen_max)
|
||||
params.datalen_min = params.datalen_max;
|
||||
continue;
|
||||
}
|
||||
|
@ -182,6 +182,9 @@ void osal_killall_actors(void) {
|
||||
}
|
||||
|
||||
int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
struct timespec ts;
|
||||
ts.tv_nsec = 0;
|
||||
ts.tv_sec = timeout;
|
||||
retry:
|
||||
int status, options = WNOHANG;
|
||||
#ifdef WUNTRACED
|
||||
@ -209,9 +212,16 @@ retry:
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if (timeout && sleep(timeout))
|
||||
/* child still running */
|
||||
if (ts.tv_sec == 0 && ts.tv_nsec == 0)
|
||||
ts.tv_nsec = 1;
|
||||
if (nanosleep(&ts, &ts) == 0) {
|
||||
/* timeout and no signal fomr child */
|
||||
pid = 0;
|
||||
return 0;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
goto retry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (errno) {
|
||||
|
@ -262,15 +262,24 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
STARTUPINFOA StartupInfo;
|
||||
GetStartupInfoA(&StartupInfo);
|
||||
|
||||
char exename[_MAX_PATH];
|
||||
char exename[_MAX_PATH + 1];
|
||||
DWORD exename_size = sizeof(exename);
|
||||
if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, exename,
|
||||
&exename_size))
|
||||
failure_perror("QueryFullProcessImageName()", GetLastError());
|
||||
|
||||
std::string cmdline = "test_mdbx.child ";
|
||||
if (exename[1] != ':') {
|
||||
exename_size = GetModuleFileName(NULL, exename, sizeof(exename));
|
||||
if (exename_size >= sizeof(exename))
|
||||
return ERROR_BAD_LENGTH;
|
||||
}
|
||||
|
||||
std::string cmdline = "$ ";
|
||||
ArgvQuote(cmdline, thunk_param(config));
|
||||
|
||||
if (cmdline.size() >= 32767)
|
||||
return ERROR_BAD_LENGTH;
|
||||
|
||||
PROCESS_INFORMATION ProcessInformation;
|
||||
if (!CreateProcessA(exename, const_cast<char *>(cmdline.c_str()),
|
||||
NULL, // Retuned process handle is not inheritable.
|
||||
@ -280,7 +289,7 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
||||
NULL, // Inherit the parent's environment.
|
||||
NULL, // Inherit the parent's current directory.
|
||||
&StartupInfo, &ProcessInformation))
|
||||
return GetLastError();
|
||||
failure_perror(exename, GetLastError());
|
||||
|
||||
CloseHandle(ProcessInformation.hThread);
|
||||
pid = ProcessInformation.dwProcessId;
|
||||
|
40
test/test.cc
40
test/test.cc
@ -68,31 +68,6 @@ const char *keygencase2str(const keygen_case keycase) {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void mdbx_logger(int type, const char *function, int line,
|
||||
const char *msg, va_list args) {
|
||||
logging::loglevel level = logging::info;
|
||||
if (type & MDBX_DBG_EXTRA)
|
||||
level = logging::extra;
|
||||
if (type & MDBX_DBG_TRACE)
|
||||
level = logging::trace;
|
||||
if (type & MDBX_DBG_PRINT)
|
||||
level = logging::verbose;
|
||||
|
||||
if (!function)
|
||||
function = "unknown";
|
||||
if (type & MDBX_DBG_ASSERT) {
|
||||
log_error("mdbx: assertion failure: %s, %d", function, line);
|
||||
level = logging::failure;
|
||||
}
|
||||
|
||||
if (logging::output(
|
||||
level,
|
||||
strncmp(function, "mdbx_", 5) == 0 ? "%s: " : "mdbx: %s: ", function))
|
||||
logging::feed(msg, args);
|
||||
if (type & MDBX_DBG_ASSERT)
|
||||
abort();
|
||||
}
|
||||
|
||||
int testcase::oom_callback(MDBX_env *env, int pid, mdbx_tid_t tid, uint64_t txn,
|
||||
unsigned gap, int retry) {
|
||||
|
||||
@ -117,16 +92,8 @@ void testcase::db_prepare() {
|
||||
log_trace(">> db_prepare");
|
||||
assert(!db_guard);
|
||||
|
||||
int mdbx_dbg_opts = MDBX_DBG_ASSERT | MDBX_DBG_JITTER | MDBX_DBG_DUMP;
|
||||
if (config.params.loglevel <= logging::trace)
|
||||
mdbx_dbg_opts |= MDBX_DBG_TRACE;
|
||||
if (config.params.loglevel <= logging::verbose)
|
||||
mdbx_dbg_opts |= MDBX_DBG_PRINT;
|
||||
int rc = mdbx_setup_debug(mdbx_dbg_opts, mdbx_logger);
|
||||
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
||||
|
||||
MDBX_env *env = nullptr;
|
||||
rc = mdbx_env_create(&env);
|
||||
int rc = mdbx_env_create(&env);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_env_create()", rc);
|
||||
|
||||
@ -149,7 +116,10 @@ void testcase::db_prepare() {
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_env_set_oomfunc()", rc);
|
||||
|
||||
rc = mdbx_env_set_mapsize(env, (size_t)config.params.size);
|
||||
rc = mdbx_env_set_geometry(
|
||||
env, config.params.size_lower, config.params.size_now,
|
||||
config.params.size_upper, config.params.growth_step,
|
||||
config.params.shrink_threshold, config.params.pagesize);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_env_set_mapsize()", rc);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user