From ba719ef12a413f5dba1ddc4c3879627f859ab4ef 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, 21 Feb 2024 01:28:51 +0300 Subject: [PATCH] =?UTF-8?q?mdbx-test:=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20after-fork=20=D1=81=D1=86=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=D1=80=D0=B8=D0=B5=D0=B2=20=D1=81=20=D1=83=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BB?= =?UTF-8?q?=D0=BE=D0=B3=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B9=20=D0=BE?= =?UTF-8?q?=D1=88=D0=B8=D0=B1=D0=BA=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/fork.c++ | 93 +++++++++++++++++++++++++++++++++++++++++++++------ test/test.h++ | 5 +-- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/test/fork.c++ b/test/fork.c++ index 7f1c9b19..81af98b4 100644 --- a/test/fork.c++ +++ b/test/fork.c++ @@ -22,13 +22,58 @@ class testcase_smoke4fork : public testcase { using inherited = testcase; +protected: + bool dbi_invalid{true}; + bool dbi_stable{false}; + unsigned dbi_state{0}; + public: testcase_smoke4fork(const actor_config &config, const mdbx_pid_t pid) : testcase(config, pid) {} + virtual void txn_end(bool abort) override; bool run() override; virtual bool smoke() = 0; + bool open_dbi(); }; +bool testcase_smoke4fork::open_dbi() { + if (!dbi || dbi_invalid) { + if (dbi_stable || + (mdbx_txn_flags(txn_guard.get()) & int(MDBX_TXN_RDONLY)) == 0) { + dbi = db_table_open(!dbi_stable); + dbi_invalid = false; + } + } + + dbi_state = 0; + if (dbi && !dbi_invalid) { + unsigned unused_dbi_flags; + int err = + mdbx_dbi_flags_ex(txn_guard.get(), dbi, &unused_dbi_flags, &dbi_state); + if (unlikely(err != MDBX_SUCCESS)) + failure_perror("mdbx_dbi_flags_ex()", err); + if ((dbi_state & (MDBX_DBI_CREAT | MDBX_DBI_FRESH)) == 0) + dbi_stable = true; + } + return !dbi_invalid; +} + +void testcase_smoke4fork::txn_end(bool abort) { + if (dbi) { + if (abort) { + if (dbi_state & MDBX_DBI_CREAT) + dbi_stable = false; + if (dbi_state & MDBX_DBI_FRESH) + dbi_invalid = true; + } else { + if (dbi_state & (MDBX_DBI_CREAT | MDBX_DBI_FRESH)) + dbi_stable = true; + } + dbi_state = 0; + } + inherited::txn_end(abort); +} + bool testcase_smoke4fork::run() { static std::vector history; const pid_t current_pid = getpid(); @@ -52,6 +97,7 @@ bool testcase_smoke4fork::run() { current_pid, mdbx_strerror(err)); return false; } + open_dbi(); if (flipcoin()) { if (!smoke()) { @@ -65,11 +111,11 @@ bool testcase_smoke4fork::run() { log_verbose("%s[deep %d, pid %d] probe %s", "pre-fork", deep, current_pid, "skipped"); #ifdef __SANITIZE_ADDRESS__ - const bool abort_txn_to_avoid_memleak = true; + const bool commit_txn_to_avoid_memleak = true; #else - const bool abort_txn_to_avoid_memleak = !RUNNING_ON_VALGRIND && flipcoin(); + const bool commit_txn_to_avoid_memleak = !RUNNING_ON_VALGRIND && flipcoin(); #endif - if (abort_txn_to_avoid_memleak && txn_guard) + if (commit_txn_to_avoid_memleak && txn_guard) txn_end(false); } @@ -90,8 +136,14 @@ bool testcase_smoke4fork::run() { log_flush(); if (err != MDBX_SUCCESS) failure_perror("mdbx_env_resurrect_after_fork()", err); - if (txn_guard) + if (txn_guard) { + if (dbi_state & MDBX_DBI_CREAT) + dbi_invalid = true; + // if (dbi_state & MDBX_DBI_FRESH) + // dbi_invalid = true; + dbi_state = 0; mdbx_txn_abort(txn_guard.release()); + } if (!smoke()) { log_notice("%s[deep %d, pid %d] probe %s", "fork-child", deep, new_pid, "failed"); @@ -182,9 +234,19 @@ bool testcase_forkread::smoke() { failure_perror("mdbx_env_info_ex()", err); uint64_t seq; - err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 0); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_dbi_sequence(get)", err); + if (dbi_invalid) { + err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 0); + if (unlikely(err != (dbi ? MDBX_BAD_DBI : MDBX_SUCCESS))) + failure("unexpected '%s' from mdbx_dbi_sequence(get, bad_dbi %d)", + mdbx_strerror(err), dbi); + open_dbi(); + } + if (!dbi_invalid) { + err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 0); + if (unlikely(err != MDBX_SUCCESS)) + failure("unexpected '%s' from mdbx_dbi_sequence(get, dbi %d)", + mdbx_strerror(err), dbi); + } txn_end(false); return true; } @@ -210,10 +272,21 @@ bool testcase_forkwrite::smoke() { if (!txn_guard) txn_begin(false); + uint64_t seq; - int err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 1); - if (unlikely(err != MDBX_SUCCESS)) - failure_perror("mdbx_dbi_sequence(inc)", err); + if (dbi_invalid) { + int err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 0); + if (unlikely(err != (dbi ? MDBX_BAD_DBI : MDBX_EACCESS))) + failure("unexpected '%s' from mdbx_dbi_sequence(get, bad_dbi %d)", + mdbx_strerror(err), dbi); + open_dbi(); + } + if (!dbi_invalid) { + int err = mdbx_dbi_sequence(txn_guard.get(), dbi, &seq, 1); + if (unlikely(err != MDBX_SUCCESS)) + failure("unexpected '%s' from mdbx_dbi_sequence(inc, dbi %d)", + mdbx_strerror(err), dbi); + } txn_end(false); if (!firstly_read && !testcase_forkread::smoke()) diff --git a/test/test.h++ b/test/test.h++ index 96d93a7c..b03b80e1 100644 --- a/test/test.h++ +++ b/test/test.h++ @@ -248,9 +248,10 @@ protected: void db_prepare(); void db_open(); void db_close(); - void txn_begin(bool readonly, MDBX_txn_flags_t flags = MDBX_TXN_READWRITE); + virtual void txn_begin(bool readonly, + MDBX_txn_flags_t flags = MDBX_TXN_READWRITE); int breakable_commit(); - void txn_end(bool abort); + virtual void txn_end(bool abort); int breakable_restart(); void txn_restart(bool abort, bool readonly, MDBX_txn_flags_t flags = MDBX_TXN_READWRITE);