mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx: add MDBX_txn.mt_owner and MDBX_THREAD_MISMATCH.
This commit is contained in:
parent
3bf3a08f96
commit
465459dc58
@ -2,6 +2,7 @@ AUTHORS
|
||||
LICENSE
|
||||
Makefile
|
||||
README.md
|
||||
TODO.md
|
||||
mdbx.h
|
||||
src/bits.h
|
||||
src/defs.h
|
||||
|
8
mdbx.h
8
mdbx.h
@ -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.
|
||||
|
@ -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.
|
||||
|
93
src/mdbx.c
93
src/mdbx.c
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user