mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d58857f8f | ||
|
|
db389cde2a | ||
|
|
43cb9133ee | ||
|
|
71df2ec129 | ||
|
|
e2fb593504 | ||
|
|
2930b304dc | ||
|
|
a39dfd99a7 | ||
|
|
66d116c301 | ||
|
|
f71b729759 | ||
|
|
566b0f93c7 | ||
|
|
df3a18d0cf | ||
|
|
675b462601 | ||
|
|
7c990542e3 | ||
|
|
9093435ce6 | ||
|
|
7ef7a1f983 | ||
|
|
ac275d246b | ||
|
|
d2f4697df3 | ||
|
|
b107842c3d | ||
|
|
cb428e613f | ||
|
|
5c69cb322a | ||
|
|
6318ca701a | ||
|
|
9c1f3aa4b5 | ||
|
|
759d0442d4 | ||
|
|
6cb9305b31 | ||
|
|
68f9dc18be | ||
|
|
f5aa804a2d | ||
|
|
7468ce6ada | ||
|
|
decf34fd2b | ||
|
|
f1b933c541 | ||
|
|
230fbd64f5 | ||
|
|
e8bfffc9f6 | ||
|
|
6abaa67eb8 | ||
|
|
266937e72d | ||
|
|
5c44dd201c | ||
|
|
f4384800b5 | ||
|
|
a971c76aff | ||
|
|
b6f918aa1c | ||
|
|
ab2f661c97 | ||
|
|
5548ef20f6 | ||
|
|
679c1eb939 | ||
|
|
76a588f91b | ||
|
|
6b5515908b | ||
|
|
214fa153e2 | ||
|
|
819551ce13 | ||
|
|
a22c0c5c48 | ||
|
|
9540cabf5f | ||
|
|
0e3b093eb5 | ||
|
|
5d38add405 | ||
|
|
b55a41f604 | ||
|
|
29bed7cf5d | ||
|
|
8d0eceee9f | ||
|
|
56a6377622 | ||
|
|
19dc93fc76 | ||
|
|
5f1d8dcb3e | ||
|
|
3d2b221256 | ||
|
|
ca1808d57f | ||
|
|
aa98d6a88e | ||
|
|
b9b14f0061 |
160
ChangeLog.md
160
ChangeLog.md
@@ -4,6 +4,164 @@ ChangeLog
|
||||
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).
|
||||
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx) and mirrors on [abf.io](https://abf.io/erthink/libmdbx), [hub.mos.ru](https://hub.mos.ru/leo/libmdbx) and [Github](https://github.com/erthink/libmdbx).
|
||||
Please use the `stable` branch or the latest release for production environment through stagging, but the `master` branch for development a derivative projects.
|
||||
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||
Всё будет хорошо!
|
||||
|
||||
## v0.13.8 "Всеобуч" (v`seabooch) от 2025-08-31
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов,
|
||||
в день 100 летнего юбилея Постановления Всероссийского центрального исполнительного комитета о всеобщем бесплатном начальном образовании.
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Erigon](https://erigon.tech/) за спонсорство.
|
||||
|
||||
Исправления:
|
||||
|
||||
- Устранена возможность получения неожиданного `SIGBUS` из-за отложенного/ленивого выделение места в заполненной файловой системе после приращения файла БД.
|
||||
Более подробное пояснение в комментарии коммита [`2930b304dc674bbccd188b7ce7c3f83755ef706e`](https://gitflic.ru/project/erthink/libmdbx/commit/2930b304dc674bbccd188b7ce7c3f83755ef706e).
|
||||
|
||||
Изменение поведения:
|
||||
|
||||
- Вновь включена/разрешена на старых ядрах Linux, начиная с версии 3.16, так как
|
||||
сейчас уже нет причин отказываться от работы на 3.16 поддерживая при этом ядра 4.x,
|
||||
и еще есть проекты (Isar, Isar-Community, Hive) которым требуется такая поддержка.
|
||||
|
||||
- Ошибка `MDBX_WANNA_RECOVERY` при открытии БД в режиме только-чтение теперь возвращается если размер БД не кратен размеру системной страницы,
|
||||
но игнорируется не кратность размеру блока выделения виртуальной памяти.
|
||||
Этим устраняется регресс, проявившейся вследствие изменения поведения после задействования
|
||||
системного вызова `fallocate()` для предотвращения `SIGBUS` после приращения файла БД в заполненной файловой системе.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.13.7 "Дружба" (Friendship) от 2025-07-30.
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов,
|
||||
в [международный день дружбы](https://www.un.org/ru/observances/friendship-day).
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Erigon](https://erigon.tech/) за спонсорство.
|
||||
- [Артёму Воротникову](https://github.com/vorot93) за сообщение об ошибках и тестировании [призязок для Rust](https://github.com/vorot93/libmdbx-rs).
|
||||
|
||||
Исправления:
|
||||
|
||||
- Устранена критическая ошибка в функционале `mdbx_env_resurrect_after_fork()` при использовании SysV-семафоров.
|
||||
|
||||
Проявлялась ошибка только после порождения дочернего процесса посредством `fork()` на фоне выполняющейся пишущей транзакции, что
|
||||
приводило к неверной работе семафоров и далее к самым различным ошибкам, вплоть до повреждения БД. Проблема существовала начиная с появления
|
||||
`mdbx_env_resurrect_after_fork()` и затрагивала OSX, а также POSIX-платформы при сборке с опцией `MDBX_LOCKING=5`.
|
||||
|
||||
- Устранена проблема в API копирования БД на отличных от Linux системах POSIX,
|
||||
а также в некоторых случаях при расположении целевого файла на не-локальной файловой системе.
|
||||
Проблема проявлялась в основном на OSX, возвратом ошибки `EWOULDBLOCK`/`EAGAIN` (35),
|
||||
что обусловлено недочетом/конфликтом блокировок `fcntl(F_SETLK)` и `flock()` в ядре ОС.
|
||||
Переработана обработка ошибок захвата файловых блокировок в API копирования на системах POSIX.
|
||||
|
||||
- Устранена ошибка приводившая к неожиданному возврату `MDBX_BAD_DBI` при одновременном старте нескольких транзакций внутри одного процесса после открытия БД.
|
||||
|
||||
- Устранена ошибка приводившая к неожиданному возврату `MDBX_DBS_FULL` при повторном открытии уже открытых таблиц и уже достигнутом лимите открытых DBI-дескрипторов.
|
||||
|
||||
- Исправлена ошибка сборки для платформы Android при явном определении `_FILE_OFFSET_BITS`.
|
||||
|
||||
- Исправлена ошибка использования `ENOMEM` вместо `MDBX_ENOMEM`.
|
||||
Что могло ломать сборку на не-POSIX/Windows платформах, в зависимости от конфигурации и/или версии SDK.
|
||||
|
||||
- Поправлено либо удалено несколько неверных assert-проверок, из-за которых происходили падения отладочных сборок в специфических ситуациях.
|
||||
Главным образом, в коде функций `txn_end()`, `txn_lock()` и `txn_unlock()` как на Windows, так и на POSIX.
|
||||
|
||||
- Устранены несущественные предупреждения MSVC. Отключены предупреждения `C5286` и `C5287`.
|
||||
|
||||
Прочие доработки:
|
||||
|
||||
- Доработана логика отказа от использования OFD-блокировок на POSIX-платформах.
|
||||
Теперь кроме `EINVAL` учитываются дополнительные коды ошибок (`ENOSYS`, `ENOIMPL`, `ENOTSUP`, `ENOSUPP`, `EOPNOTSUPP`),
|
||||
что позволит работать собранной библиотеке в некоторых случаях,
|
||||
когда актуальное ядро/контейнер/эмулятор не поддерживает требуемых системных вызовов.
|
||||
|
||||
- В тестовый фреймворк добавлена поддержка опции --numa # для привязки стохастического теста к NUMA-узлу,
|
||||
а в battery/tmux-скрипте добавлено явное распределение по NUMA-узлам, что существенно увеличило КПД
|
||||
при тестировании на NUMA-машинах.
|
||||
|
||||
- В стохастическом скрипте реализован случайный порядок запуска отдельных тестов.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
||||
@@ -107,7 +265,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()`.
|
||||
|
||||
Прочие доработки:
|
||||
|
||||
|
||||
29
GNUmakefile
29
GNUmakefile
@@ -384,8 +384,9 @@ endef
|
||||
|
||||
define uname2titer
|
||||
case "$(UNAME)" in
|
||||
CYGWIN*|MINGW*|MSYS*|Windows*) echo 2;;
|
||||
Darwin*|Mach*) echo 2;;
|
||||
*) echo 12;;
|
||||
*) if [ -z "${CI}" ]; then echo 7; else echo 3; fi;;
|
||||
esac
|
||||
endef
|
||||
|
||||
@@ -809,17 +810,21 @@ endif
|
||||
# Cross-compilation simple test
|
||||
|
||||
CROSS_LIST = \
|
||||
mips64-linux-gnuabi64-gcc mips-linux-gnu-gcc \
|
||||
hppa-linux-gnu-gcc s390x-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc powerpc-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc
|
||||
aarch64-linux-gnu-gcc \
|
||||
arm-linux-gnueabihf-gcc \
|
||||
hppa-linux-gnu-gcc \
|
||||
mips64-linux-gnuabi64-gcc \
|
||||
mips-linux-gnu-gcc \
|
||||
powerpc64-linux-gnu-gcc\
|
||||
riscv64-linux-gnu-gcc \
|
||||
s390x-linux-gnu-gcc \
|
||||
sh4-linux-gnu-gcc
|
||||
|
||||
## On Ubuntu Focal (22.04) with QEMU 6.2 (1:6.2+dfsg-2ubuntu6.6) & GCC 11.3 (11.3.0-1ubuntu1~22.04)
|
||||
# sh4-linux-gnu-gcc - coredump (qemu mmap-troubles)
|
||||
# sparc64-linux-gnu-gcc - coredump (qemu mmap-troubles, previously: qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
# alpha-linux-gnu-gcc - coredump (qemu mmap-troubles)
|
||||
# risc64-linux-gnu-gcc - coredump (qemu qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
CROSS_LIST_NOQEMU = sh4-linux-gnu-gcc sparc64-linux-gnu-gcc alpha-linux-gnu-gcc riscv64-linux-gnu-gcc
|
||||
## On Ubuntu Noble (24.04.2) with QEMU 8.2 (8.2.2+ds-0ubuntu1.7) & GCC 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
|
||||
# sparc64-linux-gnu-gcc - fails mmap/BAD_ADDRESS (previously: qemu-coredump sice mmap-troubles, qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
# alpha-linux-gnu-gcc - qemu-coredump (qemu mmap-troubles)
|
||||
# powerpc-linux-gnu-gcc - fails mmap/BAD_ADDRESS (previously: qemu-coredump sice mmap-troubles, qemu fails fcntl for F_SETLK/F_GETLK)
|
||||
CROSS_LIST_NOQEMU = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc powerpc-linux-gnu-gcc
|
||||
|
||||
cross-gcc:
|
||||
@echo ' Re-building by cross-compiler for: $(CROSS_LIST_NOQEMU) $(CROSS_LIST)'
|
||||
@@ -841,7 +846,7 @@ cross-qemu:
|
||||
$(QUIET)for CC in $(CROSS_LIST); do \
|
||||
echo "===================== $$CC + qemu"; \
|
||||
$(MAKE) IOARENA=false CXXSTD= clean && \
|
||||
CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \
|
||||
CC=$$CC CXX=$$(echo $$CC | $(SED) 's/-gcc/-g++/') EXE_LDFLAGS=-static MDBX_BUILD_OPTIONS="-DMDBX_LOCKING=5 -DMDBX_SAFE4QEMU $(MDBX_BUILD_OPTIONS)" \
|
||||
$(MAKE) IOARENA=false smoke-singleprocess test-singleprocess || exit $$?; \
|
||||
done
|
||||
|
||||
|
||||
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
|
||||
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>
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
For notes about the license change, credits and acknowledgments,
|
||||
please refer to the COPYRIGHT file within original libmdbx source code
|
||||
repository https://gitflic.ru/project/erthink/libmdbx
|
||||
please refer to the COPYRIGHT file within libmdbx source.
|
||||
|
||||
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.
|
||||
For the same reason ~~Github~~ is blacklisted forever.
|
||||
---
|
||||
|
||||
On 2022-04-15, without any warnings or following explanations, the
|
||||
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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- Required extensions: pymdownx.betterem, pymdownx.tilde, pymdownx.emoji, pymdownx.tasklist, pymdownx.superfences -->
|
||||
|
||||
> Please refer to the online [documentation](https://libmdbx.dqdkfa.ru)
|
||||
> Please refer to the online [official libmdbx documentation site](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).
|
||||
|
||||
@@ -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)).
|
||||
> 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`.
|
||||
> Всё будет хорошо!
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx).
|
||||
The source code is availale on [Gitflic](https://gitflic.ru/project/erthink/libmdbx) and mirrors on [abf.io](https://abf.io/erthink/libmdbx), [hub.mos.ru](https://hub.mos.ru/leo/libmdbx) and [Github](https://github.com/erthink/libmdbx).
|
||||
Donations are welcome to ETH `0xD104d8f8B2dC312aaD74899F83EBf3EEBDC1EA3A`.
|
||||
Всё будет хорошо!
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From 49256dcd050fd0ee67860b7bc544dabe088d08e9 Mon Sep 17 00:00:00 2001
|
||||
From f2f1f6e76c1538d044b552d9e7ecedc3433e6cd9 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?=
|
||||
=?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= <leo@yuriev.ru>
|
||||
Date: Fri, 14 Feb 2025 21:34:25 +0300
|
||||
Date: Sun, 3 Aug 2025 23:59:11 +0300
|
||||
Subject: [PATCH] package/libmdbx: new package (library/database).
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
@@ -15,7 +15,7 @@ This patch adds libmdbx:
|
||||
in terms of reliability, features and performance.
|
||||
- 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.7 "Дружба" (Friendship) is stable release of _libmdbx_ branch with new superior features.
|
||||
|
||||
The complete ChangeLog: https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md
|
||||
|
||||
@@ -25,8 +25,8 @@ Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
package/Config.in | 1 +
|
||||
package/libmdbx/Config.in | 45 ++++++++++++++++++++++++++++++++++++
|
||||
package/libmdbx/libmdbx.hash | 6 +++++
|
||||
package/libmdbx/libmdbx.mk | 42 +++++++++++++++++++++++++++++++++
|
||||
5 files changed, 97 insertions(+)
|
||||
package/libmdbx/libmdbx.mk | 41 ++++++++++++++++++++++++++++++++
|
||||
5 files changed, 96 insertions(+)
|
||||
create mode 100644 package/libmdbx/Config.in
|
||||
create mode 100644 package/libmdbx/libmdbx.hash
|
||||
create mode 100644 package/libmdbx/libmdbx.mk
|
||||
@@ -110,35 +110,34 @@ index 0000000000..a9a4ac45c5
|
||||
+ !BR2_TOOLCHAIN_GCC_AT_LEAST_4_4
|
||||
diff --git a/package/libmdbx/libmdbx.hash b/package/libmdbx/libmdbx.hash
|
||||
new file mode 100644
|
||||
index 0000000000..202937e7be
|
||||
index 0000000000..8c7efb184b
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.hash
|
||||
@@ -0,0 +1,6 @@
|
||||
+# Hashes from: https://libmdbx.dqdkfa.ru/release/SHA256SUMS
|
||||
+sha256 86df30ca2231c9b3ad71424bb829dca9041947f5539d4295030c653d4982c1be libmdbx-amalgamated-0.13.4.tar.xz
|
||||
+sha256 d00c1287ec6bbc366363ccdd3eea97bd470ccb5cc102d56b341f84a9fba7e8e9 libmdbx-amalgamated-0.13.7.tar.xz
|
||||
+
|
||||
+# Locally calculated
|
||||
+sha256 0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594 LICENSE
|
||||
+sha256 699a62986b6c8d31124646dffd4b15872c7d3bc5eecea5994edb1f5195df49d1 NOTICE
|
||||
+sha256 651f71b46c6bb0046d2122df7f9def9cb24f4dc28c5b11cef059f66565cda30f NOTICE
|
||||
diff --git a/package/libmdbx/libmdbx.mk b/package/libmdbx/libmdbx.mk
|
||||
new file mode 100644
|
||||
index 0000000000..a8a6f3dbdf
|
||||
index 0000000000..bbb37f21a6
|
||||
--- /dev/null
|
||||
+++ b/package/libmdbx/libmdbx.mk
|
||||
@@ -0,0 +1,42 @@
|
||||
@@ -0,0 +1,41 @@
|
||||
+################################################################################
|
||||
+#
|
||||
+# libmdbx
|
||||
+#
|
||||
+################################################################################
|
||||
+
|
||||
+LIBMDBX_VERSION = 0.13.4
|
||||
+LIBMDBX_VERSION = 0.13.7
|
||||
+LIBMDBX_SOURCE = libmdbx-amalgamated-$(LIBMDBX_VERSION).tar.xz
|
||||
+LIBMDBX_SITE = https://libmdbx.dqdkfa.ru/release
|
||||
+LIBMDBX_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
+LIBMDBX_LICENSE = Apache-2.0
|
||||
+LIBMDBX_LICENSE_FILES = LICENSE NOTICE
|
||||
+LIBMDBX_REDISTRIBUTE = YES
|
||||
+LIBMDBX_STRIP_COMPONENTS = 0
|
||||
+LIBMDBX_INSTALL_STAGING = YES
|
||||
+
|
||||
@@ -169,5 +168,5 @@ index 0000000000..a8a6f3dbdf
|
||||
+
|
||||
+$(eval $(cmake-package))
|
||||
--
|
||||
2.48.1
|
||||
2.50.1
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@ __cold static int copy_with_compacting(MDBX_env *env, MDBX_txn *txn, mdbx_fileha
|
||||
if (meta->geometry.now != meta->geometry.first_unallocated) {
|
||||
const size_t whole_size = pgno2bytes(env, meta->geometry.now);
|
||||
if (!dest_is_pipe)
|
||||
return osal_ftruncate(fd, whole_size);
|
||||
return osal_fallocate(fd, whole_size);
|
||||
|
||||
const size_t used_size = pgno2bytes(env, meta->geometry.first_unallocated);
|
||||
memset(data_buffer, 0, (size_t)MDBX_ENVCOPY_WRITEBUF);
|
||||
@@ -571,11 +571,17 @@ retry_snap_meta:
|
||||
uint8_t *const data_buffer = buffer + ceil_powerof2(meta_bytes, globals.sys_pagesize);
|
||||
#if MDBX_USE_COPYFILERANGE
|
||||
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;
|
||||
struct statfs statfs_info;
|
||||
if (fstatfs(fd, &statfs_info) || statfs_info.f_type == /* ECRYPTFS_SUPER_MAGIC */ 0xf15f)
|
||||
/* avoid use copyfilerange_unavailable() to ecryptfs due bugs */
|
||||
not_the_same_filesystem = true;
|
||||
if (!copyfilerange_unavailable) {
|
||||
struct statfs statfs_info;
|
||||
if (fstatfs(fd, &statfs_info) || statfs_info.f_type == /* ECRYPTFS_SUPER_MAGIC */ 0xf15f)
|
||||
/* avoid use copyfilerange_unavailable() to ecryptfs due bugs */
|
||||
not_the_same_filesystem = true;
|
||||
}
|
||||
#endif /* MDBX_USE_COPYFILERANGE */
|
||||
|
||||
for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
|
||||
@@ -597,7 +603,7 @@ retry_snap_meta:
|
||||
continue;
|
||||
}
|
||||
rc = MDBX_ENODATA;
|
||||
if (written == 0 || ignore_enosys(rc = errno) != MDBX_RESULT_TRUE)
|
||||
if (written == 0 || ignore_enosys_and_eagain(rc = errno) != MDBX_RESULT_TRUE)
|
||||
break;
|
||||
sendfile_unavailable = true;
|
||||
}
|
||||
@@ -621,7 +627,7 @@ retry_snap_meta:
|
||||
maybe useful for others FS */
|
||||
EINVAL)
|
||||
not_the_same_filesystem = true;
|
||||
else if (ignore_enosys(rc) == MDBX_RESULT_TRUE)
|
||||
else if (ignore_enosys_and_eagain(rc) == MDBX_RESULT_TRUE)
|
||||
copyfilerange_unavailable = true;
|
||||
else
|
||||
break;
|
||||
@@ -642,7 +648,7 @@ retry_snap_meta:
|
||||
/* Extend file if required */
|
||||
if (likely(rc == MDBX_SUCCESS) && whole_size != used_size) {
|
||||
if (!dest_is_pipe)
|
||||
rc = osal_ftruncate(fd, whole_size);
|
||||
rc = osal_fallocate(fd, whole_size);
|
||||
else {
|
||||
memset(data_buffer, 0, (size_t)MDBX_ENVCOPY_WRITEBUF);
|
||||
for (size_t offset = used_size; rc == MDBX_SUCCESS && offset < whole_size;) {
|
||||
@@ -749,24 +755,66 @@ __cold static int copy2pathname(MDBX_txn *txn, const pathchar_t *dest_path, MDBX
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
|
||||
#endif
|
||||
);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* no locking required since the file opened with ShareMode == 0 */
|
||||
#else
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
MDBX_STRUCT_FLOCK lock_op;
|
||||
memset(&lock_op, 0, sizeof(lock_op));
|
||||
lock_op.l_type = F_WRLCK;
|
||||
lock_op.l_whence = SEEK_SET;
|
||||
lock_op.l_start = 0;
|
||||
lock_op.l_len = OFF_T_MAX;
|
||||
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)
|
||||
MDBX_STRUCT_FLOCK lock_op;
|
||||
memset(&lock_op, 0, sizeof(lock_op));
|
||||
lock_op.l_type = F_WRLCK;
|
||||
lock_op.l_whence = SEEK_SET;
|
||||
lock_op.l_start = 0;
|
||||
lock_op.l_len = OFF_T_MAX;
|
||||
const int err_fcntl = MDBX_FCNTL(newfd, MDBX_F_SETLK, &lock_op) ? errno : MDBX_SUCCESS;
|
||||
|
||||
const int err_flock =
|
||||
#ifdef LOCK_EX
|
||||
flock(newfd, LOCK_EX | LOCK_NB) ? errno : MDBX_SUCCESS;
|
||||
#else
|
||||
MDBX_ENOSYS;
|
||||
#endif /* LOCK_EX */
|
||||
|
||||
const int err_check_fs_local =
|
||||
/* avoid call osal_check_fs_local() on success */
|
||||
(!err_fcntl && !err_flock && !MDBX_DEBUG) ? MDBX_SUCCESS :
|
||||
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 24
|
||||
osal_check_fs_local(newfd, 0);
|
||||
#else
|
||||
MDBX_ENOSYS;
|
||||
#endif
|
||||
|
||||
const bool flock_may_fail =
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
err_check_fs_local != 0;
|
||||
#else
|
||||
true;
|
||||
#endif /* Linux */
|
||||
)
|
||||
rc = errno;
|
||||
|
||||
if (!err_fcntl &&
|
||||
(err_flock == EWOULDBLOCK || err_flock == EAGAIN || ignore_enosys_and_eremote(err_flock) == MDBX_RESULT_TRUE)) {
|
||||
rc = err_flock;
|
||||
if (flock_may_fail) {
|
||||
WARNING("ignore %s(%" MDBX_PRIsPATH ") error %d: since %s done, local/remote-fs check %d", "flock", dest_path,
|
||||
err_flock, "fcntl-lock", err_check_fs_local);
|
||||
rc = MDBX_SUCCESS;
|
||||
}
|
||||
} else if (!err_flock && err_check_fs_local == MDBX_RESULT_TRUE &&
|
||||
ignore_enosys_and_eremote(err_fcntl) == MDBX_RESULT_TRUE) {
|
||||
WARNING("ignore %s(%" MDBX_PRIsPATH ") error %d: since %s done, local/remote-fs check %d", "fcntl-lock", dest_path,
|
||||
err_fcntl, "flock", err_check_fs_local);
|
||||
} else if (err_fcntl || err_flock) {
|
||||
ERROR("file-lock(%" MDBX_PRIsPATH ") failed: fcntl-lock %d, flock %d, local/remote-fs check %d", dest_path,
|
||||
err_fcntl, err_flock, err_check_fs_local);
|
||||
if (err_fcntl == ENOLCK || err_flock == ENOLCK)
|
||||
rc = ENOLCK;
|
||||
else if (err_fcntl == EWOULDBLOCK || err_flock == EWOULDBLOCK)
|
||||
rc = EWOULDBLOCK;
|
||||
else if (EWOULDBLOCK != EAGAIN && (err_fcntl == EAGAIN || err_flock == EAGAIN))
|
||||
rc = EAGAIN;
|
||||
else
|
||||
rc = (err_fcntl && ignore_enosys_and_eremote(err_fcntl) != MDBX_RESULT_TRUE) ? err_fcntl : err_flock;
|
||||
}
|
||||
#endif /* Windows / POSIX */
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) {
|
||||
return MDBX_SUCCESS;
|
||||
rc = mdbx_cursor_unbind(mc);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
return (rc == MDBX_BAD_TXN) ? MDBX_EINVAL : rc;
|
||||
}
|
||||
cASSERT(mc, mc->next == mc);
|
||||
|
||||
@@ -88,8 +88,16 @@ int mdbx_cursor_unbind(MDBX_cursor *mc) {
|
||||
return LOG_IFERR(MDBX_EINVAL);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -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;
|
||||
mc->next = bk->next;
|
||||
mc->backup = bk->backup;
|
||||
mc->backup = nullptr;
|
||||
bk->backup = nullptr;
|
||||
bk->signature = 0;
|
||||
bk = bk->next;
|
||||
osal_free(bk);
|
||||
} else {
|
||||
mc->signature = cur_signature_ready4dispose;
|
||||
|
||||
@@ -208,10 +208,19 @@ __cold int mdbx_env_create(MDBX_env **penv) {
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
if (unlikely(globals.linux_kernel_version < 0x04000000)) {
|
||||
/* 2022-09-01: Прошло уже более двух лет после окончания какой-либо
|
||||
* поддержки самого "долгоиграющего" ядра 3.16.85 ветки 3.x */
|
||||
ERROR("too old linux kernel %u.%u.%u.%u, the >= 4.0.0 is required", globals.linux_kernel_version >> 24,
|
||||
if (unlikely(globals.linux_kernel_version < 0x03100000)) {
|
||||
/* 2025-08-05: Ядро 3.16 выпущено 11 лет назад и было самым долго поддерживаемым из 3.x до июля 2020.
|
||||
* Три года назад (в 2022) здесь была заблокирована работа на ядрах меньше 4.x, как устаревших и для которых
|
||||
* крайне затруднительно обеспечить какое-либо тестирование. Теперь же я решил изменить решение и разрешить
|
||||
* работу на старых ядрах начиная с 3.16, логика тут такая:
|
||||
* - поведение старых ядер уже точно не будет меняться,
|
||||
* а в текущем коде libmdbx есть всё необходимое для работы начиная с 3.16;
|
||||
* - есть широко-используемые проекты (Isar), которым требуется поддержка старых ядер;
|
||||
* - сейчас тестирование для 4.x также затруднено, как и для 3.16, уже не приносит какого-либо облегчения
|
||||
* с тестированием и мне приходится полагаться на гарантии совместимости API ядра и glibc/musl;
|
||||
* - использование возможностей из новых ядер всё равно требует проверок/ветвлений;
|
||||
* = поэтому сейчас нет причин отказываться от работы на 3.16 поддерживая ядра 4.0 */
|
||||
ERROR("too old linux kernel %u.%u.%u.%u, the >= 3.16 is required", globals.linux_kernel_version >> 24,
|
||||
(globals.linux_kernel_version >> 16) & 255, (globals.linux_kernel_version >> 8) & 255,
|
||||
globals.linux_kernel_version & 255);
|
||||
return LOG_IFERR(MDBX_INCOMPATIBLE);
|
||||
|
||||
@@ -140,7 +140,7 @@ int mdbx_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
|
||||
if (unlikely(env->flags & MDBX_RDONLY))
|
||||
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(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 */
|
||||
eASSERT(env, parent->n_dbi == txn->n_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];
|
||||
/* preserve parent's status */
|
||||
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",
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ __cold static void MDBX_PRINTF_ARGS(5, 6)
|
||||
issue->next = chk->usr->scope->issues;
|
||||
chk->usr->scope->issues = issue;
|
||||
} else
|
||||
chk_error_rc(scope, ENOMEM, "adding issue");
|
||||
chk_error_rc(scope, MDBX_ENOMEM, "adding issue");
|
||||
}
|
||||
|
||||
va_list args;
|
||||
|
||||
17
src/cogs.h
17
src/cogs.h
@@ -352,7 +352,7 @@ MDBX_CONST_FUNCTION static inline lck_t *lckless_stub(const MDBX_env *env) {
|
||||
}
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
MDBX_MAYBE_UNUSED static inline int ignore_enosys(int err) {
|
||||
MDBX_CONST_FUNCTION static inline int ignore_enosys(int err) {
|
||||
#ifdef ENOSYS
|
||||
if (err == ENOSYS)
|
||||
return MDBX_RESULT_TRUE;
|
||||
@@ -373,10 +373,21 @@ MDBX_MAYBE_UNUSED static inline int ignore_enosys(int err) {
|
||||
if (err == EOPNOTSUPP)
|
||||
return MDBX_RESULT_TRUE;
|
||||
#endif /* EOPNOTSUPP */
|
||||
if (err == EAGAIN)
|
||||
return MDBX_RESULT_TRUE;
|
||||
return err;
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_eagain(int err) {
|
||||
return (err == EAGAIN) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_einval(int err) {
|
||||
return (err == EINVAL) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_CONST_FUNCTION static inline int ignore_enosys_and_eremote(int err) {
|
||||
return (err == MDBX_EREMOTE) ? MDBX_RESULT_TRUE : ignore_enosys(err);
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
static inline int check_env(const MDBX_env *env, const bool wanna_active) {
|
||||
|
||||
97
src/dbi.c
97
src/dbi.c
@@ -84,7 +84,7 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) {
|
||||
/* dbi-слот еще не инициализирован в транзакции, а хендл не использовался */
|
||||
txn->cursors[dbi] = nullptr;
|
||||
MDBX_txn *const parent = txn->parent;
|
||||
if (parent) {
|
||||
if (unlikely(parent)) {
|
||||
/* вложенная пишущая транзакция */
|
||||
int rc = dbi_check(parent, dbi);
|
||||
/* копируем состояние table очищая new-флаги. */
|
||||
@@ -107,26 +107,31 @@ __noinline int dbi_import(MDBX_txn *txn, const size_t dbi) {
|
||||
txn->dbi_state[dbi] = DBI_LINDO;
|
||||
} else {
|
||||
eASSERT(env, txn->dbi_seqs[dbi] != env->dbi_seqs[dbi].weak);
|
||||
if (unlikely((txn->dbi_state[dbi] & (DBI_VALID | DBI_OLDEN)) || txn->cursors[dbi])) {
|
||||
/* хендл уже использовался в транзакции, но был закрыт или переоткрыт,
|
||||
* либо при явном пере-открытии хендла есть висячие курсоры */
|
||||
eASSERT(env, (txn->dbi_state[dbi] & DBI_STALE) == 0);
|
||||
if (unlikely(txn->cursors[dbi])) {
|
||||
/* хендл уже использовался в транзакции и остались висячие курсоры */
|
||||
txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak;
|
||||
txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO;
|
||||
return txn->cursors[dbi] ? MDBX_DANGLING_DBI : MDBX_BAD_DBI;
|
||||
return MDBX_DANGLING_DBI;
|
||||
}
|
||||
if (unlikely(txn->dbi_state[dbi] & (DBI_OLDEN | DBI_VALID))) {
|
||||
/* хендл уже использовался в транзакции, но был закрыт или переоткрыт,
|
||||
* висячих курсоров нет */
|
||||
txn->dbi_seqs[dbi] = env->dbi_seqs[dbi].weak;
|
||||
txn->dbi_state[dbi] = DBI_OLDEN | DBI_LINDO;
|
||||
return MDBX_BAD_DBI;
|
||||
}
|
||||
}
|
||||
|
||||
/* хендл не использовался в транзакции, либо явно пере-отрывается при
|
||||
* отсутствии висячих курсоров */
|
||||
eASSERT(env, (txn->dbi_state[dbi] & DBI_LINDO) && !txn->cursors[dbi]);
|
||||
eASSERT(env, (txn->dbi_state[dbi] & (DBI_LINDO | DBI_VALID)) == DBI_LINDO && !txn->cursors[dbi]);
|
||||
|
||||
/* читаем актуальные флаги и sequence */
|
||||
struct dbi_snap_result snap = dbi_snap(env, dbi);
|
||||
txn->dbi_seqs[dbi] = snap.sequence;
|
||||
if (snap.flags & DB_VALID) {
|
||||
txn->dbs[dbi].flags = snap.flags & DB_PERSISTENT_FLAGS;
|
||||
txn->dbi_state[dbi] = DBI_LINDO | DBI_VALID | DBI_STALE;
|
||||
txn->dbi_state[dbi] = (dbi >= CORE_DBS) ? DBI_LINDO | DBI_VALID | DBI_STALE : DBI_LINDO | DBI_VALID;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
return MDBX_BAD_DBI;
|
||||
@@ -380,7 +385,7 @@ static int dbi_open_locked(MDBX_txn *txn, unsigned user_flags, MDBX_dbi *dbi, MD
|
||||
slot = (slot < scan) ? slot : scan;
|
||||
continue;
|
||||
}
|
||||
if (!env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[scan].name)) {
|
||||
if (env->kvs[MAIN_DBI].clc.k.cmp(&name, &env->kvs[scan].name) == 0) {
|
||||
slot = scan;
|
||||
int err = dbi_check(txn, slot);
|
||||
if (err == MDBX_BAD_DBI && txn->dbi_state[slot] == (DBI_OLDEN | DBI_LINDO)) {
|
||||
@@ -536,54 +541,68 @@ int dbi_open(MDBX_txn *txn, const MDBX_val *const name, unsigned user_flags, MDB
|
||||
#if MDBX_ENABLE_DBI_LOCKFREE
|
||||
/* Is the DB already open? */
|
||||
const MDBX_env *const env = txn->env;
|
||||
size_t free_slot = env->n_dbi;
|
||||
bool have_free_slot = env->n_dbi < env->max_dbi;
|
||||
for (size_t i = CORE_DBS; i < env->n_dbi; ++i) {
|
||||
retry:
|
||||
if ((env->dbs_flags[i] & DB_VALID) == 0) {
|
||||
free_slot = i;
|
||||
have_free_slot = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t snap_seq = atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease);
|
||||
const uint16_t snap_flags = env->dbs_flags[i];
|
||||
struct dbi_snap_result snap = dbi_snap(env, i);
|
||||
const MDBX_val snap_name = env->kvs[i].name;
|
||||
if (user_flags != MDBX_ACCEDE &&
|
||||
(((user_flags ^ snap_flags) & DB_PERSISTENT_FLAGS) || (keycmp && keycmp != env->kvs[i].clc.k.cmp) ||
|
||||
(datacmp && datacmp != env->kvs[i].clc.v.cmp)))
|
||||
continue;
|
||||
const uint32_t main_seq = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
MDBX_cmp_func *const snap_cmp = env->kvs[MAIN_DBI].clc.k.cmp;
|
||||
if (unlikely(!(snap_flags & DB_VALID) || !snap_name.iov_base || !snap_name.iov_len || !snap_cmp))
|
||||
continue;
|
||||
if (unlikely(!(snap.flags & DB_VALID) || !snap_name.iov_base || !snap_name.iov_len || !snap_cmp))
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
|
||||
const bool name_match = snap_cmp(&snap_name, name) == 0;
|
||||
osal_flush_incoherent_cpu_writeback();
|
||||
if (unlikely(snap_seq != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
if (unlikely(snap.sequence != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
main_seq != atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease) ||
|
||||
snap_flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap.flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap_name.iov_len != env->kvs[i].name.iov_len))
|
||||
goto retry;
|
||||
if (name_match) {
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
|
||||
if (!name_match)
|
||||
continue;
|
||||
|
||||
osal_flush_incoherent_cpu_writeback();
|
||||
if (user_flags != MDBX_ACCEDE &&
|
||||
(((user_flags ^ snap.flags) & DB_PERSISTENT_FLAGS) || (keycmp && keycmp != env->kvs[i].clc.k.cmp) ||
|
||||
(datacmp && datacmp != env->kvs[i].clc.v.cmp)))
|
||||
/* есть подозрение что пользователь открывает таблицу с другими флагами/атрибутами
|
||||
* или другими компараторами, поэтому уходим в безопасный режим */
|
||||
goto slowpath_locking;
|
||||
|
||||
rc = dbi_check(txn, i);
|
||||
if (rc == MDBX_BAD_DBI && txn->dbi_state[i] == (DBI_OLDEN | DBI_LINDO)) {
|
||||
/* хендл использовался, стал невалидным,
|
||||
* но теперь явно пере-открывается в этой транзакци */
|
||||
eASSERT(env, !txn->cursors[i]);
|
||||
txn->dbi_state[i] = DBI_LINDO;
|
||||
rc = dbi_check(txn, i);
|
||||
if (rc == MDBX_BAD_DBI && txn->dbi_state[i] == (DBI_OLDEN | DBI_LINDO)) {
|
||||
/* хендл использовался, стал невалидным,
|
||||
* но теперь явно пере-открывается в этой транзакци */
|
||||
eASSERT(env, !txn->cursors[i]);
|
||||
txn->dbi_state[i] = DBI_LINDO;
|
||||
rc = dbi_check(txn, i);
|
||||
}
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
rc = dbi_bind(txn, i, user_flags, keycmp, datacmp);
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
*dbi = (MDBX_dbi)i;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
if (unlikely(snap.sequence != atomic_load32(&env->dbi_seqs[i], mo_AcquireRelease) ||
|
||||
main_seq != atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease) ||
|
||||
snap.flags != env->dbs_flags[i] || snap_name.iov_base != env->kvs[i].name.iov_base ||
|
||||
snap_name.iov_len != env->kvs[i].name.iov_len))
|
||||
/* похоже на столкновение с параллельно работающим обновлением */
|
||||
goto slowpath_locking;
|
||||
rc = dbi_bind(txn, i, user_flags, keycmp, datacmp);
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
*dbi = (MDBX_dbi)i;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Fail, if no free slot and max hit */
|
||||
if (unlikely(free_slot >= env->max_dbi))
|
||||
if (unlikely(!have_free_slot))
|
||||
return MDBX_DBS_FULL;
|
||||
|
||||
slowpath_locking:
|
||||
|
||||
#endif /* MDBX_ENABLE_DBI_LOCKFREE */
|
||||
|
||||
rc = osal_fastmutex_acquire(&txn->env->dbi_lock);
|
||||
|
||||
@@ -53,6 +53,7 @@ static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
|
||||
I = (I - 1) | (bitmap_chunk - 1); \
|
||||
bitmap_item = TXN->dbi_sparse[(1 + I) / bitmap_chunk]; \
|
||||
if (!bitmap_item) \
|
||||
/* coverity[const_overflow] */ \
|
||||
I += bitmap_chunk; \
|
||||
continue; \
|
||||
} else if ((bitmap_item & 1) == 0) { \
|
||||
|
||||
37
src/dxb.c
37
src/dxb.c
@@ -234,13 +234,14 @@ __cold int dxb_resize(MDBX_env *const env, const pgno_t used_pgno, const pgno_t
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
#if defined(MADV_REMOVE)
|
||||
if (env->flags & MDBX_WRITEMAP)
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_REMOVE) ? ignore_enosys(errno)
|
||||
: MDBX_SUCCESS;
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_REMOVE)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#endif /* MADV_REMOVE */
|
||||
#if defined(MADV_DONTNEED)
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
rc = madvise(ptr_disp(env->dxb_mmap.base, size_bytes), prev_size - size_bytes, MADV_DONTNEED)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#elif defined(POSIX_MADV_DONTNEED)
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
@@ -426,7 +427,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
void *const ptr = ptr_disp(env->dxb_mmap.base, offset);
|
||||
if (enable) {
|
||||
#if defined(MADV_NORMAL)
|
||||
err = madvise(ptr, length, MADV_NORMAL) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_NORMAL) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_NORMAL)
|
||||
@@ -454,7 +455,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
hint.ra_count = unlikely(length > INT_MAX && sizeof(length) > sizeof(hint.ra_count)) ? INT_MAX : (int)length;
|
||||
(void)/* Ignore ENOTTY for DB on the ram-disk and so on */ fcntl(env->lazy_fd, F_RDADVISE, &hint);
|
||||
#elif defined(MADV_WILLNEED)
|
||||
err = madvise(ptr, length, MADV_WILLNEED) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_WILLNEED) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_WILLNEED)
|
||||
@@ -479,7 +480,7 @@ __cold int dxb_set_readahead(const MDBX_env *env, const pgno_t edge, const bool
|
||||
} else {
|
||||
mincore_clean_cache(env);
|
||||
#if defined(MADV_RANDOM)
|
||||
err = madvise(ptr, length, MADV_RANDOM) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(ptr, length, MADV_RANDOM) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_RANDOM)
|
||||
@@ -531,7 +532,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
|
||||
err = osal_ftruncate(env->lazy_fd, env->dxb_mmap.filesize = env->dxb_mmap.current = env->geo_in_bytes.now);
|
||||
err = osal_fallocate(env->lazy_fd, env->dxb_mmap.filesize = env->dxb_mmap.current = env->geo_in_bytes.now);
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
|
||||
@@ -660,9 +661,8 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
}
|
||||
|
||||
if (env->flags & MDBX_RDONLY) {
|
||||
if (filesize_before & (globals.sys_allocation_granularity - 1)) {
|
||||
ERROR("filesize should be rounded-up to system allocation granularity %u",
|
||||
globals.sys_allocation_granularity);
|
||||
if (filesize_before & (globals.sys_pagesize - 1)) {
|
||||
ERROR("filesize should be rounded-up to system page size %u", globals.sys_pagesize);
|
||||
return MDBX_WANNA_RECOVERY;
|
||||
}
|
||||
WARNING("%s", "ignore filesize mismatch in readonly-mode");
|
||||
@@ -681,19 +681,21 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
!(env->flags & MDBX_NORDAHEAD) && mdbx_is_readahead_reasonable(used_bytes, 0) == MDBX_RESULT_TRUE;
|
||||
|
||||
err = osal_mmap(env->flags, &env->dxb_mmap, env->geo_in_bytes.now, env->geo_in_bytes.upper,
|
||||
(lck_rc && env->stuck_meta < 0) ? MMAP_OPTION_TRUNCATE : 0, env->pathname.dxb);
|
||||
(lck_rc && env->stuck_meta < 0) ? MMAP_OPTION_SETLENGTH : 0, env->pathname.dxb);
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
|
||||
#if defined(MADV_DONTDUMP)
|
||||
err = madvise(env->dxb_mmap.base, env->dxb_mmap.limit, MADV_DONTDUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err =
|
||||
madvise(env->dxb_mmap.base, env->dxb_mmap.limit, MADV_DONTDUMP) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#endif /* MADV_DONTDUMP */
|
||||
#if defined(MADV_DODUMP)
|
||||
if (globals.runtime_flags & MDBX_DBG_DUMP) {
|
||||
const size_t meta_length_aligned2os = pgno_align2os_bytes(env, NUM_METAS);
|
||||
err = madvise(env->dxb_mmap.base, meta_length_aligned2os, MADV_DODUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->dxb_mmap.base, meta_length_aligned2os, MADV_DODUMP) ? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
}
|
||||
@@ -932,7 +934,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
bytes2pgno(env, env->dxb_mmap.current));
|
||||
err = madvise(ptr_disp(env->dxb_mmap.base, used_aligned2os_bytes), env->dxb_mmap.current - used_aligned2os_bytes,
|
||||
MADV_REMOVE)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
@@ -942,7 +944,7 @@ __cold int dxb_setup(MDBX_env *env, const int lck_rc, const mdbx_mode_t mode_bit
|
||||
NOTICE("open-MADV_%s %u..%u", "DONTNEED", env->lck->discarded_tail.weak, bytes2pgno(env, env->dxb_mmap.current));
|
||||
err = madvise(ptr_disp(env->dxb_mmap.base, used_aligned2os_bytes), env->dxb_mmap.current - used_aligned2os_bytes,
|
||||
MADV_DONTNEED)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
@@ -1034,7 +1036,7 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika
|
||||
#endif /* MADV_FREE */
|
||||
int err = madvise(ptr_disp(env->dxb_mmap.base, discard_edge_bytes), prev_discarded_bytes - discard_edge_bytes,
|
||||
advise)
|
||||
? ignore_enosys(errno)
|
||||
? ignore_enosys_and_eagain(errno)
|
||||
: MDBX_SUCCESS;
|
||||
#else
|
||||
int err = ignore_enosys(posix_madvise(ptr_disp(env->dxb_mmap.base, discard_edge_bytes),
|
||||
@@ -1157,7 +1159,8 @@ int dxb_sync_locked(MDBX_env *env, unsigned flags, meta_t *const pending, troika
|
||||
if (!head.is_steady && meta_is_steady(pending))
|
||||
target = (meta_t *)head.ptr_c;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -28,12 +28,6 @@
|
||||
typedef struct iov_ctx iov_ctx_t;
|
||||
#include "osal.h"
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64)
|
||||
#define MDBX_WORDBITS 64
|
||||
#else
|
||||
#define MDBX_WORDBITS 32
|
||||
#endif /* MDBX_WORDBITS */
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include "atomics-types.h"
|
||||
|
||||
@@ -872,10 +872,8 @@ pgr_t gc_alloc_ex(const MDBX_cursor *const mc, const size_t num, uint8_t flags)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
if (unlikely(!is_gc_usable(txn, mc, flags))) {
|
||||
eASSERT(env, (txn->flags & txn_gc_drained) || num > 1);
|
||||
if (unlikely(!is_gc_usable(txn, mc, flags)))
|
||||
goto no_gc;
|
||||
}
|
||||
|
||||
eASSERT(env, (flags & (ALLOC_COALESCE | ALLOC_LIFO | ALLOC_SHOULD_SCAN)) == 0);
|
||||
flags += (env->flags & MDBX_LIFORECLAIM) ? ALLOC_LIFO : 0;
|
||||
|
||||
@@ -93,10 +93,11 @@ __cold static void choice_fcntl(void) {
|
||||
|
||||
static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_t offset, off_t len) {
|
||||
STATIC_ASSERT(sizeof(off_t) >= sizeof(void *) && sizeof(off_t) >= sizeof(size_t));
|
||||
#ifdef __ANDROID_API__
|
||||
STATIC_ASSERT_MSG((sizeof(off_t) * 8 == MDBX_WORDBITS), "The bitness of system `off_t` type is mismatch. Please "
|
||||
"fix build and/or NDK configuration.");
|
||||
#endif /* Android */
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
|
||||
STATIC_ASSERT_MSG((sizeof(off_t) * CHAR_BIT == MDBX_WORDBITS),
|
||||
"The bitness of system `off_t` type is mismatch. Please "
|
||||
"fix build and/or NDK configuration.");
|
||||
#endif /* Android && API < 24 */
|
||||
assert(offset >= 0 && len > 0);
|
||||
assert((uint64_t)offset < (uint64_t)INT64_MAX && (uint64_t)len < (uint64_t)INT64_MAX &&
|
||||
(uint64_t)(offset + len) > (uint64_t)offset);
|
||||
@@ -132,7 +133,8 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_
|
||||
}
|
||||
rc = errno;
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (rc == EINVAL && (cmd == MDBX_F_OFD_SETLK || cmd == MDBX_F_OFD_SETLKW || cmd == MDBX_F_OFD_GETLK)) {
|
||||
if (ignore_enosys_and_einval(rc) == MDBX_RESULT_TRUE &&
|
||||
(cmd == MDBX_F_OFD_SETLK || cmd == MDBX_F_OFD_SETLKW || cmd == MDBX_F_OFD_GETLK)) {
|
||||
/* fallback to non-OFD locks */
|
||||
if (cmd == MDBX_F_OFD_SETLK)
|
||||
cmd = MDBX_F_SETLK;
|
||||
@@ -460,6 +462,10 @@ __cold MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor
|
||||
jitter4testing(false);
|
||||
}
|
||||
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
env->me_sysv_ipc.semid = -1;
|
||||
#endif /* MDBX_LOCKING */
|
||||
|
||||
if (current_pid != env->pid) {
|
||||
eASSERT(env, !inprocess_neighbor);
|
||||
NOTICE("drown env %p after-fork pid %d -> %d", __Wpedantic_format_voidptr(env), env->pid, current_pid);
|
||||
@@ -776,14 +782,14 @@ static int osal_ipclock_lock(MDBX_env *env, osal_ipclock_t *ipc, const bool dont
|
||||
return rc;
|
||||
}
|
||||
|
||||
int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
static int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
int err = MDBX_ENOSYS;
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
err = pthread_mutex_unlock(ipc);
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
err = sem_post(ipc) ? errno : MDBX_SUCCESS;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
if (unlikely(*ipc != (pid_t)env->pid))
|
||||
if (unlikely(*ipc != (pid_t)env->pid || env->me_sysv_ipc.key == -1))
|
||||
err = EPERM;
|
||||
else {
|
||||
*ipc = 0;
|
||||
@@ -823,7 +829,6 @@ MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
|
||||
int lck_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
TRACE("%swait %s", dont_wait ? "dont-" : "", ">>");
|
||||
eASSERT(env, env->basal_txn || (env->lck == lckless_stub(env) && (env->flags & MDBX_RDONLY)));
|
||||
jitter4testing(true);
|
||||
const int err = osal_ipclock_lock(env, &env->lck->wrt_lock, dont_wait);
|
||||
int rc = err;
|
||||
@@ -841,10 +846,8 @@ int lck_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
void lck_txn_unlock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
if (env->basal_txn) {
|
||||
eASSERT(env, !env->basal_txn || env->basal_txn->owner == osal_thread_self());
|
||||
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
||||
env->basal_txn->owner = 0;
|
||||
} else {
|
||||
eASSERT(env, env->lck == lckless_stub(env) && (env->flags & MDBX_RDONLY));
|
||||
}
|
||||
int err = osal_ipclock_unlock(env, &env->lck->wrt_lock);
|
||||
TRACE("<< err %d", err);
|
||||
|
||||
@@ -87,7 +87,7 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
}
|
||||
|
||||
eASSERT(env, !env->basal_txn->owner);
|
||||
eASSERT(env, !env->basal_txn || !env->basal_txn->owner);
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
goto done;
|
||||
|
||||
@@ -104,10 +104,11 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
done:
|
||||
if (env->basal_txn)
|
||||
env->basal_txn->owner = osal_thread_self();
|
||||
/* Zap: Failing to release lock 'env->windowsbug_lock'
|
||||
* in function 'mdbx_txn_lock' */
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(26115);
|
||||
env->basal_txn->owner = osal_thread_self();
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -116,14 +117,15 @@ int lck_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
|
||||
void lck_txn_unlock(MDBX_env *env) {
|
||||
eASSERT(env, env->basal_txn->owner == osal_thread_self());
|
||||
eASSERT(env, !env->basal_txn || env->basal_txn->owner == osal_thread_self());
|
||||
if ((env->flags & MDBX_EXCLUSIVE) == 0) {
|
||||
const HANDLE fd4data = env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
int err = funlock(fd4data, DXB_BODY);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
env->basal_txn->owner = 0;
|
||||
if (env->basal_txn)
|
||||
env->basal_txn->owner = 0;
|
||||
LeaveCriticalSection(&env->windowsbug_lock);
|
||||
}
|
||||
|
||||
|
||||
10
src/lck.c
10
src/lck.c
@@ -62,20 +62,20 @@ __cold static int lck_setup_locked(MDBX_env *env) {
|
||||
}
|
||||
env->max_readers = (maxreaders <= MDBX_READERS_LIMIT) ? (unsigned)maxreaders : (unsigned)MDBX_READERS_LIMIT;
|
||||
|
||||
err =
|
||||
osal_mmap((env->flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, &env->lck_mmap, (size_t)size, (size_t)size,
|
||||
lck_seize_rc ? MMAP_OPTION_TRUNCATE | MMAP_OPTION_SEMAPHORE : MMAP_OPTION_SEMAPHORE, env->pathname.lck);
|
||||
err = osal_mmap((env->flags & MDBX_EXCLUSIVE) | MDBX_WRITEMAP, &env->lck_mmap, (size_t)size, (size_t)size,
|
||||
lck_seize_rc ? MMAP_OPTION_SETLENGTH | MMAP_OPTION_SEMAPHORE : MMAP_OPTION_SEMAPHORE,
|
||||
env->pathname.lck);
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
|
||||
#ifdef MADV_DODUMP
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_DODUMP) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#endif /* MADV_DODUMP */
|
||||
|
||||
#ifdef MADV_WILLNEED
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_WILLNEED) ? ignore_enosys(errno) : MDBX_SUCCESS;
|
||||
err = madvise(env->lck_mmap.lck, size, MADV_WILLNEED) ? ignore_enosys_and_eagain(errno) : MDBX_SUCCESS;
|
||||
if (unlikely(MDBX_IS_ERROR(err)))
|
||||
return err;
|
||||
#elif defined(POSIX_MADV_WILLNEED)
|
||||
|
||||
@@ -373,7 +373,7 @@ __cold std::string error::message() const {
|
||||
__cold void error::throw_exception() const {
|
||||
switch (code()) {
|
||||
case MDBX_EINVAL:
|
||||
throw std::invalid_argument("mdbx");
|
||||
throw std::invalid_argument("MDBX_EINVAL");
|
||||
case MDBX_ENOMEM:
|
||||
throw std::bad_alloc();
|
||||
case MDBX_SUCCESS:
|
||||
|
||||
47
src/osal.c
47
src/osal.c
@@ -1592,6 +1592,7 @@ MDBX_INTERNAL int osal_is_pipe(mdbx_filehandle_t fd) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* truncate file: just set the length of a file */
|
||||
MDBX_INTERNAL int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (imports.SetFileInformationByHandle) {
|
||||
@@ -1611,6 +1612,29 @@ MDBX_INTERNAL int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* extend file: set the length of a file AND ensure the space has been allocated */
|
||||
MDBX_INTERNAL int osal_fallocate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
assert(length > 0);
|
||||
int err = MDBX_RESULT_TRUE;
|
||||
#if (defined(__linux__) || defined(__gnu_linux__)) && \
|
||||
((defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 10)) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 21))
|
||||
err = fallocate(fd, 0, 0, length) ? ignore_enosys_and_eremote(errno) : MDBX_SUCCESS;
|
||||
#elif defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L && !defined(__APPLE__)
|
||||
err = posix_fallocate(fd, 0, length) ? ignore_enosys_and_eremote(errno) : MDBX_SUCCESS;
|
||||
#elif defined(__APPLE__)
|
||||
fstore_t store = {F_ALLOCATEALL, F_PEOFPOSMODE, 0, length, 0};
|
||||
if (fcntl(fd, F_PREALLOCATE, &store))
|
||||
err = ignore_enosys_and_eremote(errno);
|
||||
#endif /* Apple */
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
/* Workaround for testing: ignore ENOSPC for TMPFS/RAMFS.
|
||||
* This is insignificant for production, but it helps in some tests using /dev/shm inside docker/containers. */
|
||||
if (err == ENOSPC && osal_check_fs_incore(fd) == MDBX_RESULT_TRUE)
|
||||
err = MDBX_RESULT_TRUE;
|
||||
#endif /* !Windows */
|
||||
return (err == MDBX_RESULT_TRUE) ? osal_ftruncate(fd, length) : err;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fseek(mdbx_filehandle_t fd, uint64_t pos) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LARGE_INTEGER li;
|
||||
@@ -1745,7 +1769,7 @@ MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle) {
|
||||
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 (globals.running_under_Wine && !(flags & MDBX_EXCLUSIVE))
|
||||
return ERROR_NOT_CAPABLE /* workaround for Wine */;
|
||||
@@ -2061,8 +2085,8 @@ MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, cons
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
return err;
|
||||
|
||||
if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_TRUNCATE) != 0) {
|
||||
err = osal_ftruncate(map->fd, size);
|
||||
if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_SETLENGTH) != 0) {
|
||||
err = osal_fallocate(map->fd, size);
|
||||
VERBOSE("ftruncate %zu, err %d", size, err);
|
||||
if (err != MDBX_SUCCESS)
|
||||
return err;
|
||||
@@ -2308,7 +2332,7 @@ retry_file_and_section:
|
||||
}
|
||||
|
||||
if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) {
|
||||
err = osal_ftruncate(map->fd, size);
|
||||
err = osal_fallocate(map->fd, size);
|
||||
if (err == MDBX_SUCCESS)
|
||||
map->filesize = size;
|
||||
/* ignore error, because Windows unable shrink file
|
||||
@@ -2386,10 +2410,15 @@ retry_mapview:;
|
||||
rc = MDBX_EPERM;
|
||||
map->current = (map->filesize > limit) ? limit : (size_t)map->filesize;
|
||||
} else {
|
||||
if (size > map->filesize || (size < map->filesize && (flags & txn_shrink_allowed))) {
|
||||
rc = osal_ftruncate(map->fd, size);
|
||||
VERBOSE("ftruncate %zu, err %d", size, rc);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
if (map->filesize != size) {
|
||||
if (size > map->filesize) {
|
||||
rc = osal_fallocate(map->fd, size);
|
||||
VERBOSE("f%s-%s %zu, err %d", "allocate", "extend", size, rc);
|
||||
} else if (flags & txn_shrink_allowed) {
|
||||
rc = osal_ftruncate(map->fd, size);
|
||||
VERBOSE("f%s-%s %zu, err %d", "truncate", "shrink", size, rc);
|
||||
}
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
map->filesize = size;
|
||||
}
|
||||
@@ -2856,7 +2885,7 @@ __cold static LSTATUS mdbx_RegGetValue(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValu
|
||||
}
|
||||
#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) {
|
||||
unsigned bits = 0;
|
||||
for (unsigned i = 0; i < n; ++i) /* try parse an UUID in text form */ {
|
||||
|
||||
11
src/osal.h
11
src/osal.h
@@ -193,7 +193,14 @@ typedef struct osal_mmap {
|
||||
#elif defined(__ANDROID_API__)
|
||||
|
||||
#if __ANDROID_API__ < 24
|
||||
/* https://android-developers.googleblog.com/2017/09/introducing-android-native-development.html
|
||||
* https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "_FILE_OFFSET_BITS != MDBX_WORDBITS and __ANDROID_API__ < 24" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "__FILE_OFFSET_BITS != MDBX_WORDBITS and __ANDROID_API__ < 24" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_HAVE_PWRITEV 1
|
||||
#endif
|
||||
@@ -427,6 +434,7 @@ enum osal_syncmode_bits {
|
||||
|
||||
MDBX_INTERNAL int osal_fsync(mdbx_filehandle_t fd, const enum osal_syncmode_bits mode_bits);
|
||||
MDBX_INTERNAL int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length);
|
||||
MDBX_INTERNAL int osal_fallocate(mdbx_filehandle_t fd, uint64_t length);
|
||||
MDBX_INTERNAL int osal_fseek(mdbx_filehandle_t fd, uint64_t pos);
|
||||
MDBX_INTERNAL int osal_filesize(mdbx_filehandle_t fd, uint64_t *length);
|
||||
|
||||
@@ -462,7 +470,7 @@ MDBX_INTERNAL int osal_removedirectory(const pathchar_t *pathname);
|
||||
MDBX_INTERNAL int osal_is_pipe(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait);
|
||||
|
||||
#define MMAP_OPTION_TRUNCATE 1
|
||||
#define MMAP_OPTION_SETLENGTH 1
|
||||
#define MMAP_OPTION_SEMAPHORE 2
|
||||
MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
|
||||
const pathchar_t *pathname4logging);
|
||||
@@ -481,6 +489,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_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_local(mdbx_filehandle_t handle, int flags);
|
||||
|
||||
MDBX_MAYBE_UNUSED static inline uint32_t osal_getpid(void) {
|
||||
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
|
||||
|
||||
@@ -122,6 +122,8 @@
|
||||
#pragma warning(disable : 6235) /* <expression> is always a constant */
|
||||
#pragma warning(disable : 6237) /* <expression> is never evaluated and might \
|
||||
have side effects */
|
||||
#pragma warning(disable : 5286) /* implicit conversion from enum type 'type 1' to enum type 'type 2' */
|
||||
#pragma warning(disable : 5287) /* operands are different enum types 'type 1' and 'type 2' */
|
||||
#endif
|
||||
#pragma warning(disable : 4710) /* 'xyz': function not inlined */
|
||||
#pragma warning(disable : 4711) /* function 'xyz' selected for automatic \
|
||||
@@ -433,11 +435,6 @@ __extern_C key_t ftok(const char *, int);
|
||||
#if __ANDROID_API__ >= 21
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "_FILE_OFFSET_BITS != MDBX_WORDBITS" (_FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#elif defined(__FILE_OFFSET_BITS) && __FILE_OFFSET_BITS != MDBX_WORDBITS
|
||||
#error "__FILE_OFFSET_BITS != MDBX_WORDBITS" (__FILE_OFFSET_BITS != MDBX_WORDBITS)
|
||||
#endif
|
||||
#endif /* Android */
|
||||
|
||||
#if defined(HAVE_SYS_STAT_H) || __has_include(<sys/stat.h>)
|
||||
@@ -522,6 +519,12 @@ __extern_C key_t ftok(const char *, int);
|
||||
#endif
|
||||
#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64)
|
||||
#define MDBX_WORDBITS 64
|
||||
#else
|
||||
#define MDBX_WORDBITS 32
|
||||
#endif /* MDBX_WORDBITS */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Availability of CMOV or equivalent */
|
||||
|
||||
|
||||
24
src/txn.c
24
src/txn.c
@@ -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) {
|
||||
tASSERT(txn, txn->cursors[FREE_DBI] == nullptr);
|
||||
TXN_FOREACH_DBI_FROM(txn, i, /* skip FREE_DBI */ 1) {
|
||||
TXN_FOREACH_DBI_ALL(txn, i) {
|
||||
MDBX_cursor *mc = txn->cursors[i];
|
||||
if (mc) {
|
||||
txn->cursors[i] = nullptr;
|
||||
@@ -677,7 +676,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
txn->dbi_seqs[FREE_DBI] = 0;
|
||||
txn->dbi_seqs[MAIN_DBI] = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
|
||||
if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags))) {
|
||||
if (unlikely(env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags) || !txn->dbi_seqs[MAIN_DBI])) {
|
||||
const bool need_txn_lock = env->basal_txn && env->basal_txn->owner != osal_thread_self();
|
||||
bool should_unlock = false;
|
||||
if (need_txn_lock) {
|
||||
@@ -689,24 +688,24 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
}
|
||||
rc = osal_fastmutex_acquire(&env->dbi_lock);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
uint32_t seq = dbi_seq_next(env, MAIN_DBI);
|
||||
/* проверяем повторно после захвата блокировки */
|
||||
uint32_t seq = atomic_load32(&env->dbi_seqs[MAIN_DBI], mo_AcquireRelease);
|
||||
if (env->dbs_flags[MAIN_DBI] != (DB_VALID | txn->dbs[MAIN_DBI].flags)) {
|
||||
if (!need_txn_lock || should_unlock ||
|
||||
/* если нет активной пишущей транзакции,
|
||||
* то следующая будет ждать на dbi_lock */
|
||||
!env->txn) {
|
||||
if (env->dbs_flags[MAIN_DBI] != 0 || MDBX_DEBUG)
|
||||
if (!(env->dbs_flags[MAIN_DBI] & DB_VALID) || !need_txn_lock || should_unlock ||
|
||||
/* если нет активной пишущей транзакции, * то следующая будет ждать на dbi_lock */ !env->txn) {
|
||||
if (env->dbs_flags[MAIN_DBI] & DB_VALID) {
|
||||
NOTICE("renew MainDB for %s-txn %" PRIaTXN " since db-flags changes 0x%x -> 0x%x",
|
||||
(txn->flags & MDBX_TXN_RDONLY) ? "ro" : "rw", txn->txnid, env->dbs_flags[MAIN_DBI] & ~DB_VALID,
|
||||
txn->dbs[MAIN_DBI].flags);
|
||||
env->dbs_flags[MAIN_DBI] = DB_POISON;
|
||||
atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
seq = dbi_seq_next(env, MAIN_DBI);
|
||||
env->dbs_flags[MAIN_DBI] = DB_POISON;
|
||||
atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
}
|
||||
rc = tbl_setup(env, &env->kvs[MAIN_DBI], &txn->dbs[MAIN_DBI]);
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
seq = dbi_seq_next(env, MAIN_DBI);
|
||||
env->dbs_flags[MAIN_DBI] = DB_VALID | txn->dbs[MAIN_DBI].flags;
|
||||
txn->dbi_seqs[MAIN_DBI] = atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
atomic_store32(&env->dbi_seqs[MAIN_DBI], seq, mo_AcquireRelease);
|
||||
}
|
||||
} else {
|
||||
ERROR("MainDB db-flags changes 0x%x -> 0x%x ahead of read-txn "
|
||||
@@ -715,6 +714,7 @@ int txn_renew(MDBX_txn *txn, unsigned flags) {
|
||||
rc = MDBX_INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
txn->dbi_seqs[MAIN_DBI] = seq;
|
||||
ENSURE(env, osal_fastmutex_release(&env->dbi_lock) == MDBX_SUCCESS);
|
||||
} else {
|
||||
DEBUG("dbi_lock failed, err %d", rc);
|
||||
|
||||
@@ -3,36 +3,62 @@
|
||||
# Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
TEST="./test/stochastic.sh --skip-make --db-upto-gb 32"
|
||||
TMUX=tmux
|
||||
DIR="$(dirname ${BASH_SOURCE[0]})"
|
||||
TEST="${DIR}/stochastic.sh --skip-make --db-upto-gb 32"
|
||||
PREFIX="/dev/shm/mdbxtest-"
|
||||
|
||||
tmux kill-session -t mdbx
|
||||
NUMACTL="$(which numactl 2>-)"
|
||||
NUMALIST=()
|
||||
NUMAIDX=0
|
||||
if [ -n "${NUMACTL}" -a $(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | wc -l) -gt 1 ]; then
|
||||
NUMALIST=($(${NUMACTL} --hardware | grep 'node [0-9]\+ cpus' | cut -d ' ' -f 2))
|
||||
fi
|
||||
|
||||
function test_numacycle {
|
||||
NUMAIDX=$((NUMAIDX + 1))
|
||||
if [ ${NUMAIDX} -ge ${#NUMALIST[@]} ]; then
|
||||
NUMAIDX=0
|
||||
fi
|
||||
}
|
||||
|
||||
function test_numanode {
|
||||
if [[ ${#NUMALIST[@]} > 1 ]]; then
|
||||
echo "${TEST} --numa ${NUMALIST[$NUMAIDX]}"
|
||||
else
|
||||
echo "${TEST}"
|
||||
fi
|
||||
}
|
||||
|
||||
${TMUX} kill-session -t mdbx
|
||||
rm -rf ${PREFIX}*
|
||||
# git clean -x -f -d && make test-assertions
|
||||
tmux -f ./test/tmux.conf new-session -d -s mdbx htop
|
||||
${TMUX} -f "${DIR}/tmux.conf" new-session -d -s mdbx htop
|
||||
|
||||
W=0
|
||||
for ps in min 4k max; do
|
||||
for from in 1 30000; do
|
||||
for n in 0 1 2 3; do
|
||||
CMD="${TEST} --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
|
||||
CMD="$(test_numanode) --delay $((n * 7)) --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}"
|
||||
if [ $n -eq 0 ]; then
|
||||
tmux new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
|
||||
tmux select-layout -E tiled
|
||||
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}" -k -d "$CMD"
|
||||
${TMUX} select-layout -E tiled
|
||||
else
|
||||
tmux split-window -t mdbx:$W -l 20% -d $CMD
|
||||
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
||||
fi
|
||||
test_numacycle
|
||||
done
|
||||
for n in 0 1 2 3; do
|
||||
CMD="${TEST} --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
|
||||
CMD="$(test_numanode) --delay $((3 + n * 7)) --extra --page-size ${ps} --from ${from} --dir ${PREFIX}page-${ps}.from-${from}.${n}-extra"
|
||||
if [ $n -eq 0 ]; then
|
||||
tmux new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
|
||||
tmux select-layout -E tiled
|
||||
${TMUX} new-window -t mdbx:$((++W)) -n "page-${ps}.from-${from}-extra" -k -d "$CMD"
|
||||
${TMUX} select-layout -E tiled
|
||||
else
|
||||
tmux split-window -t mdbx:$W -l 20% -d $CMD
|
||||
${TMUX} split-window -t mdbx:$W -l 20% -d $CMD
|
||||
fi
|
||||
test_numacycle
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
tmux attach -t mdbx
|
||||
${TMUX} attach -t mdbx
|
||||
|
||||
@@ -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,
|
||||
mdbx::cursor pre, bool nested = false) {
|
||||
for (auto c : pool)
|
||||
mdbx::cursor(c).bind(txn, case1_cycle_dbi(dbi));
|
||||
pre.bind(txn, case1_cycle_dbi(dbi));
|
||||
if (nested) {
|
||||
for (auto c : pool)
|
||||
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) {
|
||||
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)) {
|
||||
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();)
|
||||
if (mdbx_cursor_txn(*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)
|
||||
case1_write_cycle(txn.start_nested(), dbi, pool, pre, true);
|
||||
|
||||
case1_read_cycle(txn, dbi, pool, pre, nested);
|
||||
|
||||
if (flipcoin())
|
||||
txn.commit();
|
||||
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() {
|
||||
mdbx::path db_filename = "test-cursor-closing";
|
||||
mdbx::env::remove(db_filename);
|
||||
@@ -341,6 +386,7 @@ int doit() {
|
||||
|
||||
bool ok = case0(env);
|
||||
ok = case1(env) && ok;
|
||||
ok = case2(env) && ok;
|
||||
|
||||
if (ok) {
|
||||
std::cout << "OK\n";
|
||||
|
||||
@@ -2,17 +2,9 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static char log_buffer[1024];
|
||||
mdbx::path db_filename = "test-dbi";
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int doit() {
|
||||
mdbx::path db_filename = "test-dbi";
|
||||
bool case1() {
|
||||
mdbx::env::remove(db_filename);
|
||||
|
||||
mdbx::env::operate_parameters operateParameters(100, 10, mdbx::env::nested_transactions);
|
||||
@@ -45,15 +37,15 @@ int doit() {
|
||||
MDBX_stat stat;
|
||||
int err = mdbx_dbi_stat(txn, dbi, &stat, sizeof(stat));
|
||||
if (err != MDBX_BAD_DBI) {
|
||||
std::cerr << "unexpected result err-code " << err;
|
||||
return EXIT_FAILURE;
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_BAD_DBI/-30780)\n";
|
||||
return false;
|
||||
}
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
{
|
||||
// снова проверяем что таблица открывается и хендл доступень в родительской транзакции после коммита открывшей его
|
||||
// дочерней
|
||||
// снова проверяем что таблица открывается и хендл доступень в родительской транзакции,
|
||||
// после коммита открывшей его дочерней
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::txn_managed nested = txn.start_nested();
|
||||
mdbx::map_handle dbi = nested.open_map_accede("fap1");
|
||||
@@ -63,8 +55,165 @@ int doit() {
|
||||
env.close_map(dbi);
|
||||
}
|
||||
|
||||
std::cout << "OK\n";
|
||||
return EXIT_SUCCESS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool case2() {
|
||||
bool ok = true;
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
mdbx::env::remove(db_filename);
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_CREATE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_CREATE | MDBX_DUPSORT | MDBX_DUPFIXED, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::map_handle dbi = txn.create_map("dup", mdbx::key_mode::ordinal, mdbx::value_mode::multi_ordinal);
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
mdbx::map_handle dbi = txn.create_map("uni", mdbx::key_mode::reverse, mdbx::value_mode::single);
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(0, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_DBS_FULL) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DBS_FULL/-30791)\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "uni", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
std::cerr << "Unexpected err " << err << "\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_read();
|
||||
MDBX_dbi dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "dup", MDBX_DB_ACCEDE, &dbi);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
std::cerr << "Unexpected err " << err << "\n";
|
||||
ok = false;
|
||||
}
|
||||
if (dbi)
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool case3() {
|
||||
bool ok = true;
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
mdbx::env::remove(db_filename);
|
||||
{
|
||||
mdbx::env::operate_parameters operateParameters(1, 10, mdbx::env::nested_transactions);
|
||||
mdbx::env_managed env(db_filename, createParameters, operateParameters);
|
||||
{
|
||||
mdbx::txn_managed txn = env.start_write();
|
||||
MDBX_dbi notexists_dbi = 0;
|
||||
int err = mdbx_dbi_open(txn, "test", MDBX_DB_DEFAULTS, ¬exists_dbi);
|
||||
if (err != MDBX_NOTFOUND) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_NOTFOUND/-30798)\n";
|
||||
ok = false;
|
||||
}
|
||||
mdbx::map_handle dbi = txn.create_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
|
||||
dbi = txn.open_map("test", mdbx::key_mode::ordinal, mdbx::value_mode::single);
|
||||
err = mdbx_dbi_close(env, dbi);
|
||||
if (err != MDBX_DANGLING_DBI) {
|
||||
std::cerr << "Unexpected err " << err << " (wanna MDBX_DANGLING_DBI/-30412)\n";
|
||||
ok = false;
|
||||
}
|
||||
txn.commit();
|
||||
env.close_map(dbi);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
int doit() {
|
||||
|
||||
bool ok = true;
|
||||
ok = case1() && ok;
|
||||
ok = case2() && ok;
|
||||
ok = case3() && ok;
|
||||
|
||||
if (ok) {
|
||||
std::cout << "OK\n";
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
std::cerr << "FAIL\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -31,15 +31,6 @@ int main(int argc, const char *argv[]) {
|
||||
#include <latch>
|
||||
#include <thread>
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
bool case0(const mdbx::path &path) {
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB);
|
||||
@@ -322,19 +313,85 @@ bool case2(const mdbx::path &path, bool no_sticky_threads) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool case3(const mdbx::path &path, bool no_sticky_threads) {
|
||||
mdbx::env::remove(path);
|
||||
mdbx::env_managed::create_parameters createParameters;
|
||||
createParameters.geometry.make_dynamic(21 * mdbx::env::geometry::MiB, 84 * mdbx::env::geometry::MiB);
|
||||
mdbx::env::operate_parameters operateParameters(100, 10);
|
||||
operateParameters.options.no_sticky_threads = no_sticky_threads;
|
||||
mdbx::env_managed env(path, createParameters, operateParameters);
|
||||
|
||||
mdbx::pair pair = {"key", "val"};
|
||||
const auto N = std::thread::hardware_concurrency() * 2;
|
||||
std::latch s0(N + 1), s1(N + 1), s2(N + 1);
|
||||
std::vector<std::thread> l;
|
||||
|
||||
volatile bool ok = true;
|
||||
for (size_t n = 0; n < N; ++n)
|
||||
l.push_back(std::thread([&]() {
|
||||
try {
|
||||
s0.arrive_and_wait();
|
||||
{
|
||||
auto txn = env.start_read();
|
||||
mdbx::slice value;
|
||||
int err = mdbx_get(txn, 1, pair.key, &value);
|
||||
if (err != MDBX_NOTFOUND) {
|
||||
ok = false;
|
||||
std::cerr << "Unexpected error " << err << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
s1.arrive_and_wait();
|
||||
s2.arrive_and_wait();
|
||||
{
|
||||
auto txn = env.start_read();
|
||||
if (txn.get(1, pair.key) != pair.value)
|
||||
ok = false;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
std::cerr << "Exception: " << ex.what() << "\n";
|
||||
ok = false;
|
||||
}
|
||||
}));
|
||||
|
||||
s0.arrive_and_wait();
|
||||
auto txn = env.start_write();
|
||||
s1.arrive_and_wait();
|
||||
txn.insert(1, pair);
|
||||
txn.commit();
|
||||
s2.arrive_and_wait();
|
||||
|
||||
for (auto &t : l)
|
||||
t.join();
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int doit() {
|
||||
mdbx::path path = "test-txn";
|
||||
mdbx::env::remove(path);
|
||||
|
||||
bool ok = case0(path);
|
||||
bool ok = true;
|
||||
ok = case0(path) && ok;
|
||||
ok = case1(path) && ok;
|
||||
ok = case2(path, false) && ok;
|
||||
ok = case2(path, true) && ok;
|
||||
ok = case3(path, false) && ok;
|
||||
ok = case3(path, true) && ok;
|
||||
|
||||
std::cout << (ok ? "OK\n" : "FAIL\n");
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static char log_buffer[1024];
|
||||
|
||||
static void logger_nofmt(MDBX_log_level_t loglevel, const char *function, int line, const char *msg,
|
||||
unsigned length) noexcept {
|
||||
(void)length;
|
||||
(void)loglevel;
|
||||
fprintf(stdout, "%s:%u %s", function, line, msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
@@ -510,6 +510,7 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
options |= WCONTINUED;
|
||||
#endif
|
||||
|
||||
pid = 0;
|
||||
while (sigalarm_tail == sigalarm_head) {
|
||||
int status;
|
||||
pid = waitpid(0, &status, options);
|
||||
|
||||
@@ -28,6 +28,7 @@ REPORT_DEPTH=no
|
||||
REPEAT=11
|
||||
ROUNDS=1
|
||||
SMALL=no
|
||||
NUMABIND=
|
||||
|
||||
while [ -n "$1" ]
|
||||
do
|
||||
@@ -51,6 +52,7 @@ do
|
||||
echo "--db-upto-gb NN --''--''--''--''--''--''--''--''-- NN gigabytes"
|
||||
echo "--no-geometry-jitter Disable jitter for geometry upper-size"
|
||||
echo "--pagesize NN Use specified page size (256 is minimal and used by default)"
|
||||
echo "--numa NODE Bind to the specified NUMA node"
|
||||
echo "--dont-check-ram-size Don't check available RAM"
|
||||
echo "--extra Iterate extra modes/flags"
|
||||
echo "--taillog Dump tail of test log on failure"
|
||||
@@ -209,6 +211,15 @@ do
|
||||
--small)
|
||||
SMALL=yes
|
||||
;;
|
||||
--numa)
|
||||
NUMANODE=$2
|
||||
if [[ ! $NUMANODE =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid value '$NUMANODE' for --numa option, expect an integer of NUMA-node"
|
||||
exit -2
|
||||
fi
|
||||
NUMABIND="numactl --membind ${NUMANODE} --cpunodebind ${NUMANODE}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option '$1'"
|
||||
exit -2
|
||||
@@ -393,7 +404,7 @@ if [ "$SKIP_MAKE" != "yes" ]; then
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# 5. run stochastic iterations
|
||||
# 5. internal preparations
|
||||
|
||||
if which setsid >/dev/null 2>/dev/null; then
|
||||
SETSID=$(which setsid)
|
||||
@@ -504,9 +515,9 @@ function probe {
|
||||
else
|
||||
exec {LFD}> >(logger)
|
||||
fi
|
||||
${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=${REPEAT} --pathname=${TESTDB_DIR}/long.db --cleanup-after=no --geometry-jitter=${GEOMETRY_JITTER} "$@" $case >&${LFD} \
|
||||
&& ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
|
||||
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${MONITOR} ./mdbx_chk -q ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|
||||
${NUMABIND} ${MONITOR} ./mdbx_test ${speculum} --random-writemap=no --ignore-dbfull --repeat=${REPEAT} --pathname=${TESTDB_DIR}/long.db --cleanup-after=no --geometry-jitter=${GEOMETRY_JITTER} "$@" $case >&${LFD} \
|
||||
&& ${NUMABIND} ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db | tee ${TESTDB_DIR}/long-chk.log \
|
||||
&& ([ ! -e ${TESTDB_DIR}/long.db-copy ] || ${NUMABIND} ${MONITOR} ./mdbx_chk ${TESTDB_DIR}/long.db-copy | tee ${TESTDB_DIR}/long-chk-copy.log) \
|
||||
|| failed
|
||||
if [ ${LFD} -ne 0 ]; then
|
||||
echo "@@@ END-OF-LOG/ITERATION" >&${LFD}
|
||||
@@ -516,6 +527,115 @@ function probe {
|
||||
done
|
||||
}
|
||||
|
||||
# generate caseset
|
||||
declare -A caseset_id2caption
|
||||
declare -A caseset_id2args
|
||||
cases=0
|
||||
for ((bits=2**${#options[@]}; --bits >= 0; )); do
|
||||
|
||||
split=30
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
split=24
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
split=16
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="with-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
fi
|
||||
|
||||
split=4
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,int-data, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="w/o-dups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="int-key,fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
cases=$((++cases))
|
||||
caseset_id2caption[${cases}]="fixdups, split=${split}"
|
||||
caseset_id2args[${cases}]="--table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd --mode=$(bits2options $bits)${syncmodes[cases%4]}"
|
||||
done
|
||||
|
||||
###############################################################################
|
||||
# 6. run stochastic iterations
|
||||
|
||||
function pass {
|
||||
for ((round=1; round <= ROUNDS; ++round)); do
|
||||
echo "======================================================================="
|
||||
@@ -524,122 +644,22 @@ function pass {
|
||||
else
|
||||
${BANNER} "$nops / $wbatch"
|
||||
fi
|
||||
|
||||
seed=$(($(date +%s) + RANDOM))
|
||||
subcase=0
|
||||
for ((bits=2**${#options[@]}; --bits >= 0; )); do
|
||||
seed=$(($(date +%s) + RANDOM))
|
||||
|
||||
split=30
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=24
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
split=16
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
fi
|
||||
|
||||
split=4
|
||||
caption="$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.integer --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=max \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.multi --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen.min=min --datalen.max=1111 \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) int-key,fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
caption="$((++count)) fixdups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.fixed --keygen.split=${split} --keylen.min=min --keylen.max=max --datalen=rnd \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]}
|
||||
done # options
|
||||
cases="${subcase}"
|
||||
for id in $(seq 1 ${cases} | shuf); do
|
||||
caption="$((++count)) ${caseset_id2caption[${id}]}, case $((++subcase))/${id} of ${cases}" probe \
|
||||
--prng-seed=${seed} --pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M ${caseset_id2args[${id}]} --nops=$nops --batch.write=$wbatch
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
if [ "$DELAY" != "0" ]; then
|
||||
sleep $DELAY
|
||||
fi
|
||||
|
||||
count=0
|
||||
loop=0
|
||||
cases='?'
|
||||
if [[ $SMALL != "yes" ]]; then
|
||||
for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10000000 33333333 100000000 333333333 1000000000; do
|
||||
if [ $nops -lt $FROM ]; then continue; fi
|
||||
|
||||
Reference in New Issue
Block a user