diff --git a/src/dbi.c b/src/dbi.c index 871632a8..ef7a1411 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -84,7 +84,7 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) { /* dbi-слот еще не инициализирован в транзакции, а хендл не использовался */ txn->cursors[dbi] = nullptr; MDBX_txn *const parent = txn->parent; - if (parent) { + if (unlikely(parent)) { /* вложенная пишущая транзакция */ int rc = dbi_check(parent, dbi); /* копируем состояние dbi-хендла очищая new-флаги. */ @@ -100,26 +100,31 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) { txn->dbi_state[dbi] = DBI_LINDO; } else { eASSERT(env, txn->dbi_seqs[dbi] != env->dbi_seqs[dbi].weak); - if (unlikely((txn->dbi_state[dbi] & (DBI_VALID | DBI_OLDEN)) || txn->cursors[dbi])) { - /* хендл уже использовался в транзакции, но был закрыт или переоткрыт, - * либо при явном пере-открытии хендла есть висячие курсоры */ - eASSERT(env, (txn->dbi_state[dbi] & DBI_STALE) == 0); + if (unlikely(txn->cursors[dbi])) { + /* хендл уже использовался в транзакции и остались висячие курсоры */ txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak; txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO; - return txn->cursors[dbi] ? MDBX_DANGLING_DBI : MDBX_BAD_DBI; + return MDBX_DANGLING_DBI; + } + if (unlikely(txn->dbi_state[dbi] & (DBI_OLDEN | DBI_VALID))) { + /* хендл уже использовался в транзакции, но был закрыт или переоткрыт, + * висячих курсоров нет */ + txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak; + txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO; + return MDBX_BAD_DBI; } } /* хендл не использовался в транзакции, либо явно пере-отрывается при * отсутствии висячих курсоров */ - eASSERT(env, (txn->dbi_state[dbi] & DBI_LINDO) && !txn->cursors[dbi]); + eASSERT(env, (txn->dbi_state[dbi] & (DBI_LINDO | DBI_VALID)) == DBI_LINDO && !txn->cursors[dbi]); /* читаем актуальные флаги и sequence */ struct dbi_snap_result snap = dbi_snap(env, dbi); txn->dbi_seqs[dbi] = snap.sequence; if (snap.flags & DB_VALID) { txn->dbs[dbi].flags = snap.flags & DB_PERSISTENT_FLAGS; - txn->dbi_state[dbi] = DBI_LINDO | DBI_VALID | DBI_STALE; + txn->dbi_state[dbi] = (dbi >= CORE_DBS) ? DBI_LINDO | DBI_VALID | DBI_STALE : DBI_LINDO | DBI_VALID; return MDBX_SUCCESS; } return MDBX_BAD_DBI; diff --git a/src/txn.c b/src/txn.c index 93f3d66f..9b70367e 100644 --- a/src/txn.c +++ b/src/txn.c @@ -155,7 +155,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) { txn->dbi_seqs[FREE_DBI] = 0; txn->dbi_seqs[MAIN_DBI] = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease); - if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags))) { + if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags) || !txn->dbi_seqs[MAIN_DBI])) { const bool need_txn_lock = env->basal_txn && env->basal_txn->owner != osal_thread_self(); bool should_unlock = false; if (need_txn_lock) { @@ -167,24 +167,24 @@ int txn_renew(MDBX_txn *txn, unsigned flags) { } rc = osal_fastmutex_acquire(&env->dbi_lock); if (likely(rc == MDBX_SUCCESS)) { - uint32_t seq = dbi_seq_next(env, MAIN_DBI); /* проверяем повторно после захвата блокировки */ + uint32_t seq = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease); if (env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags)) { - if (!need_txn_lock || should_unlock || - /* если нет активной пишущей транзакции, - * то следующая будет ждать на dbi_lock */ - !env->txn) { - if (env->dbs_flags[MAIN_DBI] != 0 || MDBX_DEBUG) + if (!(env->dbs_flags[MAIN_DBI] & DB_VALID) || !need_txn_lock || should_unlock || + /* если нет активной пишущей транзакции, * то следующая будет ждать на dbi_lock */ !env->txn) { + if (env->dbs_flags[MAIN_DBI] & DB_VALID) { NOTICE("renew MainDB for %s-txn %" PRIaTXN " since db-flags changes 0x%x -> 0x%x", (txn->flags & MDBX_TXN_RDONLY) ? "ro" : "rw", txn->txnid, env->dbs_flags[MAIN_DBI] & ~DB_VALID, txn->dbs[MAIN_DBI].flags); - env->dbs_flags[MAIN_DBI] = DB_POISON; - atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease); + seq = dbi_seq_next(env, MAIN_DBI); + env->dbs_flags[MAIN_DBI] = DB_POISON; + atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease); + } rc = tbl_setup(env, &env->kvs[MAIN_DBI], &txn->dbs[MAIN_DBI]); if (likely(rc == MDBX_SUCCESS)) { seq = dbi_seq_next(env, MAIN_DBI); env->dbs_flags[MAIN_DBI] = DB_VALID | txn->dbs[MAIN_DBI].flags; - txn->dbi_seqs[MAIN_DBI] = atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease); + atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease); } } else { ERROR("MainDB db-flags changes 0x%x -> 0x%x ahead of read-txn " @@ -193,6 +193,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) { rc = MDBX_INCOMPATIBLE; } } + txn->dbi_seqs[MAIN_DBI] = seq; ENSURE(env, osal_fastmutex_release(&env->dbi_lock) == MDBX_SUCCESS); } else { DEBUG("dbi_lock failed, err %d", rc);