From 23117062727aed537261f04dc69748542e384088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Wed, 10 Jul 2024 22:31:41 +0300 Subject: [PATCH] =?UTF-8?q?mdbx-testing:=20=D1=82=D0=B5=D1=81=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D0=BA=D0=B8=20=D1=82=D1=80=D0=B0=D0=BD=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D1=86=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/config.c++ | 12 +++++- test/config.h++ | 2 +- test/fork.c++ | 2 +- test/jitter.c++ | 3 ++ test/main.c++ | 4 +- test/osal-unix.c++ | 2 + test/osal-windows.c++ | 4 ++ test/osal.h++ | 1 + test/test.c++ | 93 +++++++++++++++++++++++++++++++++++++++++++ test/test.h++ | 4 +- 10 files changed, 120 insertions(+), 7 deletions(-) diff --git a/test/config.c++ b/test/config.c++ index a06b99d2..4732d95b 100644 --- a/test/config.c++ +++ b/test/config.c++ @@ -137,8 +137,16 @@ bool parse_option(int argc, char *const argv[], int &narg, const char *option, if (strcmp(value_cstr, "rnd") == 0 || strcmp(value_cstr, "rand") == 0 || strcmp(value_cstr, "random") == 0) { value = minval; - if (maxval > minval) - value += (prng32() + UINT64_C(44263400549519813)) % (maxval - minval); + if (maxval > minval) { + uint64_t salt = (scale != entropy) + ? prng64() ^ UINT64_C(44263400549519813) + : (chrono::now_monotonic().fixedpoint ^ + UINT64_C(0xD85794512ED321FD)) * + UINT64_C(0x9120038359EAF3) ^ + chrono::now_realtime().fixedpoint * + UINT64_C(0x2FE5232BDC8E5F); + value += salt % (maxval - minval); + } if (scale == intkey) value &= ~3u; return true; diff --git a/test/config.h++ b/test/config.h++ index 4da0ed3a..12bc1b66 100644 --- a/test/config.h++ +++ b/test/config.h++ @@ -52,7 +52,7 @@ const char *keygencase2str(const keygen_case); namespace config { -enum scale_mode { no_scale, decimal, binary, duration, intkey }; +enum scale_mode { no_scale, decimal, binary, duration, intkey, entropy }; bool parse_option(int argc, char *const argv[], int &narg, const char *option, const char **value, const char *default_value = nullptr); diff --git a/test/fork.c++ b/test/fork.c++ index 29c95ff8..05fb250a 100644 --- a/test/fork.c++ +++ b/test/fork.c++ @@ -28,7 +28,7 @@ public: bool testcase_smoke4fork::open_dbi() { if (!dbi || dbi_invalid) { if (dbi_stable || - (mdbx_txn_flags(txn_guard.get()) & int(MDBX_TXN_RDONLY)) == 0) { + (mdbx_txn_flags(txn_guard.get()) & MDBX_TXN_RDONLY) == 0) { dbi = db_table_open(!dbi_stable); dbi_invalid = false; } diff --git a/test/jitter.c++ b/test/jitter.c++ index b868c9c5..8a4cd0b3 100644 --- a/test/jitter.c++ +++ b/test/jitter.c++ @@ -164,6 +164,9 @@ bool testcase_jitter::run() { failure_perror("mdbx_env_set_geometry-1", err); } } + if (flipcoin()) { + // err = + } txn_end(flipcoin()); if (global::config::geometry_jitter) { diff --git a/test/main.c++ b/test/main.c++ index 6b482807..9a7fb4df 100644 --- a/test/main.c++ +++ b/test/main.c++ @@ -394,7 +394,7 @@ int main(int argc, char *const argv[]) { continue; } if (config::parse_option(argc, argv, narg, "repeat", params.nrepeat, - config::no_scale)) + config::entropy)) continue; if (config::parse_option(argc, argv, narg, "threads", params.nthreads, config::no_scale, 1, 64)) @@ -443,7 +443,7 @@ int main(int argc, char *const argv[]) { params.keygen.mesh, 0, 64)) continue; if (config::parse_option(argc, argv, narg, "prng-seed", params.prng_seed, - config::no_scale)) { + config::entropy)) { prng_seed(params.prng_seed); continue; } diff --git a/test/osal-unix.c++ b/test/osal-unix.c++ index 91cf7da5..df340c1c 100644 --- a/test/osal-unix.c++ +++ b/test/osal-unix.c++ @@ -320,6 +320,8 @@ static void handler_SIGUSR(int signum) { } } +bool osal_multiactor_mode(void) { return overlord_pid != 0; } + bool osal_progress_push(bool active) { if (overlord_pid) { if (kill(overlord_pid, active ? SIGUSR1 : SIGUSR2)) diff --git a/test/osal-windows.c++ b/test/osal-windows.c++ index 54a4ed15..0ce04cc8 100644 --- a/test/osal-windows.c++ +++ b/test/osal-windows.c++ @@ -175,6 +175,10 @@ bool actor_config::osal_deserialize(const char *str, const char *end, typedef std::pair child; static std::unordered_map children; +bool osal_multiactor_mode(void) { + return hProgressActiveEvent || hProgressPassiveEvent; +} + bool osal_progress_push(bool active) { if (!children.empty()) { if (!SetEvent(active ? hProgressActiveEvent : hProgressPassiveEvent)) diff --git a/test/osal.h++ b/test/osal.h++ index 7d11dbf3..058f7078 100644 --- a/test/osal.h++ +++ b/test/osal.h++ @@ -16,6 +16,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout); void osal_wait4barrier(void); bool osal_progress_push(bool active); +bool osal_multiactor_mode(void); int osal_delay(unsigned seconds); void osal_udelay(size_t us); diff --git a/test/test.c++ b/test/test.c++ index 0451b162..0c865116 100644 --- a/test/test.c++ +++ b/test/test.c++ @@ -212,6 +212,9 @@ void testcase::txn_begin(bool readonly, MDBX_txn_flags_t flags) { log_trace("== counter %u, env_warmup(flags %u), rc %d", counter, warmup_flags, err); } + + if (readonly && flipcoin()) + txn_probe_parking(); } int testcase::breakable_commit() { @@ -267,6 +270,9 @@ void testcase::txn_end(bool abort) { log_trace(">> txn_end(%s)", abort ? "abort" : "commit"); assert(txn_guard); + if (flipcoin()) + txn_probe_parking(); + MDBX_txn *txn = txn_guard.release(); if (abort) { int err = mdbx_txn_abort(txn); @@ -321,6 +327,13 @@ int testcase::breakable_restart() { int rc = MDBX_SUCCESS; if (txn_guard) rc = breakable_commit(); + if (flipcoin()) { + txn_begin(true); + txn_probe_parking(); + int err = mdbx_txn_abort(txn_guard.release()); + if (unlikely(err != MDBX_SUCCESS)) + failure_perror("mdbx_txn_abort()", err); + } txn_begin(false, MDBX_TXN_READWRITE); if (cursor_guard) cursor_renew(); @@ -1426,3 +1439,83 @@ bool testcase::check_batch_get() { mdbx_cursor_close(batch_cursor); return rc; } + +bool testcase::txn_probe_parking() { + MDBX_txn_flags_t state = + mdbx_txn_flags(txn_guard.get()) & + (MDBX_TXN_RDONLY | MDBX_TXN_PARKED | MDBX_TXN_AUTOUNPARK | + MDBX_TXN_OUSTED | MDBX_TXN_BLOCKED); + if (state != MDBX_TXN_RDONLY) + return true; + + const bool autounpark = flipcoin(); + int err = mdbx_txn_park(txn_guard.get(), autounpark); + if (err != MDBX_SUCCESS) + failure("mdbx_txn_park(), err %d", err); + + MDBX_txn_info txn_info; + if (flipcoin()) { + err = mdbx_txn_info(txn_guard.get(), &txn_info, flipcoin()); + if (err != MDBX_SUCCESS) + failure("mdbx_txn_info(1), state 0x%x, err %d", + state = mdbx_txn_flags(txn_guard.get()), err); + } + + if (osal_multiactor_mode() && !mode_readonly()) { + while (flipcoin() && + ((state = mdbx_txn_flags(txn_guard.get())) & MDBX_TXN_OUSTED) == 0) + osal_udelay(4242); + } + + if (flipcoin()) { + err = mdbx_txn_info(txn_guard.get(), &txn_info, flipcoin()); + if (err != MDBX_SUCCESS) + failure("mdbx_txn_info(2), state 0x%x, err %d", + state = mdbx_txn_flags(txn_guard.get()), err); + } + + if (flipcoin()) { + MDBX_envinfo env_info; + err = mdbx_env_info_ex(db_guard.get(), txn_guard.get(), &env_info, + sizeof(env_info)); + if (!autounpark) { + if (err != MDBX_BAD_TXN) + failure("mdbx_env_info_ex(autounpark=%s), flags 0x%x, unexpected err " + "%d, must %d", + autounpark ? "true" : "false", state, err, MDBX_BAD_TXN); + } else if (err != MDBX_SUCCESS) { + if (err != MDBX_OUSTED || + ((state = mdbx_txn_flags(txn_guard.get())) & MDBX_TXN_OUSTED) == 0) + failure("mdbx_env_info_ex(autounpark=%s), flags 0x%x, err %d", + autounpark ? "true" : "false", state, err); + else { + err = mdbx_txn_renew(txn_guard.get()); + if (err != MDBX_SUCCESS) + failure("mdbx_txn_renew(), state 0x%x, err %d", + state = mdbx_txn_flags(txn_guard.get()), err); + } + } + } + + const bool autorestart = flipcoin(); + err = mdbx_txn_unpark(txn_guard.get(), autorestart); + if (MDBX_IS_ERROR(err)) { + if (err != MDBX_OUSTED || autorestart) + failure("mdbx_txn_unpark(autounpark=%s, autorestart=%s), err %d", + autounpark ? "true" : "false", autorestart ? "true" : "false", + err); + else { + err = mdbx_txn_renew(txn_guard.get()); + if (err != MDBX_SUCCESS) + failure("mdbx_txn_renew(), state 0x%x, err %d", + state = mdbx_txn_flags(txn_guard.get()), err); + } + } + + state = mdbx_txn_flags(txn_guard.get()) & + (MDBX_TXN_RDONLY | MDBX_TXN_PARKED | MDBX_TXN_AUTOUNPARK | + MDBX_TXN_OUSTED | MDBX_TXN_BLOCKED); + if (state != MDBX_TXN_RDONLY) + failure("unexpected txn-state 0x%x", state); + return state == MDBX_TXN_RDONLY; +} diff --git a/test/test.h++ b/test/test.h++ index f3375a6e..39ce1118 100644 --- a/test/test.h++ +++ b/test/test.h++ @@ -254,6 +254,8 @@ protected: void cursor_renew(); void txn_inject_writefault(void); void txn_inject_writefault(MDBX_txn *txn); + bool txn_probe_parking(); + void fetch_canary(); void update_canary(uint64_t increment); bool checkdata(const char *step, MDBX_dbi handle, MDBX_val key2check, @@ -275,7 +277,7 @@ protected: void signal(); bool should_continue(bool check_timeout_only = false) const; - bool failure(const char *fmt, ...) const; + bool MDBX_PRINTF_ARGS(2, 3) failure(const char *fmt, ...) const; void generate_pair(const keygen::serial_t serial, keygen::buffer &out_key, keygen::buffer &out_value, keygen::serial_t data_age) { keyvalue_maker.pair(serial, out_key, out_value, data_age, false);