mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-29 23:19:20 +08:00
mdbx: исправление и рефакторинг цикла чтения мета-страниц при старте читающих транзакций.
Сценарий достаточно запутанный/сложный.
This commit is contained in:
parent
aca692212f
commit
b054a69e72
@ -1274,7 +1274,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower,
|
|||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
while ("workaround for "
|
while ("workaround for "
|
||||||
"https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
"https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
||||||
rc = coherency_check_head(env->basal_txn, head, ×tamp);
|
rc = coherency_fetch_head(env->basal_txn, head, ×tamp);
|
||||||
if (likely(rc == MDBX_SUCCESS))
|
if (likely(rc == MDBX_SUCCESS))
|
||||||
break;
|
break;
|
||||||
if (unlikely(rc != MDBX_RESULT_TRUE))
|
if (unlikely(rc != MDBX_RESULT_TRUE))
|
||||||
|
@ -152,18 +152,20 @@ __cold int coherency_timeout(uint64_t *timestamp, intptr_t pgno,
|
|||||||
|
|
||||||
/* check with timeout as the workaround
|
/* check with timeout as the workaround
|
||||||
* for https://libmdbx.dqdkfa.ru/dead-github/issues/269 */
|
* for https://libmdbx.dqdkfa.ru/dead-github/issues/269 */
|
||||||
__hot int coherency_check_head(MDBX_txn *txn, const meta_ptr_t head,
|
__hot int coherency_fetch_head(MDBX_txn *txn, const meta_ptr_t head,
|
||||||
uint64_t *timestamp) {
|
uint64_t *timestamp) {
|
||||||
/* Copy the DB info and flags */
|
/* Copy the DB info and flags */
|
||||||
txn->geo = head.ptr_v->geometry;
|
txn->txnid = head.txnid;
|
||||||
|
txn->geo = head.ptr_c->geometry;
|
||||||
memcpy(txn->dbs, &head.ptr_c->trees, sizeof(head.ptr_c->trees));
|
memcpy(txn->dbs, &head.ptr_c->trees, sizeof(head.ptr_c->trees));
|
||||||
STATIC_ASSERT(sizeof(head.ptr_c->trees) == CORE_DBS * sizeof(tree_t));
|
STATIC_ASSERT(sizeof(head.ptr_c->trees) == CORE_DBS * sizeof(tree_t));
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(txn->dbs + CORE_DBS,
|
VALGRIND_MAKE_MEM_UNDEFINED(txn->dbs + CORE_DBS,
|
||||||
txn->env->max_dbi - CORE_DBS);
|
txn->env->max_dbi - CORE_DBS);
|
||||||
txn->canary = head.ptr_v->canary;
|
txn->canary = head.ptr_c->canary;
|
||||||
|
|
||||||
if (unlikely(!coherency_check(txn->env, head.txnid, txn->dbs, head.ptr_v,
|
if (unlikely(!coherency_check(txn->env, head.txnid, txn->dbs, head.ptr_v,
|
||||||
*timestamp == 0)))
|
*timestamp == 0) ||
|
||||||
|
txn->txnid != meta_txnid(head.ptr_v)))
|
||||||
return coherency_timeout(timestamp, -1, txn->env);
|
return coherency_timeout(timestamp, -1, txn->env);
|
||||||
|
|
||||||
if (unlikely(txn->dbs[FREE_DBI].flags != MDBX_INTEGERKEY)) {
|
if (unlikely(txn->dbs[FREE_DBI].flags != MDBX_INTEGERKEY)) {
|
||||||
|
@ -113,7 +113,7 @@ MDBX_INTERNAL int __must_check_result tbl_setup(const MDBX_env *env,
|
|||||||
MDBX_INTERNAL bool coherency_check_meta(const MDBX_env *env,
|
MDBX_INTERNAL bool coherency_check_meta(const MDBX_env *env,
|
||||||
const volatile meta_t *meta,
|
const volatile meta_t *meta,
|
||||||
bool report);
|
bool report);
|
||||||
MDBX_INTERNAL int coherency_check_head(MDBX_txn *txn, const meta_ptr_t head,
|
MDBX_INTERNAL int coherency_fetch_head(MDBX_txn *txn, const meta_ptr_t head,
|
||||||
uint64_t *timestamp);
|
uint64_t *timestamp);
|
||||||
MDBX_INTERNAL int coherency_check_written(const MDBX_env *env,
|
MDBX_INTERNAL int coherency_check_written(const MDBX_env *env,
|
||||||
const txnid_t txnid,
|
const txnid_t txnid,
|
||||||
|
75
src/txn.c
75
src/txn.c
@ -982,7 +982,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
|||||||
likely(env->stuck_meta < 0)
|
likely(env->stuck_meta < 0)
|
||||||
? /* regular */ meta_recent(env, &troika)
|
? /* regular */ meta_recent(env, &troika)
|
||||||
: /* recovery mode */ meta_ptr(env, env->stuck_meta);
|
: /* recovery mode */ meta_ptr(env, env->stuck_meta);
|
||||||
if (likely(r)) {
|
if (likely(r != nullptr)) {
|
||||||
safe64_reset(&r->txnid, true);
|
safe64_reset(&r->txnid, true);
|
||||||
atomic_store32(&r->snapshot_pages_used,
|
atomic_store32(&r->snapshot_pages_used,
|
||||||
head.ptr_v->geometry.first_unallocated, mo_Relaxed);
|
head.ptr_v->geometry.first_unallocated, mo_Relaxed);
|
||||||
@ -1005,46 +1005,57 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
|||||||
}
|
}
|
||||||
jitter4testing(true);
|
jitter4testing(true);
|
||||||
|
|
||||||
/* Snap the state from current meta-head */
|
if (unlikely(meta_should_retry(env, &troika))) {
|
||||||
txn->txnid = head.txnid;
|
retry:
|
||||||
if (likely(env->stuck_meta < 0) &&
|
if (likely(++loop < 42)) {
|
||||||
unlikely(meta_should_retry(env, &troika) ||
|
timestamp = 0;
|
||||||
head.txnid < atomic_load64(&env->lck->cached_oldest,
|
continue;
|
||||||
mo_AcquireRelease))) {
|
|
||||||
if (unlikely(++loop > 42)) {
|
|
||||||
ERROR("bailout waiting for valid snapshot (%s)",
|
|
||||||
"metapages are too volatile");
|
|
||||||
rc = MDBX_PROBLEM;
|
|
||||||
txn->txnid = INVALID_TXNID;
|
|
||||||
if (likely(r))
|
|
||||||
safe64_reset(&r->txnid, true);
|
|
||||||
goto bailout;
|
|
||||||
}
|
}
|
||||||
timestamp = 0;
|
ERROR("bailout waiting for valid snapshot (%s)",
|
||||||
continue;
|
"meta-pages are too volatile");
|
||||||
|
rc = MDBX_PROBLEM;
|
||||||
|
goto read_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = coherency_check_head(txn, head, ×tamp);
|
/* Snap the state from current meta-head */
|
||||||
|
rc = coherency_fetch_head(txn, head, ×tamp);
|
||||||
jitter4testing(false);
|
jitter4testing(false);
|
||||||
if (likely(rc == MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
break;
|
if (rc == MDBX_RESULT_TRUE)
|
||||||
|
goto retry;
|
||||||
if (unlikely(rc != MDBX_RESULT_TRUE)) {
|
else
|
||||||
txn->txnid = INVALID_TXNID;
|
goto read_failed;
|
||||||
if (likely(r))
|
|
||||||
safe64_reset(&r->txnid, true);
|
|
||||||
goto bailout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)) {
|
if (unlikely(txn->txnid < MIN_TXNID || txn->txnid > MAX_TXNID)) {
|
||||||
ERROR("%s", "environment corrupted by died writer, must shutdown!");
|
ERROR("%s", "environment corrupted by died writer, must shutdown!");
|
||||||
if (likely(r))
|
|
||||||
safe64_reset(&r->txnid, true);
|
|
||||||
txn->txnid = INVALID_TXNID;
|
|
||||||
rc = MDBX_CORRUPTED;
|
rc = MDBX_CORRUPTED;
|
||||||
|
read_failed:
|
||||||
|
txn->txnid = INVALID_TXNID;
|
||||||
|
if (likely(r != nullptr))
|
||||||
|
safe64_reset(&r->txnid, true);
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tASSERT(txn, rc == MDBX_SUCCESS);
|
||||||
ENSURE(env,
|
ENSURE(env,
|
||||||
txn->txnid >=
|
txn->txnid >=
|
||||||
/* paranoia is appropriate here */ env->lck->cached_oldest.weak);
|
/* paranoia is appropriate here */ env->lck->cached_oldest.weak);
|
||||||
@ -1092,14 +1103,14 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
|||||||
const meta_ptr_t head = meta_recent(env, &txn->tw.troika);
|
const meta_ptr_t head = meta_recent(env, &txn->tw.troika);
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
||||||
rc = coherency_check_head(txn, head, ×tamp);
|
rc = coherency_fetch_head(txn, head, ×tamp);
|
||||||
if (likely(rc == MDBX_SUCCESS))
|
if (likely(rc == MDBX_SUCCESS))
|
||||||
break;
|
break;
|
||||||
if (unlikely(rc != MDBX_RESULT_TRUE))
|
if (unlikely(rc != MDBX_RESULT_TRUE))
|
||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
eASSERT(env, meta_txnid(head.ptr_v) == head.txnid);
|
eASSERT(env, meta_txnid(head.ptr_v) == txn->txnid);
|
||||||
txn->txnid = safe64_txnid_next(head.txnid);
|
txn->txnid = safe64_txnid_next(txn->txnid);
|
||||||
if (unlikely(txn->txnid > MAX_TXNID)) {
|
if (unlikely(txn->txnid > MAX_TXNID)) {
|
||||||
rc = MDBX_TXN_FULL;
|
rc = MDBX_TXN_FULL;
|
||||||
ERROR("txnid overflow, raise %d", rc);
|
ERROR("txnid overflow, raise %d", rc);
|
||||||
|
Loading…
Reference in New Issue
Block a user