mdbx: add MDBX_txn.mt_owner and MDBX_THREAD_MISMATCH.

This commit is contained in:
Leo Yuriev 2017-06-06 17:05:30 +03:00
parent 3bf3a08f96
commit 465459dc58
6 changed files with 104 additions and 16 deletions

View File

@ -2,6 +2,7 @@ AUTHORS
LICENSE
Makefile
README.md
TODO.md
mdbx.h
src/bits.h
src/defs.h

8
mdbx.h
View File

@ -414,10 +414,14 @@ typedef enum MDBX_cursor_op {
* when mdbx_cursor_put() called with MDBX_CURRENT option. */
#define MDBX_EKEYMISMATCH (-30418)
/* Database is too large for current system, i.e. could NOT be mapped into RAM.
*/
/* Database is too large for current system,
* e.g. could NOT be mapped into RAM. */
#define MDBX_TOO_LARGE (-30417)
/* A thread has attempted to use a not owned object,
* e.g. a transaction that started by another thread. */
#define MDBX_THREAD_MISMATCH (-30416)
/* Statistics for a database in the environment */
typedef struct MDBX_stat {
uint32_t ms_psize; /* Size of a database page.

View File

@ -527,6 +527,7 @@ struct MDBX_txn {
* dirtylist into mt_parent after freeing hidden mt_parent pages. */
unsigned mt_dirtyroom;
mdbx_canary mt_canary;
mdbx_tid_t mt_owner; /* thread ID that owns this transaction */
};
/* Enough space for 2^32 nodes with minimum of 2 keys per node. I.e., plenty.

View File

@ -690,8 +690,11 @@ static const char *__mdbx_strerr(int errnum) {
return "MDBX_EKEYMISMATCH: The given key value is mismatched to the "
"current cursor position";
case MDBX_TOO_LARGE:
return "Database is too large for current system, i.e.could NOT be mapped "
"into RAM.";
return "MDBX_TOO_LARGE: Database is too large for current system, "
"e.g. could NOT be mapped into RAM";
case MDBX_THREAD_MISMATCH:
return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not "
"owned object, e.g. a transaction that started by another thread";
default:
return NULL;
}
@ -968,13 +971,13 @@ static void mdbx_audit(MDBX_txn *txn) {
int mdbx_cmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
const MDBX_val *b) {
mdbx_ensure(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
mdbx_assert(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
return txn->mt_dbxs[dbi].md_cmp(a, b);
}
int mdbx_dcmp(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a,
const MDBX_val *b) {
mdbx_ensure(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
mdbx_assert(NULL, txn->mt_signature == MDBX_MT_SIGNATURE);
return txn->mt_dbxs[dbi].md_dcmp(a, b);
}
@ -2394,6 +2397,9 @@ int mdbx_txn_renew(MDBX_txn *txn) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY | MDBX_TXN_FINISHED)))
return MDBX_EINVAL;
@ -2434,6 +2440,9 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (unlikely(parent->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EINVAL;
if (unlikely(parent->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
/* Nested transactions: Max 1 child, write txns only, no writemap */
flags |= parent->mt_flags;
if (unlikely(flags & (MDBX_RDONLY | MDBX_WRITEMAP | MDBX_TXN_BLOCKED))) {
@ -2510,6 +2519,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
if (txn != env->me_txn0)
free(txn);
} else {
txn->mt_owner = mdbx_thread_self();
txn->mt_signature = MDBX_MT_SIGNATURE;
*ret = txn;
mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "",
@ -2593,7 +2603,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
mdbx_coherent_barrier();
txn->mt_numdbs = 0; /* prevent further DBI activity */
txn->mt_flags |= MDBX_TXN_FINISHED;
txn->mt_owner = 0;
} else if (!F_ISSET(txn->mt_flags, MDBX_TXN_FINISHED)) {
pgno_t *pghead = env->me_pghead;
@ -2621,6 +2631,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
env->me_pglast = 0;
env->me_txn = NULL;
txn->mt_owner = 0;
txn->mt_signature = 0;
mode = 0; /* txn == env->me_txn0, do not free() it */
@ -2640,6 +2651,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
if (mode & MDBX_END_FREE) {
mdbx_ensure(env, txn != env->me_txn0);
txn->mt_owner = 0;
txn->mt_signature = 0;
free(txn);
}
@ -2654,6 +2666,9 @@ int mdbx_txn_reset(MDBX_txn *txn) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
/* This call is only valid for read-only txns */
if (unlikely(!(txn->mt_flags & MDBX_TXN_RDONLY)))
return MDBX_EINVAL;
@ -2669,6 +2684,9 @@ int mdbx_txn_abort(MDBX_txn *txn) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (F_ISSET(txn->mt_flags, MDBX_TXN_RDONLY))
/* LY: don't close DBI-handles in MDBX mode */
return mdbx_txn_end(txn, MDBX_END_ABORT | MDBX_END_UPDATE | MDBX_END_SLOT |
@ -3133,6 +3151,9 @@ int mdbx_txn_commit(MDBX_txn *txn) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
MDBX_env *env = txn->mt_env;
if (unlikely(env->me_pid != mdbx_getpid())) {
env->me_flags |= MDBX_FATAL_ERROR;
@ -5256,6 +5277,9 @@ int mdbx_get(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -7162,6 +7186,9 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return MDBX_EINVAL;
@ -7197,6 +7224,9 @@ int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *mc) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE &&
mc->mc_signature != MDBX_MC_READY4CLOSE))
return MDBX_EINVAL;
@ -7231,6 +7261,9 @@ int mdbx_cursor_count(MDBX_cursor *mc, size_t *countp) {
if (unlikely(mc->mc_signature != MDBX_MC_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(mc->mc_txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(mc->mc_txn->mt_flags & MDBX_TXN_BLOCKED))
return MDBX_BAD_TXN;
@ -8054,6 +8087,9 @@ int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -8543,6 +8579,9 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -9236,6 +9275,9 @@ int mdbx_dbi_open_ex(MDBX_txn *txn, const char *table_name, unsigned user_flags,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
return MDBX_BAD_TXN;
@ -9368,6 +9410,9 @@ int __cold mdbx_dbi_stat(MDBX_txn *txn, MDBX_dbi dbi, MDBX_stat *arg,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return MDBX_EINVAL;
@ -9422,6 +9467,9 @@ int mdbx_dbi_flags(MDBX_txn *txn, MDBX_dbi dbi, unsigned *flags) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_VALID)))
return MDBX_EINVAL;
@ -9528,6 +9576,9 @@ int mdbx_drop(MDBX_txn *txn, MDBX_dbi dbi, int del) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -9602,6 +9653,9 @@ int mdbx_set_compare(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -9616,6 +9670,9 @@ int mdbx_set_dupsort(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cmp_func *cmp) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -9887,6 +9944,9 @@ int mdbx_txn_straggler(MDBX_txn *txn, int *percent)
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!txn->mt_ro_reader))
return -1;
@ -10041,9 +10101,13 @@ int __cold mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
void *user) {
if (unlikely(!txn))
return MDBX_BAD_TXN;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
mdbx_walk_ctx_t ctx;
ctx.mw_txn = txn;
ctx.mw_user = user;
@ -10069,6 +10133,9 @@ int mdbx_canary_put(MDBX_txn *txn, const mdbx_canary *canary) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(txn->mt_flags & MDBX_TXN_BLOCKED))
return MDBX_BAD_TXN;
@ -10097,9 +10164,13 @@ int mdbx_canary_put(MDBX_txn *txn, const mdbx_canary *canary) {
int mdbx_canary_get(MDBX_txn *txn, mdbx_canary *canary) {
if (unlikely(txn == NULL || canary == NULL))
return MDBX_EINVAL;
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
*canary = txn->mt_canary;
return MDBX_SUCCESS;
}
@ -10197,6 +10268,9 @@ int mdbx_replace(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *new_data,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(old_data->iov_base == NULL && old_data->iov_len))
return MDBX_EINVAL;
@ -10332,6 +10406,9 @@ int mdbx_get_ex(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;
@ -10396,6 +10473,9 @@ int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr) {
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(txn->mt_flags & MDBX_TXN_RDONLY))
return MDBX_RESULT_FALSE;
@ -10457,6 +10537,9 @@ int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE))
return MDBX_EBADSIGN;
if (unlikely(txn->mt_owner != mdbx_thread_self()))
return MDBX_THREAD_MISMATCH;
if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)))
return MDBX_EINVAL;

View File

@ -615,14 +615,6 @@ void mdbx_thread_rthc_set(mdbx_thread_key_t key, const void *value) {
#endif
}
mdbx_tid_t mdbx_thread_self(void) {
#if defined(_WIN32) || defined(_WIN64)
return GetCurrentThreadId();
#else
return pthread_self();
#endif
}
int mdbx_thread_create(mdbx_thread_t *thread,
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
void *arg) {

View File

@ -439,7 +439,6 @@ int mdbx_thread_create(mdbx_thread_t *thread,
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
void *arg);
int mdbx_thread_join(mdbx_thread_t thread);
mdbx_tid_t mdbx_thread_self(void);
int mdbx_thread_key_create(mdbx_thread_key_t *key);
void mdbx_thread_key_delete(mdbx_thread_key_t key);
void *mdbx_thread_rthc_get(mdbx_thread_key_t key);
@ -465,6 +464,14 @@ static __inline mdbx_pid_t mdbx_getpid(void) {
#endif
}
static __inline mdbx_tid_t mdbx_thread_self(void) {
#if defined(_WIN32) || defined(_WIN64)
return GetCurrentThreadId();
#else
return pthread_self();
#endif
}
void mdbx_osal_jitter(bool tiny);
/*----------------------------------------------------------------------------*/