diff --git a/mdbx.h b/mdbx.h index d8453d05..421d833b 100644 --- a/mdbx.h +++ b/mdbx.h @@ -327,7 +327,7 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a, const MDBX_val *b); /* Store multiple data items in one call. Only for MDBX_DUPFIXED. */ #define MDBX_MULTIPLE 0x80000u -/* Transaction Flags*/ +/* Transaction Flags */ /* Do not block when starting a write transaction */ #define MDBX_TRYTXN 0x10000000u diff --git a/src/bits.h b/src/bits.h index b22c1f25..7fe6836c 100644 --- a/src/bits.h +++ b/src/bits.h @@ -553,8 +553,8 @@ struct MDBX_txn { /* Transaction Flags */ /* mdbx_txn_begin() flags */ -#define MDBX_TXN_BEGIN_FLAGS_PERSISTENT (MDBX_NOMETASYNC | MDBX_NOSYNC | MDBX_RDONLY) -#define MDBX_TXN_BEGIN_FLAGS (MDBX_TXN_BEGIN_FLAGS_PERSISTENT | MDBX_TRYTXN) +#define MDBX_TXN_BEGIN_FLAGS \ + (MDBX_NOMETASYNC | MDBX_NOSYNC | MDBX_RDONLY | MDBX_TRYTXN) #define MDBX_TXN_NOMETASYNC \ MDBX_NOMETASYNC /* don't sync meta for this txn on commit */ #define MDBX_TXN_NOSYNC MDBX_NOSYNC /* don't sync this txn on commit */ diff --git a/src/lck-posix.c b/src/lck-posix.c index 0c8cb41b..14ce3d50 100644 --- a/src/lck-posix.c +++ b/src/lck-posix.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2015-2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -186,9 +186,9 @@ static int mdbx_robust_lock(MDBX_env *env, pthread_mutex_t *mutex) { static int mdbx_robust_trylock(MDBX_env *env, pthread_mutex_t *mutex) { int rc = pthread_mutex_trylock(mutex); - if (unlikely(rc != 0)) + if (unlikely(rc != 0 && rc != EBUSY)) rc = mdbx_mutex_failed(env, mutex, rc); - return rc; + return (rc != EBUSY) ? rc : MDBX_BUSY; } static int mdbx_robust_unlock(MDBX_env *env, pthread_mutex_t *mutex) { @@ -213,16 +213,10 @@ void mdbx_rdt_unlock(MDBX_env *env) { mdbx_panic("%s() failed: errcode %d\n", mdbx_func_, rc); } -int mdbx_txn_lock(MDBX_env *env) { +int mdbx_txn_lock(MDBX_env *env, bool dontwait) { mdbx_trace(">>"); - int rc = mdbx_robust_lock(env, &env->me_lck->mti_wmutex); - mdbx_trace("<< rc %d", rc); - return MDBX_IS_ERROR(rc) ? rc : MDBX_SUCCESS; -} - -int mdbx_txn_trylock(MDBX_env *env) { - mdbx_trace(">>"); - int rc = mdbx_robust_trylock(env, &env->me_lck->mti_wmutex); + int rc = dontwait ? mdbx_robust_trylock(env, &env->me_lck->mti_wmutex) + : mdbx_robust_lock(env, &env->me_lck->mti_wmutex); mdbx_trace("<< rc %d", rc); return MDBX_IS_ERROR(rc) ? rc : MDBX_SUCCESS; } @@ -327,9 +321,7 @@ static int __cold mdbx_mutex_failed(MDBX_env *env, pthread_mutex_t *mutex, #endif /* MDBX_USE_ROBUST */ mdbx_error("mutex (un)lock failed, %s", mdbx_strerror(rc)); - if (rc == EBUSY) { - rc = MDBX_BUSY; - } else if (rc != EDEADLK && rc != EBUSY) { + if (rc != EDEADLK) { env->me_flags |= MDBX_FATAL_ERROR; rc = MDBX_PANIC; } diff --git a/src/lck-windows.c b/src/lck-windows.c index d3340d58..672512a7 100644 --- a/src/lck-windows.c +++ b/src/lck-windows.c @@ -1,4 +1,4 @@ -/* +/* * Copyright 2015-2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -126,20 +126,13 @@ static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset, #define LCK_BODY LCK_BODY_OFFSET, LCK_BODY_LEN #define LCK_WHOLE 0, LCK_MAXLEN -int mdbx_txn_lock(MDBX_env *env) { - if (flock(env->me_fd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_BODY)) - return MDBX_SUCCESS; - return GetLastError(); -} - -int mdbx_txn_trylock(MDBX_env *env) { - if (flock(env->me_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY)) +int mdbx_txn_lock(MDBX_env *env, bool dontwait) { + if (flock(env->me_fd, dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT) + : (LCK_EXCLUSIVE | LCK_WAITFOR), + LCK_BODY)) return MDBX_SUCCESS; int rc = GetLastError(); - if (rc == ERROR_LOCK_VIOLATION) { - rc = MDBX_BUSY; - } - return rc; + return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY; } void mdbx_txn_unlock(MDBX_env *env) { diff --git a/src/mdbx.c b/src/mdbx.c index 01373842..57b74336 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -2313,7 +2313,7 @@ int mdbx_env_sync(MDBX_env *env, int force) { (!env->me_txn0 || env->me_txn0->mt_owner != mdbx_thread_self()); if (outside_txn) { - int rc = mdbx_txn_lock(env); + int rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) return rc; } @@ -2342,7 +2342,7 @@ int mdbx_env_sync(MDBX_env *env, int force) { if (unlikely(rc != MDBX_SUCCESS)) return rc; - rc = mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -2587,7 +2587,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) { } else { /* Not yet touching txn == env->me_txn0, it may be active */ mdbx_jitter4testing(false); - rc = F_ISSET(flags, MDBX_TRYTXN) ? mdbx_txn_trylock(env) : mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN)); if (unlikely(rc)) return rc; @@ -2689,7 +2689,6 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, MDBX_txn **ret) { MDBX_txn *txn; MDBX_ntxn *ntxn; - //unsigned pflags; int rc, size, tsize; if (unlikely(!env || !ret)) @@ -2744,7 +2743,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags, txn->mt_dbxs = env->me_dbxs; /* static */ txn->mt_dbs = (MDBX_db *)((char *)txn + tsize); txn->mt_dbflags = (uint8_t *)txn + size - env->me_maxdbs; - txn->mt_flags = flags & MDBX_TXN_BEGIN_FLAGS_PERSISTENT; + txn->mt_flags = flags; txn->mt_env = env; if (parent) { @@ -4468,7 +4467,7 @@ LIBMDBX_API int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, return MDBX_EACCESS; if (outside_txn) { - int err = mdbx_txn_lock(env); + int err = mdbx_txn_lock(env, false); if (unlikely(err != MDBX_SUCCESS)) return err; } @@ -9796,7 +9795,7 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, mdbx_filehandle_t fd) { goto bailout; /* FIXME: or just return? */ /* Temporarily block writers until we snapshot the meta pages */ - rc = mdbx_txn_lock(env); + rc = mdbx_txn_lock(env, false); if (unlikely(rc != MDBX_SUCCESS)) goto bailout; @@ -9881,7 +9880,7 @@ int __cold mdbx_env_set_flags(MDBX_env *env, unsigned flags, int onoff) { if (unlikely(flags & ~CHANGEABLE)) return MDBX_EINVAL; - int rc = mdbx_txn_lock(env); + int rc = mdbx_txn_lock(env, false); if (unlikely(rc)) return rc; diff --git a/src/osal.h b/src/osal.h index ad9fd275..871e52b0 100644 --- a/src/osal.h +++ b/src/osal.h @@ -505,8 +505,7 @@ void mdbx_lck_destroy(MDBX_env *env); int mdbx_rdt_lock(MDBX_env *env); void mdbx_rdt_unlock(MDBX_env *env); -int mdbx_txn_lock(MDBX_env *env); -int mdbx_txn_trylock(MDBX_env *env); +int mdbx_txn_lock(MDBX_env *env, bool dontwait); void mdbx_txn_unlock(MDBX_env *env); int mdbx_rpid_set(MDBX_env *env); diff --git a/test/config.h b/test/config.h index aecfcd3e..c2ac1389 100644 --- a/test/config.h +++ b/test/config.h @@ -20,7 +20,14 @@ #define ACTOR_ID_MAX INT16_MAX -enum actor_testcase { ac_none, ac_hill, ac_deadread, ac_deadwrite, ac_jitter, ac_try }; +enum actor_testcase { + ac_none, + ac_hill, + ac_deadread, + ac_deadwrite, + ac_jitter, + ac_try +}; enum actor_status { as_unknown, diff --git a/test/dead.cc b/test/dead.cc index acea1193..c7b338ff 100644 --- a/test/dead.cc +++ b/test/dead.cc @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -25,7 +25,7 @@ bool testcase_deadread::setup() { bool testcase_deadread::run() { db_open(); - txn_begin(MDBX_RDONLY); + txn_begin(true); return true; } @@ -50,7 +50,7 @@ bool testcase_deadwrite::setup() { bool testcase_deadwrite::run() { db_open(); - txn_begin(0); + txn_begin(false); return true; } diff --git a/test/hill.cc b/test/hill.cc index 2b7aeb00..72a6e95b 100644 --- a/test/hill.cc +++ b/test/hill.cc @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -28,7 +28,7 @@ bool testcase_hill::setup() { bool testcase_hill::run() { db_open(); - txn_begin(0); + txn_begin(false); MDBX_dbi dbi = db_table_open(true); txn_end(false); @@ -70,7 +70,7 @@ bool testcase_hill::run() { uint64_t serial_count = 0; unsigned txn_nops = 0; if (!txn_guard) - txn_begin(0); + txn_begin(false); while (should_continue()) { const keygen::serial_t a_serial = serial_count; @@ -91,7 +91,7 @@ bool testcase_hill::run() { failure_perror("mdbx_put(insert-a.1)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -104,7 +104,7 @@ bool testcase_hill::run() { failure_perror("mdbx_put(insert-b)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -118,7 +118,7 @@ bool testcase_hill::run() { failure_perror("mdbx_put(update-a: 1->0)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -129,7 +129,7 @@ bool testcase_hill::run() { failure_perror("mdbx_del(b)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -164,7 +164,7 @@ bool testcase_hill::run() { failure_perror("mdbx_put(update-a: 0->1)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -177,7 +177,7 @@ bool testcase_hill::run() { failure_perror("mdbx_put(insert-b)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -189,7 +189,7 @@ bool testcase_hill::run() { failure_perror("mdbx_del(a)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -200,7 +200,7 @@ bool testcase_hill::run() { failure_perror("mdbx_del(b)", rc); if (++txn_nops >= config.params.batch_write) { - txn_restart(false, 0); + txn_restart(false, false); txn_nops = 0; } @@ -212,7 +212,7 @@ bool testcase_hill::run() { if (dbi) { if (config.params.drop_table && !mode_readonly()) { - txn_begin(0); + txn_begin(false); db_table_drop(dbi); txn_end(false); } else diff --git a/test/jitter.cc b/test/jitter.cc index 27f208a3..92d272e1 100644 --- a/test/jitter.cc +++ b/test/jitter.cc @@ -30,7 +30,7 @@ bool testcase_jitter::run() { if (flipcoin()) { jitter_delay(); - txn_begin(MDBX_RDONLY); + txn_begin(true); fetch_canary(); jitter_delay(); txn_end(flipcoin()); @@ -51,7 +51,7 @@ bool testcase_jitter::run() { if (flipcoin()) { jitter_delay(); - txn_begin(MDBX_RDONLY); + txn_begin(true); jitter_delay(); txn_end(flipcoin()); } diff --git a/test/test.cc b/test/test.cc index 6bb17735..f1dc2264 100644 --- a/test/test.cc +++ b/test/test.cc @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -177,18 +177,21 @@ void testcase::db_close() { log_trace("<< db_close"); } -void testcase::txn_begin(unsigned flags) { - log_trace(">> txn_begin(%s)", flags & MDBX_RDONLY ? "read-only" : "read-write"); +void testcase::txn_begin(bool readonly, unsigned flags) { + assert((flags & MDBX_RDONLY) == 0); + log_trace(">> txn_begin(%s, 0x%04X)", readonly ? "read-only" : "read-write", + flags); assert(!txn_guard); MDBX_txn *txn = nullptr; - int rc = - mdbx_txn_begin(db_guard.get(), nullptr, flags, &txn); + int rc = mdbx_txn_begin(db_guard.get(), nullptr, + readonly ? flags | MDBX_RDONLY : flags, &txn); if (unlikely(rc != MDBX_SUCCESS)) failure_perror("mdbx_txn_begin()", rc); txn_guard.reset(txn); - log_trace("<< txn_begin(%s)", flags & MDBX_RDONLY ? "read-only" : "read-write"); + log_trace("<< txn_begin(%s, 0x%04X)", readonly ? "read-only" : "read-write", + flags); } void testcase::txn_end(bool abort) { @@ -209,10 +212,10 @@ void testcase::txn_end(bool abort) { log_trace("<< txn_end(%s)", abort ? "abort" : "commit"); } -void testcase::txn_restart(bool abort, unsigned flags) { +void testcase::txn_restart(bool abort, bool readonly, unsigned flags) { if (txn_guard) txn_end(abort); - txn_begin(flags); + txn_begin(readonly, flags); } bool testcase::wait4start() { diff --git a/test/test.h b/test/test.h index 500caef0..67fadebf 100644 --- a/test/test.h +++ b/test/test.h @@ -1,4 +1,4 @@ -/* +/* * Copyright 2017 Leonid Yuriev * and other libmdbx authors: please see AUTHORS file. * All rights reserved. @@ -104,9 +104,9 @@ protected: void db_prepare(); void db_open(); void db_close(); - void txn_begin(unsigned flags); + void txn_begin(bool readonly, unsigned flags = 0); void txn_end(bool abort); - void txn_restart(bool abort, unsigned flags); + void txn_restart(bool abort, bool readonly, unsigned flags = 0); void fetch_canary(); void update_canary(uint64_t increment); void kick_progress(bool active) const; @@ -130,8 +130,8 @@ protected: generate_pair(serial, key, data, data_age); } - unsigned mode_readonly() const { - return (config.params.mode_flags & MDBX_RDONLY) ? MDBX_RDONLY : 0; + bool mode_readonly() const { + return (config.params.mode_flags & MDBX_RDONLY) ? true : false; } public: diff --git a/test/try.cc b/test/try.cc index 4071c24c..1deae71d 100644 --- a/test/try.cc +++ b/test/try.cc @@ -15,8 +15,7 @@ bool testcase_try::run() { MDBX_txn *txn = nullptr; MDBX_txn *txn2 = nullptr; - int rc = - mdbx_txn_begin(db_guard.get(), nullptr, 0, &txn); + int rc = mdbx_txn_begin(db_guard.get(), nullptr, 0, &txn); if (unlikely(rc != MDBX_SUCCESS)) failure_perror("mdbx_txn_begin(MDBX_TRYTXN)", rc); else {