mdbx: rework find_oldest_reader().

1. Fix regression `assert: oldest >= lck->mti_oldest_reader.weak` after d4bf0a3332c7b05331ab0a87e3cd65b0903edc3c.
2. Add explicit check, kick and notice for stuck reader.
3. Made more e2k-frendly.
This commit is contained in:
Леонид Юрьев (Leonid Yuriev) 2022-07-08 22:14:28 +03:00
parent d572052178
commit a4a35ce9cb

View File

@ -5952,53 +5952,66 @@ static const char *mdbx_durable_str(volatile const MDBX_meta *const meta) {
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
/* Find oldest txnid still referenced. */ /* Find oldest txnid still referenced. */
static txnid_t find_oldest_reader(const MDBX_env *env) { static txnid_t find_oldest_reader(MDBX_env *env) {
const txnid_t steady_edge = const uint32_t nothing_changed = MDBX_STRING_TETRAD("None");
constmeta_txnid(env, constmeta_prefer_steady(env)); const txnid_t steady = constmeta_txnid(env, constmeta_prefer_steady(env));
mdbx_assert(env, steady_edge <= env->me_txn0->mt_txnid); mdbx_assert(env, steady <= env->me_txn0->mt_txnid);
MDBX_lockinfo *const lck = env->me_lck_mmap.lck; MDBX_lockinfo *const lck = env->me_lck_mmap.lck;
if (unlikely(lck == NULL /* exclusive without-lck mode */)) { if (unlikely(lck == NULL /* exclusive without-lck mode */)) {
mdbx_assert(env, env->me_lck == (void *)&env->x_lckless_stub); mdbx_assert(env, env->me_lck == (void *)&env->x_lckless_stub);
return env->me_lck->mti_oldest_reader.weak = steady_edge; return env->me_lck->mti_oldest_reader.weak = steady;
} }
const txnid_t last_oldest = const txnid_t prev_oldest =
atomic_load64(&lck->mti_oldest_reader, mo_AcquireRelease); atomic_load64(&lck->mti_oldest_reader, mo_AcquireRelease);
mdbx_assert(env, steady_edge >= last_oldest); mdbx_assert(env, steady >= prev_oldest);
if (likely(last_oldest == steady_edge))
return steady_edge;
const uint32_t nothing_changed = MDBX_STRING_TETRAD("None"); txnid_t new_oldest = prev_oldest;
const uint32_t snap_readers_refresh_flag = while (new_oldest != steady &&
atomic_load32(&lck->mti_readers_refresh_flag, mo_AcquireRelease); nothing_changed !=
mdbx_jitter4testing(false); atomic_load32(&lck->mti_readers_refresh_flag, mo_AcquireRelease)) {
if (snap_readers_refresh_flag == nothing_changed) lck->mti_readers_refresh_flag.weak = nothing_changed;
return last_oldest; mdbx_jitter4testing(false);
const unsigned snap_nreaders =
atomic_load32(&lck->mti_numreaders, mo_AcquireRelease);
new_oldest = steady;
atomic_store32(&lck->mti_readers_refresh_flag, nothing_changed, mo_Relaxed); for (unsigned i = 0; i < snap_nreaders; ++i) {
const unsigned snap_nreaders = const mdbx_pid_t pid =
atomic_load32(&lck->mti_numreaders, mo_AcquireRelease); atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease);
txnid_t oldest = steady_edge; if (!pid)
for (unsigned i = 0; i < snap_nreaders; ++i) { continue;
if (atomic_load32(&lck->mti_readers[i].mr_pid, mo_AcquireRelease)) { mdbx_jitter4testing(true);
/* mdbx_jitter4testing(true); */
const txnid_t snap = safe64_read(&lck->mti_readers[i].mr_txnid); const txnid_t rtxn = safe64_read(&lck->mti_readers[i].mr_txnid);
if (oldest > snap && /* ignore pending updates */ snap <= steady_edge) { if (unlikely(rtxn < prev_oldest)) {
oldest = snap; if (unlikely(nothing_changed ==
if (oldest == last_oldest) atomic_load32(&lck->mti_readers_refresh_flag,
return oldest; mo_AcquireRelease)) &&
safe64_reset_compare(&lck->mti_readers[i].mr_txnid, rtxn)) {
mdbx_notice("kick stuck reader[%u of %u].pid_%u %" PRIaTXN
" < prev-oldest %" PRIaTXN ", steady-txn %" PRIaTXN,
i, snap_nreaders, pid, rtxn, prev_oldest, steady);
}
continue;
}
if (rtxn < new_oldest) {
new_oldest = rtxn;
if (!MDBX_DEBUG && !MDBX_FORCE_ASSERTIONS && new_oldest == prev_oldest)
break;
} }
} }
}
if (oldest != last_oldest) { if (new_oldest != prev_oldest) {
mdbx_verbose("update oldest %" PRIaTXN " -> %" PRIaTXN, last_oldest, mdbx_verbose("update oldest %" PRIaTXN " -> %" PRIaTXN, prev_oldest,
oldest); new_oldest);
mdbx_assert(env, oldest >= lck->mti_oldest_reader.weak); mdbx_assert(env, new_oldest >= lck->mti_oldest_reader.weak);
atomic_store64(&lck->mti_oldest_reader, oldest, mo_Relaxed); atomic_store64(&lck->mti_oldest_reader, new_oldest, mo_Relaxed);
}
} }
return oldest; return new_oldest;
} }
/* Find largest mvcc-snapshot still referenced. */ /* Find largest mvcc-snapshot still referenced. */