mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-29 23:19:20 +08:00
mdbx: доработка mdbx_close_dbi()
для возврата MDBX_DANGLING_DBI
при попытке закрыть dbi-хендл измененной в транзакции таблицы.
This commit is contained in:
parent
7232d7b5fc
commit
3049bb87b5
47
src/dbi.c
47
src/dbi.c
@ -859,8 +859,53 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
return MDBX_BAD_DBI;
|
||||
|
||||
rc = osal_fastmutex_acquire(&env->dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
if (likely(rc == MDBX_SUCCESS && dbi < env->n_dbi)) {
|
||||
retry:
|
||||
if (env->basal_txn && (env->dbs_flags[dbi] & DB_VALID) &&
|
||||
(env->basal_txn->flags & MDBX_TXN_FINISHED) == 0) {
|
||||
/* LY: Опасный код, так как env->txn может быть изменено в другом потоке.
|
||||
* К сожалению тут нет надежного решения и может быть падение при неверном
|
||||
* использовании API (вызове mdbx_dbi_close конкурентно с завершением
|
||||
* пишущей транзакции).
|
||||
*
|
||||
* Для минимизации вероятности падения сначала проверяем dbi-флаги
|
||||
* в basal_txn, а уже после в env->txn. Таким образом, падение может быть
|
||||
* только при коллизии с завершением вложенной транзакции.
|
||||
*
|
||||
* Альтернативно можно попробовать выполнять обновление/put записи в
|
||||
* mainDb соответствующей таблице закрываемого хендла. Семантически это
|
||||
* верный путь, но проблема в текущем API, в котором исторически dbi-хендл
|
||||
* живет и закрывается вне транзакции. Причем проблема не только в том,
|
||||
* что нет указателя на текущую пишущую транзакцию, а в том что
|
||||
* пользователь точно не ожидает что закрытие хендла приведет к
|
||||
* скрытой/непрозрачной активности внутри транзакции потенциально
|
||||
* выполняемой в другом потоке. Другими словами, проблема может быть
|
||||
* только при неверном использовании API и если пользователь это
|
||||
* допускает, то точно не будет ожидать скрытых действий внутри
|
||||
* транзакции, и поэтому этот путь потенциально более опасен. */
|
||||
const MDBX_txn *const hazard = env->txn;
|
||||
osal_compiler_barrier();
|
||||
if ((dbi_state(env->basal_txn, dbi) &
|
||||
(DBI_LINDO | DBI_DIRTY | DBI_CREAT)) > DBI_LINDO) {
|
||||
bailout_dirty_dbi:
|
||||
osal_fastmutex_release(&env->dbi_lock);
|
||||
return MDBX_DANGLING_DBI;
|
||||
}
|
||||
osal_memory_barrier();
|
||||
if (unlikely(hazard != env->txn))
|
||||
goto retry;
|
||||
if (hazard != env->basal_txn && hazard &&
|
||||
(hazard->flags & MDBX_TXN_FINISHED) == 0 &&
|
||||
hazard->signature == txn_signature &&
|
||||
(dbi_state(hazard, dbi) & (DBI_LINDO | DBI_DIRTY | DBI_CREAT)) >
|
||||
DBI_LINDO)
|
||||
goto bailout_dirty_dbi;
|
||||
osal_compiler_barrier();
|
||||
if (unlikely(hazard != env->txn))
|
||||
goto retry;
|
||||
}
|
||||
rc = defer_and_release(env, dbi_close_locked(env, dbi));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user