mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-20 05:28:21 +08:00
mdbx: refine/simplify read-latch loop inside mdbx_txn_renew0()
.
1. Explicitly check and handle a race/collision case with `find_oldest_reader()`. 2. Handle "recovery mode" (me_stuck_meta >= 0) by the same code as for regular latch. 3. Add bailout error message for buggy compiler and/or hardware (paranoid).
This commit is contained in:
parent
434ad8edc8
commit
9421bb424d
125
src/core.c
125
src/core.c
@ -8054,84 +8054,77 @@ static int mdbx_txn_renew0(MDBX_txn *txn, const unsigned flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Seek & fetch the last meta */
|
/* Seek & fetch the last meta */
|
||||||
if (likely(/* not recovery mode */ env->me_stuck_meta < 0)) {
|
uint64_t timestamp = 0;
|
||||||
uint64_t timestamp = 0;
|
unsigned loop = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
meta_cache_clear(env);
|
meta_cache_clear(env);
|
||||||
volatile const MDBX_meta *const meta = meta_prefer_last(env);
|
volatile const MDBX_meta *const meta =
|
||||||
mdbx_jitter4testing(false);
|
likely(env->me_stuck_meta < 0)
|
||||||
const txnid_t snap = meta_txnid(env, meta);
|
? /* regular */ meta_prefer_last(env)
|
||||||
mdbx_jitter4testing(false);
|
: /* recovery mode */ METAPAGE(env, env->me_stuck_meta);
|
||||||
if (likely(r)) {
|
mdbx_jitter4testing(false);
|
||||||
safe64_reset(&r->mr_txnid, false);
|
const txnid_t target_txnid = meta_txnid(env, meta);
|
||||||
atomic_store32(&r->mr_snapshot_pages_used, meta->mm_geo.next,
|
mdbx_jitter4testing(false);
|
||||||
mo_Relaxed);
|
|
||||||
atomic_store64(&r->mr_snapshot_pages_retired,
|
|
||||||
unaligned_peek_u64_volatile(4, meta->mm_pages_retired),
|
|
||||||
mo_Relaxed);
|
|
||||||
safe64_write(&r->mr_txnid, snap);
|
|
||||||
mdbx_jitter4testing(false);
|
|
||||||
mdbx_assert(env, r->mr_pid.weak == mdbx_getpid());
|
|
||||||
mdbx_assert(
|
|
||||||
env, r->mr_tid.weak ==
|
|
||||||
((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
|
|
||||||
mdbx_assert(env, r->mr_txnid.weak == snap);
|
|
||||||
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
|
|
||||||
mo_AcquireRelease);
|
|
||||||
} else {
|
|
||||||
/* exclusive mode without lck */
|
|
||||||
}
|
|
||||||
mdbx_jitter4testing(true);
|
|
||||||
|
|
||||||
/* Snap the state from current meta-head */
|
|
||||||
txn->mt_txnid = snap;
|
|
||||||
txn->mt_geo = meta->mm_geo;
|
|
||||||
STATIC_ASSERT(CORE_DBS == 2);
|
|
||||||
txn->mt_dbs[0] = meta->mm_dbs[0];
|
|
||||||
txn->mt_dbs[1] = meta->mm_dbs[1];
|
|
||||||
txn->mt_canary = meta->mm_canary;
|
|
||||||
|
|
||||||
/* LY: Retry on a race, ITS#7970.
|
|
||||||
* The barrier is not needed here since C11-atomics are used,
|
|
||||||
* but it is reasonable paranoia to avoid compiler misoptimization
|
|
||||||
* and makes clarity for code readers. */
|
|
||||||
mdbx_compiler_barrier();
|
|
||||||
if (likely(meta == meta_prefer_last(env) &&
|
|
||||||
snap == meta_txnid(env, meta) &&
|
|
||||||
snap >= atomic_load64(&env->me_lck->mti_oldest_reader,
|
|
||||||
mo_AcquireRelease))) {
|
|
||||||
rc = meta_waittxnid(env, (const MDBX_meta *)meta, ×tamp);
|
|
||||||
mdbx_jitter4testing(false);
|
|
||||||
if (likely(rc == MDBX_SUCCESS))
|
|
||||||
break;
|
|
||||||
if (likely(rc == MDBX_RESULT_TRUE))
|
|
||||||
continue;
|
|
||||||
goto bailout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* r/o recovery mode */
|
|
||||||
MDBX_meta *const meta = METAPAGE(env, env->me_stuck_meta);
|
|
||||||
txn->mt_txnid = constmeta_txnid(env, meta);
|
|
||||||
txn->mt_geo = meta->mm_geo;
|
|
||||||
memcpy(txn->mt_dbs, meta->mm_dbs, CORE_DBS * sizeof(MDBX_db));
|
|
||||||
txn->mt_canary = meta->mm_canary;
|
|
||||||
if (likely(r)) {
|
if (likely(r)) {
|
||||||
|
safe64_reset(&r->mr_txnid, false);
|
||||||
atomic_store32(&r->mr_snapshot_pages_used, meta->mm_geo.next,
|
atomic_store32(&r->mr_snapshot_pages_used, meta->mm_geo.next,
|
||||||
mo_Relaxed);
|
mo_Relaxed);
|
||||||
atomic_store64(&r->mr_snapshot_pages_retired,
|
atomic_store64(&r->mr_snapshot_pages_retired,
|
||||||
unaligned_peek_u64(4, meta->mm_pages_retired),
|
unaligned_peek_u64_volatile(4, meta->mm_pages_retired),
|
||||||
mo_Relaxed);
|
mo_Relaxed);
|
||||||
atomic_store64(&r->mr_txnid, txn->mt_txnid, mo_Relaxed);
|
safe64_write(&r->mr_txnid, target_txnid);
|
||||||
mdbx_jitter4testing(false);
|
mdbx_jitter4testing(false);
|
||||||
mdbx_assert(env, r->mr_pid.weak == mdbx_getpid());
|
mdbx_assert(env, r->mr_pid.weak == mdbx_getpid());
|
||||||
mdbx_assert(
|
mdbx_assert(
|
||||||
env, r->mr_tid.weak ==
|
env, r->mr_tid.weak ==
|
||||||
((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
|
((env->me_flags & MDBX_NOTLS) ? 0 : mdbx_thread_self()));
|
||||||
mdbx_assert(env, r->mr_txnid.weak == txn->mt_txnid);
|
mdbx_assert(env,
|
||||||
|
r->mr_txnid.weak == target_txnid ||
|
||||||
|
(r->mr_txnid.weak >= SAFE64_INVALID_THRESHOLD &&
|
||||||
|
target_txnid < env->me_lck->mti_oldest_reader.weak));
|
||||||
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
|
atomic_store32(&env->me_lck->mti_readers_refresh_flag, true,
|
||||||
mo_Relaxed);
|
mo_AcquireRelease);
|
||||||
|
} else {
|
||||||
|
/* exclusive mode without lck */
|
||||||
|
mdbx_assert(env, !env->me_lck_mmap.lck &&
|
||||||
|
env->me_lck == (void *)&env->x_lckless_stub);
|
||||||
}
|
}
|
||||||
|
mdbx_jitter4testing(true);
|
||||||
|
|
||||||
|
/* Snap the state from current meta-head */
|
||||||
|
txn->mt_txnid = target_txnid;
|
||||||
|
txn->mt_geo = meta->mm_geo;
|
||||||
|
STATIC_ASSERT(CORE_DBS == 2);
|
||||||
|
txn->mt_dbs[0] = meta->mm_dbs[0];
|
||||||
|
txn->mt_dbs[1] = meta->mm_dbs[1];
|
||||||
|
txn->mt_canary = meta->mm_canary;
|
||||||
|
|
||||||
|
/* LY: Retry on a race, ITS#7970.
|
||||||
|
* The barrier is not needed here since C11-atomics are used,
|
||||||
|
* but it is reasonable paranoia to avoid compiler misoptimization
|
||||||
|
* and makes clarity for code readers. */
|
||||||
|
mdbx_compiler_barrier();
|
||||||
|
const txnid_t oldest =
|
||||||
|
atomic_load64(&env->me_lck->mti_oldest_reader, mo_AcquireRelease);
|
||||||
|
if (unlikely(target_txnid < oldest ||
|
||||||
|
(meta != meta_prefer_last(env) && env->me_stuck_meta < 0) ||
|
||||||
|
target_txnid != meta_txnid(env, meta))) {
|
||||||
|
if (unlikely(++loop > 42)) {
|
||||||
|
mdbx_error("bailout waiting for valid snapshot (%s)",
|
||||||
|
"metapages are too volatile");
|
||||||
|
rc = MDBX_PROBLEM;
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
timestamp = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = meta_waittxnid(env, meta, ×tamp);
|
||||||
|
mdbx_jitter4testing(false);
|
||||||
|
if (likely(rc == MDBX_SUCCESS))
|
||||||
|
break;
|
||||||
|
if (unlikely(rc != MDBX_RESULT_TRUE))
|
||||||
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(txn->mt_txnid < MIN_TXNID || txn->mt_txnid > MAX_TXNID)) {
|
if (unlikely(txn->mt_txnid < MIN_TXNID || txn->mt_txnid > MAX_TXNID)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user