mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-16 17:12:23 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b16c2570f0 | ||
|
|
ac8402283f | ||
|
|
945899e4fd | ||
|
|
222150bb28 | ||
|
|
497aabcb2e | ||
|
|
cf6d441e1b |
46
ChangeLog.md
46
ChangeLog.md
@@ -4,6 +4,49 @@ ChangeLog
|
||||
English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en)
|
||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||
|
||||
## v0.12.12 "Доллежаль" от 2024-10-27
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
в память о советском ученом-энергетике Николае Антоновиче Доллежаль в день 125-летия со дня его рождения.
|
||||
|
||||
Это последний выпуск куста стабильных версий 0.12.x, спустя более двух
|
||||
лет после выпуска 0.12.1. Последующие выпуски 0.12.x будут формироваться
|
||||
только в случае существенных проблем/ошибок, вероятность чего близка к
|
||||
нулю. Для всех проектов находящихся в стадии активной разраборки
|
||||
рекомендуется использовать ветку `master`.
|
||||
|
||||
```
|
||||
git diff' stat: x commits, y files changed, z insertions(+), zz deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Значимые исправления:
|
||||
|
||||
- Исправление упущенного `TXN_END_EOTDONE` при сбое старта читающей транзакции.
|
||||
Упомянутый флажок отсутствовал в пути разрушения транзакции при ошибке
|
||||
её запуска. Из-за чего делалась попытка разрушить курсоры, что приводило
|
||||
к падению **отладочных сборок**, так как в них соответствующий массив
|
||||
намеренно заполнен некорректными указателями.
|
||||
|
||||
- Устранение возможности `SIGSEGV` внутри `coherency_check()` после
|
||||
изменения геометрии другим процессом с увеличением верхнего размера БД
|
||||
и увеличением БД больше предыдущего лимита.
|
||||
|
||||
- Доработка `mdbx_close_dbi()` для возврата ошибки при попытке закрыть
|
||||
dbi-дескриптор таблицы, созданной и/или измененной в ещё выполняющейся
|
||||
транзакции. Такое преждевременное закрытие дескриптора является неверным
|
||||
использованием API и нарушением контракта/предусловий сформулированных
|
||||
в описании `mdbx_close_dbi()`. Однако, вместо возврата ошибки
|
||||
выполнялось некорректное закрытие дескриптора, что могло приводить к
|
||||
созданию таблицы с пустым именем, утечки страниц БД и/или нарушению
|
||||
структуры b-tree (неверной ссылкой на корень таблицы).
|
||||
Добавлен соответствующий тест `extra/early_close_dbi`.
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.11 "Лиза и Соня" от 2024-07-23
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов,
|
||||
@@ -71,6 +114,9 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
- Отключение установки признака фатальной ошибки для не-активной среды при отличии идентификатора процесса.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.10 "СЭМ" от 2024-03-12
|
||||
|
||||
Поддерживающий выпуск с исправлением обнаруженных ошибок и устранением недочетов
|
||||
|
||||
36
src/core.c
36
src/core.c
@@ -8703,7 +8703,9 @@ static bool coherency_check(const MDBX_env *env, const txnid_t txnid,
|
||||
: "(wagering meta)");
|
||||
ok = false;
|
||||
}
|
||||
if (likely(freedb_root && freedb_mod_txnid)) {
|
||||
if (likely(freedb_root && freedb_mod_txnid &&
|
||||
(size_t)ptr_dist(env->me_dxb_mmap.base, freedb_root) <
|
||||
env->me_dxb_mmap.limit)) {
|
||||
VALGRIND_MAKE_MEM_DEFINED(freedb_root, sizeof(freedb_root->mp_txnid));
|
||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(freedb_root,
|
||||
sizeof(freedb_root->mp_txnid));
|
||||
@@ -8719,7 +8721,9 @@ static bool coherency_check(const MDBX_env *env, const txnid_t txnid,
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (likely(maindb_root && maindb_mod_txnid)) {
|
||||
if (likely(maindb_root && maindb_mod_txnid &&
|
||||
(size_t)ptr_dist(env->me_dxb_mmap.base, maindb_root) <
|
||||
env->me_dxb_mmap.limit)) {
|
||||
VALGRIND_MAKE_MEM_DEFINED(maindb_root, sizeof(maindb_root->mp_txnid));
|
||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(maindb_root,
|
||||
sizeof(maindb_root->mp_txnid));
|
||||
@@ -9188,7 +9192,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) {
|
||||
}
|
||||
bailout:
|
||||
tASSERT(txn, rc != MDBX_SUCCESS);
|
||||
txn_end(txn, MDBX_END_SLOT | MDBX_END_FAIL_BEGIN);
|
||||
txn_end(txn, MDBX_END_SLOT | MDBX_END_EOTDONE | MDBX_END_FAIL_BEGIN);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -23130,9 +23134,29 @@ int mdbx_dbi_close(MDBX_env *env, MDBX_dbi dbi) {
|
||||
|
||||
rc = osal_fastmutex_acquire(&env->me_dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
rc = (dbi < env->me_maxdbs && (env->me_dbflags[dbi] & DB_VALID))
|
||||
? dbi_close_locked(env, dbi)
|
||||
: MDBX_BAD_DBI;
|
||||
retry:
|
||||
rc = MDBX_BAD_DBI;
|
||||
if (dbi < env->me_maxdbs && (env->me_dbflags[dbi] & DB_VALID)) {
|
||||
const MDBX_txn *const hazard = env->me_txn;
|
||||
osal_compiler_barrier();
|
||||
if (env->me_txn0 && (env->me_txn0->mt_flags & MDBX_TXN_FINISHED) == 0) {
|
||||
if (env->me_txn0->mt_dbistate[dbi] & (DBI_DIRTY | DBI_CREAT))
|
||||
goto bailout_dirty_dbi;
|
||||
osal_memory_barrier();
|
||||
if (unlikely(hazard != env->me_txn))
|
||||
goto retry;
|
||||
if (hazard != env->me_txn0 && hazard &&
|
||||
(hazard->mt_flags & MDBX_TXN_FINISHED) == 0 &&
|
||||
hazard->mt_signature == MDBX_MT_SIGNATURE &&
|
||||
(hazard->mt_dbistate[dbi] & (DBI_DIRTY | DBI_CREAT)))
|
||||
goto bailout_dirty_dbi;
|
||||
osal_compiler_barrier();
|
||||
if (unlikely(hazard != env->me_txn))
|
||||
goto retry;
|
||||
}
|
||||
rc = dbi_close_locked(env, dbi);
|
||||
}
|
||||
bailout_dirty_dbi:
|
||||
ENSURE(env, osal_fastmutex_release(&env->me_dbi_lock) == MDBX_SUCCESS);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -91,6 +91,20 @@ if(UNIX AND NOT SUBPROJECT)
|
||||
set_target_properties(test_extra_dupfixed_multiple PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
add_executable(test_extra_dbi extra/dbi.c++)
|
||||
target_include_directories(test_extra_dbi PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_dbi ${TOOL_MDBX_LIB})
|
||||
if(MDBX_CXX_STANDARD)
|
||||
set_target_properties(test_extra_dbi PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
add_executable(test_extra_early_close_dbi extra/early_close_dbi.c++)
|
||||
target_include_directories(test_extra_early_close_dbi PRIVATE "${PROJECT_SOURCE_DIR}")
|
||||
target_link_libraries(test_extra_early_close_dbi ${TOOL_MDBX_LIB})
|
||||
if(MDBX_CXX_STANDARD)
|
||||
set_target_properties(test_extra_early_close_dbi PROPERTIES
|
||||
CXX_STANDARD ${MDBX_CXX_STANDARD} CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -176,6 +190,7 @@ else()
|
||||
if(MDBX_BUILD_CXX)
|
||||
add_test(NAME extra_maindb_ordinal COMMAND test_extra_maindb_ordinal)
|
||||
add_test(NAME extra_dupfixed_multiple COMMAND test_extra_dupfixed_multiple)
|
||||
add_test(NAME extra_dbi COMMAND test_extra_dbi)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
38
test/extra/dbi.c++
Normal file
38
test/extra/dbi.c++
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "mdbx.h++"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static void logger(MDBX_log_level_t loglevel, const char *function, int line,
|
||||
const char *fmt, va_list args) noexcept {
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u ", function, line);
|
||||
vfprintf(stdout, fmt, args);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
mdbx_setup_debug(MDBX_LOG_NOTICE, MDBX_DBG_ASSERT, logger);
|
||||
|
||||
mdbx::path path = "test-dbi";
|
||||
mdbx::env::remove(path);
|
||||
|
||||
mdbx::env::operate_parameters operateParameters(100, 10);
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
{
|
||||
mdbx::env_managed env2(path, createParameters, operateParameters);
|
||||
mdbx::txn_managed txn2 = env2.start_write(false);
|
||||
/* mdbx::map_handle testHandle2 = */ txn2.create_map(
|
||||
"fap1", mdbx::key_mode::reverse, mdbx::value_mode::single);
|
||||
txn2.commit();
|
||||
}
|
||||
mdbx::env_managed env(path, createParameters, operateParameters);
|
||||
mdbx::txn_managed txn = env.start_write(false);
|
||||
/* mdbx::map_handle testHandle = */ txn.create_map(
|
||||
"fap1", mdbx::key_mode::usual, mdbx::value_mode::single);
|
||||
txn.commit();
|
||||
|
||||
std::cout << "OK\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
110
test/extra/early_close_dbi.c++
Normal file
110
test/extra/early_close_dbi.c++
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "mdbx.h++"
|
||||
#include <cstring>
|
||||
|
||||
static const char *const testkey = "testkey";
|
||||
static uint64_t testval = 11;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
mdbx::path db_filename = "test-early_close_dbi";
|
||||
mdbx::env_managed::remove(db_filename);
|
||||
|
||||
MDBX_env *environment;
|
||||
MDBX_MAYBE_UNUSED int err = mdbx_env_create(&environment);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
err = mdbx_env_set_option(environment, MDBX_opt_max_db, 2);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_env_set_option(environment, MDBX_opt_max_readers, 2);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
// status = mdbx_env_set_option(environment, MDBX_opt_prefault_write_enable,
|
||||
// 1); assert(err == MDBX_SUCCESS);
|
||||
|
||||
intptr_t lowerbound(0), size(0), upperbound(mdbx::env::geometry::GiB / 2);
|
||||
intptr_t step(128 * mdbx::env::geometry::MiB),
|
||||
shrink(256 * mdbx::env::geometry::MiB), pagesize(-1);
|
||||
err =
|
||||
#ifdef _WIN32
|
||||
mdbx_env_set_geometryW
|
||||
#else
|
||||
mdbx_env_set_geometry
|
||||
#endif
|
||||
(environment, lowerbound, size, upperbound, step, shrink, pagesize);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_env_flags_t flags(MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_LIFORECLAIM |
|
||||
MDBX_NORDAHEAD);
|
||||
err = mdbx_env_open(environment, db_filename.c_str(), flags, 0644);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
MDBX_txn *transaction;
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_READWRITE, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_dbi textindex;
|
||||
err = mdbx_dbi_open(transaction, "testdb", MDBX_DB_DEFAULTS, &textindex);
|
||||
assert(err == MDBX_NOTFOUND);
|
||||
err = mdbx_dbi_open(transaction, "testdb", MDBX_CREATE, &textindex);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_val mdbxkey{(void *)testkey, std::strlen(testkey)}, mdbxval{};
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_NOTFOUND);
|
||||
|
||||
unsigned dbi_flags, dbi_state;
|
||||
err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert((dbi_state & (MDBX_DBI_CREAT | MDBX_DBI_DIRTY)) != 0);
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err != MDBX_SUCCESS);
|
||||
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_READWRITE, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
MDBX_val mdbxput{&testval, sizeof(uint64_t)};
|
||||
err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_put(transaction, textindex, &mdbxkey, &mdbxput, MDBX_NOOVERWRITE);
|
||||
assert(err == MDBX_KEYEXIST);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_dbi_flags_ex(transaction, textindex, &dbi_flags, &dbi_state);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert((dbi_state & MDBX_DBI_DIRTY) != 0);
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err != MDBX_SUCCESS);
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
// ---
|
||||
|
||||
err = mdbx_txn_begin(environment, nullptr, MDBX_TXN_RDONLY, &transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_get(transaction, textindex, &mdbxkey, &mdbxval);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
assert(testval == *reinterpret_cast<uint64_t *>(mdbxval.iov_base));
|
||||
|
||||
err = mdbx_dbi_close(environment, textindex);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_txn_commit(transaction);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
err = mdbx_env_close_ex(environment, true);
|
||||
assert(err == MDBX_SUCCESS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user