mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-18 17:52:22 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a971c76aff | ||
|
|
b6f918aa1c | ||
|
|
ab2f661c97 | ||
|
|
5548ef20f6 | ||
|
|
679c1eb939 | ||
|
|
76a588f91b | ||
|
|
6b5515908b | ||
|
|
214fa153e2 | ||
|
|
819551ce13 | ||
|
|
a22c0c5c48 | ||
|
|
9540cabf5f | ||
|
|
0e3b093eb5 | ||
|
|
5d38add405 | ||
|
|
b55a41f604 | ||
|
|
29bed7cf5d | ||
|
|
8d0eceee9f | ||
|
|
56a6377622 | ||
|
|
19dc93fc76 | ||
|
|
5f1d8dcb3e | ||
|
|
3d2b221256 | ||
|
|
ca1808d57f | ||
|
|
aa98d6a88e | ||
|
|
b9b14f0061 |
71
ChangeLog.md
71
ChangeLog.md
@@ -4,6 +4,75 @@ ChangeLog
|
|||||||
English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__change_log.html?_x_tr_sl=ru&_x_tr_tl=en)
|
English version [by liar Google](https://libmdbx-dqdkfa-ru.translate.goog/md__change_log.html?_x_tr_sl=ru&_x_tr_tl=en)
|
||||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html).
|
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx.dqdkfa.ru/md__change_log.html).
|
||||||
|
|
||||||
|
## v0.13.6 "Бузина" от 2025-04-22.
|
||||||
|
|
||||||
|
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов,
|
||||||
|
в память о погибшем украинском историке и писателе [Алесе Бузине](https://ru.ruwiki.ru/wiki/Бузина,_Олесь_Алексеевич).
|
||||||
|
|
||||||
|
Благодарности:
|
||||||
|
|
||||||
|
- [Erigon](https://erigon.tech/) за спонсорство.
|
||||||
|
- [Илье Михееву](https://t.me/IlyaMkhv) и команде [Erigon](https://github.com/erigontech) за сообщения о проблеме и тестирование.
|
||||||
|
- [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения о проблеме копирования на NFS.
|
||||||
|
|
||||||
|
Исправления:
|
||||||
|
|
||||||
|
- Устранён регресс при использовании курсоров для DBI=0 (aka GC/FreeDB) в читающих транзакциях.
|
||||||
|
|
||||||
|
В результате рефакторинга и ряда оптимизаций для завершения/гашения
|
||||||
|
курсоров в читающих и пишущих транзакций, стал использоваться общий код.
|
||||||
|
Причем за основу, был взят соответствующий фрагмент относящийся к
|
||||||
|
пишущим транзакциям, в которых пользователю не позволяется
|
||||||
|
использоваться курсоры для DBI=0 и поэтому эта итераций пропускалась.
|
||||||
|
|
||||||
|
В результате, при завершении читающих транзакциях, курсоры связанные с
|
||||||
|
DBI=0 не завершались должным образом, а при их повторном использовании
|
||||||
|
или явном закрытии после завершения читающей транзакции происходило
|
||||||
|
обращение к уже освобожденной памяти. Если же такие курсоры
|
||||||
|
отсоединялись или закрывались до завершения читающей транзакции, то
|
||||||
|
ошибка не имела шансов на проявление.
|
||||||
|
|
||||||
|
- Устранён регресс в виде ошибки `EAGAIN` при копировании БД на NFS и CIFS/SMB.
|
||||||
|
|
||||||
|
При доработках/развитии API в функции копирования был добавлен захват
|
||||||
|
файловой блокировки посредством как `fcntl()`, так и `flock()`. Однако,
|
||||||
|
в зависимости от версии локального ядра, версии удалённого сервера NFS и
|
||||||
|
опций монтирования, это могло приводить к возврату POSIX-ошибки `EAGAIN`
|
||||||
|
(`11` на большинстве платформ, включая Linux).
|
||||||
|
|
||||||
|
- Устранена ошибка merge/rebase внутри `mdbx_txn_release_all_cursors_ex()`,
|
||||||
|
что могло приводить к последующим неожиданным ошибкам `MDBX_EBADSIGN` и утечкам памяти.
|
||||||
|
Для проверки сценария дополнен соответствующий тест.
|
||||||
|
|
||||||
|
- Исправлена assert-проверка в пути завершения вложенных транзакций.
|
||||||
|
Для проверки сценария дополнен соответствующий тест.
|
||||||
|
|
||||||
|
- Устранена возможность возврата неожиданной ошибки `MDBX_BUSY` из `mdbx_txn_lock(dont_wait=false)`.
|
||||||
|
|
||||||
|
- Для совместимости с GCC 15.x в режиме C23 изменен порядок указания атрибутов функций.
|
||||||
|
|
||||||
|
Изменение поведения:
|
||||||
|
|
||||||
|
- При невозможности отвязки курсора от его текущей транзакции функция `mdbx_cursor_bind()`
|
||||||
|
теперь возвращает `MDBX_EINVAL` вместо `MDBX_BAD_TXN`.
|
||||||
|
|
||||||
|
Прочие доработки:
|
||||||
|
|
||||||
|
- Во избежание потенциальных проблем отключено использование `copy_file_range()` на ядрах Linux 5.3 - 5.18.
|
||||||
|
|
||||||
|
- Вброс `std::invalid_argument` теперь производится явным сообщением `MDBX_EINVAL`.
|
||||||
|
|
||||||
|
- Уточнен тип адреса для пожертвований.
|
||||||
|
Ethereum/ERC-20 позволяет перечислять не только ETH, но и другие валюты/токены, в том числе USDC.
|
||||||
|
|
||||||
|
- Дополнен тест курсоров extra/cursor-closing.
|
||||||
|
|
||||||
|
- В `NOTICE` обновлена информация о Github.
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
## v0.13.5 "Труба" от 2025-03-21
|
## v0.13.5 "Труба" от 2025-03-21
|
||||||
|
|
||||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
||||||
@@ -107,7 +176,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
поломать родительскую, сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые
|
поломать родительскую, сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые
|
||||||
курсоры, что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения.
|
курсоры, что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения.
|
||||||
|
|
||||||
- В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вывоза `mdbx::cursor::txn()`.
|
- В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вызова `mdbx::cursor::txn()`.
|
||||||
|
|
||||||
Прочие доработки:
|
Прочие доработки:
|
||||||
|
|
||||||
|
|||||||
30
NOTICE
30
NOTICE
@@ -8,16 +8,32 @@ documentation, C++ API description and links to the original git repo
|
|||||||
with the source code. Questions, feedback and suggestions are welcome
|
with the source code. Questions, feedback and suggestions are welcome
|
||||||
to the Telegram' group https://t.me/libmdbx.
|
to the Telegram' group https://t.me/libmdbx.
|
||||||
|
|
||||||
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||||
Всё будет хорошо!
|
Всё будет хорошо!
|
||||||
|
|
||||||
Copyright 2015-2025 Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
|
Copyright 2015-2025 Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
For notes about the license change, credits and acknowledgments,
|
For notes about the license change, credits and acknowledgments,
|
||||||
please refer to the COPYRIGHT file within original libmdbx source code
|
please refer to the COPYRIGHT file within libmdbx source.
|
||||||
repository https://gitflic.ru/project/erthink/libmdbx
|
|
||||||
|
|
||||||
On 2022-04-15 the Github administration, without any warning nor
|
---
|
||||||
explanation, deleted _libmdbx_ along with a lot of other projects,
|
|
||||||
simultaneously blocking access for many developers.
|
On 2022-04-15, without any warnings or following explanations, the
|
||||||
For the same reason ~~Github~~ is blacklisted forever.
|
Github administration deleted _libmdbx_, my account and all other
|
||||||
|
projects (status 404). A few months later, without any involvement or
|
||||||
|
notification from/to me, the projects were restored/opened in the "public
|
||||||
|
read-only archive" status from some kind of incomplete backup. I regard
|
||||||
|
these actions of Github as malicious sabotage, and I consider the Github
|
||||||
|
service itself to have lost trust forever.
|
||||||
|
|
||||||
|
As a result of what has happened, I will never, under any circumstances,
|
||||||
|
post the primary sources (aka origins) of my projects on Github, or rely
|
||||||
|
in any way on the Github infrastructure.
|
||||||
|
|
||||||
|
Nevertheless, realizing that it is more convenient for users of
|
||||||
|
_libmdbx_ and other my projects to access ones on Github, I do not want
|
||||||
|
to restrict their freedom or create inconvenience, and therefore I place
|
||||||
|
mirrors (aka mirrors) of such repositories on Github since 2025. At the
|
||||||
|
same time, I would like to emphasize once again that these are only
|
||||||
|
mirrors that can be frozen, blocked or deleted at any time, as was the
|
||||||
|
case in 2022.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
> [5](https://libmdbx.dqdkfa.ru/tg-archive/messages5.html), [6](https://libmdbx.dqdkfa.ru/tg-archive/messages6.html), [7](https://libmdbx.dqdkfa.ru/tg-archive/messages7.html)).
|
> [5](https://libmdbx.dqdkfa.ru/tg-archive/messages5.html), [6](https://libmdbx.dqdkfa.ru/tg-archive/messages6.html), [7](https://libmdbx.dqdkfa.ru/tg-archive/messages7.html)).
|
||||||
> See the [ChangeLog](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md) for `NEWS` and latest updates.
|
> See the [ChangeLog](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md) for `NEWS` and latest updates.
|
||||||
|
|
||||||
> Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
> Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||||
> Всё будет хорошо!
|
> Всё будет хорошо!
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -571,11 +571,17 @@ retry_snap_meta:
|
|||||||
uint8_t *const data_buffer = buffer + ceil_powerof2(meta_bytes, globals.sys_pagesize);
|
uint8_t *const data_buffer = buffer + ceil_powerof2(meta_bytes, globals.sys_pagesize);
|
||||||
#if MDBX_USE_COPYFILERANGE
|
#if MDBX_USE_COPYFILERANGE
|
||||||
static bool copyfilerange_unavailable;
|
static bool copyfilerange_unavailable;
|
||||||
|
#if (defined(__linux__) || defined(__gnu_linux__))
|
||||||
|
if (globals.linux_kernel_version >= 0x05030000 && globals.linux_kernel_version < 0x05130000)
|
||||||
|
copyfilerange_unavailable = true;
|
||||||
|
#endif /* linux */
|
||||||
bool not_the_same_filesystem = false;
|
bool not_the_same_filesystem = false;
|
||||||
struct statfs statfs_info;
|
if (!copyfilerange_unavailable) {
|
||||||
if (fstatfs(fd, &statfs_info) || statfs_info.f_type == /* ECRYPTFS_SUPER_MAGIC */ 0xf15f)
|
struct statfs statfs_info;
|
||||||
/* avoid use copyfilerange_unavailable() to ecryptfs due bugs */
|
if (fstatfs(fd, &statfs_info) || statfs_info.f_type == /* ECRYPTFS_SUPER_MAGIC */ 0xf15f)
|
||||||
not_the_same_filesystem = true;
|
/* avoid use copyfilerange_unavailable() to ecryptfs due bugs */
|
||||||
|
not_the_same_filesystem = true;
|
||||||
|
}
|
||||||
#endif /* MDBX_USE_COPYFILERANGE */
|
#endif /* MDBX_USE_COPYFILERANGE */
|
||||||
|
|
||||||
for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
|
for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
|
||||||
@@ -760,14 +766,24 @@ __cold static int copy2pathname(MDBX_txn *txn, const pathchar_t *dest_path, MDBX
|
|||||||
lock_op.l_whence = SEEK_SET;
|
lock_op.l_whence = SEEK_SET;
|
||||||
lock_op.l_start = 0;
|
lock_op.l_start = 0;
|
||||||
lock_op.l_len = OFF_T_MAX;
|
lock_op.l_len = OFF_T_MAX;
|
||||||
if (MDBX_FCNTL(newfd, MDBX_F_SETLK, &lock_op)
|
if (MDBX_FCNTL(newfd, MDBX_F_SETLK, &lock_op))
|
||||||
#if (defined(__linux__) || defined(__gnu_linux__)) && defined(LOCK_EX) && \
|
|
||||||
(!defined(__ANDROID_API__) || __ANDROID_API__ >= 24)
|
|
||||||
|| flock(newfd, LOCK_EX | LOCK_NB)
|
|
||||||
#endif /* Linux */
|
|
||||||
)
|
|
||||||
rc = errno;
|
rc = errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LOCK_EX) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 24)
|
||||||
|
if (rc == MDBX_SUCCESS && flock(newfd, LOCK_EX | LOCK_NB)) {
|
||||||
|
const int err_flock = errno, err_fs = osal_check_fs_local(newfd, 0);
|
||||||
|
if (err_flock != EAGAIN || err_fs != MDBX_EREMOTE) {
|
||||||
|
ERROR("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "unexpected", dest_path, err_flock,
|
||||||
|
err_fs);
|
||||||
|
rc = err_flock;
|
||||||
|
} else {
|
||||||
|
WARNING("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "ignore", dest_path, err_flock,
|
||||||
|
err_fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* LOCK_EX && ANDROID_API >= 24 */
|
||||||
|
|
||||||
#endif /* Windows / POSIX */
|
#endif /* Windows / POSIX */
|
||||||
|
|
||||||
if (rc == MDBX_SUCCESS)
|
if (rc == MDBX_SUCCESS)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
|
|||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
rc = mdbx_cursor_unbind(mc);
|
rc = mdbx_cursor_unbind(mc);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return (rc == MDBX_BAD_TXN) ? MDBX_EINVAL : rc;
|
||||||
}
|
}
|
||||||
cASSERT(mc, mc->next == mc);
|
cASSERT(mc, mc->next == mc);
|
||||||
|
|
||||||
@@ -88,8 +88,16 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) {
|
|||||||
return LOG_IFERR(MDBX_EINVAL);
|
return LOG_IFERR(MDBX_EINVAL);
|
||||||
|
|
||||||
int rc = check_txn(mc->txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD);
|
int rc = check_txn(mc->txn, MDBX_TXN_FINISHED | MDBX_TXN_HAS_CHILD);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
|
for (const MDBX_txn *txn = mc->txn; rc == MDBX_BAD_TXN && check_txn(txn, MDBX_TXN_FINISHED) == MDBX_SUCCESS;
|
||||||
|
txn = txn->nested)
|
||||||
|
if (dbi_state(txn, cursor_dbi(mc)) == 0)
|
||||||
|
/* специальный случай: курсор прикреплён к родительской транзакции, но соответствующий dbi-дескриптор ещё
|
||||||
|
* не использовался во вложенной транзакции, т.е. курсор ещё не импортирован в дочернюю транзакцию и не имеет
|
||||||
|
* связанного сохранённого состояния (поэтому mc→backup равен nullptr). */
|
||||||
|
rc = MDBX_EINVAL;
|
||||||
return LOG_IFERR(rc);
|
return LOG_IFERR(rc);
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) {
|
if (unlikely(!mc->txn || mc->txn->signature != txn_signature)) {
|
||||||
ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0);
|
ERROR("Wrong cursor's transaction %p 0x%x", __Wpedantic_format_voidptr(mc->txn), mc->txn ? mc->txn->signature : 0);
|
||||||
@@ -244,9 +252,8 @@ int mdbx_txn_release_all_cursors_ex(const MDBX_txn *txn, bool unbind, size_t *co
|
|||||||
MDBX_cursor *bk = mc->backup;
|
MDBX_cursor *bk = mc->backup;
|
||||||
mc->next = bk->next;
|
mc->next = bk->next;
|
||||||
mc->backup = bk->backup;
|
mc->backup = bk->backup;
|
||||||
mc->backup = nullptr;
|
bk->backup = nullptr;
|
||||||
bk->signature = 0;
|
bk->signature = 0;
|
||||||
bk = bk->next;
|
|
||||||
osal_free(bk);
|
osal_free(bk);
|
||||||
} else {
|
} else {
|
||||||
mc->signature = cur_signature_ready4dispose;
|
mc->signature = cur_signature_ready4dispose;
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ int mdbx_txn_lock(MDBX_env *env, bool dont_wait) {
|
|||||||
|
|
||||||
if (unlikely(env->flags & MDBX_RDONLY))
|
if (unlikely(env->flags & MDBX_RDONLY))
|
||||||
return LOG_IFERR(MDBX_EACCESS);
|
return LOG_IFERR(MDBX_EACCESS);
|
||||||
if (unlikely(env->basal_txn->owner || (env->basal_txn->flags & MDBX_TXN_FINISHED) == 0))
|
if (dont_wait && unlikely(env->basal_txn->owner || (env->basal_txn->flags & MDBX_TXN_FINISHED) == 0))
|
||||||
return LOG_IFERR(MDBX_BUSY);
|
return LOG_IFERR(MDBX_BUSY);
|
||||||
|
|
||||||
return LOG_IFERR(lck_txn_lock(env, dont_wait));
|
return LOG_IFERR(lck_txn_lock(env, dont_wait));
|
||||||
|
|||||||
@@ -545,15 +545,16 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) {
|
|||||||
/* Update parent's DBs array */
|
/* Update parent's DBs array */
|
||||||
eASSERT(env, parent->n_dbi == txn->n_dbi);
|
eASSERT(env, parent->n_dbi == txn->n_dbi);
|
||||||
TXN_FOREACH_DBI_ALL(txn, dbi) {
|
TXN_FOREACH_DBI_ALL(txn, dbi) {
|
||||||
if (txn->dbi_state[dbi] & (DBI_CREAT | DBI_FRESH | DBI_DIRTY)) {
|
if (txn->dbi_state[dbi] != (parent->dbi_state[dbi] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY))) {
|
||||||
|
eASSERT(env, (txn->dbi_state[dbi] & (DBI_CREAT | DBI_FRESH | DBI_DIRTY)) != 0 ||
|
||||||
|
(txn->dbi_state[dbi] | DBI_STALE) ==
|
||||||
|
(parent->dbi_state[dbi] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY)));
|
||||||
parent->dbs[dbi] = txn->dbs[dbi];
|
parent->dbs[dbi] = txn->dbs[dbi];
|
||||||
/* preserve parent's status */
|
/* preserve parent's status */
|
||||||
const uint8_t state = txn->dbi_state[dbi] | (parent->dbi_state[dbi] & (DBI_CREAT | DBI_FRESH | DBI_DIRTY));
|
const uint8_t state = txn->dbi_state[dbi] | (parent->dbi_state[dbi] & (DBI_CREAT | DBI_FRESH | DBI_DIRTY));
|
||||||
DEBUG("dbi %zu dbi-state %s 0x%02x -> 0x%02x", dbi, (parent->dbi_state[dbi] != state) ? "update" : "still",
|
DEBUG("dbi %zu dbi-state %s 0x%02x -> 0x%02x", dbi, (parent->dbi_state[dbi] != state) ? "update" : "still",
|
||||||
parent->dbi_state[dbi], state);
|
parent->dbi_state[dbi], state);
|
||||||
parent->dbi_state[dbi] = state;
|
parent->dbi_state[dbi] = state;
|
||||||
} else {
|
|
||||||
eASSERT(env, txn->dbi_state[dbi] == (parent->dbi_state[dbi] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
|
|||||||
I = (I - 1) | (bitmap_chunk - 1); \
|
I = (I - 1) | (bitmap_chunk - 1); \
|
||||||
bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk]; \
|
bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk]; \
|
||||||
if (!bitmap_item) \
|
if (!bitmap_item) \
|
||||||
|
/* coverity[const_overflow] */ \
|
||||||
I += bitmap_chunk; \
|
I += bitmap_chunk; \
|
||||||
continue; \
|
continue; \
|
||||||
} else if ((bitmap_item & 1) == 0) { \
|
} else if ((bitmap_item & 1) == 0) { \
|
||||||
|
|||||||
@@ -1157,7 +1157,8 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika
|
|||||||
if (!head.is_steady && meta_is_steady(pending))
|
if (!head.is_steady && meta_is_steady(pending))
|
||||||
target = (meta_t *)head.ptr_c;
|
target = (meta_t *)head.ptr_c;
|
||||||
else {
|
else {
|
||||||
WARNING("%s", "skip update meta");
|
NOTICE("skip update meta%" PRIaPGNO " for txn#%" PRIaTXN ", since it is already steady",
|
||||||
|
data_page(head.ptr_c)->pgno, head.txnid);
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ __cold std::string error::message() const {
|
|||||||
__cold void error::throw_exception() const {
|
__cold void error::throw_exception() const {
|
||||||
switch (code()) {
|
switch (code()) {
|
||||||
case MDBX_EINVAL:
|
case MDBX_EINVAL:
|
||||||
throw std::invalid_argument("mdbx");
|
throw std::invalid_argument("MDBX_EINVAL");
|
||||||
case MDBX_ENOMEM:
|
case MDBX_ENOMEM:
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
case MDBX_SUCCESS:
|
case MDBX_SUCCESS:
|
||||||
|
|||||||
@@ -1745,7 +1745,7 @@ MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle) {
|
|||||||
return MDBX_RESULT_FALSE;
|
return MDBX_RESULT_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int osal_check_fs_local(mdbx_filehandle_t handle, int flags) {
|
MDBX_INTERNAL int osal_check_fs_local(mdbx_filehandle_t handle, int flags) {
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
if (globals.running_under_Wine && !(flags & MDBX_EXCLUSIVE))
|
if (globals.running_under_Wine && !(flags & MDBX_EXCLUSIVE))
|
||||||
return ERROR_NOT_CAPABLE /* workaround for Wine */;
|
return ERROR_NOT_CAPABLE /* workaround for Wine */;
|
||||||
@@ -2856,7 +2856,7 @@ __cold static LSTATUS mdbx_RegGetValue(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValu
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__cold MDBX_MAYBE_UNUSED static bool bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
|
MDBX_MAYBE_UNUSED __cold static bool bootid_parse_uuid(bin128_t *s, const void *p, const size_t n) {
|
||||||
if (n > 31) {
|
if (n > 31) {
|
||||||
unsigned bits = 0;
|
unsigned bits = 0;
|
||||||
for (unsigned i = 0; i < n; ++i) /* try parse an UUID in text form */ {
|
for (unsigned i = 0; i < n; ++i) /* try parse an UUID in text form */ {
|
||||||
|
|||||||
@@ -481,6 +481,7 @@ MDBX_INTERNAL int osal_resume_threads_after_remap(mdbx_handle_array_t *array);
|
|||||||
MDBX_INTERNAL int osal_msync(const osal_mmap_t *map, size_t offset, size_t length, enum osal_syncmode_bits mode_bits);
|
MDBX_INTERNAL int osal_msync(const osal_mmap_t *map, size_t offset, size_t length, enum osal_syncmode_bits mode_bits);
|
||||||
MDBX_INTERNAL int osal_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_t *pathname, int err);
|
MDBX_INTERNAL int osal_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_t *pathname, int err);
|
||||||
MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle);
|
MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle);
|
||||||
|
MDBX_INTERNAL int osal_check_fs_local(mdbx_filehandle_t handle, int flags);
|
||||||
|
|
||||||
MDBX_MAYBE_UNUSED static inline uint32_t osal_getpid(void) {
|
MDBX_MAYBE_UNUSED static inline uint32_t osal_getpid(void) {
|
||||||
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
|
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ __hot txnid_t txn_snapshot_oldest(const MDBX_txn *const txn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void txn_done_cursors(MDBX_txn *txn, const bool merge) {
|
void txn_done_cursors(MDBX_txn *txn, const bool merge) {
|
||||||
tASSERT(txn, txn->cursors[FREE_DBI] == nullptr);
|
TXN_FOREACH_DBI_ALL(txn, i) {
|
||||||
TXN_FOREACH_DBI_FROM(txn, i, /* skip FREE_DBI */ 1) {
|
|
||||||
MDBX_cursor *mc = txn->cursors[i];
|
MDBX_cursor *mc = txn->cursors[i];
|
||||||
if (mc) {
|
if (mc) {
|
||||||
txn->cursors[i] = nullptr;
|
txn->cursors[i] = nullptr;
|
||||||
|
|||||||
@@ -172,9 +172,21 @@ mdbx::map_handle case1_cycle_dbi(std::deque<mdbx::map_handle> &dbi) {
|
|||||||
|
|
||||||
void case1_read_cycle(mdbx::txn txn, std::deque<mdbx::map_handle> &dbi, std::vector<MDBX_cursor *> &pool,
|
void case1_read_cycle(mdbx::txn txn, std::deque<mdbx::map_handle> &dbi, std::vector<MDBX_cursor *> &pool,
|
||||||
mdbx::cursor pre, bool nested = false) {
|
mdbx::cursor pre, bool nested = false) {
|
||||||
for (auto c : pool)
|
if (nested) {
|
||||||
mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
|
for (auto c : pool)
|
||||||
pre.bind(txn, case1_cycle_dbi(dbi));
|
try {
|
||||||
|
mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
|
||||||
|
} catch (const std::invalid_argument &) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
pre.bind(txn, case1_cycle_dbi(dbi));
|
||||||
|
} catch (const std::invalid_argument &) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto c : pool)
|
||||||
|
mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
|
||||||
|
pre.bind(txn, case1_cycle_dbi(dbi));
|
||||||
|
}
|
||||||
|
|
||||||
for (auto n = prng(3 + dbi.size()); n > 0; --n) {
|
for (auto n = prng(3 + dbi.size()); n > 0; --n) {
|
||||||
auto c = txn.open_cursor(dbi[prng(dbi.size())]);
|
auto c = txn.open_cursor(dbi[prng(dbi.size())]);
|
||||||
@@ -215,6 +227,16 @@ void case1_read_cycle(mdbx::txn txn, std::deque<mdbx::map_handle> &dbi, std::vec
|
|||||||
|
|
||||||
switch (prng(nested ? 7 : 3)) {
|
switch (prng(nested ? 7 : 3)) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (pre.txn()) {
|
||||||
|
if (nested)
|
||||||
|
try {
|
||||||
|
pre.unbind();
|
||||||
|
} catch (const std::invalid_argument &) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pre.unbind();
|
||||||
|
}
|
||||||
for (auto i = pool.begin(); i != pool.end();)
|
for (auto i = pool.begin(); i != pool.end();)
|
||||||
if (mdbx_cursor_txn(*i))
|
if (mdbx_cursor_txn(*i))
|
||||||
i = pool.erase(i);
|
i = pool.erase(i);
|
||||||
@@ -253,6 +275,8 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque<mdbx::map_handle> &dbi,
|
|||||||
if (prng(16) > 8)
|
if (prng(16) > 8)
|
||||||
case1_write_cycle(txn.start_nested(), dbi, pool, pre, true);
|
case1_write_cycle(txn.start_nested(), dbi, pool, pre, true);
|
||||||
|
|
||||||
|
case1_read_cycle(txn, dbi, pool, pre, nested);
|
||||||
|
|
||||||
if (flipcoin())
|
if (flipcoin())
|
||||||
txn.commit();
|
txn.commit();
|
||||||
else
|
else
|
||||||
@@ -332,6 +356,27 @@ bool case1(mdbx::env env) {
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool case2(mdbx::env env) {
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
auto txn = env.start_write();
|
||||||
|
auto dbi = txn.create_map("case2", mdbx::key_mode::usual, mdbx::value_mode::single);
|
||||||
|
txn.commit_embark_read();
|
||||||
|
auto cursor1 = txn.open_cursor(dbi);
|
||||||
|
auto cursor2 = txn.open_cursor(0);
|
||||||
|
cursor1.move(mdbx::cursor::next, false);
|
||||||
|
cursor2.move(mdbx::cursor::next, false);
|
||||||
|
txn.commit_embark_read();
|
||||||
|
cursor2.bind(txn, dbi);
|
||||||
|
cursor1.bind(txn, 0);
|
||||||
|
cursor1.move(mdbx::cursor::last, false);
|
||||||
|
cursor2.move(mdbx::cursor::last, false);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
int doit() {
|
int doit() {
|
||||||
mdbx::path db_filename = "test-cursor-closing";
|
mdbx::path db_filename = "test-cursor-closing";
|
||||||
mdbx::env::remove(db_filename);
|
mdbx::env::remove(db_filename);
|
||||||
@@ -341,6 +386,7 @@ int doit() {
|
|||||||
|
|
||||||
bool ok = case0(env);
|
bool ok = case0(env);
|
||||||
ok = case1(env) && ok;
|
ok = case1(env) && ok;
|
||||||
|
ok = case2(env) && ok;
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
std::cout << "OK\n";
|
std::cout << "OK\n";
|
||||||
|
|||||||
@@ -510,6 +510,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
|||||||
options |= WCONTINUED;
|
options |= WCONTINUED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
pid = 0;
|
||||||
while (sigalarm_tail == sigalarm_head) {
|
while (sigalarm_tail == sigalarm_head) {
|
||||||
int status;
|
int status;
|
||||||
pid = waitpid(0, &status, options);
|
pid = waitpid(0, &status, options);
|
||||||
|
|||||||
Reference in New Issue
Block a user