mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-10 11:54:14 +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) {
|
if (narg + 1 < argc && strncmp("--", argv[narg + 1], 2) != 0) {
|
||||||
*value = argv[narg + 1];
|
*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;
|
++narg;
|
||||||
return true;
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
std::string &value, bool allow_empty) {
|
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;
|
const char *value_cstr;
|
||||||
if (!parse_option(argc, argv, narg, option, &value_cstr,
|
if (!parse_option(argc, argv, narg, option, &value_cstr, default_value))
|
||||||
allow_empty ? "" : nullptr))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!allow_empty && strlen(value_cstr) == 0)
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
uint64_t &value, const scale_mode scale,
|
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;
|
const char *value_cstr;
|
||||||
if (!parse_option(argc, argv, narg, option, &value_cstr))
|
if (!parse_option(argc, argv, narg, option, &value_cstr))
|
||||||
return false;
|
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;
|
char *suffix = nullptr;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
unsigned long long raw = strtoull(value_cstr, &suffix, 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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
unsigned &value, const scale_mode scale,
|
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;
|
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;
|
return false;
|
||||||
value = (unsigned)huge;
|
value = (unsigned)huge;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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;
|
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;
|
return false;
|
||||||
value = (uint8_t)huge;
|
value = (uint8_t)huge;
|
||||||
return true;
|
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 parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
bool &value) {
|
bool &value) {
|
||||||
const char *value_cstr = NULL;
|
const char *value_cstr = nullptr;
|
||||||
if (!parse_option(argc, argv, narg, option, &value_cstr, "yes")) {
|
if (!parse_option(argc, argv, narg, option, &value_cstr, "yes")) {
|
||||||
const char *current = argv[narg];
|
const char *current = argv[narg];
|
||||||
if (strncmp(current, "--no-", 5) == 0 && strcmp(current + 5, option) == 0) {
|
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;
|
++verbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
logging::feed("\n");
|
logging::feed("%s\n", (*comma == '\0') ? "none" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_duration(const char *caption, unsigned duration) {
|
static void dump_duration(const char *caption, unsigned duration) {
|
||||||
@ -300,8 +357,12 @@ void dump(const char *title) {
|
|||||||
: i->params.pathname_log.c_str());
|
: i->params.pathname_log.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("database: %s, size %" PRIu64 "\n", i->params.pathname_db.c_str(),
|
log_info("database: %s, size %" PRIuPTR "[%" PRIiPTR "..%" PRIiPTR
|
||||||
i->params.size);
|
", %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("mode", i->params.mode_flags, mode_bits);
|
||||||
dump_verbs("table", i->params.table_flags, table_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("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("keygen.seed: %u\n", i->params.keygen.seed);
|
||||||
log_info("key: minlen %u, maxlen %u\n", i->params.keylen_min,
|
log_info("key: minlen %u, maxlen %u\n", i->params.keylen_min,
|
||||||
i->params.keylen_max);
|
i->params.keylen_max);
|
||||||
@ -481,3 +548,27 @@ bool actor_config::deserialize(const char *str, actor_config &config) {
|
|||||||
TRACE("<< actor_config::deserialize: OK\n");
|
TRACE("<< actor_config::deserialize: OK\n");
|
||||||
return true;
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
std::string &value, bool allow_empty = false);
|
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 parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
bool &value);
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
uint64_t &value, const scale_mode scale,
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
unsigned &value, const scale_mode scale,
|
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,
|
bool parse_option(int argc, char *const argv[], int &narg, const char *option,
|
||||||
uint8_t &value, const uint8_t minval = 0,
|
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)
|
#pragma pack(push, 1)
|
||||||
@ -121,6 +134,8 @@ struct keygen_params_pod {
|
|||||||
* Иначе говоря, нет смысла в со-координации генерации паттернов для
|
* Иначе говоря, нет смысла в со-координации генерации паттернов для
|
||||||
* ключей и значений. Более того, генерацию значений всегда необходимо
|
* ключей и значений. Более того, генерацию значений всегда необходимо
|
||||||
* рассматривать в контексте связки с одним значением ключа.
|
* рассматривать в контексте связки с одним значением ключа.
|
||||||
|
* - Тем не менее, во всех случаях достаточно важным является равномерная
|
||||||
|
* всех возможных сочетаний длин ключей и данных.
|
||||||
*
|
*
|
||||||
* width:
|
* width:
|
||||||
* Большинство тестов предполагают создание или итерирование некоторого
|
* Большинство тестов предполагают создание или итерирование некоторого
|
||||||
@ -156,7 +171,7 @@ struct keygen_params_pod {
|
|||||||
* псевдо-случайные значений ключей без псевдо-случайности в значениях.
|
* псевдо-случайные значений ключей без псевдо-случайности в значениях.
|
||||||
*
|
*
|
||||||
* Такое ограничение соответствуют внутренней алгоритмике libmdbx. Проще
|
* Такое ограничение соответствуют внутренней алгоритмике libmdbx. Проще
|
||||||
* говоря мы можем проверить движок псевдо-случайной последовательностью
|
* говоря, мы можем проверить движок псевдо-случайной последовательностью
|
||||||
* ключей на таблицах без дубликатов (без multi-value), а затем проверить
|
* ключей на таблицах без дубликатов (без multi-value), а затем проверить
|
||||||
* корректность работу псевдо-случайной последовательностью значений на
|
* корректность работу псевдо-случайной последовательностью значений на
|
||||||
* таблицах с дубликатами (с multi-value), опционально добавляя
|
* таблицах с дубликатами (с multi-value), опционально добавляя
|
||||||
@ -203,7 +218,12 @@ struct actor_params_pod {
|
|||||||
|
|
||||||
unsigned mode_flags;
|
unsigned mode_flags;
|
||||||
unsigned table_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_duration;
|
||||||
unsigned test_nops;
|
unsigned test_nops;
|
||||||
@ -246,6 +266,11 @@ struct actor_params : public config::actor_params_pod {
|
|||||||
std::string pathname_log;
|
std::string pathname_log;
|
||||||
std::string pathname_db;
|
std::string pathname_db;
|
||||||
void set_defaults(const std::string &tmpdir);
|
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 {
|
struct actor_config : public config::actor_config_pod {
|
||||||
|
@ -53,7 +53,7 @@ bool testcase_hill::run() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* TODO: работа в несколько потоков */
|
/* 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_key = keygen::alloc(config.params.keylen_max);
|
||||||
keygen::buffer a_data_0 = keygen::alloc(config.params.datalen_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_NODUPDATA | MDBX_NOOVERWRITE;
|
: MDBX_NODUPDATA | MDBX_NOOVERWRITE;
|
||||||
const unsigned update_flags =
|
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;
|
uint64_t serial_count = 0;
|
||||||
unsigned txn_nops = 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,
|
rc = mdbx_replace(txn_guard.get(), dbi, &a_key->value, &a_data_0->value,
|
||||||
&a_data_1->value, update_flags);
|
&a_data_1->value, update_flags);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
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) {
|
if (++txn_nops >= config.params.batch_write) {
|
||||||
txn_restart(false, false);
|
txn_restart(false, false);
|
||||||
|
@ -58,7 +58,11 @@ bool testcase_jitter::run() {
|
|||||||
|
|
||||||
jitter_delay();
|
jitter_delay();
|
||||||
db_close();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ serial_t injective(const serial_t serial,
|
|||||||
/* LY: All these "magic" prime numbers were found
|
/* LY: All these "magic" prime numbers were found
|
||||||
* and verified with a bit of brute force. */
|
* 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 */
|
/* 8 - 24 */
|
||||||
113, 157, 397, 653, 1753, 5641, 9697, 23873, 25693, 80833, 105953, 316937,
|
113, 157, 397, 653, 1753, 5641, 9697, 23873, 25693, 80833, 105953, 316937,
|
||||||
309277, 834497, 1499933, 4373441, 10184137,
|
309277, 834497, 1499933, 4373441, 10184137,
|
||||||
@ -43,26 +43,31 @@ serial_t injective(const serial_t serial,
|
|||||||
2420886491930041, 3601632139991929, 11984491914483833, 21805846439714153,
|
2420886491930041, 3601632139991929, 11984491914483833, 21805846439714153,
|
||||||
23171543400565993, 53353226456762893, 155627817337932409,
|
23171543400565993, 53353226456762893, 155627817337932409,
|
||||||
227827205384840249, 816509268558278821, 576933057762605689,
|
227827205384840249, 816509268558278821, 576933057762605689,
|
||||||
2623957345935638441, 5048241705479929949, 4634245581946485653};
|
2623957345935638441, 5048241705479929949, 4634245581946485653,
|
||||||
static const uint8_t s[64 - serial_minwith] = {
|
4613509448041658233, 4952535426879925961};
|
||||||
|
static const uint8_t s[64 - serial_minwith + 1] = {
|
||||||
/* 8 - 24 */
|
/* 8 - 24 */
|
||||||
2, 3, 4, 4, 2, 4, 3, 3, 7, 3, 3, 4, 8, 3, 10, 3, 11,
|
2, 3, 4, 4, 2, 4, 3, 3, 7, 3, 3, 4, 8, 3, 10, 3, 11,
|
||||||
/* 25 - 64 */
|
/* 25 - 64 */
|
||||||
11, 9, 9, 9, 11, 10, 5, 14, 11, 16, 14, 12, 13, 16, 19, 10, 10, 21, 7, 20,
|
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) {
|
if (salt) {
|
||||||
const unsigned left = bits / 2;
|
const unsigned left = bits / 2;
|
||||||
const unsigned right = bits - left;
|
const unsigned right = bits - left;
|
||||||
result = (result << left) | ((result & mask(bits)) >> right);
|
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);
|
result &= mask(bits);
|
||||||
log_trace("keygen-injective: serial %" PRIu64 " into %" PRIu64, serial,
|
log_trace("keygen-injective: serial %" PRIu64 "/%u @%" PRIx64 ",%u,%" PRIu64
|
||||||
result);
|
" => %" PRIu64 "/%u",
|
||||||
|
serial, bits, mult, shift, salt, result, bits);
|
||||||
return result;
|
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.mesh <= mapping.width);
|
||||||
assert(mapping.rotate <= mapping.width);
|
assert(mapping.rotate <= mapping.width);
|
||||||
assert(mapping.offset <= mask(mapping.width));
|
assert(mapping.offset <= mask(mapping.width));
|
||||||
assert(!(key_essentials.flags & (MDBX_INTEGERDUP | MDBX_REVERSEDUP)));
|
assert(!(key_essentials.flags &
|
||||||
assert(!(value_essentials.flags & (MDBX_INTEGERKEY | MDBX_REVERSEKEY)));
|
~(MDBX_INTEGERKEY | MDBX_REVERSEKEY | MDBX_DUPSORT)));
|
||||||
|
assert(!(value_essentials.flags & ~(MDBX_INTEGERDUP | MDBX_REVERSEDUP)));
|
||||||
|
|
||||||
log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial,
|
log_trace("keygen-pair: serial %" PRIu64 ", data-age %" PRIu64, serial,
|
||||||
value_age);
|
value_age);
|
||||||
@ -82,31 +88,49 @@ void __hot maker::pair(serial_t serial, const buffer &key, buffer &value,
|
|||||||
if (mapping.mesh >= serial_minwith) {
|
if (mapping.mesh >= serial_minwith) {
|
||||||
serial =
|
serial =
|
||||||
(serial & ~mask(mapping.mesh)) | injective(serial, mapping.mesh, salt);
|
(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) {
|
if (mapping.rotate) {
|
||||||
const unsigned right = mapping.rotate;
|
const unsigned right = mapping.rotate;
|
||||||
const unsigned left = mapping.width - right;
|
const unsigned left = mapping.width - right;
|
||||||
serial = (serial << left) | ((serial & mask(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);
|
if (mapping.offset) {
|
||||||
log_trace("keygen-pair: offset %" PRIu64, serial);
|
serial = (serial + mapping.offset) & mask(mapping.width);
|
||||||
serial += base;
|
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 key_serial = serial;
|
||||||
serial_t value_serial = value_age;
|
serial_t value_serial = value_age << mapping.split;
|
||||||
if (mapping.split) {
|
if (mapping.split) {
|
||||||
key_serial = serial >> mapping.split;
|
if (key_essentials.flags & MDBX_DUPSORT) {
|
||||||
value_serial =
|
key_serial >>= mapping.split;
|
||||||
(serial & mask(mapping.split)) | (value_age << 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,
|
log_trace("keygen-pair: key %" PRIu64 ", value %" PRIu64, key_serial,
|
||||||
value_serial);
|
value_serial);
|
||||||
|
|
||||||
mk(key_serial, key_essentials, *key);
|
mk(key_serial, key_essentials, *key);
|
||||||
mk(value_serial, value_essentials, *value);
|
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) {
|
unsigned thread_number) {
|
||||||
key_essentials.flags =
|
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);
|
assert(actor.keylen_min <= UINT8_MAX);
|
||||||
key_essentials.minlen = (uint8_t)actor.keylen_min;
|
key_essentials.minlen = (uint8_t)actor.keylen_min;
|
||||||
assert(actor.keylen_max <= UINT16_MAX);
|
assert(actor.keylen_max <= UINT16_MAX);
|
||||||
@ -137,7 +161,7 @@ void maker::setup(const config::actor_params_pod &actor,
|
|||||||
assert(thread_number < 2);
|
assert(thread_number < 2);
|
||||||
(void)thread_number;
|
(void)thread_number;
|
||||||
mapping = actor.keygen;
|
mapping = actor.keygen;
|
||||||
salt = actor.keygen.seed * UINT64_C(14653293970879851569);
|
salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569);
|
||||||
|
|
||||||
// FIXME: TODO
|
// FIXME: TODO
|
||||||
base = 0;
|
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;
|
size_t n = 0;
|
||||||
if (serial > UINT32_MAX) {
|
if (serial > UINT32_MAX) {
|
||||||
n = 4;
|
n = 4;
|
||||||
@ -199,7 +223,10 @@ void __hot maker::mk(const serial_t serial, const essentials ¶ms,
|
|||||||
assert(params.maxlen >= length(serial));
|
assert(params.maxlen >= length(serial));
|
||||||
|
|
||||||
out.value.iov_base = out.bytes;
|
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)) {
|
if (params.flags & (MDBX_INTEGERKEY | MDBX_INTEGERDUP)) {
|
||||||
assert(params.maxlen == params.minlen);
|
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 {
|
enum : serial_t {
|
||||||
serial_minwith = 8,
|
serial_minwith = 8,
|
||||||
serial_maxwith = sizeof(serial_t) * 8,
|
serial_maxwith = sizeof(serial_t) * 8,
|
||||||
serial_allones = ~(serial_t)0
|
serial_allones = ~(serial_t)0u
|
||||||
};
|
};
|
||||||
|
|
||||||
struct result {
|
struct result {
|
||||||
@ -85,6 +85,10 @@ struct result {
|
|||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
uint64_t u64;
|
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,
|
void pair(serial_t serial, const buffer &key, buffer &value,
|
||||||
serial_t value_age);
|
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);
|
bool increment(serial_t &serial, int delta);
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t length(serial_t serial);
|
|
||||||
|
|
||||||
} /* namespace keygen */
|
} /* 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 {
|
namespace logging {
|
||||||
|
|
||||||
static std::string prefix;
|
static std::string prefix;
|
||||||
@ -44,8 +69,19 @@ static std::string suffix;
|
|||||||
static loglevel level;
|
static loglevel level;
|
||||||
static FILE *last;
|
static FILE *last;
|
||||||
|
|
||||||
void setup(loglevel _level, const std::string &_prefix) {
|
void setlevel(loglevel _level) {
|
||||||
level = (_level > error) ? failure : _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;
|
prefix = _prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +193,7 @@ bool output(const logging::loglevel priority, const char *format, va_list ap) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool feed(const char *format, va_list ap) {
|
bool feed_ap(const char *format, va_list ap) {
|
||||||
if (!last)
|
if (!last)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -176,7 +212,7 @@ bool feed(const char *format, ...) {
|
|||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
feed(format, ap);
|
feed_ap(format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,12 @@ enum loglevel {
|
|||||||
const char *level2str(const loglevel level);
|
const char *level2str(const loglevel level);
|
||||||
void setup(loglevel level, const std::string &prefix);
|
void setup(loglevel level, const std::string &prefix);
|
||||||
void setup(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 output(const loglevel priority, const char *format, va_list ap);
|
||||||
bool __printf_args(2, 3)
|
bool __printf_args(2, 3)
|
||||||
output(const loglevel priority, const char *format, ...);
|
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, ...);
|
bool __printf_args(1, 2) feed(const char *format, ...);
|
||||||
|
|
||||||
class local_suffix {
|
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 |
|
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NORDAHEAD |
|
||||||
MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_LIFORECLAIM;
|
MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_LIFORECLAIM;
|
||||||
table_flags = MDBX_DUPSORT;
|
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.seed = 1;
|
||||||
keygen.keycase = kc_random;
|
keygen.keycase = kc_random;
|
||||||
keygen.width = 32;
|
keygen.width = (table_flags & MDBX_DUPSORT) ? 32 : 64;
|
||||||
keygen.mesh = 32;
|
keygen.mesh = keygen.width;
|
||||||
keygen.split = keygen.width / 2;
|
keygen.split = keygen.width / 2;
|
||||||
keygen.rotate = 0;
|
keygen.rotate = 3;
|
||||||
keygen.offset = 0;
|
keygen.offset = 41;
|
||||||
|
|
||||||
test_duration = 0;
|
test_duration = 0;
|
||||||
test_nops = 1000;
|
test_nops = 1000;
|
||||||
nrepeat = 1;
|
nrepeat = 1;
|
||||||
nthreads = 1;
|
nthreads = 1;
|
||||||
|
|
||||||
keylen_min = 0;
|
keylen_min = mdbx_keylen_min();
|
||||||
keylen_max = 42;
|
keylen_max = mdbx_keylen_max();
|
||||||
datalen_min = 0;
|
datalen_min = mdbx_datalen_min();
|
||||||
datalen_max = 256;
|
datalen_max = std::min(mdbx_datalen_max(), 256u * 1024 + 42);
|
||||||
|
|
||||||
batch_read = 4;
|
batch_read = 4;
|
||||||
batch_write = 4;
|
batch_write = 4;
|
||||||
@ -148,10 +154,53 @@ int main(int argc, char *const argv[]) {
|
|||||||
config::mode_bits))
|
config::mode_bits))
|
||||||
continue;
|
continue;
|
||||||
if (config::parse_option(argc, argv, narg, "table", params.table_flags,
|
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;
|
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;
|
continue;
|
||||||
|
|
||||||
if (config::parse_option(argc, argv, narg, "keygen.width",
|
if (config::parse_option(argc, argv, narg, "keygen.width",
|
||||||
@ -188,30 +237,36 @@ int main(int argc, char *const argv[]) {
|
|||||||
config::duration, 1))
|
config::duration, 1))
|
||||||
continue;
|
continue;
|
||||||
if (config::parse_option(argc, argv, narg, "keylen.min", params.keylen_min,
|
if (config::parse_option(argc, argv, narg, "keylen.min", params.keylen_min,
|
||||||
config::no_scale, 0, UINT8_MAX)) {
|
config::no_scale, params.mdbx_keylen_min(),
|
||||||
if (params.keylen_max < params.keylen_min)
|
params.mdbx_keylen_max())) {
|
||||||
|
if ((params.table_flags & MDBX_INTEGERKEY) ||
|
||||||
|
params.keylen_max < params.keylen_min)
|
||||||
params.keylen_max = params.keylen_min;
|
params.keylen_max = params.keylen_min;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (config::parse_option(
|
if (config::parse_option(argc, argv, narg, "keylen.max", params.keylen_max,
|
||||||
argc, argv, narg, "keylen.max", params.keylen_max, config::no_scale,
|
config::no_scale, params.mdbx_keylen_min(),
|
||||||
0,
|
params.mdbx_keylen_max())) {
|
||||||
std::min((unsigned)mdbx_get_maxkeysize(0), (unsigned)UINT16_MAX))) {
|
if ((params.table_flags & MDBX_INTEGERKEY) ||
|
||||||
if (params.keylen_min > params.keylen_max)
|
params.keylen_min > params.keylen_max)
|
||||||
params.keylen_min = params.keylen_max;
|
params.keylen_min = params.keylen_max;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (config::parse_option(argc, argv, narg, "datalen.min",
|
if (config::parse_option(argc, argv, narg, "datalen.min",
|
||||||
params.datalen_min, config::no_scale, 0,
|
params.datalen_min, config::no_scale,
|
||||||
UINT8_MAX)) {
|
params.mdbx_datalen_min(),
|
||||||
if (params.datalen_max < params.datalen_min)
|
params.mdbx_datalen_max())) {
|
||||||
|
if ((params.table_flags & MDBX_DUPFIXED) ||
|
||||||
|
params.datalen_max < params.datalen_min)
|
||||||
params.datalen_max = params.datalen_min;
|
params.datalen_max = params.datalen_min;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (config::parse_option(argc, argv, narg, "datalen.max",
|
if (config::parse_option(argc, argv, narg, "datalen.max",
|
||||||
params.datalen_max, config::no_scale, 0,
|
params.datalen_max, config::no_scale,
|
||||||
std::min((int)UINT16_MAX, MDBX_MAXDATASIZE))) {
|
params.mdbx_datalen_min(),
|
||||||
if (params.datalen_min > params.datalen_max)
|
params.mdbx_datalen_max())) {
|
||||||
|
if ((params.table_flags & MDBX_DUPFIXED) ||
|
||||||
|
params.datalen_min > params.datalen_max)
|
||||||
params.datalen_min = params.datalen_max;
|
params.datalen_min = params.datalen_max;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -182,6 +182,9 @@ void osal_killall_actors(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
ts.tv_sec = timeout;
|
||||||
retry:
|
retry:
|
||||||
int status, options = WNOHANG;
|
int status, options = WNOHANG;
|
||||||
#ifdef WUNTRACED
|
#ifdef WUNTRACED
|
||||||
@ -209,9 +212,16 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
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;
|
goto retry;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
|
@ -262,15 +262,24 @@ int osal_actor_start(const actor_config &config, mdbx_pid_t &pid) {
|
|||||||
STARTUPINFOA StartupInfo;
|
STARTUPINFOA StartupInfo;
|
||||||
GetStartupInfoA(&StartupInfo);
|
GetStartupInfoA(&StartupInfo);
|
||||||
|
|
||||||
char exename[_MAX_PATH];
|
char exename[_MAX_PATH + 1];
|
||||||
DWORD exename_size = sizeof(exename);
|
DWORD exename_size = sizeof(exename);
|
||||||
if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, exename,
|
if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, exename,
|
||||||
&exename_size))
|
&exename_size))
|
||||||
failure_perror("QueryFullProcessImageName()", GetLastError());
|
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));
|
ArgvQuote(cmdline, thunk_param(config));
|
||||||
|
|
||||||
|
if (cmdline.size() >= 32767)
|
||||||
|
return ERROR_BAD_LENGTH;
|
||||||
|
|
||||||
PROCESS_INFORMATION ProcessInformation;
|
PROCESS_INFORMATION ProcessInformation;
|
||||||
if (!CreateProcessA(exename, const_cast<char *>(cmdline.c_str()),
|
if (!CreateProcessA(exename, const_cast<char *>(cmdline.c_str()),
|
||||||
NULL, // Retuned process handle is not inheritable.
|
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 environment.
|
||||||
NULL, // Inherit the parent's current directory.
|
NULL, // Inherit the parent's current directory.
|
||||||
&StartupInfo, &ProcessInformation))
|
&StartupInfo, &ProcessInformation))
|
||||||
return GetLastError();
|
failure_perror(exename, GetLastError());
|
||||||
|
|
||||||
CloseHandle(ProcessInformation.hThread);
|
CloseHandle(ProcessInformation.hThread);
|
||||||
pid = ProcessInformation.dwProcessId;
|
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,
|
int testcase::oom_callback(MDBX_env *env, int pid, mdbx_tid_t tid, uint64_t txn,
|
||||||
unsigned gap, int retry) {
|
unsigned gap, int retry) {
|
||||||
|
|
||||||
@ -117,16 +92,8 @@ void testcase::db_prepare() {
|
|||||||
log_trace(">> db_prepare");
|
log_trace(">> db_prepare");
|
||||||
assert(!db_guard);
|
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;
|
MDBX_env *env = nullptr;
|
||||||
rc = mdbx_env_create(&env);
|
int rc = mdbx_env_create(&env);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
failure_perror("mdbx_env_create()", rc);
|
failure_perror("mdbx_env_create()", rc);
|
||||||
|
|
||||||
@ -149,7 +116,10 @@ void testcase::db_prepare() {
|
|||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
failure_perror("mdbx_env_set_oomfunc()", rc);
|
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))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
failure_perror("mdbx_env_set_mapsize()", rc);
|
failure_perror("mdbx_env_set_mapsize()", rc);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user