mirror of
https://github.com/isar/libmdbx.git
synced 2025-11-07 07:18:56 +08:00
mdbx: рефакторинг читающих транзакций в вычленением txn_ro_start(), txn_ro_seize(), txn_ro_slot().
This commit is contained in:
120
src/txn.c
120
src/txn.c
@@ -76,125 +76,9 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
|
||||
flags |= env->flags & (MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP);
|
||||
if (flags & MDBX_TXN_RDONLY) {
|
||||
eASSERT(env, (flags & ~(txn_ro_begin_flags | MDBX_WRITEMAP | MDBX_NOSTICKYTHREADS)) == 0);
|
||||
txn->flags = flags;
|
||||
reader_slot_t *r = txn->to.reader;
|
||||
STATIC_ASSERT(sizeof(uintptr_t) <= sizeof(r->tid));
|
||||
if (likely(env->flags & ENV_TXKEY)) {
|
||||
eASSERT(env, !(env->flags & MDBX_NOSTICKYTHREADS));
|
||||
r = thread_rthc_get(env->me_txkey);
|
||||
if (likely(r)) {
|
||||
if (unlikely(!r->pid.weak) && (globals.runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN)) {
|
||||
thread_rthc_set(env->me_txkey, nullptr);
|
||||
r = nullptr;
|
||||
} else {
|
||||
eASSERT(env, r->pid.weak == env->pid);
|
||||
eASSERT(env, r->tid.weak == osal_thread_self());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eASSERT(env, !env->lck_mmap.lck || (env->flags & MDBX_NOSTICKYTHREADS));
|
||||
}
|
||||
|
||||
if (likely(r)) {
|
||||
if (unlikely(r->pid.weak != env->pid || r->txnid.weak < SAFE64_INVALID_THRESHOLD))
|
||||
return MDBX_BAD_RSLOT;
|
||||
} else if (env->lck_mmap.lck) {
|
||||
bsr_t brs = mvcc_bind_slot(env);
|
||||
if (unlikely(brs.err != MDBX_SUCCESS))
|
||||
return brs.err;
|
||||
r = brs.rslot;
|
||||
}
|
||||
txn->to.reader = r;
|
||||
STATIC_ASSERT(MDBX_TXN_RDONLY_PREPARE > MDBX_TXN_RDONLY);
|
||||
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY)) {
|
||||
eASSERT(env, txn->txnid == 0);
|
||||
eASSERT(env, txn->owner == 0);
|
||||
eASSERT(env, txn->n_dbi == 0);
|
||||
if (likely(r)) {
|
||||
eASSERT(env, r->snapshot_pages_used.weak == 0);
|
||||
eASSERT(env, r->txnid.weak >= SAFE64_INVALID_THRESHOLD);
|
||||
atomic_store32(&r->snapshot_pages_used, 0, mo_Relaxed);
|
||||
}
|
||||
txn->flags = MDBX_TXN_RDONLY | MDBX_TXN_FINISHED;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
txn->owner = likely(r) ? (uintptr_t)r->tid.weak : ((env->flags & MDBX_NOSTICKYTHREADS) ? 0 : osal_thread_self());
|
||||
if ((env->flags & MDBX_NOSTICKYTHREADS) == 0 && env->txn && unlikely(env->basal_txn->owner == txn->owner) &&
|
||||
(globals.runtime_flags & MDBX_DBG_LEGACY_OVERLAP) == 0)
|
||||
return MDBX_TXN_OVERLAPPING;
|
||||
|
||||
/* Seek & fetch the last meta */
|
||||
uint64_t timestamp = 0;
|
||||
size_t loop = 0;
|
||||
troika_t troika = meta_tap(env);
|
||||
while (1) {
|
||||
const meta_ptr_t head = likely(env->stuck_meta < 0) ? /* regular */ meta_recent(env, &troika)
|
||||
: /* recovery mode */ meta_ptr(env, env->stuck_meta);
|
||||
if (likely(r != nullptr)) {
|
||||
safe64_reset(&r->txnid, true);
|
||||
atomic_store32(&r->snapshot_pages_used, head.ptr_v->geometry.first_unallocated, mo_Relaxed);
|
||||
atomic_store64(&r->snapshot_pages_retired, unaligned_peek_u64_volatile(4, head.ptr_v->pages_retired),
|
||||
mo_Relaxed);
|
||||
safe64_write(&r->txnid, head.txnid);
|
||||
eASSERT(env, r->pid.weak == osal_getpid());
|
||||
eASSERT(env, r->tid.weak == ((env->flags & MDBX_NOSTICKYTHREADS) ? 0 : osal_thread_self()));
|
||||
eASSERT(env, r->txnid.weak == head.txnid ||
|
||||
(r->txnid.weak >= SAFE64_INVALID_THRESHOLD && head.txnid < env->lck->cached_oldest.weak));
|
||||
atomic_store32(&env->lck->rdt_refresh_flag, true, mo_AcquireRelease);
|
||||
} else {
|
||||
/* exclusive mode without lck */
|
||||
eASSERT(env, !env->lck_mmap.lck && env->lck == lckless_stub(env));
|
||||
}
|
||||
jitter4testing(true);
|
||||
|
||||
if (unlikely(meta_should_retry(env, &troika))) {
|
||||
retry:
|
||||
if (likely(++loop < 42)) {
|
||||
timestamp = 0;
|
||||
continue;
|
||||
}
|
||||
ERROR("bailout waiting for valid snapshot (%s)", "meta-pages are too volatile");
|
||||
rc = MDBX_PROBLEM;
|
||||
goto read_failed;
|
||||
}
|
||||
|
||||
/* Snap the state from current meta-head */
|
||||
rc = coherency_fetch_head(txn, head, ×tamp);
|
||||
jitter4testing(false);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
goto retry;
|
||||
else
|
||||
goto read_failed;
|
||||
}
|
||||
|
||||
const uint64_t snap_oldest = atomic_load64(&env->lck->cached_oldest, mo_AcquireRelease);
|
||||
if (unlikely(txn->txnid < snap_oldest)) {
|
||||
if (env->stuck_meta < 0)
|
||||
goto retry;
|
||||
ERROR("target meta-page %i is referenced to an obsolete MVCC-snapshot "
|
||||
"%" PRIaTXN " < cached-oldest %" PRIaTXN,
|
||||
env->stuck_meta, txn->txnid, snap_oldest);
|
||||
rc = MDBX_MVCC_RETARDED;
|
||||
goto read_failed;
|
||||
}
|
||||
|
||||
if (likely(r != nullptr) && unlikely(txn->txnid != atomic_load64(&r->txnid, mo_Relaxed)))
|
||||
goto retry;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(txn->txnid < MIN_TXNID || txn->txnid > MAX_TXNID)) {
|
||||
ERROR("%s", "environment corrupted by died writer, must shutdown!");
|
||||
rc = MDBX_CORRUPTED;
|
||||
read_failed:
|
||||
txn->txnid = INVALID_TXNID;
|
||||
if (likely(r != nullptr))
|
||||
safe64_reset(&r->txnid, true);
|
||||
rc = txn_ro_start(txn, flags);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
tASSERT(txn, rc == MDBX_SUCCESS);
|
||||
ENSURE(env, txn->txnid >=
|
||||
/* paranoia is appropriate here */ env->lck->cached_oldest.weak);
|
||||
|
||||
Reference in New Issue
Block a user