mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx: check read/write txn overlapping for the same thread (MDBX_TXN_OVERLAPPING).
Change-Id: If3488df96bd1903d5e4ca0a1fea504075dbd4a20
This commit is contained in:
parent
db27654330
commit
17fe5f106b
3
mdbx.h
3
mdbx.h
@ -1479,6 +1479,9 @@ typedef enum MDBX_cursor_op {
|
|||||||
* e.g. a transaction that started by another thread. */
|
* e.g. a transaction that started by another thread. */
|
||||||
#define MDBX_THREAD_MISMATCH (-30416)
|
#define MDBX_THREAD_MISMATCH (-30416)
|
||||||
|
|
||||||
|
/* Overlapping read and write transactions for the same thread */
|
||||||
|
#define MDBX_TXN_OVERLAPPING (-30415)
|
||||||
|
|
||||||
/**** FUNCTIONS & RELATED STRUCTURES ******************************************/
|
/**** FUNCTIONS & RELATED STRUCTURES ******************************************/
|
||||||
|
|
||||||
/* Return a string describing a given error code.
|
/* Return a string describing a given error code.
|
||||||
|
@ -3229,6 +3229,9 @@ static const char *__mdbx_strerr(int errnum) {
|
|||||||
case MDBX_THREAD_MISMATCH:
|
case MDBX_THREAD_MISMATCH:
|
||||||
return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not "
|
return "MDBX_THREAD_MISMATCH: A thread has attempted to use a not "
|
||||||
"owned object, e.g. a transaction that started by another thread";
|
"owned object, e.g. a transaction that started by another thread";
|
||||||
|
case MDBX_TXN_OVERLAPPING:
|
||||||
|
return "MDBX_TXN_OVERLAPPING: Overlapping read and write transactions for "
|
||||||
|
"the same thread";
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -5957,6 +5960,21 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
|||||||
/* paranoia is appropriate here */ *env->me_oldest);
|
/* paranoia is appropriate here */ *env->me_oldest);
|
||||||
txn->mt_numdbs = env->me_numdbs;
|
txn->mt_numdbs = env->me_numdbs;
|
||||||
} else {
|
} else {
|
||||||
|
if (unlikely(txn->mt_owner == tid))
|
||||||
|
return MDBX_BUSY;
|
||||||
|
MDBX_lockinfo *const lck = env->me_lck;
|
||||||
|
if (lck && (env->me_flags & MDBX_NOTLS) == 0) {
|
||||||
|
const unsigned snap_nreaders = lck->mti_numreaders;
|
||||||
|
for (unsigned i = 0; i < snap_nreaders; ++i) {
|
||||||
|
if (lck->mti_readers[i].mr_pid == env->me_pid &&
|
||||||
|
unlikely(lck->mti_readers[i].mr_tid == tid)) {
|
||||||
|
const txnid_t txnid = safe64_read(&lck->mti_readers[i].mr_txnid);
|
||||||
|
if (txnid >= MIN_TXNID && txnid < SAFE64_INVALID_THRESHOLD)
|
||||||
|
return MDBX_TXN_OVERLAPPING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Not yet touching txn == env->me_txn0, it may be active */
|
/* Not yet touching txn == env->me_txn0, it may be active */
|
||||||
mdbx_jitter4testing(false);
|
mdbx_jitter4testing(false);
|
||||||
rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN));
|
rc = mdbx_txn_lock(env, F_ISSET(flags, MDBX_TRYTXN));
|
||||||
@ -6187,15 +6205,13 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
|||||||
size += tsize = sizeof(MDBX_txn);
|
size += tsize = sizeof(MDBX_txn);
|
||||||
} else if (flags & MDBX_RDONLY) {
|
} else if (flags & MDBX_RDONLY) {
|
||||||
if (env->me_txn0 && unlikely(env->me_txn0->mt_owner == mdbx_thread_self()))
|
if (env->me_txn0 && unlikely(env->me_txn0->mt_owner == mdbx_thread_self()))
|
||||||
return MDBX_BUSY;
|
return MDBX_TXN_OVERLAPPING;
|
||||||
size = env->me_maxdbs * (sizeof(MDBX_db) + 1);
|
size = env->me_maxdbs * (sizeof(MDBX_db) + 1);
|
||||||
size += tsize = sizeof(MDBX_txn);
|
size += tsize = sizeof(MDBX_txn);
|
||||||
} else {
|
} else {
|
||||||
/* Reuse preallocated write txn. However, do not touch it until
|
/* Reuse preallocated write txn. However, do not touch it until
|
||||||
* mdbx_txn_renew0() succeeds, since it currently may be active. */
|
* mdbx_txn_renew0() succeeds, since it currently may be active. */
|
||||||
txn = env->me_txn0;
|
txn = env->me_txn0;
|
||||||
if (unlikely(txn->mt_owner == mdbx_thread_self()))
|
|
||||||
return MDBX_BUSY;
|
|
||||||
goto renew;
|
goto renew;
|
||||||
}
|
}
|
||||||
if (unlikely((txn = mdbx_malloc(size)) == NULL)) {
|
if (unlikely((txn = mdbx_malloc(size)) == NULL)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user