From b054a69e72c01b3ac98b060b7426e2d9c7c8632f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Sun, 11 Aug 2024 00:00:22 +0300 Subject: [PATCH] =?UTF-8?q?mdbx:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8=20=D1=80=D0=B5=D1=84?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=86=D0=B8?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=B0-=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=86=20=D0=BF=D1=80=D0=B8=20=D1=81=D1=82=D0=B0=D1=80=D1=82?= =?UTF-8?q?=D0=B5=20=D1=87=D0=B8=D1=82=D0=B0=D1=8E=D1=89=D0=B8=D1=85=20?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Сценарий достаточно запутанный/сложный. --- src/api-env.c | 2 +- src/coherency.c | 10 ++++--- src/proto.h | 2 +- src/txn.c | 75 ++++++++++++++++++++++++++++--------------------- 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/api-env.c b/src/api-env.c index 4aa7bd2e..48324f68 100644 --- a/src/api-env.c +++ b/src/api-env.c @@ -1274,7 +1274,7 @@ __cold int mdbx_env_set_geometry(MDBX_env *env, intptr_t size_lower, uint64_t timestamp = 0; while ("workaround for " "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)) break; if (unlikely(rc != MDBX_RESULT_TRUE)) diff --git a/src/coherency.c b/src/coherency.c index 9e55a894..7701271b 100644 --- a/src/coherency.c +++ b/src/coherency.c @@ -152,18 +152,20 @@ __cold int coherency_timeout(uint64_t *timestamp, intptr_t pgno, /* check with timeout as the workaround * 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) { /* 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)); STATIC_ASSERT(sizeof(head.ptr_c->trees) == CORE_DBS * sizeof(tree_t)); VALGRIND_MAKE_MEM_UNDEFINED(txn->dbs + 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, - *timestamp == 0))) + *timestamp == 0) || + txn->txnid != meta_txnid(head.ptr_v))) return coherency_timeout(timestamp, -1, txn->env); if (unlikely(txn->dbs[FREE_DBI].flags != MDBX_INTEGERKEY)) { diff --git a/src/proto.h b/src/proto.h index 531196c0..80f9394b 100644 --- a/src/proto.h +++ b/src/proto.h @@ -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, const volatile meta_t *meta, 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); MDBX_INTERNAL int coherency_check_written(const MDBX_env *env, const txnid_t txnid, diff --git a/src/txn.c b/src/txn.c index 845c0436..bd8a1a59 100644 --- a/src/txn.c +++ b/src/txn.c @@ -982,7 +982,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) { likely(env->stuck_meta < 0) ? /* regular */ meta_recent(env, &troika) : /* recovery mode */ meta_ptr(env, env->stuck_meta); - if (likely(r)) { + if (likely(r != nullptr)) { safe64_reset(&r->txnid, true); atomic_store32(&r->snapshot_pages_used, head.ptr_v->geometry.first_unallocated, mo_Relaxed); @@ -1005,46 +1005,57 @@ int txn_renew(MDBX_txn *txn, unsigned flags) { } jitter4testing(true); - /* Snap the state from current meta-head */ - txn->txnid = head.txnid; - if (likely(env->stuck_meta < 0) && - unlikely(meta_should_retry(env, &troika) || - head.txnid < atomic_load64(&env->lck->cached_oldest, - 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; + if (unlikely(meta_should_retry(env, &troika))) { + retry: + if (likely(++loop < 42)) { + timestamp = 0; + continue; } - timestamp = 0; - continue; + ERROR("bailout waiting for valid snapshot (%s)", + "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); - if (likely(rc == MDBX_SUCCESS)) - break; - - if (unlikely(rc != MDBX_RESULT_TRUE)) { - txn->txnid = INVALID_TXNID; - if (likely(r)) - safe64_reset(&r->txnid, true); - goto bailout; + 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!"); - if (likely(r)) - safe64_reset(&r->txnid, true); - txn->txnid = INVALID_TXNID; rc = MDBX_CORRUPTED; + read_failed: + txn->txnid = INVALID_TXNID; + if (likely(r != nullptr)) + safe64_reset(&r->txnid, true); goto bailout; } + + tASSERT(txn, rc == MDBX_SUCCESS); ENSURE(env, txn->txnid >= /* 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); uint64_t timestamp = 0; 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)) break; if (unlikely(rc != MDBX_RESULT_TRUE)) goto bailout; } - eASSERT(env, meta_txnid(head.ptr_v) == head.txnid); - txn->txnid = safe64_txnid_next(head.txnid); + eASSERT(env, meta_txnid(head.ptr_v) == txn->txnid); + txn->txnid = safe64_txnid_next(txn->txnid); if (unlikely(txn->txnid > MAX_TXNID)) { rc = MDBX_TXN_FULL; ERROR("txnid overflow, raise %d", rc);