mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
926e90ac9a | ||
|
|
0a168bee9f | ||
|
|
a51bec9582 | ||
|
|
3135dfb5df | ||
|
|
55f2ffda3b | ||
|
|
7a6a4eae8d | ||
|
|
b9591e2cfe | ||
|
|
e63f55c717 | ||
|
|
eccb777bd7 | ||
|
|
2172c4f60a | ||
|
|
e09d835766 | ||
|
|
339be13778 | ||
|
|
f4dafd62d1 | ||
|
|
57e28198ce | ||
|
|
ba1bb34cbe | ||
|
|
15fa152097 | ||
|
|
af8dea2e60 | ||
|
|
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 |
@@ -574,9 +574,8 @@ if(WIN32 AND EXISTS "${MDBX_SOURCE_DIR}/ntdll.def")
|
||||
if(MSVC)
|
||||
if(NOT MSVC_LIB_EXE)
|
||||
# Find lib.exe
|
||||
get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME)
|
||||
string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME})
|
||||
find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE})
|
||||
get_filename_component(CC_DIR ${CMAKE_C_COMPILER} DIRECTORY)
|
||||
find_program(MSVC_LIB_EXE "lib.exe" HINTS ${CC_DIR})
|
||||
endif()
|
||||
if(MSVC_LIB_EXE)
|
||||
message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}")
|
||||
@@ -588,25 +587,24 @@ if(WIN32 AND EXISTS "${MDBX_SOURCE_DIR}/ntdll.def")
|
||||
COMMAND ${MSVC_LIB_EXE} /def:"${MDBX_SOURCE_DIR}/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}"
|
||||
${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
|
||||
else()
|
||||
message(WARNING "MSVC's lib tool not found")
|
||||
message(WARNING "MSVC's lib.exe not found")
|
||||
endif()
|
||||
elseif(MINGW OR MINGW64)
|
||||
if(NOT DLLTOOL)
|
||||
# Find dlltool
|
||||
get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME)
|
||||
string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME})
|
||||
find_program(DLLTOOL NAMES ${DLLTOOL_NAME})
|
||||
if(NOT MINGW_DLLTOOL_EXE)
|
||||
# Find dlltool.exe
|
||||
get_filename_component(CC_DIR ${CMAKE_C_COMPILER} DIRECTORY)
|
||||
find_program(MINGW_DLLTOOL_EXE "dlltool.exe" HINTS ${CC_DIR})
|
||||
endif()
|
||||
if(DLLTOOL)
|
||||
message(STATUS "Found dlltool: ${DLLTOOL}")
|
||||
if(MINGW_DLLTOOL_EXE)
|
||||
message(STATUS "Found MINGW's dlltool: ${MINGW_DLLTOOL_EXE}")
|
||||
set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a")
|
||||
add_custom_command(
|
||||
OUTPUT "${MDBX_NTDLL_EXTRA_IMPLIB}"
|
||||
COMMENT "Create extra-import-library for ntdll.dll"
|
||||
MAIN_DEPENDENCY "${MDBX_SOURCE_DIR}/ntdll.def"
|
||||
COMMAND ${DLLTOOL} -d "${MDBX_SOURCE_DIR}/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
|
||||
COMMAND ${MINGW_DLLTOOL_EXE} -d "${MDBX_SOURCE_DIR}/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
|
||||
else()
|
||||
message(WARNING "dlltool not found")
|
||||
message(WARNING "MINGW's dlltool.exe not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -702,6 +700,8 @@ mark_as_advanced(MDBX_ENABLE_PROFGC)
|
||||
add_option(MDBX ENABLE_DBI_SPARSE
|
||||
"Support for sparse sets of DBI handles to reduce overhead when starting and processing transactions" ON)
|
||||
add_option(MDBX ENABLE_DBI_LOCKFREE "Support for deferred releasing and a lockfree path to quickly open DBI handles" ON)
|
||||
add_option(MDBX USE_FALLOCATE "Using posix_fallocate() or fcntl(F_PREALLOCATE) on OSX" AUTO)
|
||||
mark_as_advanced(MDBX_USE_FALLOCATE)
|
||||
|
||||
if(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
||||
|
||||
126
ChangeLog.md
126
ChangeLog.md
@@ -4,6 +4,130 @@ 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.9 "ИС-2" (IS-2) от 2025-10-31
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов.
|
||||
Выпуск назван в память о cамом мощном тяжелом советском танке ["ИС-2"](https://ru.ruwiki.ru/wiki/ИС-2), который был принят на вооружение
|
||||
31 октября 1943 года в разгар Великой Отечественной Войны и долгое время оставался одной из сильнейших машин мира в категории по массе 40—50 тонн.
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Erigon](https://erigon.tech/) за спонсорство.
|
||||
|
||||
Исправления:
|
||||
|
||||
- Исправлена assert-проверка в пути сканирования битовой карты DBI-дексрипторов приводившая к редким падениям 32-битных отладочных сборок.
|
||||
|
||||
- Переделан поиск утилит `lib.exe` и `dlltool.exe` при сборке посредством CMake на Windows.
|
||||
|
||||
- Устранён регресс проявлявшийся увеличением (не-уменьшением) размера БД, после добавления использования `fallocate()`
|
||||
ради предотвращения SIGBUS при нехватке места в файловой системе где расположена БД.
|
||||
|
||||
- Устранена опечатка в тестовом скрипте `test/battery-tmux.sh` приводящая к созданию мусорного файла с именем `-`.
|
||||
|
||||
- Удалено лишнее/ненужное использование макроса `MDBX_INTERNAL` оставшееся после рефакторинга.
|
||||
|
||||
- Для Android добавлен обход (workaround) для уменьшения вероятности системной ошибки `EAGAIN` возникающей
|
||||
из-за нехватки системных ресурсов и переходных процессов при закрытии и быстром повтороном открытии БД.
|
||||
|
||||
Прочие доработки:
|
||||
|
||||
- Поддержка Harmony OS (OHOS).
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
Поддерживающий выпуск стабильной ветки с исправлением обнаруженных ошибок и устранением недочётов,
|
||||
@@ -19,7 +143,7 @@ and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/libmdbx
|
||||
|
||||
- Устранён регресс при использовании курсоров для DBI=0 (aka GC/FreeDB) в читающих транзакциях.
|
||||
|
||||
В результате рефакторинга и ряда оптимизаций для завершения/гашения
|
||||
После рефакторинга и ряда оптимизаций для завершения/гашения
|
||||
курсоров в читающих и пишущих транзакций, стал использоваться общий код.
|
||||
Причем за основу, был взят соответствующий фрагмент относящийся к
|
||||
пишущим транзакциям, в которых пользователю не позволяется
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
43
TODO.md
43
TODO.md
@@ -1,43 +0,0 @@
|
||||
TODO
|
||||
----
|
||||
|
||||
Unfortunately, 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. Therefore
|
||||
on 2022-04-21 we have migrated to a reliable trusted infrastructure.
|
||||
The origin for now is at[GitFlic](https://gitflic.ru/project/erthink/libmdbx)
|
||||
with backup at [ABF by ROSA Лаб](https://abf.rosalinux.ru/erthink/libmdbx).
|
||||
For the same reason ~~Github~~ is blacklisted forever.
|
||||
|
||||
So currently most of the links are broken due to noted malicious ~~Github~~ sabotage.
|
||||
|
||||
- Внутри `txn_renew()` вынести проверку когерентности mmap за/после изменение размера.
|
||||
- [Migration guide from LMDB to MDBX](https://libmdbx.dqdkfa.ru/dead-github/issues/199).
|
||||
- [Support for RAW devices](https://libmdbx.dqdkfa.ru/dead-github/issues/124).
|
||||
- [Support MessagePack for Keys & Values](https://libmdbx.dqdkfa.ru/dead-github/issues/115).
|
||||
- Packages for [Astra Linux](https://astralinux.ru/), [ALT Linux](https://www.altlinux.org/), [ROSA Linux](https://www.rosalinux.ru/), etc.
|
||||
|
||||
Done
|
||||
----
|
||||
|
||||
- [Engage new terminology](https://libmdbx.dqdkfa.ru/dead-github/issues/137).
|
||||
- [More flexible support of asynchronous runtime/framework(s)](https://libmdbx.dqdkfa.ru/dead-github/issues/200).
|
||||
- [Move most of `mdbx_chk` functional to the library API](https://libmdbx.dqdkfa.ru/dead-github/issues/204).
|
||||
- [Simple careful mode for working with corrupted DB](https://libmdbx.dqdkfa.ru/dead-github/issues/223).
|
||||
- [Engage an "overlapped I/O" on Windows](https://libmdbx.dqdkfa.ru/dead-github/issues/224).
|
||||
- [Large/Overflow pages accounting for dirty-room](https://libmdbx.dqdkfa.ru/dead-github/issues/192).
|
||||
- [Get rid of dirty-pages list in MDBX_WRITEMAP mode](https://libmdbx.dqdkfa.ru/dead-github/issues/193).
|
||||
|
||||
Cancelled
|
||||
--------
|
||||
|
||||
- [Replace SRW-lock on Windows to allow shrink DB with `MDBX_NOSTICKYTHREADS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/210).
|
||||
Доработка не может быть реализована, так как замена SRW-блокировки
|
||||
лишает лишь предварительную проблему, но не главную. На Windows
|
||||
уменьшение размера отображенного в память файла не поддерживается ядром
|
||||
ОС. Для этого необходимо снять отображение, изменить размер файла и
|
||||
затем отобразить обратно. В свою очередь, для это необходимо
|
||||
приостановить работающие с БД потоки выполняющие транзакции чтения, либо
|
||||
готовые к такому выполнению. Но в режиме MDBX_NOSTICKYTHREADS нет
|
||||
возможности отслеживать работающие с БД потоки, а приостановка всех
|
||||
потоков неприемлема для большинства приложений.
|
||||
@@ -82,6 +82,7 @@ class libmdbx(ConanFile):
|
||||
'mdbx.use_mincore': ['Auto', True, False],
|
||||
'mdbx.use_ofdlocks': ['Auto', True, False],
|
||||
'mdbx.use_sendfile': ['Auto', True, False],
|
||||
'mdbx.use_fallocate': ['Auto', True, False],
|
||||
'mdbx.without_msvc_crt': ['Default', True, False],
|
||||
'shared': [True, False],
|
||||
}
|
||||
@@ -113,6 +114,7 @@ class libmdbx(ConanFile):
|
||||
'mdbx.use_mincore': 'Auto',
|
||||
'mdbx.use_ofdlocks': 'Auto',
|
||||
'mdbx.use_sendfile': 'Auto',
|
||||
'mdbx.use_fallocate': 'Auto',
|
||||
'mdbx.without_msvc_crt': 'Default',
|
||||
'shared': True,
|
||||
}
|
||||
@@ -143,7 +145,8 @@ class libmdbx(ConanFile):
|
||||
'mdbx.use_copyfilerange': 'Advanced: Use `copy_file_range()` syscall. ',
|
||||
'mdbx.use_mincore': "Use Unix' `mincore()` to determine whether database pages are resident in memory. ",
|
||||
'mdbx.use_ofdlocks': 'Advanced: Use POSIX OFD-locks. ',
|
||||
'mdbx.use_sendfile': 'Advancedc: Use `sendfile()` syscall. ',
|
||||
'mdbx.use_sendfile': 'Advanced: Use `sendfile()` syscall. ',
|
||||
'mdbx.use_fallocate': 'Advanced: Use posix_fallocate() or fcntl(F_PREALLOCATE) on OSX. ',
|
||||
'mdbx.without_msvc_crt': 'Avoid dependence from MSVC CRT and use ntdll.dll instead. ',
|
||||
}
|
||||
|
||||
@@ -160,6 +163,7 @@ class libmdbx(ConanFile):
|
||||
self.options.rm_safe('mdbx.mmap_incoherent_file_write')
|
||||
self.options.rm_safe('mdbx.use_mincore')
|
||||
self.options.rm_safe('mdbx.use_ofdlocks')
|
||||
self.options.rm_safe('mdbx.use_fallocate')
|
||||
else:
|
||||
self.options.rm_safe('mdbx.without_msvc_crt')
|
||||
if is_apple_os(self):
|
||||
|
||||
@@ -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_fsetsize(fd, whole_size);
|
||||
|
||||
const size_t used_size = pgno2bytes(env, meta->geometry.first_unallocated);
|
||||
memset(data_buffer, 0, (size_t)MDBX_ENVCOPY_WRITEBUF);
|
||||
@@ -603,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;
|
||||
}
|
||||
@@ -627,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;
|
||||
@@ -648,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_fsetsize(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;) {
|
||||
@@ -755,35 +755,67 @@ __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))
|
||||
rc = errno;
|
||||
}
|
||||
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;
|
||||
|
||||
#if defined(LOCK_EX) && (!defined(__ANDROID_API__) || __ANDROID_API__ >= 24)
|
||||
if (rc == MDBX_SUCCESS && flock(newfd, LOCK_EX | LOCK_NB)) {
|
||||
const int err_flock = errno, err_fs = osal_check_fs_local(newfd, 0);
|
||||
if (err_flock != EAGAIN || err_fs != MDBX_EREMOTE) {
|
||||
ERROR("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "unexpected", dest_path, err_flock,
|
||||
err_fs);
|
||||
rc = err_flock;
|
||||
} else {
|
||||
WARNING("%s flock(%" MDBX_PRIsPATH ") error %d, remote-fs check status %d", "ignore", dest_path, err_flock,
|
||||
err_fs);
|
||||
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 */
|
||||
|
||||
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 /* LOCK_EX && ANDROID_API >= 24 */
|
||||
|
||||
#endif /* Windows / POSIX */
|
||||
|
||||
if (rc == MDBX_SUCCESS)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -171,10 +171,8 @@ MDBX_MAYBE_UNUSED static __always_inline void atomic_yield(void) {
|
||||
#elif defined(__mips) || defined(__mips__) || defined(__mips64) || defined(__mips64__) || defined(_M_MRX000) || \
|
||||
defined(_MIPS_) || defined(__MWERKS__) || defined(__sgi)
|
||||
__asm__ __volatile__(".word 0x00000140");
|
||||
#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE)
|
||||
sched_yield();
|
||||
#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS)
|
||||
pthread_yield();
|
||||
#else
|
||||
osal_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -103,15 +103,7 @@ __cold int coherency_timeout(uint64_t *timestamp, intptr_t pgno, const MDBX_env
|
||||
}
|
||||
|
||||
osal_memory_fence(mo_AcquireRelease, true);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SwitchToThread();
|
||||
#elif defined(__linux__) || defined(__gnu_linux__) || defined(_UNIX03_SOURCE)
|
||||
sched_yield();
|
||||
#elif (defined(_GNU_SOURCE) && __GLIBC_PREREQ(2, 1)) || defined(_OPEN_THREADS)
|
||||
pthread_yield();
|
||||
#else
|
||||
usleep(42);
|
||||
#endif
|
||||
osal_yield();
|
||||
return MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,11 @@
|
||||
|
||||
#cmakedefine01 MDBX_USE_MINCORE
|
||||
|
||||
#cmakedefine MDBX_USE_FALLOCATE_AUTO
|
||||
#ifndef MDBX_USE_FALLOCATE_AUTO
|
||||
#cmakedefine01 MDBX_USE_FALLOCATE
|
||||
#endif /* MDBX_USE_FALLOCATE */
|
||||
|
||||
/* Build Info */
|
||||
#ifndef MDBX_BUILD_TIMESTAMP
|
||||
#cmakedefine MDBX_BUILD_TIMESTAMP "@MDBX_BUILD_TIMESTAMP@"
|
||||
|
||||
@@ -236,7 +236,7 @@ enum cursor_checking {
|
||||
MDBX_INTERNAL int __must_check_result cursor_validate(const MDBX_cursor *mc);
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static inline size_t cursor_dbi(const MDBX_cursor *mc) {
|
||||
cASSERT(mc, mc->txn && mc->txn->signature == txn_signature);
|
||||
cASSERT(mc, mc->txn->signature == txn_signature);
|
||||
size_t dbi = mc->dbi_state - mc->txn->dbi_state;
|
||||
cASSERT(mc, dbi < mc->txn->env->n_dbi);
|
||||
return dbi;
|
||||
|
||||
108
src/dbi.c
108
src/dbi.c
@@ -5,7 +5,7 @@
|
||||
|
||||
#if MDBX_ENABLE_DBI_SPARSE
|
||||
size_t dbi_bitmap_ctz_fallback(const MDBX_txn *txn, intptr_t bmi) {
|
||||
tASSERT(txn, bmi > 0);
|
||||
tASSERT(txn, bmi != 0);
|
||||
bmi &= -bmi;
|
||||
if (sizeof(txn->dbi_sparse[0]) > 4) {
|
||||
static const uint8_t debruijn_ctz64[64] = {0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
|
||||
@@ -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;
|
||||
@@ -167,13 +172,8 @@ int dbi_defer_release(MDBX_env *const env, defer_free_item_t *const chain) {
|
||||
#endif /* MDBX_ENABLE_DBI_LOCKFREE */
|
||||
|
||||
ENSURE(env, osal_fastmutex_release(&env->dbi_lock) == MDBX_SUCCESS);
|
||||
if (length > 42) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SwitchToThread();
|
||||
#else
|
||||
sched_yield();
|
||||
#endif /* Windows */
|
||||
}
|
||||
if (length > 42)
|
||||
osal_yield();
|
||||
while (obsolete_chain) {
|
||||
defer_free_item_t *item = obsolete_chain;
|
||||
obsolete_chain = obsolete_chain->next;
|
||||
@@ -380,7 +380,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 +536,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);
|
||||
|
||||
@@ -11,7 +11,7 @@ MDBX_NOTHROW_CONST_FUNCTION MDBX_MAYBE_UNUSED MDBX_INTERNAL size_t dbi_bitmap_ct
|
||||
intptr_t bmi);
|
||||
|
||||
static inline size_t dbi_bitmap_ctz(const MDBX_txn *txn, intptr_t bmi) {
|
||||
tASSERT(txn, bmi > 0);
|
||||
tASSERT(txn, bmi != 0);
|
||||
STATIC_ASSERT(sizeof(bmi) >= sizeof(txn->dbi_sparse[0]));
|
||||
#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
|
||||
if (sizeof(txn->dbi_sparse[0]) <= sizeof(int))
|
||||
|
||||
34
src/dxb.c
34
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_fsetsize(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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -379,6 +379,7 @@ __dll_export
|
||||
#else /* Windows */
|
||||
" MDBX_LOCKING=" MDBX_LOCKING_CONFIG
|
||||
" MDBX_USE_OFDLOCKS=" MDBX_USE_OFDLOCKS_CONFIG
|
||||
" MDBX_USE_FALLOCATE=" MDBX_USE_FALLOCATE_CONFIG
|
||||
#endif /* !Windows */
|
||||
" MDBX_CACHELINE_SIZE=" MDBX_STRINGIFY(MDBX_CACHELINE_SIZE)
|
||||
" MDBX_CPU_WRITEBACK_INCOHERENT=" MDBX_STRINGIFY(MDBX_CPU_WRITEBACK_INCOHERENT)
|
||||
|
||||
@@ -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;
|
||||
@@ -153,7 +155,28 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck, const off_
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
static int lck_setlk_with3retries(const mdbx_filehandle_t fd, const int lck, const off_t offset, off_t len) {
|
||||
assert(lck != F_UNLCK);
|
||||
int retry_left = 3;
|
||||
#if defined(__ANDROID_API__)
|
||||
retry_left *= 3;
|
||||
#endif /* Android */
|
||||
while (true) {
|
||||
int rc = lck_op(fd, op_setlk, lck, offset, len);
|
||||
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK || rc == EDEADLK) || --retry_left < 1)
|
||||
return rc;
|
||||
#if defined(__ANDROID_API__)
|
||||
if (retry_left == 5 || retry_left == 3) {
|
||||
usleep(1000 * 42 / 2);
|
||||
continue;
|
||||
}
|
||||
#endif /* Android */
|
||||
if (osal_yield())
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (unlikely(op_setlk == 0))
|
||||
choice_fcntl();
|
||||
@@ -161,7 +184,7 @@ MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_rpid_set(MDBX_env *env) {
|
||||
int lck_rpid_set(MDBX_env *env) {
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
assert(env->pid > 0);
|
||||
if (unlikely(osal_getpid() != env->pid))
|
||||
@@ -169,13 +192,13 @@ MDBX_INTERNAL int lck_rpid_set(MDBX_env *env) {
|
||||
return lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, env->pid, 1);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env) {
|
||||
int lck_rpid_clear(MDBX_env *env) {
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
assert(env->pid > 0);
|
||||
return lck_op(env->lck_mmap.fd, op_setlk, F_UNLCK, env->pid, 1);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
assert(pid > 0);
|
||||
return lck_op(env->lck_mmap.fd, op_getlk, F_WRLCK, pid, 1);
|
||||
@@ -184,7 +207,7 @@ MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#if MDBX_LOCKING > MDBX_LOCKING_SYSV
|
||||
MDBX_INTERNAL int lck_ipclock_stubinit(osal_ipclock_t *ipc) {
|
||||
int lck_ipclock_stubinit(osal_ipclock_t *ipc) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
return sem_init(ipc, false, 1) ? errno : 0;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
@@ -194,7 +217,7 @@ MDBX_INTERNAL int lck_ipclock_stubinit(osal_ipclock_t *ipc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_ipclock_destroy(osal_ipclock_t *ipc) {
|
||||
int lck_ipclock_destroy(osal_ipclock_t *ipc) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
return sem_destroy(ipc) ? errno : 0;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
@@ -258,7 +281,7 @@ static int check_fstat(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
__cold int lck_seize(MDBX_env *env) {
|
||||
assert(env->lazy_fd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(osal_getpid() != env->pid))
|
||||
return MDBX_PANIC;
|
||||
@@ -282,7 +305,7 @@ __cold MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
|
||||
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE) {
|
||||
/* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
|
||||
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
||||
rc = lck_setlk_with3retries(env->lazy_fd, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
ERROR("%s, err %u", "without-lck", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
@@ -290,9 +313,6 @@ __cold MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
}
|
||||
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
||||
}
|
||||
#if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
|
||||
sched_yield();
|
||||
#endif
|
||||
|
||||
retry:
|
||||
if (rc == MDBX_RESULT_TRUE) {
|
||||
@@ -305,14 +325,14 @@ retry:
|
||||
}
|
||||
|
||||
/* Firstly try to get exclusive locking. */
|
||||
rc = lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, 0, 1);
|
||||
rc = lck_setlk_with3retries(env->lck_mmap.fd, F_WRLCK, 0, 1);
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
rc = check_fstat(env);
|
||||
if (MDBX_IS_ERROR(rc))
|
||||
return rc;
|
||||
|
||||
continue_dxb_exclusive:
|
||||
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
||||
rc = lck_setlk_with3retries(env->lazy_fd, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
||||
|
||||
@@ -360,7 +380,7 @@ retry:
|
||||
}
|
||||
|
||||
/* got shared, retry exclusive */
|
||||
rc = lck_op(env->lck_mmap.fd, op_setlk, F_WRLCK, 0, 1);
|
||||
rc = lck_setlk_with3retries(env->lck_mmap.fd, F_WRLCK, 0, 1);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
goto continue_dxb_exclusive;
|
||||
|
||||
@@ -371,7 +391,7 @@ retry:
|
||||
}
|
||||
|
||||
/* Lock against another process operating in without-lck or exclusive mode. */
|
||||
rc = lck_op(env->lazy_fd, op_setlk, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, env->pid, 1);
|
||||
rc = lck_setlk_with3retries(env->lazy_fd, (env->flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, env->pid, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
ERROR("%s, err %u", "lock-against-without-lck", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
@@ -382,7 +402,7 @@ retry:
|
||||
return MDBX_RESULT_FALSE;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
int lck_downgrade(MDBX_env *env) {
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(osal_getpid() != env->pid))
|
||||
return MDBX_PANIC;
|
||||
@@ -394,7 +414,7 @@ MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
rc = lck_op(env->lazy_fd, op_setlk, F_UNLCK, env->pid + 1, OFF_T_MAX - env->pid - 1);
|
||||
}
|
||||
if (rc == MDBX_SUCCESS)
|
||||
rc = lck_op(env->lck_mmap.fd, op_setlk, F_RDLCK, 0, 1);
|
||||
rc = lck_setlk_with3retries(env->lck_mmap.fd, F_RDLCK, 0, 1);
|
||||
if (unlikely(rc != 0)) {
|
||||
ERROR("%s, err %u", "lck", rc);
|
||||
assert(MDBX_IS_ERROR(rc));
|
||||
@@ -402,7 +422,7 @@ MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(osal_getpid() != env->pid))
|
||||
return MDBX_PANIC;
|
||||
@@ -413,10 +433,10 @@ MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
rc = (env->pid > 1) ? lck_op(env->lazy_fd, cmd, F_WRLCK, 0, env->pid - 1) : MDBX_SUCCESS;
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
rc = lck_op(env->lazy_fd, cmd, F_WRLCK, env->pid + 1, OFF_T_MAX - env->pid - 1);
|
||||
if (rc != MDBX_SUCCESS && env->pid > 1 && lck_op(env->lazy_fd, op_setlk, F_UNLCK, 0, env->pid - 1))
|
||||
if (rc != MDBX_SUCCESS && env->pid > 1 && lck_setlk_with3retries(env->lazy_fd, F_UNLCK, 0, env->pid - 1))
|
||||
rc = MDBX_PANIC;
|
||||
}
|
||||
if (rc != MDBX_SUCCESS && lck_op(env->lck_mmap.fd, op_setlk, F_RDLCK, 0, 1))
|
||||
if (rc != MDBX_SUCCESS && lck_setlk_with3retries(env->lck_mmap.fd, F_RDLCK, 0, 1))
|
||||
rc = MDBX_PANIC;
|
||||
}
|
||||
if (unlikely(rc != 0)) {
|
||||
@@ -426,7 +446,7 @@ MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid) {
|
||||
__cold int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid) {
|
||||
eASSERT(env, osal_getpid() == current_pid);
|
||||
int rc = MDBX_SUCCESS;
|
||||
struct stat lck_info;
|
||||
@@ -460,6 +480,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);
|
||||
@@ -511,7 +535,7 @@ __cold MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
__cold MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag) {
|
||||
__cold int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
int semid = -1;
|
||||
/* don't initialize semaphores twice */
|
||||
@@ -721,7 +745,7 @@ __cold static int osal_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc, const
|
||||
}
|
||||
|
||||
#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
|
||||
MDBX_INTERNAL int osal_check_tid4bionic(void) {
|
||||
int osal_check_tid4bionic(void) {
|
||||
/* avoid 32-bit Bionic bug/hang with 32-pit TID */
|
||||
if (sizeof(pthread_mutex_t) < sizeof(pid_t) + sizeof(unsigned)) {
|
||||
pid_t tid = gettid();
|
||||
@@ -776,14 +800,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;
|
||||
@@ -804,7 +828,7 @@ int osal_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
||||
int lck_rdt_lock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
jitter4testing(true);
|
||||
int rc = osal_ipclock_lock(env, &env->lck->rdt_lock, false);
|
||||
@@ -812,7 +836,7 @@ MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
void lck_rdt_unlock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
int err = osal_ipclock_unlock(env, &env->lck->rdt_lock);
|
||||
TRACE("<< err %d", err);
|
||||
@@ -823,7 +847,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 +864,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);
|
||||
}
|
||||
|
||||
@@ -138,7 +140,7 @@ void lck_txn_unlock(MDBX_env *env) {
|
||||
#define LCK_LOWER LCK_LO_OFFSET, LCK_LO_LEN
|
||||
#define LCK_UPPER LCK_UP_OFFSET, LCK_UP_LEN
|
||||
|
||||
MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
||||
int lck_rdt_lock(MDBX_env *env) {
|
||||
imports.srwl_AcquireShared(&env->remap_guard);
|
||||
if (env->lck_mmap.fd == INVALID_HANDLE_VALUE)
|
||||
return MDBX_SUCCESS; /* readonly database in readonly filesystem */
|
||||
@@ -156,7 +158,7 @@ MDBX_INTERNAL int lck_rdt_lock(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
void lck_rdt_unlock(MDBX_env *env) {
|
||||
if (env->lck_mmap.fd != INVALID_HANDLE_VALUE && (env->flags & MDBX_EXCLUSIVE) == 0) {
|
||||
/* transition from S-E (locked) to S-? (used), e.g. unlock upper-part */
|
||||
int err = funlock(env->lck_mmap.fd, LCK_UPPER);
|
||||
@@ -166,7 +168,7 @@ MDBX_INTERNAL void lck_rdt_unlock(MDBX_env *env) {
|
||||
imports.srwl_ReleaseShared(&env->remap_guard);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return flock(fd, wait ? LCK_EXCLUSIVE | LCK_WAITFOR : LCK_EXCLUSIVE | LCK_DONTWAIT, 0, DXB_MAXLEN);
|
||||
}
|
||||
|
||||
@@ -202,7 +204,7 @@ static int suspend_and_append(mdbx_handle_array_t **array, const DWORD ThreadId)
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
int osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
eASSERT(env, (env->flags & MDBX_NOSTICKYTHREADS) == 0);
|
||||
const uintptr_t CurrentTid = GetCurrentThreadId();
|
||||
int rc;
|
||||
@@ -269,7 +271,7 @@ MDBX_INTERNAL int osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_a
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
int osal_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
int rc = MDBX_SUCCESS;
|
||||
for (unsigned i = 0; i < array->count; ++i) {
|
||||
const HANDLE hThread = array->handles[i];
|
||||
@@ -405,7 +407,7 @@ static int internal_seize_lck(HANDLE lfd) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
int lck_seize(MDBX_env *env) {
|
||||
const HANDLE fd4data = env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
if (env->flags & MDBX_EXCLUSIVE)
|
||||
@@ -447,7 +449,7 @@ MDBX_INTERNAL int lck_seize(MDBX_env *env) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
int lck_downgrade(MDBX_env *env) {
|
||||
const HANDLE fd4data = env->ioring.overlapped_fd ? env->ioring.overlapped_fd : env->lazy_fd;
|
||||
/* Transite from exclusive-write state (E-E) to used (S-?) */
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
@@ -477,7 +479,7 @@ MDBX_INTERNAL int lck_downgrade(MDBX_env *env) {
|
||||
return MDBX_SUCCESS /* 5) now at S-? (used), done */;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
/* Transite from used state (S-?) to exclusive-write (E-E) */
|
||||
assert(env->lck_mmap.fd != INVALID_HANDLE_VALUE);
|
||||
|
||||
@@ -511,7 +513,7 @@ MDBX_INTERNAL int lck_upgrade(MDBX_env *env, bool dont_wait) {
|
||||
return MDBX_SUCCESS /* 6) now at E-E (exclusive-write), done */;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag) {
|
||||
int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int global_uniqueness_flag) {
|
||||
(void)env;
|
||||
(void)inprocess_neighbor;
|
||||
(void)global_uniqueness_flag;
|
||||
@@ -532,7 +534,7 @@ MDBX_INTERNAL int lck_init(MDBX_env *env, MDBX_env *inprocess_neighbor, int glob
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid) {
|
||||
int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const uint32_t current_pid) {
|
||||
(void)current_pid;
|
||||
/* LY: should unmap before releasing the locks to avoid race condition and
|
||||
* STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */
|
||||
@@ -544,7 +546,7 @@ MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const
|
||||
if (synced && !inprocess_neighbor && env->lck_mmap.fd != INVALID_HANDLE_VALUE &&
|
||||
lck_upgrade(env, true) == MDBX_SUCCESS)
|
||||
/* this will fail if LCK is used/mmapped by other process(es) */
|
||||
osal_ftruncate(env->lck_mmap.fd, 0);
|
||||
osal_fsetsize(env->lck_mmap.fd, 0);
|
||||
}
|
||||
lck_unlock(env);
|
||||
return MDBX_SUCCESS;
|
||||
@@ -553,12 +555,12 @@ MDBX_INTERNAL int lck_destroy(MDBX_env *env, MDBX_env *inprocess_neighbor, const
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* reader checking (by pid) */
|
||||
|
||||
MDBX_INTERNAL int lck_rpid_set(MDBX_env *env) {
|
||||
int lck_rpid_set(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env) {
|
||||
int lck_rpid_clear(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
@@ -569,7 +571,7 @@ MDBX_INTERNAL int lck_rpid_clear(MDBX_env *env) {
|
||||
* MDBX_RESULT_TRUE, if pid is live (unable to acquire lock)
|
||||
* MDBX_RESULT_FALSE, if pid is dead (lock acquired)
|
||||
* or otherwise the errcode. */
|
||||
MDBX_INTERNAL int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
int lck_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
(void)env;
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
int rc;
|
||||
|
||||
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)
|
||||
|
||||
@@ -204,7 +204,7 @@ static bool pid_insert(uint32_t *list, uint32_t pid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL int mvcc_cleanup_dead(MDBX_env *env, int rdt_locked, int *dead) {
|
||||
__cold int mvcc_cleanup_dead(MDBX_env *env, int rdt_locked, int *dead) {
|
||||
int rc = check_env(env, true);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
@@ -295,7 +295,8 @@
|
||||
((defined(_POSIX_THREAD_ROBUST_PRIO_INHERIT) && _POSIX_THREAD_ROBUST_PRIO_INHERIT > 0) || \
|
||||
(defined(_POSIX_THREAD_ROBUST_PRIO_PROTECT) && _POSIX_THREAD_ROBUST_PRIO_PROTECT > 0) || \
|
||||
defined(PTHREAD_MUTEX_ROBUST) || defined(PTHREAD_MUTEX_ROBUST_NP)) && \
|
||||
(!defined(__GLIBC__) || __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */)
|
||||
(!defined(__GLIBC__) || __GLIBC_PREREQ(2, 10) /* troubles with Robust mutexes before 2.10 */) && \
|
||||
!defined(__OHOS__) /* Harmony OS doesn't support robust mutexes at the end of 2025 */
|
||||
#define MDBX_LOCKING MDBX_LOCKING_POSIX2008
|
||||
#else
|
||||
#define MDBX_LOCKING MDBX_LOCKING_POSIX2001
|
||||
@@ -350,6 +351,22 @@
|
||||
#error MDBX_USE_COPYFILERANGE must be defined as 0 or 1
|
||||
#endif /* MDBX_USE_COPYFILERANGE */
|
||||
|
||||
/** Advanced: Using posix_fallocate() or fcntl(F_PREALLOCATE) on OSX (autodetection by default). */
|
||||
#ifndef MDBX_USE_FALLOCATE
|
||||
#if defined(__APPLE__)
|
||||
#define MDBX_USE_FALLOCATE 0 /* Too slow and unclean, but not required to prevent SIGBUS */
|
||||
#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (__GLIBC_PREREQ(2, 10) && defined(_GNU_SOURCE))
|
||||
#define MDBX_USE_FALLOCATE 1
|
||||
#else
|
||||
#define MDBX_USE_FALLOCATE 0
|
||||
#endif
|
||||
#define MDBX_USE_FALLOCATE_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_FALLOCATE)
|
||||
#elif !(MDBX_USE_FALLOCATE == 0 || MDBX_USE_FALLOCATE == 1)
|
||||
#error MDBX_USE_FALLOCATE must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_USE_FALLOCATE_CONFIG MDBX_STRINGIFY(MDBX_USE_FALLOCATE)
|
||||
#endif /* MDBX_USE_FALLOCATE */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef MDBX_CPU_WRITEBACK_INCOHERENT
|
||||
|
||||
180
src/osal.c
180
src/osal.c
@@ -271,7 +271,7 @@ __cold void mdbx_panic(const char *fmt, ...) {
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef osal_vasprintf
|
||||
MDBX_INTERNAL int osal_vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
int osal_vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
va_list ones;
|
||||
va_copy(ones, ap);
|
||||
const int needed = vsnprintf(nullptr, 0, fmt, ones);
|
||||
@@ -303,7 +303,7 @@ MDBX_INTERNAL int osal_vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
#endif /* osal_vasprintf */
|
||||
|
||||
#ifndef osal_asprintf
|
||||
MDBX_INTERNAL int osal_asprintf(char **strp, const char *fmt, ...) {
|
||||
int osal_asprintf(char **strp, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
const int rc = osal_vasprintf(strp, fmt, ap);
|
||||
@@ -313,7 +313,7 @@ MDBX_INTERNAL int osal_asprintf(char **strp, const char *fmt, ...) {
|
||||
#endif /* osal_asprintf */
|
||||
|
||||
#ifndef osal_memalign_alloc
|
||||
MDBX_INTERNAL int osal_memalign_alloc(size_t alignment, size_t bytes, void **result) {
|
||||
int osal_memalign_alloc(size_t alignment, size_t bytes, void **result) {
|
||||
assert(is_powerof2(alignment) && alignment >= sizeof(void *));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(void)alignment;
|
||||
@@ -335,7 +335,7 @@ MDBX_INTERNAL int osal_memalign_alloc(size_t alignment, size_t bytes, void **res
|
||||
#endif /* osal_memalign_alloc */
|
||||
|
||||
#ifndef osal_memalign_free
|
||||
MDBX_INTERNAL void osal_memalign_free(void *ptr) {
|
||||
void osal_memalign_free(void *ptr) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
#else
|
||||
@@ -358,7 +358,7 @@ char *osal_strdup(const char *str) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_init(osal_condpair_t *condpair) {
|
||||
int osal_condpair_init(osal_condpair_t *condpair) {
|
||||
int rc;
|
||||
memset(condpair, 0, sizeof(osal_condpair_t));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -397,7 +397,7 @@ bailout_mutex:
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_destroy(osal_condpair_t *condpair) {
|
||||
int osal_condpair_destroy(osal_condpair_t *condpair) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int rc = CloseHandle(condpair->mutex) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
rc = CloseHandle(condpair->event[0]) ? rc : (int)GetLastError();
|
||||
@@ -411,7 +411,7 @@ MDBX_INTERNAL int osal_condpair_destroy(osal_condpair_t *condpair) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_lock(osal_condpair_t *condpair) {
|
||||
int osal_condpair_lock(osal_condpair_t *condpair) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD code = WaitForSingleObject(condpair->mutex, INFINITE);
|
||||
return waitstatus2errcode(code);
|
||||
@@ -420,7 +420,7 @@ MDBX_INTERNAL int osal_condpair_lock(osal_condpair_t *condpair) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_unlock(osal_condpair_t *condpair) {
|
||||
int osal_condpair_unlock(osal_condpair_t *condpair) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return ReleaseMutex(condpair->mutex) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
#else
|
||||
@@ -428,7 +428,7 @@ MDBX_INTERNAL int osal_condpair_unlock(osal_condpair_t *condpair) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_signal(osal_condpair_t *condpair, bool part) {
|
||||
int osal_condpair_signal(osal_condpair_t *condpair, bool part) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return SetEvent(condpair->event[part]) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
#else
|
||||
@@ -436,7 +436,7 @@ MDBX_INTERNAL int osal_condpair_signal(osal_condpair_t *condpair, bool part) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_condpair_wait(osal_condpair_t *condpair, bool part) {
|
||||
int osal_condpair_wait(osal_condpair_t *condpair, bool part) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD code = SignalObjectAndWait(condpair->mutex, condpair->event[part], INFINITE, FALSE);
|
||||
if (code == WAIT_OBJECT_0) {
|
||||
@@ -452,7 +452,7 @@ MDBX_INTERNAL int osal_condpair_wait(osal_condpair_t *condpair, bool part) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_INTERNAL int osal_fastmutex_init(osal_fastmutex_t *fastmutex) {
|
||||
int osal_fastmutex_init(osal_fastmutex_t *fastmutex) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
InitializeCriticalSection(fastmutex);
|
||||
return MDBX_SUCCESS;
|
||||
@@ -471,7 +471,7 @@ MDBX_INTERNAL int osal_fastmutex_init(osal_fastmutex_t *fastmutex) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fastmutex_destroy(osal_fastmutex_t *fastmutex) {
|
||||
int osal_fastmutex_destroy(osal_fastmutex_t *fastmutex) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DeleteCriticalSection(fastmutex);
|
||||
return MDBX_SUCCESS;
|
||||
@@ -480,7 +480,7 @@ MDBX_INTERNAL int osal_fastmutex_destroy(osal_fastmutex_t *fastmutex) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fastmutex_acquire(osal_fastmutex_t *fastmutex) {
|
||||
int osal_fastmutex_acquire(osal_fastmutex_t *fastmutex) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
__try {
|
||||
EnterCriticalSection(fastmutex);
|
||||
@@ -495,7 +495,7 @@ MDBX_INTERNAL int osal_fastmutex_acquire(osal_fastmutex_t *fastmutex) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fastmutex_release(osal_fastmutex_t *fastmutex) {
|
||||
int osal_fastmutex_release(osal_fastmutex_t *fastmutex) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LeaveCriticalSection(fastmutex);
|
||||
return MDBX_SUCCESS;
|
||||
@@ -508,7 +508,7 @@ MDBX_INTERNAL int osal_fastmutex_release(osal_fastmutex_t *fastmutex) {
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
MDBX_INTERNAL int osal_mb2w(const char *const src, wchar_t **const pdst) {
|
||||
int osal_mb2w(const char *const src, wchar_t **const pdst) {
|
||||
const size_t dst_wlen = MultiByteToWideChar(CP_THREAD_ACP, MB_ERR_INVALID_CHARS, src, -1, nullptr, 0);
|
||||
wchar_t *dst = *pdst;
|
||||
int rc = ERROR_INVALID_NAME;
|
||||
@@ -578,10 +578,10 @@ static size_t osal_iov_max;
|
||||
#undef OSAL_IOV_MAX
|
||||
#endif /* OSAL_IOV_MAX */
|
||||
|
||||
MDBX_INTERNAL int osal_ioring_create(osal_ioring_t *ior
|
||||
int osal_ioring_create(osal_ioring_t *ior
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
,
|
||||
bool enable_direct, mdbx_filehandle_t overlapped_fd
|
||||
,
|
||||
bool enable_direct, mdbx_filehandle_t overlapped_fd
|
||||
#endif /* Windows */
|
||||
) {
|
||||
memset(ior, 0, sizeof(osal_ioring_t));
|
||||
@@ -624,7 +624,7 @@ static inline ior_item_t *ior_next(ior_item_t *item, size_t sgvcnt) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_ioring_add(osal_ioring_t *ior, const size_t offset, void *data, const size_t bytes) {
|
||||
int osal_ioring_add(osal_ioring_t *ior, const size_t offset, void *data, const size_t bytes) {
|
||||
assert(bytes && data);
|
||||
assert(bytes % MDBX_MIN_PAGESIZE == 0 && bytes <= MAX_WRITE);
|
||||
assert(offset % MDBX_MIN_PAGESIZE == 0 && offset + (uint64_t)bytes <= MAX_MAPSIZE);
|
||||
@@ -736,8 +736,8 @@ MDBX_INTERNAL int osal_ioring_add(osal_ioring_t *ior, const size_t offset, void
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL void osal_ioring_walk(osal_ioring_t *ior, iov_ctx_t *ctx,
|
||||
void (*callback)(iov_ctx_t *ctx, size_t offset, void *data, size_t bytes)) {
|
||||
void osal_ioring_walk(osal_ioring_t *ior, iov_ctx_t *ctx,
|
||||
void (*callback)(iov_ctx_t *ctx, size_t offset, void *data, size_t bytes)) {
|
||||
for (ior_item_t *item = ior->pool; item <= ior->last;) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
size_t offset = ior_offset(item);
|
||||
@@ -778,7 +778,7 @@ MDBX_INTERNAL void osal_ioring_walk(osal_ioring_t *ior, iov_ctx_t *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL osal_ioring_write_result_t osal_ioring_write(osal_ioring_t *ior, mdbx_filehandle_t fd) {
|
||||
osal_ioring_write_result_t osal_ioring_write(osal_ioring_t *ior, mdbx_filehandle_t fd) {
|
||||
osal_ioring_write_result_t r = {MDBX_SUCCESS, 0};
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -999,7 +999,7 @@ MDBX_INTERNAL osal_ioring_write_result_t osal_ioring_write(osal_ioring_t *ior, m
|
||||
return r;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL void osal_ioring_reset(osal_ioring_t *ior) {
|
||||
void osal_ioring_reset(osal_ioring_t *ior) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (ior->last) {
|
||||
for (ior_item_t *item = ior->pool; item <= ior->last;) {
|
||||
@@ -1041,7 +1041,7 @@ static void ior_cleanup(osal_ioring_t *ior, const size_t since) {
|
||||
#endif /* Windows */
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_ioring_resize(osal_ioring_t *ior, size_t items) {
|
||||
int osal_ioring_resize(osal_ioring_t *ior, size_t items) {
|
||||
assert(items > 0 && items < INT_MAX / sizeof(ior_item_t));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (ior->state & IOR_STATE_LOCKED)
|
||||
@@ -1093,7 +1093,7 @@ MDBX_INTERNAL int osal_ioring_resize(osal_ioring_t *ior, size_t items) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL void osal_ioring_destroy(osal_ioring_t *ior) {
|
||||
void osal_ioring_destroy(osal_ioring_t *ior) {
|
||||
if (ior->allocated)
|
||||
ior_cleanup(ior, 0);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -1110,7 +1110,7 @@ MDBX_INTERNAL void osal_ioring_destroy(osal_ioring_t *ior) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_INTERNAL int osal_removefile(const pathchar_t *pathname) {
|
||||
int osal_removefile(const pathchar_t *pathname) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return DeleteFileW(pathname) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
#else
|
||||
@@ -1122,7 +1122,7 @@ MDBX_INTERNAL int osal_removefile(const pathchar_t *pathname) {
|
||||
static bool is_valid_fd(int fd) { return !(isatty(fd) < 0 && errno == EBADF); }
|
||||
#endif /*! Windows */
|
||||
|
||||
MDBX_INTERNAL int osal_removedirectory(const pathchar_t *pathname) {
|
||||
int osal_removedirectory(const pathchar_t *pathname) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return RemoveDirectoryW(pathname) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
#else
|
||||
@@ -1130,7 +1130,7 @@ MDBX_INTERNAL int osal_removedirectory(const pathchar_t *pathname) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fileexists(const pathchar_t *pathname) {
|
||||
int osal_fileexists(const pathchar_t *pathname) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (GetFileAttributesW(pathname) != INVALID_FILE_ATTRIBUTES)
|
||||
return MDBX_RESULT_TRUE;
|
||||
@@ -1144,7 +1144,7 @@ MDBX_INTERNAL int osal_fileexists(const pathchar_t *pathname) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL pathchar_t *osal_fileext(const pathchar_t *pathname, size_t len) {
|
||||
pathchar_t *osal_fileext(const pathchar_t *pathname, size_t len) {
|
||||
const pathchar_t *ext = nullptr;
|
||||
for (size_t i = 0; i < len && pathname[i]; i++)
|
||||
if (pathname[i] == '.')
|
||||
@@ -1154,7 +1154,7 @@ MDBX_INTERNAL pathchar_t *osal_fileext(const pathchar_t *pathname, size_t len) {
|
||||
return (pathchar_t *)ext;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL bool osal_pathequal(const pathchar_t *l, const pathchar_t *r, size_t len) {
|
||||
bool osal_pathequal(const pathchar_t *l, const pathchar_t *r, size_t len) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
pathchar_t a = l[i];
|
||||
@@ -1170,8 +1170,8 @@ MDBX_INTERNAL bool osal_pathequal(const pathchar_t *l, const pathchar_t *r, size
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_openfile(const enum osal_openfile_purpose purpose, const MDBX_env *env,
|
||||
const pathchar_t *pathname, mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits) {
|
||||
int osal_openfile(const enum osal_openfile_purpose purpose, const MDBX_env *env, const pathchar_t *pathname,
|
||||
mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits) {
|
||||
*fd = INVALID_HANDLE_VALUE;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -1380,7 +1380,7 @@ MDBX_INTERNAL int osal_openfile(const enum osal_openfile_purpose purpose, const
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_closefile(mdbx_filehandle_t fd) {
|
||||
int osal_closefile(mdbx_filehandle_t fd) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return CloseHandle(fd) ? MDBX_SUCCESS : (int)GetLastError();
|
||||
#else
|
||||
@@ -1389,7 +1389,7 @@ MDBX_INTERNAL int osal_closefile(mdbx_filehandle_t fd) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_pread(mdbx_filehandle_t fd, void *buf, size_t bytes, uint64_t offset) {
|
||||
int osal_pread(mdbx_filehandle_t fd, void *buf, size_t bytes, uint64_t offset) {
|
||||
if (bytes > MAX_WRITE)
|
||||
return MDBX_EINVAL;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@@ -1414,7 +1414,7 @@ MDBX_INTERNAL int osal_pread(mdbx_filehandle_t fd, void *buf, size_t bytes, uint
|
||||
return (bytes == (size_t)read) ? MDBX_SUCCESS : MDBX_ENODATA;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_pwrite(mdbx_filehandle_t fd, const void *buf, size_t bytes, uint64_t offset) {
|
||||
int osal_pwrite(mdbx_filehandle_t fd, const void *buf, size_t bytes, uint64_t offset) {
|
||||
while (true) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
OVERLAPPED ov;
|
||||
@@ -1445,7 +1445,7 @@ MDBX_INTERNAL int osal_pwrite(mdbx_filehandle_t fd, const void *buf, size_t byte
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_write(mdbx_filehandle_t fd, const void *buf, size_t bytes) {
|
||||
int osal_write(mdbx_filehandle_t fd, const void *buf, size_t bytes) {
|
||||
while (true) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD written;
|
||||
@@ -1498,7 +1498,7 @@ int osal_pwritev(mdbx_filehandle_t fd, struct iovec *iov, size_t sgvcnt, uint64_
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fsync(mdbx_filehandle_t fd, enum osal_syncmode_bits mode_bits) {
|
||||
int osal_fsync(mdbx_filehandle_t fd, enum osal_syncmode_bits mode_bits) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if ((mode_bits & (MDBX_SYNC_DATA | MDBX_SYNC_IODQ)) && !FlushFileBuffers(fd))
|
||||
return (int)GetLastError();
|
||||
@@ -1561,7 +1561,7 @@ int osal_filesize(mdbx_filehandle_t fd, uint64_t *length) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_is_pipe(mdbx_filehandle_t fd) {
|
||||
int osal_is_pipe(mdbx_filehandle_t fd) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
switch (GetFileType(fd)) {
|
||||
case FILE_TYPE_DISK:
|
||||
@@ -1592,7 +1592,7 @@ MDBX_INTERNAL int osal_is_pipe(mdbx_filehandle_t fd) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
int osal_fsetsize(mdbx_filehandle_t fd, const uint64_t length) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (imports.SetFileInformationByHandle) {
|
||||
FILE_END_OF_FILE_INFO EndOfFileInfo;
|
||||
@@ -1607,11 +1607,51 @@ MDBX_INTERNAL int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
}
|
||||
#else
|
||||
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t), "libmdbx requires 64-bit file I/O on 64-bit systems");
|
||||
return ftruncate(fd, length) == 0 ? MDBX_SUCCESS : errno;
|
||||
|
||||
#if MDBX_USE_FALLOCATE
|
||||
struct stat info;
|
||||
if (unlikely(fstat(fd, &info)))
|
||||
return errno;
|
||||
|
||||
const uint64_t allocated = UINT64_C(512) * info.st_blocks;
|
||||
if (length > allocated) {
|
||||
#if defined(__APPLE__)
|
||||
fstore_t store = {
|
||||
.fst_flags = F_ALLOCATECONTIG, .fst_posmode = F_PEOFPOSMODE, .fst_offset = 0, .fst_length = length};
|
||||
int err = MDBX_SUCCESS;
|
||||
if (fcntl(fd, F_PREALLOCATE, &store)) {
|
||||
/* TODO: implement step-by-step allocation in chunks of 16384, 8192, 4094, 2048, 1024 Kb */
|
||||
store.fst_flags = F_ALLOCATEALL;
|
||||
if (fcntl(fd, F_PREALLOCATE, &store))
|
||||
err = errno;
|
||||
}
|
||||
#elif defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
|
||||
const int err = posix_fallocate(fd, 0, length);
|
||||
if (!err && length > (uint64_t)info.st_size)
|
||||
info.st_size = length /* posix_fallocate() extends the file */;
|
||||
#else
|
||||
const int err = fallocate(fd, 0, 0, length) ? errno : MDBX_SUCCESS;
|
||||
if (!err && length > (uint64_t)info.st_size)
|
||||
info.st_size = length /* fallocate() extends the file */;
|
||||
#endif
|
||||
if (unlikely(err) && ignore_enosys_and_eremote(err) != MDBX_RESULT_TRUE) {
|
||||
/* 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)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (length == (uint64_t)info.st_size)
|
||||
return MDBX_SUCCESS;
|
||||
#endif
|
||||
|
||||
return unlikely(ftruncate(fd, length)) ? errno : MDBX_SUCCESS;
|
||||
|
||||
#endif /* !Windows */
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_fseek(mdbx_filehandle_t fd, uint64_t pos) {
|
||||
int osal_fseek(mdbx_filehandle_t fd, uint64_t pos) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = pos;
|
||||
@@ -1624,8 +1664,7 @@ MDBX_INTERNAL int osal_fseek(mdbx_filehandle_t fd, uint64_t pos) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_INTERNAL int osal_thread_create(osal_thread_t *thread, THREAD_RESULT(THREAD_CALL *start_routine)(void *),
|
||||
void *arg) {
|
||||
int osal_thread_create(osal_thread_t *thread, THREAD_RESULT(THREAD_CALL *start_routine)(void *), void *arg) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
*thread = CreateThread(nullptr, 0, start_routine, arg, 0, nullptr);
|
||||
return *thread ? MDBX_SUCCESS : (int)GetLastError();
|
||||
@@ -1634,7 +1673,7 @@ MDBX_INTERNAL int osal_thread_create(osal_thread_t *thread, THREAD_RESULT(THREAD
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_thread_join(osal_thread_t thread) {
|
||||
int osal_thread_join(osal_thread_t thread) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD code = WaitForSingleObject(thread, INFINITE);
|
||||
return waitstatus2errcode(code);
|
||||
@@ -1646,7 +1685,7 @@ MDBX_INTERNAL int osal_thread_join(osal_thread_t thread) {
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_INTERNAL int osal_msync(const osal_mmap_t *map, size_t offset, size_t length, enum osal_syncmode_bits mode_bits) {
|
||||
int osal_msync(const osal_mmap_t *map, size_t offset, size_t length, enum osal_syncmode_bits mode_bits) {
|
||||
if (!MDBX_MMAP_NEEDS_JOLT && mode_bits == MDBX_SYNC_NONE)
|
||||
return MDBX_SUCCESS;
|
||||
|
||||
@@ -1677,7 +1716,7 @@ MDBX_INTERNAL int osal_msync(const osal_mmap_t *map, size_t offset, size_t lengt
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_t *pathname, int err) {
|
||||
int osal_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_t *pathname, int err) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(void)pathname;
|
||||
(void)err;
|
||||
@@ -1704,7 +1743,7 @@ MDBX_INTERNAL int osal_check_fs_rdonly(mdbx_filehandle_t handle, const pathchar_
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle) {
|
||||
int osal_check_fs_incore(mdbx_filehandle_t handle) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(void)handle;
|
||||
#else
|
||||
@@ -1745,7 +1784,7 @@ MDBX_INTERNAL int osal_check_fs_incore(mdbx_filehandle_t handle) {
|
||||
return MDBX_RESULT_FALSE;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_check_fs_local(mdbx_filehandle_t handle, int flags) {
|
||||
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 */;
|
||||
@@ -2023,8 +2062,8 @@ static int check_mmap_limit(const size_t limit) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
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) {
|
||||
int osal_mmap(const int flags, osal_mmap_t *map, size_t size, const size_t limit, const unsigned options,
|
||||
const pathchar_t *pathname4logging) {
|
||||
assert(size <= limit);
|
||||
map->limit = 0;
|
||||
map->current = 0;
|
||||
@@ -2061,9 +2100,9 @@ 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);
|
||||
VERBOSE("ftruncate %zu, err %d", size, err);
|
||||
if ((flags & MDBX_RDONLY) == 0 && (options & MMAP_OPTION_SETLENGTH) != 0) {
|
||||
err = osal_fsetsize(map->fd, size);
|
||||
VERBOSE("osal_fsetsize %zu, err %d", size, err);
|
||||
if (err != MDBX_SUCCESS)
|
||||
return err;
|
||||
map->filesize = size;
|
||||
@@ -2176,7 +2215,7 @@ MDBX_INTERNAL int osal_mmap(const int flags, osal_mmap_t *map, size_t size, cons
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_munmap(osal_mmap_t *map) {
|
||||
int osal_munmap(osal_mmap_t *map) {
|
||||
VALGRIND_MAKE_MEM_NOACCESS(map->base, map->current);
|
||||
/* Unpoisoning is required for ASAN to avoid false-positive diagnostic
|
||||
* when this memory will re-used by malloc or another mmapping.
|
||||
@@ -2202,7 +2241,7 @@ MDBX_INTERNAL int osal_munmap(osal_mmap_t *map) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit) {
|
||||
int osal_mresize(const int flags, osal_mmap_t *map, size_t size, size_t limit) {
|
||||
int rc = osal_filesize(map->fd, &map->filesize);
|
||||
VERBOSE("flags 0x%x, size %zu, limit %zu, filesize %" PRIu64, flags, size, limit, map->filesize);
|
||||
assert(size <= limit);
|
||||
@@ -2308,7 +2347,7 @@ retry_file_and_section:
|
||||
}
|
||||
|
||||
if ((flags & MDBX_RDONLY) == 0 && map->filesize != size) {
|
||||
err = osal_ftruncate(map->fd, size);
|
||||
err = osal_fsetsize(map->fd, size);
|
||||
if (err == MDBX_SUCCESS)
|
||||
map->filesize = size;
|
||||
/* ignore error, because Windows unable shrink file
|
||||
@@ -2386,10 +2425,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_fsetsize(map->fd, size);
|
||||
VERBOSE("osal_fsetsize-%s %zu, err %d", "extend", size, rc);
|
||||
} else if (flags & txn_shrink_allowed) {
|
||||
rc = osal_fsetsize(map->fd, size);
|
||||
VERBOSE("osal_fsetsize-%s %zu, err %d", "shrink", size, rc);
|
||||
}
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
map->filesize = size;
|
||||
}
|
||||
@@ -2576,7 +2620,7 @@ retry_mapview:;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
__cold MDBX_INTERNAL void osal_jitter(bool tiny) {
|
||||
__cold void osal_jitter(bool tiny) {
|
||||
for (;;) {
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
|
||||
unsigned salt = 5296013u * (unsigned)__rdtsc();
|
||||
@@ -2594,7 +2638,7 @@ __cold MDBX_INTERNAL void osal_jitter(bool tiny) {
|
||||
break;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (coin < 43 * 2 / 3)
|
||||
SwitchToThread();
|
||||
osal_yield();
|
||||
else {
|
||||
static HANDLE timer;
|
||||
if (!timer)
|
||||
@@ -2609,7 +2653,7 @@ __cold MDBX_INTERNAL void osal_jitter(bool tiny) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
sched_yield();
|
||||
osal_yield();
|
||||
if (coin > 43 * 2 / 3)
|
||||
usleep(coin);
|
||||
#endif
|
||||
@@ -2645,7 +2689,7 @@ __cold static clockid_t choice_monoclock(void) {
|
||||
#define posix_clockid CLOCK_REALTIME
|
||||
#endif
|
||||
|
||||
MDBX_INTERNAL uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
|
||||
uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const uint64_t ratio = performance_frequency.QuadPart;
|
||||
#elif defined(__APPLE__) || defined(__MACH__)
|
||||
@@ -2658,7 +2702,7 @@ MDBX_INTERNAL uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16) {
|
||||
}
|
||||
|
||||
static uint64_t monotime_limit;
|
||||
MDBX_INTERNAL uint32_t osal_monotime_to_16dot16(uint64_t monotime) {
|
||||
uint32_t osal_monotime_to_16dot16(uint64_t monotime) {
|
||||
if (unlikely(monotime > monotime_limit))
|
||||
return UINT32_MAX;
|
||||
|
||||
@@ -2673,7 +2717,7 @@ MDBX_INTERNAL uint32_t osal_monotime_to_16dot16(uint64_t monotime) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL uint64_t osal_monotime(void) {
|
||||
uint64_t osal_monotime(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LARGE_INTEGER counter;
|
||||
if (QueryPerformanceCounter(&counter))
|
||||
@@ -2688,7 +2732,7 @@ MDBX_INTERNAL uint64_t osal_monotime(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL uint64_t osal_cputime(size_t *optional_page_faults) {
|
||||
uint64_t osal_cputime(size_t *optional_page_faults) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (optional_page_faults) {
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
@@ -3353,7 +3397,7 @@ __cold int mdbx_get_sysraminfo(intptr_t *page_size, intptr_t *total_pages, intpt
|
||||
#include <wincrypt.h>
|
||||
#endif /* Windows */
|
||||
|
||||
MDBX_INTERNAL bin128_t osal_guid(const MDBX_env *env) {
|
||||
bin128_t osal_guid(const MDBX_env *env) {
|
||||
struct {
|
||||
uint64_t begin, end, cputime;
|
||||
uintptr_t thread, pid;
|
||||
|
||||
19
src/osal.h
19
src/osal.h
@@ -171,6 +171,14 @@ typedef char pathchar_t;
|
||||
#define MDBX_PRIsPATH "s"
|
||||
#endif
|
||||
|
||||
static inline bool osal_yield(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return SleepEx(0, true) == WAIT_IO_COMPLETION;
|
||||
#else
|
||||
return sched_yield() != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct osal_mmap {
|
||||
union {
|
||||
void *base;
|
||||
@@ -193,7 +201,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
|
||||
@@ -426,7 +441,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_fsetsize(mdbx_filehandle_t fd, const 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 +477,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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
21
src/txn.c
21
src/txn.c
@@ -676,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) {
|
||||
@@ -688,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 "
|
||||
@@ -714,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,7 +3,7 @@
|
||||
|
||||
#include "internals.h"
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL unsigned log2n_powerof2(size_t value_uintptr) {
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION unsigned log2n_powerof2(size_t value_uintptr) {
|
||||
assert(value_uintptr > 0 && value_uintptr < INT32_MAX && is_powerof2(value_uintptr));
|
||||
assert((value_uintptr & -(intptr_t)value_uintptr) == value_uintptr);
|
||||
const uint32_t value_uint32 = (uint32_t)value_uintptr;
|
||||
@@ -22,7 +22,7 @@ MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL unsigned log2n_power
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_NOTHROW_CONST_FUNCTION MDBX_INTERNAL uint64_t rrxmrrxmsx_0(uint64_t v) {
|
||||
MDBX_NOTHROW_CONST_FUNCTION uint64_t rrxmrrxmsx_0(uint64_t v) {
|
||||
/* Pelle Evensen's mixer, https://bit.ly/2HOfynt */
|
||||
v ^= (v << 39 | v >> 25) ^ (v << 14 | v >> 50);
|
||||
v *= UINT64_C(0xA24BAED4963EE407);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -572,11 +572,6 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
return sigbreak ? EINTR : 0 /* timeout */;
|
||||
}
|
||||
|
||||
void osal_yield(void) {
|
||||
if (sched_yield())
|
||||
failure_perror("sched_yield()", errno);
|
||||
}
|
||||
|
||||
void osal_udelay(size_t us) {
|
||||
chrono::time until, now = chrono::now_monotonic();
|
||||
until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint;
|
||||
|
||||
@@ -401,8 +401,6 @@ int osal_actor_poll(mdbx_pid_t &pid, unsigned timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
void osal_yield(void) { SwitchToThread(); }
|
||||
|
||||
void osal_udelay(size_t us) {
|
||||
chrono::time until, now = chrono::now_monotonic();
|
||||
until.fixedpoint = now.fixedpoint + chrono::from_us(us).fixedpoint;
|
||||
|
||||
@@ -20,7 +20,6 @@ bool osal_multiactor_mode(void);
|
||||
|
||||
int osal_delay(unsigned seconds);
|
||||
void osal_udelay(size_t us);
|
||||
void osal_yield(void);
|
||||
bool osal_istty(int fd);
|
||||
std::string osal_tempdir(void);
|
||||
|
||||
|
||||
@@ -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