mdbx: доработка контроля потока-владельца транзакции.

1. Теперь допускается commit/abort вложенных транзакций из любого треда в режиме MDBX_NOSTICKYTHREADS.

2. Более наглядные/явные проверки без зависимости от больше/меньше.
Одна проверка внутри check_txn() для всех основных случаев (bad_bits != 0) и две проверки для abort/reset/break (bad_bits == 0).

+-------------------------------------------------------------------------------------------------------+
|          Три анализируемых txn->flags       |         Проверка txn->owner == osal_thread_self()       |
+-----------------+------------+--------------+-----------------------+---------------------------------+
| NOSTICKYTHREADS | TXN_RDONLY | TXN_FINISHED | usual (bad_bits != 0) | abort/reset/break (bad_bits==0) |
|      -          |     -      |     -        |     +                 |         +                       |
|      -          |     -      |     +        |     +                 |         +                       |
|      -          |     +      |     -        |     +                 |         +                       |
|      -          |     +      |     +        |     +                 |         -                       |
|      +          |     -      |     -        |     -                 |         -                       |
|      +          |     -      |     +        |     +                 |         +                       |
|      +          |     +      |     -        |     -                 |         -                       |
|      +          |     +      |     +        |     +                 |         -                       |
+-------------------------------------------------------------------------------------------------------+
This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2024-12-30 17:49:42 +03:00
parent 1e4e2eb3c8
commit 1bf008ac16
2 changed files with 30 additions and 20 deletions

View File

@ -385,6 +385,9 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
const uint64_t ts_0 = latency ? osal_monotime() : 0; const uint64_t ts_0 = latency ? osal_monotime() : 0;
uint64_t ts_1 = 0, ts_2 = 0, ts_3 = 0, ts_4 = 0, ts_5 = 0, gc_cputime = 0; uint64_t ts_1 = 0, ts_2 = 0, ts_3 = 0, ts_4 = 0, ts_5 = 0, gc_cputime = 0;
/* txn_end() mode for a commit which writes nothing */
unsigned end_mode = TXN_END_PURE_COMMIT | TXN_END_UPDATE | TXN_END_SLOT | TXN_END_FREE;
int rc = check_txn(txn, MDBX_TXN_FINISHED); int rc = check_txn(txn, MDBX_TXN_FINISHED);
if (unlikely(rc != MDBX_SUCCESS)) { if (unlikely(rc != MDBX_SUCCESS)) {
if (rc == MDBX_BAD_TXN && (txn->flags & MDBX_TXN_RDONLY)) { if (rc == MDBX_BAD_TXN && (txn->flags & MDBX_TXN_RDONLY)) {
@ -404,18 +407,22 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
goto bailout; goto bailout;
} }
if (unlikely(txn->flags & MDBX_TXN_ERROR)) { if (unlikely(txn->flags & MDBX_TXN_RDONLY)) {
rc = MDBX_RESULT_TRUE; if (txn->flags & MDBX_TXN_ERROR) {
goto fail; rc = MDBX_RESULT_TRUE;
goto fail;
}
goto done;
} }
/* txn_end() mode for a commit which writes nothing */ if (!txn->parent && (txn->flags & MDBX_NOSTICKYTHREADS) && unlikely(txn->owner != osal_thread_self())) {
unsigned end_mode = TXN_END_PURE_COMMIT | TXN_END_UPDATE | TXN_END_SLOT | TXN_END_FREE; txn->flags |= MDBX_TXN_ERROR;
if (unlikely(txn->flags & MDBX_TXN_RDONLY))
goto done;
if ((txn->flags & MDBX_NOSTICKYTHREADS) && unlikely(txn->owner != osal_thread_self())) {
rc = MDBX_THREAD_MISMATCH; rc = MDBX_THREAD_MISMATCH;
return LOG_IFERR(rc);
}
if (unlikely(txn->flags & MDBX_TXN_ERROR)) {
rc = MDBX_RESULT_TRUE;
goto fail; goto fail;
} }

View File

@ -400,32 +400,35 @@ static inline int check_env(const MDBX_env *env, const bool wanna_active) {
return MDBX_SUCCESS; return MDBX_SUCCESS;
} }
static inline int check_txn(const MDBX_txn *txn, int bad_bits) { static __always_inline int check_txn(const MDBX_txn *txn, int bad_bits) {
if (unlikely(!txn)) if (unlikely(!txn))
return MDBX_EINVAL; return MDBX_EINVAL;
if (unlikely(txn->signature != txn_signature)) if (unlikely(txn->signature != txn_signature))
return MDBX_EBADSIGN; return MDBX_EBADSIGN;
if (bad_bits && unlikely(txn->flags & bad_bits)) { if (bad_bits) {
if ((bad_bits & MDBX_TXN_PARKED) == 0) if (unlikely(!txn->env->dxb_mmap.base))
return MDBX_BAD_TXN; return MDBX_EPERM;
else
return txn_check_badbits_parked(txn, bad_bits); if (unlikely(txn->flags & bad_bits)) {
if ((bad_bits & MDBX_TXN_PARKED) == 0)
return MDBX_BAD_TXN;
else
return txn_check_badbits_parked(txn, bad_bits);
}
} }
tASSERT(txn, (txn->flags & MDBX_TXN_FINISHED) || tASSERT(txn, (txn->flags & MDBX_TXN_FINISHED) ||
(txn->flags & MDBX_NOSTICKYTHREADS) == (txn->env->flags & MDBX_NOSTICKYTHREADS)); (txn->flags & MDBX_NOSTICKYTHREADS) == (txn->env->flags & MDBX_NOSTICKYTHREADS));
#if MDBX_TXN_CHECKOWNER #if MDBX_TXN_CHECKOWNER
STATIC_ASSERT((long)MDBX_NOSTICKYTHREADS > (long)MDBX_TXN_FINISHED); if ((txn->flags & (MDBX_NOSTICKYTHREADS | MDBX_TXN_FINISHED)) != MDBX_NOSTICKYTHREADS &&
if ((txn->flags & (MDBX_NOSTICKYTHREADS | MDBX_TXN_FINISHED)) < MDBX_TXN_FINISHED && !(bad_bits /* abort/reset/txn-break */ == 0 &&
((txn->flags & (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED)) == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED))) &&
unlikely(txn->owner != osal_thread_self())) unlikely(txn->owner != osal_thread_self()))
return txn->owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN; return txn->owner ? MDBX_THREAD_MISMATCH : MDBX_BAD_TXN;
#endif /* MDBX_TXN_CHECKOWNER */ #endif /* MDBX_TXN_CHECKOWNER */
if (bad_bits && unlikely(!txn->env->dxb_mmap.base))
return MDBX_EPERM;
return MDBX_SUCCESS; return MDBX_SUCCESS;
} }