mirror of
https://github.com/isar/libmdbx.git
synced 2025-05-12 04:17:45 +08:00
mdbx: merge branch master
into devel
.
This commit is contained in:
commit
402a8e62be
126
ChangeLog.md
126
ChangeLog.md
@ -17,6 +17,8 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
- [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте.
|
- [Виктору Логунову](https://t.me/vl_username) за сообщение об опечатки в имени переменной в Conan-рецепте.
|
||||||
- [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру.
|
- [Илье Михееву](https://t.me/IlyaMkhv) за сообщение о лишнем/ненужном предупреждении несоответствия файла БД новому размеру.
|
||||||
- [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing.
|
- [maxc0d3r](https://gitflic.ru/user/maxc0d3r) for bug reporting and testing.
|
||||||
|
- [Алексею Костюку (aka Keller)](https://t.me/keller18306) за сообщения о проблеме копирования на NFS.
|
||||||
|
|
||||||
|
|
||||||
Новое:
|
Новое:
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
Таким образом, у пользователя появляется возможность легко диагностировать лишние/ненужные транзакции записи.
|
Таким образом, у пользователя появляется возможность легко диагностировать лишние/ненужные транзакции записи.
|
||||||
|
|
||||||
- Добавлена опция сборки `MDBX_ENABLE_NON_READONLY_EXPORT` позволяющая использовать в режиме чтения-записи БД расположенных в файловых системах экспортированных через NFS.
|
- Добавлена опция сборки `MDBX_ENABLE_NON_READONLY_EXPORT` позволяющая использовать в режиме чтения-записи БД расположенных в файловых системах экспортированных через NFS.
|
||||||
По-умолчанию опция выключена и при открытии в неэксклюзивном режиме чтения-записи БД расположенных файловых системах доступных извне по NFS будет возвращаться ошибка `MDBX_EREMOTE`.
|
По-умолчанию опция выключена и при открытии в неэксклюзивном режиме чтения-записи БД расположенных в файловых системах доступных извне по NFS будет возвращаться ошибка `MDBX_EREMOTE`.
|
||||||
Включение опции позволяет открывать БД в описанных выше ситуациях, но риск чтения неверных данных на удалённой стороне ложится на пользователя.
|
Включение опции позволяет открывать БД в описанных выше ситуациях, но риск чтения неверных данных на удалённой стороне ложится на пользователя.
|
||||||
|
|
||||||
- Поддержка MacOS universal binaries при сборке посредством CMake.
|
- Поддержка MacOS universal binaries при сборке посредством CMake.
|
||||||
@ -68,15 +70,20 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
|
|
||||||
- Запрещена отвязка/открепление курсоров во вложенных транзакциях, т.е. вызовы `mdbx_cursor_unbind()` и
|
- Запрещена отвязка/открепление курсоров во вложенных транзакциях, т.е. вызовы `mdbx_cursor_unbind()` и
|
||||||
`mdbx_txn_release_all_cursors(unbind=true)` для курсоров открытых в одной из родительских транзакций.
|
`mdbx_txn_release_all_cursors(unbind=true)` для курсоров открытых в одной из родительских транзакций.
|
||||||
Причина в том, что в случае отмены вложенной транзакции возникает неконструктивная неопределенность
|
Причина в том, что в случае отмены вложенной транзакции возникает неконструктивная неопределенность — следует ли
|
||||||
— следует ли восстанавливать состояние курсоров. Если не восстанавливать, то получается что вложенная транзакция может
|
восстанавливать состояние курсоров. Если не восстанавливать, то получается что вложенная транзакция может поломать родительскую,
|
||||||
поломать родительскую, сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые
|
сделав её продолжение невозможным. Если восстанавливать, то также следует «воскрешать» закрытые курсоры,
|
||||||
курсоры, что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения.
|
что неизбежно приведет к путанице, утечкам памяти и использованию после освобождения.
|
||||||
|
|
||||||
- В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вывоза `mdbx::cursor::txn()`.
|
- В C++ API отменён вброс исключения при запросе транзакции у отсоединённого курсора посредством вывоза `mdbx::cursor::txn()`.
|
||||||
|
|
||||||
|
- При невозможности отвязки курсора от его текущей транзакции функция `mdbx_cursor_bind()`
|
||||||
|
теперь возвращает `MDBX_EINVAL` вместо `MDBX_BAD_TXN`.
|
||||||
|
|
||||||
Исправления:
|
Исправления:
|
||||||
|
|
||||||
|
- Для совместимости с GCC 15.x в режиме C23 изменен порядок указания атрибутов функций.
|
||||||
|
|
||||||
- Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях.
|
- Устранён регресс допускающий SIGSEGV в операциях обновления после вытеснения/spilling страниц в больших транзакциях.
|
||||||
Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления.
|
Ошибка присутствует в выпусках v0.13.1, v0.13.2, v0.13.3 и оставалась незамеченной из-за специфических условий и низкой вероятности проявления.
|
||||||
Более подробная информация в описании коммита `cb8eec6d11cdab4f7d3cf87913e8009149dcf60b`.
|
Более подробная информация в описании коммита `cb8eec6d11cdab4f7d3cf87913e8009149dcf60b`.
|
||||||
@ -130,6 +137,38 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
|
|
||||||
- В C++ API добавлена упущенная проверка `__cpp_concepts >= 202002` для использования концептов C++.
|
- В C++ API добавлена упущенная проверка `__cpp_concepts >= 202002` для использования концептов C++.
|
||||||
|
|
||||||
|
- Устранён регресс при использовании курсоров для DBI=0 в читающих транзакциях.
|
||||||
|
|
||||||
|
После рефакторинга и ряда оптимизаций для завершения/гашения
|
||||||
|
курсоров в читающих и пишущих транзакций стал использоваться общий код.
|
||||||
|
Причем за основу, был взят соответствующий фрагмент относящийся к
|
||||||
|
пишущим транзакциям, в которых пользователю не позволяется
|
||||||
|
использоваться курсоры для 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)`.
|
||||||
|
|
||||||
Прочие доработки:
|
Прочие доработки:
|
||||||
|
|
||||||
- Существенный рефакторинг с реструктуризацией кода, переименованием внутренних структур, их полей и внутренних функций.
|
- Существенный рефакторинг с реструктуризацией кода, переименованием внутренних структур, их полей и внутренних функций.
|
||||||
@ -155,6 +194,10 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
|
|
||||||
- Отключено использование C23 `[[атрибутов]]` для версий CLANG меньше 20.
|
- Отключено использование C23 `[[атрибутов]]` для версий CLANG меньше 20.
|
||||||
|
|
||||||
|
- Во избежание потенциальных проблем отключено использование `copy_file_range()` на ядрах Linux 5.3 - 5.18.
|
||||||
|
|
||||||
|
- Вброс `std::invalid_argument` теперь производится явным сообщением `MDBX_EINVAL`.
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -189,7 +232,76 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
|||||||
********************************************************************************
|
********************************************************************************
|
||||||
|
|
||||||
|
|
||||||
## v0.13.5 "Труба" запланирован на 2025-03-21
|
## 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
|
||||||
|
|
||||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
||||||
|
|
||||||
@ -292,7 +404,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()`.
|
||||||
|
|
||||||
Прочие доработки:
|
Прочие доработки:
|
||||||
|
|
||||||
|
45
README.md
45
README.md
@ -1,18 +1,5 @@
|
|||||||
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
||||||
|
|
||||||
> Please refer to the online [documentation](https://libmdbx.dqdkfa.ru)
|
|
||||||
> with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html)
|
|
||||||
> and pay attention to the [`C++` API](https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1).
|
|
||||||
|
|
||||||
> Questions, feedback and suggestions are welcome to the [Telegram' group](https://t.me/libmdbx) (archive [1](https://libmdbx.dqdkfa.ru/tg-archive/messages1.html),
|
|
||||||
> [2](https://libmdbx.dqdkfa.ru/tg-archive/messages2.html), [3](https://libmdbx.dqdkfa.ru/tg-archive/messages3.html), [4](https://libmdbx.dqdkfa.ru/tg-archive/messages4.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.
|
|
||||||
|
|
||||||
> Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
|
||||||
> Всё будет хорошо!
|
|
||||||
|
|
||||||
|
|
||||||
libmdbx
|
libmdbx
|
||||||
========
|
========
|
||||||
|
|
||||||
@ -39,32 +26,44 @@ tree](https://en.wikipedia.org/wiki/B%2B_tree).
|
|||||||
[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging), but that might
|
[WAL](https://en.wikipedia.org/wiki/Write-ahead_logging), but that might
|
||||||
be a caveat for write-intensive workloads with durability requirements.
|
be a caveat for write-intensive workloads with durability requirements.
|
||||||
|
|
||||||
4. **Compact and friendly for fully embedding**. Only ≈25KLOC of `C11`,
|
4. Enforces [serializability](https://en.wikipedia.org/wiki/Serializability) for
|
||||||
≈64K x86 binary code of core, no internal threads neither server process(es),
|
|
||||||
but implements a simplified variant of the [Berkeley
|
|
||||||
DB](https://en.wikipedia.org/wiki/Berkeley_DB) and
|
|
||||||
[dbm](https://en.wikipedia.org/wiki/DBM_(computing)) API.
|
|
||||||
|
|
||||||
5. Enforces [serializability](https://en.wikipedia.org/wiki/Serializability) for
|
|
||||||
writers just by single
|
writers just by single
|
||||||
[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
|
[mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) and affords
|
||||||
[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)
|
[wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom)
|
||||||
for parallel readers without atomic/interlocked operations, while
|
for parallel readers without atomic/interlocked operations, while
|
||||||
**writing and reading transactions do not block each other**.
|
**writing and reading transactions do not block each other**.
|
||||||
|
|
||||||
6. **Guarantee data integrity** after crash unless this was explicitly
|
5. **Guarantee data integrity** after crash unless this was explicitly
|
||||||
neglected in favour of write performance.
|
neglected in favour of write performance.
|
||||||
|
|
||||||
7. Supports Linux, Windows, MacOS, Android, iOS, FreeBSD, DragonFly, Solaris,
|
6. Supports Linux, Windows, MacOS, Android, iOS, FreeBSD, DragonFly, Solaris,
|
||||||
OpenSolaris, OpenIndiana, NetBSD, OpenBSD and other systems compliant with
|
OpenSolaris, OpenIndiana, NetBSD, OpenBSD and other systems compliant with
|
||||||
**POSIX.1-2008**.
|
**POSIX.1-2008**.
|
||||||
|
|
||||||
|
7. **Compact and friendly for fully embedding**. Only ≈25KLOC of `C11`,
|
||||||
|
≈64K x86 binary code of core, no internal threads neither server process(es),
|
||||||
|
but implements a simplified variant of the [Berkeley
|
||||||
|
DB](https://en.wikipedia.org/wiki/Berkeley_DB) and
|
||||||
|
[dbm](https://en.wikipedia.org/wiki/DBM_(computing)) API.
|
||||||
|
|
||||||
<!-- section-end -->
|
<!-- section-end -->
|
||||||
|
|
||||||
Historically, _libmdbx_ is a deeply revised and extended descendant of the amazing
|
Historically, _libmdbx_ is a deeply revised and extended descendant of the legendary
|
||||||
[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||||
_libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb).
|
_libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb).
|
||||||
|
|
||||||
|
[](https://t.me/libmdbx)
|
||||||
|
|
||||||
|
> Please refer to the online [documentation](https://libmdbx.dqdkfa.ru)
|
||||||
|
> with [`C` API description](https://libmdbx.dqdkfa.ru/group__c__api.html)
|
||||||
|
> and pay attention to the [`C++` API](https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h%2B%2B#line-num-1).
|
||||||
|
> Donations are welcome to the Ethereum/ERC-20 `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||||
|
> Всё будет хорошо!
|
||||||
|
|
||||||
|
Telegram Group archive: [1](https://libmdbx.dqdkfa.ru/tg-archive/messages1.html),
|
||||||
|
[2](https://libmdbx.dqdkfa.ru/tg-archive/messages2.html), [3](https://libmdbx.dqdkfa.ru/tg-archive/messages3.html), [4](https://libmdbx.dqdkfa.ru/tg-archive/messages4.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).
|
||||||
|
|
||||||
## Github
|
## Github
|
||||||
|
|
||||||
### на Русском (мой родной язык)
|
### на Русском (мой родной язык)
|
||||||
|
2
TODO.md
2
TODO.md
@ -11,7 +11,7 @@ For the same reason ~~Github~~ is blacklisted forever.
|
|||||||
|
|
||||||
So currently most of the links are broken due to noted malicious ~~Github~~ sabotage.
|
So currently most of the links are broken due to noted malicious ~~Github~~ sabotage.
|
||||||
|
|
||||||
- SWING.
|
- [SWIG](https://www.swig.org/).
|
||||||
- Параллельная lto-сборка с устранением предупреждений.
|
- Параллельная lto-сборка с устранением предупреждений.
|
||||||
- Интеграция c DTrace и аналогами.
|
- Интеграция c DTrace и аналогами.
|
||||||
- Новый стиль обработки ошибок с записью "трассы" и причин.
|
- Новый стиль обработки ошибок с записью "трассы" и причин.
|
||||||
|
@ -54,7 +54,7 @@ cleans readers, as an a process aborting (especially with core dump) can
|
|||||||
take a long time, and checking readers cannot be performed too often due
|
take a long time, and checking readers cannot be performed too often due
|
||||||
to performance degradation.
|
to performance degradation.
|
||||||
|
|
||||||
This issue will be addressed in MithrlDB and one of libmdbx releases,
|
This issue will be addressed in MithrilDB and one of libmdbx releases,
|
||||||
presumably in 2025. To do this, nonlinear GC recycling will be
|
presumably in 2025. To do this, nonlinear GC recycling will be
|
||||||
implemented, without stopping garbage recycling on the old MVCC snapshot
|
implemented, without stopping garbage recycling on the old MVCC snapshot
|
||||||
used by a long read transaction.
|
used by a long read transaction.
|
||||||
@ -92,7 +92,7 @@ free consecutive/adjacent pages through GC has been significantly
|
|||||||
speeded, including acceleration using NOEN/SSE2/AVX2/AVX512
|
speeded, including acceleration using NOEN/SSE2/AVX2/AVX512
|
||||||
instructions.
|
instructions.
|
||||||
|
|
||||||
This issue will be addressed in MithrlDB and refined within one of
|
This issue will be addressed in MithrilDB and refined within one of
|
||||||
0.15.x libmdbx releases, presumably at end of 2025.
|
0.15.x libmdbx releases, presumably at end of 2025.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
From 49256dcd050fd0ee67860b7bc544dabe088d08e9 Mon Sep 17 00:00:00 2001
|
From 349c08cf21b66ecea851340133a1b845c25675f7 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?=
|
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?= <leo@yuriev.ru>
|
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
||||||
Date: Fri, 14 Feb 2025 21:34:25 +0300
|
Date: Tue, 22 Apr 2025 14:38:49 +0300
|
||||||
Subject: [PATCH] package/libmdbx: new package (library/database).
|
Subject: [PATCH] package/libmdbx: new package (library/database).
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
@ -15,7 +15,7 @@ This patch adds libmdbx:
|
|||||||
in terms of reliability, features and performance.
|
in terms of reliability, features and performance.
|
||||||
- more information at https://libmdbx.dqdkfa.ru
|
- more information at https://libmdbx.dqdkfa.ru
|
||||||
|
|
||||||
The 0.13.4 "Sigma Boy" is stable release of _libmdbx_ branch with new superior features.
|
The 0.13.6 "Бузина" (Elderberry) is stable release of _libmdbx_ branch with new superior features.
|
||||||
|
|
||||||
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
||||||
|
|
||||||
@ -110,19 +110,19 @@ index 0000000000..a9a4ac45c5
|
|||||||
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
||||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..202937e7be
|
index 0000000000..ae5266716b
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/package/libmdbx/libmdbx.hash
|
+++ b/package/libmdbx/libmdbx.hash
|
||||||
@@ -0,0 +1,6 @@
|
@@ -0,0 +1,6 @@
|
||||||
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
||||||
+sha256 86df30ca2231c9b3ad71424bb829dca9041947f5539d4295030c653d4982c1be libmdbx-amalgamated-0.13.4.tar.xz
|
+sha256 57db987de6f7ccc66a66ae28a7bda9f9fbb48ac5fb9279bcca92fd5de13075d1 libmdbx-amalgamated-0.13.6.tar.xz
|
||||||
+
|
+
|
||||||
+# Locally calculated
|
+# Locally calculated
|
||||||
+sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE
|
+sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE
|
||||||
+sha256 699a62986b6c8d31124646dffd4b15872c7d3bc5eecea5994edb1f5195df49d1 NOTICE
|
+sha256 651f71b46c6bb0046d2122df7f9def9cb24f4dc28c5b11cef059f66565cda30f NOTICE
|
||||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..a8a6f3dbdf
|
index 0000000000..571757262e
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/package/libmdbx/libmdbx.mk
|
+++ b/package/libmdbx/libmdbx.mk
|
||||||
@@ -0,0 +1,42 @@
|
@@ -0,0 +1,42 @@
|
||||||
@ -132,7 +132,7 @@ index 0000000000..a8a6f3dbdf
|
|||||||
+#
|
+#
|
||||||
+################################################################################
|
+################################################################################
|
||||||
+
|
+
|
||||||
+LIBMDBX_VERSION = 0.13.4
|
+LIBMDBX_VERSION = 0.13.6
|
||||||
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
||||||
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
||||||
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||||
@ -169,5 +169,5 @@ index 0000000000..a8a6f3dbdf
|
|||||||
+
|
+
|
||||||
+$(eval $(cmake-package))
|
+$(eval $(cmake-package))
|
||||||
--
|
--
|
||||||
2.48.1
|
2.49.0
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
@ -89,8 +89,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);
|
||||||
@ -245,9 +253,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));
|
||||||
|
@ -235,9 +235,11 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M
|
|||||||
flags |= parent->flags & (txn_rw_begin_flags | MDBX_TXN_SPILLS | MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP);
|
flags |= parent->flags & (txn_rw_begin_flags | MDBX_TXN_SPILLS | MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP);
|
||||||
rc = txn_nested_create(parent, flags);
|
rc = txn_nested_create(parent, flags);
|
||||||
txn = parent->nested;
|
txn = parent->nested;
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
txn_end(txn, TXN_END_FAIL_BEGIN_NESTED);
|
int err = txn_end(txn, TXN_END_FAIL_BEGIN_NESTED);
|
||||||
else if (AUDIT_ENABLED() && ASSERT_ENABLED()) {
|
return err ? err : rc;
|
||||||
|
}
|
||||||
|
if (AUDIT_ENABLED() && ASSERT_ENABLED()) {
|
||||||
txn->signature = txn_signature;
|
txn->signature = txn_signature;
|
||||||
tASSERT(txn, audit_ex(txn, 0, false) == 0);
|
tASSERT(txn, audit_ex(txn, 0, false) == 0);
|
||||||
}
|
}
|
||||||
@ -249,31 +251,30 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, M
|
|||||||
return LOG_IFERR(MDBX_ENOMEM);
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
}
|
}
|
||||||
rc = txn_renew(txn, flags);
|
rc = txn_renew(txn, flags);
|
||||||
}
|
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||||
|
if (txn != env->basal_txn)
|
||||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
osal_free(txn);
|
||||||
if (txn != env->basal_txn)
|
return LOG_IFERR(rc);
|
||||||
osal_free(txn);
|
|
||||||
} else {
|
|
||||||
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
|
|
||||||
eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
|
|
||||||
else if (flags & MDBX_TXN_RDONLY)
|
|
||||||
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
|
|
||||||
/* Win32: SRWL flag */ txn_shrink_allowed)) == 0);
|
|
||||||
else {
|
|
||||||
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors |
|
|
||||||
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0);
|
|
||||||
assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed);
|
|
||||||
}
|
}
|
||||||
txn->signature = txn_signature;
|
|
||||||
txn->userctx = context;
|
|
||||||
*ret = txn;
|
|
||||||
DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid,
|
|
||||||
(flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root,
|
|
||||||
txn->dbs[FREE_DBI].root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return LOG_IFERR(rc);
|
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
|
||||||
|
eASSERT(env, txn->flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
|
||||||
|
else if (flags & MDBX_TXN_RDONLY)
|
||||||
|
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
|
||||||
|
/* Win32: SRWL flag */ txn_shrink_allowed)) == 0);
|
||||||
|
else {
|
||||||
|
eASSERT(env, (txn->flags & ~(MDBX_NOSTICKYTHREADS | MDBX_WRITEMAP | txn_shrink_allowed | txn_may_have_cursors |
|
||||||
|
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC | MDBX_TXN_SPILLS)) == 0);
|
||||||
|
assert(!txn->wr.spilled.list && !txn->wr.spilled.least_removed);
|
||||||
|
}
|
||||||
|
txn->signature = txn_signature;
|
||||||
|
txn->userctx = context;
|
||||||
|
*ret = txn;
|
||||||
|
DEBUG("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, txn->txnid,
|
||||||
|
(flags & MDBX_TXN_RDONLY) ? 'r' : 'w', (void *)txn, (void *)env, txn->dbs[MAIN_DBI].root,
|
||||||
|
txn->dbs[FREE_DBI].root);
|
||||||
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void latency_gcprof(MDBX_commit_latency *latency, const MDBX_txn *txn) {
|
static void latency_gcprof(MDBX_commit_latency *latency, const MDBX_txn *txn) {
|
||||||
|
@ -159,12 +159,12 @@ __cold static MDBX_chk_line_t *MDBX_PRINTF_ARGS(2, 3) chk_print(MDBX_chk_line_t
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
__cold MDBX_MAYBE_UNUSED static void chk_println_va(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity,
|
MDBX_MAYBE_UNUSED __cold static void chk_println_va(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity,
|
||||||
const char *fmt, va_list args) {
|
const char *fmt, va_list args) {
|
||||||
chk_line_end(chk_print_va(chk_line_begin(scope, severity), fmt, args));
|
chk_line_end(chk_print_va(chk_line_begin(scope, severity), fmt, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
__cold MDBX_MAYBE_UNUSED static void chk_println(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity,
|
MDBX_MAYBE_UNUSED __cold static void chk_println(MDBX_chk_scope_t *const scope, enum MDBX_chk_severity severity,
|
||||||
const char *fmt, ...) {
|
const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
@ -1726,6 +1726,7 @@ __hot csr_t cursor_seek(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, MDBX_cur
|
|||||||
|
|
||||||
csr_t ret;
|
csr_t ret;
|
||||||
ret.exact = false;
|
ret.exact = false;
|
||||||
|
/* coverity[logical_vs_bitwise] */
|
||||||
if (unlikely(key->iov_len < mc->clc->k.lmin ||
|
if (unlikely(key->iov_len < mc->clc->k.lmin ||
|
||||||
(key->iov_len > mc->clc->k.lmax &&
|
(key->iov_len > mc->clc->k.lmax &&
|
||||||
(mc->clc->k.lmin == mc->clc->k.lmax || MDBX_DEBUG || MDBX_FORCE_ASSERTIONS)))) {
|
(mc->clc->k.lmin == mc->clc->k.lmax || MDBX_DEBUG || MDBX_FORCE_ASSERTIONS)))) {
|
||||||
|
40
src/dbi.h
40
src/dbi.h
@ -43,29 +43,35 @@ static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
|
|||||||
return dbi_bitmap_ctz_fallback(txn, bmi);
|
return dbi_bitmap_ctz_fallback(txn, bmi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool dbi_foreach_step(const MDBX_txn *const txn, size_t *bitmap_item, size_t *dbi) {
|
||||||
|
const size_t bitmap_chunk = CHAR_BIT * sizeof(txn->dbi_sparse[0]);
|
||||||
|
if (*bitmap_item & 1) {
|
||||||
|
*bitmap_item >>= 1;
|
||||||
|
return txn->dbi_state[*dbi] != 0;
|
||||||
|
}
|
||||||
|
if (*bitmap_item) {
|
||||||
|
size_t bitmap_skip = dbi_bitmap_ctz(txn, *bitmap_item);
|
||||||
|
*bitmap_item >>= bitmap_skip;
|
||||||
|
*dbi += bitmap_skip - 1;
|
||||||
|
} else {
|
||||||
|
*dbi = (*dbi - 1) | (bitmap_chunk - 1);
|
||||||
|
*bitmap_item = txn->dbi_sparse[(1 + *dbi) / bitmap_chunk];
|
||||||
|
if (*bitmap_item == 0)
|
||||||
|
*dbi += bitmap_chunk;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* LY: Макрос целенаправленно сделан с одним циклом, чтобы сохранить возможность
|
/* LY: Макрос целенаправленно сделан с одним циклом, чтобы сохранить возможность
|
||||||
* использования оператора break */
|
* использования оператора break */
|
||||||
#define TXN_FOREACH_DBI_FROM(TXN, I, FROM) \
|
#define TXN_FOREACH_DBI_FROM(TXN, I, FROM) \
|
||||||
for (size_t bitmap_chunk = CHAR_BIT * sizeof(TXN->dbi_sparse[0]), bitmap_item = TXN->dbi_sparse[0] >> FROM, \
|
for (size_t bitmap_item = TXN->dbi_sparse[0] >> FROM, I = FROM; I < TXN->n_dbi; ++I) \
|
||||||
I = FROM; \
|
if (dbi_foreach_step(TXN, &bitmap_item, &I))
|
||||||
I < TXN->n_dbi; ++I) \
|
|
||||||
if (bitmap_item == 0) { \
|
|
||||||
I = (I - 1) | (bitmap_chunk - 1); \
|
|
||||||
bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk]; \
|
|
||||||
if (!bitmap_item) \
|
|
||||||
I += bitmap_chunk; \
|
|
||||||
continue; \
|
|
||||||
} else if ((bitmap_item & 1) == 0) { \
|
|
||||||
size_t bitmap_skip = dbi_bitmap_ctz(txn, bitmap_item); \
|
|
||||||
bitmap_item >>= bitmap_skip; \
|
|
||||||
I += bitmap_skip - 1; \
|
|
||||||
continue; \
|
|
||||||
} else if (bitmap_item >>= 1, TXN->dbi_state[I])
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define TXN_FOREACH_DBI_FROM(TXN, I, SKIP) \
|
#define TXN_FOREACH_DBI_FROM(TXN, I, FROM) \
|
||||||
for (size_t I = SKIP; I < TXN->n_dbi; ++I) \
|
for (size_t I = FROM; I < TXN->n_dbi; ++I) \
|
||||||
if (TXN->dbi_state[I])
|
if (TXN->dbi_state[I])
|
||||||
|
|
||||||
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
||||||
|
@ -65,6 +65,8 @@ int dpl_alloc(MDBX_txn *txn) {
|
|||||||
unlikely(!dpl_reserve(txn, wanna)))
|
unlikely(!dpl_reserve(txn, wanna)))
|
||||||
return MDBX_ENOMEM;
|
return MDBX_ENOMEM;
|
||||||
|
|
||||||
|
/* LY: wr.dirtylist не может быть nullptr, так как либо уже выделен, либо будет выделен в dpl_reserve(). */
|
||||||
|
/* coverity[var_deref_model] */
|
||||||
dpl_clear(txn->wr.dirtylist);
|
dpl_clear(txn->wr.dirtylist);
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -395,7 +397,7 @@ __cold bool dpl_check(MDBX_txn *txn) {
|
|||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
__noinline void dpl_lru_reduce(MDBX_txn *txn) {
|
__noinline void dpl_lru_reduce(MDBX_txn *txn) {
|
||||||
NOTICE("lru-reduce %u -> %u", txn->wr.dirtylru, txn->wr.dirtylru >> 1);
|
VERBOSE("lru-reduce %u -> %u", txn->wr.dirtylru, txn->wr.dirtylru >> 1);
|
||||||
tASSERT(txn, (txn->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP)) == 0);
|
tASSERT(txn, (txn->flags & (MDBX_TXN_RDONLY | MDBX_WRITEMAP)) == 0);
|
||||||
do {
|
do {
|
||||||
txn->wr.dirtylru >>= 1;
|
txn->wr.dirtylru >>= 1;
|
||||||
|
@ -1158,7 +1158,7 @@ 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 {
|
||||||
NOTICE("skip update meta%" PRIaPGNO " for txn#%" PRIaTXN "since it is already steady",
|
NOTICE("skip update meta%" PRIaPGNO " for txn#%" PRIaTXN ", since it is already steady",
|
||||||
data_page(head.ptr_c)->pgno, head.txnid);
|
data_page(head.ptr_c)->pgno, head.txnid);
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1291,6 +1291,7 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
/* coverity[array_null] */
|
||||||
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
||||||
rc = coherency_check_written(env, pending->unsafe_txnid, target,
|
rc = coherency_check_written(env, pending->unsafe_txnid, target,
|
||||||
bytes2pgno(env, ptr_dist(target, env->dxb_mmap.base)), ×tamp);
|
bytes2pgno(env, ptr_dist(target, env->dxb_mmap.base)), ×tamp);
|
||||||
|
@ -186,7 +186,7 @@ typedef struct reader_slot {
|
|||||||
/* The header for the reader table (a memory-mapped lock file). */
|
/* The header for the reader table (a memory-mapped lock file). */
|
||||||
typedef struct shared_lck {
|
typedef struct shared_lck {
|
||||||
/* Stamp identifying this as an MDBX file.
|
/* Stamp identifying this as an MDBX file.
|
||||||
* It must be set to MDBX_MAGIC with with MDBX_LOCK_VERSION. */
|
* It must be set to MDBX_MAGIC with MDBX_LOCK_VERSION. */
|
||||||
uint64_t magic_and_version;
|
uint64_t magic_and_version;
|
||||||
|
|
||||||
/* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
|
/* Format of this lock file. Must be set to MDBX_LOCK_FORMAT. */
|
||||||
|
@ -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));
|
||||||
|
@ -98,6 +98,7 @@ int txn_basal_start(MDBX_txn *txn, unsigned flags) {
|
|||||||
txn->wr.troika = meta_tap(env);
|
txn->wr.troika = meta_tap(env);
|
||||||
const meta_ptr_t head = meta_recent(env, &txn->wr.troika);
|
const meta_ptr_t head = meta_recent(env, &txn->wr.troika);
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
/* coverity[array_null] */
|
||||||
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
while ("workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269") {
|
||||||
int err = coherency_fetch_head(txn, head, ×tamp);
|
int err = coherency_fetch_head(txn, head, ×tamp);
|
||||||
if (likely(err == MDBX_SUCCESS))
|
if (likely(err == MDBX_SUCCESS))
|
||||||
|
@ -326,7 +326,6 @@ static void txn_merge(MDBX_txn *const parent, MDBX_txn *const txn, const size_t
|
|||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->flags &= ~MDBX_TXN_HAS_CHILD;
|
|
||||||
if (parent->wr.spilled.list) {
|
if (parent->wr.spilled.list) {
|
||||||
assert(pnl_check_allocated(parent->wr.spilled.list, (size_t)parent->geo.first_unallocated << 1));
|
assert(pnl_check_allocated(parent->wr.spilled.list, (size_t)parent->geo.first_unallocated << 1));
|
||||||
if (MDBX_PNL_GETSIZE(parent->wr.spilled.list))
|
if (MDBX_PNL_GETSIZE(parent->wr.spilled.list))
|
||||||
@ -349,26 +348,31 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
return LOG_IFERR(MDBX_ENOMEM);
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
|
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
|
txn->txnid = parent->txnid;
|
||||||
|
txn->front_txnid = parent->front_txnid + 1;
|
||||||
|
txn->canary = parent->canary;
|
||||||
|
parent->flags |= MDBX_TXN_HAS_CHILD;
|
||||||
|
parent->nested = txn;
|
||||||
|
txn->parent = parent;
|
||||||
|
txn->env->txn = txn;
|
||||||
|
txn->owner = parent->owner;
|
||||||
|
txn->wr.troika = parent->wr.troika;
|
||||||
rkl_init(&txn->wr.gc.reclaimed);
|
rkl_init(&txn->wr.gc.reclaimed);
|
||||||
|
|
||||||
#if MDBX_ENABLE_DBI_SPARSE
|
#if MDBX_ENABLE_DBI_SPARSE
|
||||||
txn->dbi_sparse = parent->dbi_sparse;
|
txn->dbi_sparse = parent->dbi_sparse;
|
||||||
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
#endif /* MDBX_ENABLE_DBI_SPARSE */
|
||||||
txn->dbi_seqs = parent->dbi_seqs;
|
txn->dbi_seqs = parent->dbi_seqs;
|
||||||
txn->geo = parent->geo;
|
txn->geo = parent->geo;
|
||||||
|
|
||||||
int err = dpl_alloc(txn);
|
int err = dpl_alloc(txn);
|
||||||
if (likely(err == MDBX_SUCCESS)) {
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count;
|
|
||||||
txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL);
|
|
||||||
if (unlikely(!txn->wr.repnl))
|
|
||||||
err = MDBX_ENOMEM;
|
|
||||||
}
|
|
||||||
if (unlikely(err != MDBX_SUCCESS)) {
|
|
||||||
failed:
|
|
||||||
pnl_free(txn->wr.repnl);
|
|
||||||
dpl_free(txn);
|
|
||||||
osal_free(txn);
|
|
||||||
return LOG_IFERR(err);
|
return LOG_IFERR(err);
|
||||||
}
|
|
||||||
|
const size_t len = MDBX_PNL_GETSIZE(parent->wr.repnl) + parent->wr.loose_count;
|
||||||
|
txn->wr.repnl = pnl_alloc((len > MDBX_PNL_INITIAL) ? len : MDBX_PNL_INITIAL);
|
||||||
|
if (unlikely(!txn->wr.repnl))
|
||||||
|
return LOG_IFERR(MDBX_ENOMEM);
|
||||||
|
|
||||||
/* Move loose pages to reclaimed list */
|
/* Move loose pages to reclaimed list */
|
||||||
if (parent->wr.loose_count) {
|
if (parent->wr.loose_count) {
|
||||||
@ -377,7 +381,7 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
tASSERT(parent, lp->flags == P_LOOSE);
|
tASSERT(parent, lp->flags == P_LOOSE);
|
||||||
err = pnl_insert_span(&parent->wr.repnl, lp->pgno, 1);
|
err = pnl_insert_span(&parent->wr.repnl, lp->pgno, 1);
|
||||||
if (unlikely(err != MDBX_SUCCESS))
|
if (unlikely(err != MDBX_SUCCESS))
|
||||||
goto failed;
|
return LOG_IFERR(err);
|
||||||
MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *));
|
MDBX_ASAN_UNPOISON_MEMORY_REGION(&page_next(lp), sizeof(page_t *));
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *));
|
VALGRIND_MAKE_MEM_DEFINED(&page_next(lp), sizeof(page_t *));
|
||||||
parent->wr.loose_pages = page_next(lp);
|
parent->wr.loose_pages = page_next(lp);
|
||||||
@ -390,6 +394,9 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
#endif /* MDBX_ENABLE_REFUND */
|
#endif /* MDBX_ENABLE_REFUND */
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
}
|
}
|
||||||
|
#if MDBX_ENABLE_REFUND
|
||||||
|
txn->wr.loose_refund_wl = 0;
|
||||||
|
#endif /* MDBX_ENABLE_REFUND */
|
||||||
txn->wr.dirtyroom = parent->wr.dirtyroom;
|
txn->wr.dirtyroom = parent->wr.dirtyroom;
|
||||||
txn->wr.dirtylru = parent->wr.dirtylru;
|
txn->wr.dirtylru = parent->wr.dirtylru;
|
||||||
|
|
||||||
@ -399,6 +406,7 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
|
|
||||||
tASSERT(txn, MDBX_PNL_ALLOCLEN(txn->wr.repnl) >= MDBX_PNL_GETSIZE(parent->wr.repnl));
|
tASSERT(txn, MDBX_PNL_ALLOCLEN(txn->wr.repnl) >= MDBX_PNL_GETSIZE(parent->wr.repnl));
|
||||||
memcpy(txn->wr.repnl, parent->wr.repnl, MDBX_PNL_SIZEOF(parent->wr.repnl));
|
memcpy(txn->wr.repnl, parent->wr.repnl, MDBX_PNL_SIZEOF(parent->wr.repnl));
|
||||||
|
/* coverity[assignment_where_comparison_intended] */
|
||||||
tASSERT(txn, pnl_check_allocated(txn->wr.repnl, (txn->geo.first_unallocated /* LY: intentional assignment
|
tASSERT(txn, pnl_check_allocated(txn->wr.repnl, (txn->geo.first_unallocated /* LY: intentional assignment
|
||||||
here, only for assertion */
|
here, only for assertion */
|
||||||
= parent->geo.first_unallocated) -
|
= parent->geo.first_unallocated) -
|
||||||
@ -413,18 +421,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
txn->wr.retired_pages = parent->wr.retired_pages;
|
txn->wr.retired_pages = parent->wr.retired_pages;
|
||||||
parent->wr.retired_pages = (void *)(intptr_t)MDBX_PNL_GETSIZE(parent->wr.retired_pages);
|
parent->wr.retired_pages = (void *)(intptr_t)MDBX_PNL_GETSIZE(parent->wr.retired_pages);
|
||||||
|
|
||||||
txn->txnid = parent->txnid;
|
|
||||||
txn->front_txnid = parent->front_txnid + 1;
|
|
||||||
#if MDBX_ENABLE_REFUND
|
|
||||||
txn->wr.loose_refund_wl = 0;
|
|
||||||
#endif /* MDBX_ENABLE_REFUND */
|
|
||||||
txn->canary = parent->canary;
|
|
||||||
parent->flags |= MDBX_TXN_HAS_CHILD;
|
|
||||||
parent->nested = txn;
|
|
||||||
txn->parent = parent;
|
|
||||||
txn->owner = parent->owner;
|
|
||||||
txn->wr.troika = parent->wr.troika;
|
|
||||||
|
|
||||||
txn->cursors[FREE_DBI] = nullptr;
|
txn->cursors[FREE_DBI] = nullptr;
|
||||||
txn->cursors[MAIN_DBI] = nullptr;
|
txn->cursors[MAIN_DBI] = nullptr;
|
||||||
txn->dbi_state[FREE_DBI] = parent->dbi_state[FREE_DBI] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY);
|
txn->dbi_state[FREE_DBI] = parent->dbi_state[FREE_DBI] & ~(DBI_FRESH | DBI_CREAT | DBI_DIRTY);
|
||||||
@ -436,7 +432,6 @@ int txn_nested_create(MDBX_txn *parent, const MDBX_txn_flags_t flags) {
|
|||||||
(parent->parent ? parent->parent->wr.dirtyroom : parent->env->options.dp_limit));
|
(parent->parent ? parent->parent->wr.dirtyroom : parent->env->options.dp_limit));
|
||||||
tASSERT(txn, txn->wr.dirtyroom + txn->wr.dirtylist->length ==
|
tASSERT(txn, txn->wr.dirtyroom + txn->wr.dirtylist->length ==
|
||||||
(txn->parent ? txn->parent->wr.dirtyroom : txn->env->options.dp_limit));
|
(txn->parent ? txn->parent->wr.dirtyroom : txn->env->options.dp_limit));
|
||||||
parent->env->txn = txn;
|
|
||||||
tASSERT(parent, parent->cursors[FREE_DBI] == nullptr);
|
tASSERT(parent, parent->cursors[FREE_DBI] == nullptr);
|
||||||
// TODO: shadow GC' cursor
|
// TODO: shadow GC' cursor
|
||||||
return txn_shadow_cursors(parent, MAIN_DBI);
|
return txn_shadow_cursors(parent, MAIN_DBI);
|
||||||
@ -456,9 +451,6 @@ void txn_nested_abort(MDBX_txn *nested) {
|
|||||||
parent->wr.retired_pages = nested->wr.retired_pages;
|
parent->wr.retired_pages = nested->wr.retired_pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->wr.dirtylru = nested->wr.dirtylru;
|
|
||||||
parent->nested = nullptr;
|
|
||||||
parent->flags &= ~MDBX_TXN_HAS_CHILD;
|
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
tASSERT(parent, audit_ex(parent, 0, false) == 0);
|
tASSERT(parent, audit_ex(parent, 0, false) == 0);
|
||||||
dpl_release_shadows(nested);
|
dpl_release_shadows(nested);
|
||||||
@ -554,15 +546,16 @@ int txn_nested_join(MDBX_txn *txn, struct commit_timestamp *ts) {
|
|||||||
/* 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)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,9 +567,10 @@ int txn_nested_join(MDBX_txn *txn, struct commit_timestamp *ts) {
|
|||||||
ts->sync = /* no sync */ ts->write;
|
ts->sync = /* no sync */ ts->write;
|
||||||
}
|
}
|
||||||
txn_merge(parent, txn, parent_retired_len);
|
txn_merge(parent, txn, parent_retired_len);
|
||||||
|
tASSERT(parent, parent->flags & MDBX_TXN_HAS_CHILD);
|
||||||
|
parent->flags -= MDBX_TXN_HAS_CHILD;
|
||||||
env->txn = parent;
|
env->txn = parent;
|
||||||
parent->nested = nullptr;
|
parent->nested = nullptr;
|
||||||
parent->flags &= ~MDBX_TXN_HAS_CHILD;
|
|
||||||
tASSERT(parent, dpl_check(parent));
|
tASSERT(parent, dpl_check(parent));
|
||||||
|
|
||||||
#if MDBX_ENABLE_REFUND
|
#if MDBX_ENABLE_REFUND
|
||||||
|
@ -362,7 +362,10 @@ int txn_end(MDBX_txn *txn, unsigned mode) {
|
|||||||
tASSERT(txn, pnl_check_allocated(txn->wr.repnl, txn->geo.first_unallocated - MDBX_ENABLE_REFUND));
|
tASSERT(txn, pnl_check_allocated(txn->wr.repnl, txn->geo.first_unallocated - MDBX_ENABLE_REFUND));
|
||||||
tASSERT(txn, memcmp(&txn->wr.troika, &parent->wr.troika, sizeof(troika_t)) == 0);
|
tASSERT(txn, memcmp(&txn->wr.troika, &parent->wr.troika, sizeof(troika_t)) == 0);
|
||||||
tASSERT(txn, mode & TXN_END_FREE);
|
tASSERT(txn, mode & TXN_END_FREE);
|
||||||
|
tASSERT(parent, parent->flags & MDBX_TXN_HAS_CHILD);
|
||||||
env->txn = parent;
|
env->txn = parent;
|
||||||
|
parent->nested = nullptr;
|
||||||
|
parent->flags -= MDBX_TXN_HAS_CHILD;
|
||||||
const pgno_t nested_now = txn->geo.now, nested_upper = txn->geo.upper;
|
const pgno_t nested_now = txn->geo.now, nested_upper = txn->geo.upper;
|
||||||
txn_nested_abort(txn);
|
txn_nested_abort(txn);
|
||||||
|
|
||||||
|
@ -23,7 +23,13 @@
|
|||||||
#define RELIEF_FACTOR 1
|
#define RELIEF_FACTOR 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NN (1000 / RELIEF_FACTOR)
|
static const auto NN = 1000u / RELIEF_FACTOR;
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
|
||||||
|
static const auto N = std::min(17u, std::thread::hardware_concurrency());
|
||||||
|
#else
|
||||||
|
static const auto N = 3u;
|
||||||
|
#endif
|
||||||
|
|
||||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||||
unsigned length) noexcept {
|
unsigned length) noexcept {
|
||||||
@ -107,6 +113,7 @@ bool case0(mdbx::env env) {
|
|||||||
* 4. Ждем завершения фоновых потоков.
|
* 4. Ждем завершения фоновых потоков.
|
||||||
* 5. Закрываем оставшиеся курсоры и закрываем БД. */
|
* 5. Закрываем оставшиеся курсоры и закрываем БД. */
|
||||||
|
|
||||||
|
size_t global_seed = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||||
thread_local size_t salt;
|
thread_local size_t salt;
|
||||||
|
|
||||||
static size_t prng() {
|
static size_t prng() {
|
||||||
@ -172,9 +179,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 +234,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);
|
||||||
@ -240,7 +269,7 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque<mdbx::map_handle> &dbi,
|
|||||||
pre.unbind();
|
pre.unbind();
|
||||||
if (!pre.txn())
|
if (!pre.txn())
|
||||||
pre.bind(txn, dbi[prng(dbi.size())]);
|
pre.bind(txn, dbi[prng(dbi.size())]);
|
||||||
for (auto i = 0; i < NN; ++i) {
|
for (auto i = 0u; i < NN; ++i) {
|
||||||
auto k = mdbx::default_buffer::wrap(prng(NN));
|
auto k = mdbx::default_buffer::wrap(prng(NN));
|
||||||
auto v = mdbx::default_buffer::wrap(prng(NN));
|
auto v = mdbx::default_buffer::wrap(prng(NN));
|
||||||
if (pre.find_multivalue(k, v, false))
|
if (pre.find_multivalue(k, v, false))
|
||||||
@ -253,6 +282,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
|
||||||
@ -260,7 +291,16 @@ void case1_write_cycle(mdbx::txn_managed txn, std::deque<mdbx::map_handle> &dbi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool case1_thread(mdbx::env env, std::deque<mdbx::map_handle> dbi, mdbx::cursor pre) {
|
bool case1_thread(mdbx::env env, std::deque<mdbx::map_handle> dbi, mdbx::cursor pre) {
|
||||||
salt = size_t(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
|
||||||
|
mdbx::error::success_or_throw(mdbx_txn_lock(env, false));
|
||||||
|
std::hash<std::thread::id> hasher;
|
||||||
|
salt = global_seed ^ hasher(std::this_thread::get_id());
|
||||||
|
std::cout << "thread " << std::this_thread::get_id() << ", salt " << salt << std::endl << std::flush;
|
||||||
|
mdbx_txn_unlock(env);
|
||||||
|
#else
|
||||||
|
salt = global_seed;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::vector<MDBX_cursor *> pool;
|
std::vector<MDBX_cursor *> pool;
|
||||||
for (auto loop = 0; loop < 333 / RELIEF_FACTOR; ++loop) {
|
for (auto loop = 0; loop < 333 / RELIEF_FACTOR; ++loop) {
|
||||||
for (auto read = 0; read < 333 / RELIEF_FACTOR; ++read) {
|
for (auto read = 0; read < 333 / RELIEF_FACTOR; ++read) {
|
||||||
@ -287,12 +327,7 @@ bool case1(mdbx::env env) {
|
|||||||
bool ok = true;
|
bool ok = true;
|
||||||
std::deque<mdbx::map_handle> dbi;
|
std::deque<mdbx::map_handle> dbi;
|
||||||
std::vector<mdbx::cursor_managed> cursors;
|
std::vector<mdbx::cursor_managed> cursors;
|
||||||
#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
|
for (auto t = 0u; t < N; ++t) {
|
||||||
static const auto N = 10;
|
|
||||||
#else
|
|
||||||
static const auto N = 3;
|
|
||||||
#endif
|
|
||||||
for (auto t = 0; t < N; ++t) {
|
|
||||||
auto txn = env.start_write();
|
auto txn = env.start_write();
|
||||||
auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength);
|
auto table = txn.create_map(std::to_string(t), mdbx::key_mode::ordinal, mdbx::value_mode::multi_samelength);
|
||||||
auto cursor = txn.open_cursor(table);
|
auto cursor = txn.open_cursor(table);
|
||||||
@ -307,7 +342,7 @@ bool case1(mdbx::env env) {
|
|||||||
#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
|
#if defined(__cpp_lib_latch) && __cpp_lib_latch >= 201907L
|
||||||
std::latch s(1);
|
std::latch s(1);
|
||||||
std::vector<std::thread> threads;
|
std::vector<std::thread> threads;
|
||||||
for (auto t = 1; t < N; ++t) {
|
for (auto t = 1u; t < cursors.size(); ++t) {
|
||||||
case1_cycle_dbi(dbi);
|
case1_cycle_dbi(dbi);
|
||||||
threads.push_back(std::thread([&, t]() {
|
threads.push_back(std::thread([&, t]() {
|
||||||
s.wait();
|
s.wait();
|
||||||
@ -358,7 +393,7 @@ int doit() {
|
|||||||
mdbx::env::remove(db_filename);
|
mdbx::env::remove(db_filename);
|
||||||
|
|
||||||
mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(),
|
mdbx::env_managed env(db_filename, mdbx::env_managed::create_parameters(),
|
||||||
mdbx::env::operate_parameters(42, 0, mdbx::env::nested_transactions));
|
mdbx::env::operate_parameters(N + 2, 0, mdbx::env::nested_transactions));
|
||||||
|
|
||||||
bool ok = case0(env);
|
bool ok = case0(env);
|
||||||
ok = case1(env) && ok;
|
ok = case1(env) && ok;
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user