mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 03:54:13 +08:00
mdbx: merge branch master
into stable
.
Ветка 0.12 считается готовой к продуктовому использованию, получает статус стабильной и далее будет получать только исправление ошибок. Разработка будет продолжена в ветке 0.13, а ветка 0.11 становится архивной.
This commit is contained in:
commit
c81b007587
@ -1,5 +1,5 @@
|
||||
##
|
||||
## Copyright 2020-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
## Copyright 2020-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
## and other libmdbx authors: please see AUTHORS file.
|
||||
## All rights reserved.
|
||||
##
|
||||
@ -235,6 +235,7 @@ if(SUBPROJECT)
|
||||
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
|
||||
endif()
|
||||
set(MDBX_MANAGE_BUILD_FLAGS_DEFAULT OFF)
|
||||
else()
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)" ON)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Generate position independent (PIC)" ON)
|
||||
@ -351,9 +352,14 @@ else()
|
||||
endif()
|
||||
endif(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
|
||||
setup_compile_flags()
|
||||
set(MDBX_MANAGE_BUILD_FLAGS_DEFAULT ON)
|
||||
endif(SUBPROJECT)
|
||||
|
||||
option(MDBX_MANAGE_BUILD_FLAGS "Allow libmdbx to configure/manage/override its own build flags" ${MDBX_MANAGE_BUILD_FLAGS_DEFAULT})
|
||||
if(MDBX_MANAGE_BUILD_FLAGS)
|
||||
setup_compile_flags()
|
||||
endif()
|
||||
|
||||
list(FIND CMAKE_C_COMPILE_FEATURES c_std_11 HAS_C11)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 HAS_CXX11)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_14 HAS_CXX14)
|
||||
@ -500,16 +506,29 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
if(MDBX_NTDLL_EXTRA_IMPLIB)
|
||||
add_mdbx_option(MDBX_WITHOUT_MSVC_CRT "Avoid dependence from MSVC CRT and use ntdll.dll instead" OFF)
|
||||
endif()
|
||||
set(MDBX_AVOID_MSYNC_DEFAULT ON)
|
||||
else()
|
||||
add_mdbx_option(MDBX_USE_OFDLOCKS "Use Open file description locks (aka OFD locks, non-POSIX)" AUTO)
|
||||
mark_as_advanced(MDBX_USE_OFDLOCKS)
|
||||
set(MDBX_AVOID_MSYNC_DEFAULT OFF)
|
||||
endif()
|
||||
add_mdbx_option(MDBX_LOCKING "Locking method (Win32=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO)
|
||||
option(MDBX_AVOID_MSYNC "Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP mode" ${MDBX_AVOID_MSYNC_DEFAULT})
|
||||
add_mdbx_option(MDBX_LOCKING "Locking method (Windows=-1, SysV=5, POSIX=1988, POSIX=2001, POSIX=2008, Futexes=1995)" AUTO)
|
||||
mark_as_advanced(MDBX_LOCKING)
|
||||
add_mdbx_option(MDBX_TRUST_RTC "Does a system have battery-backed Real-Time Clock or just a fake" AUTO)
|
||||
mark_as_advanced(MDBX_TRUST_RTC)
|
||||
option(MDBX_FORCE_ASSERTIONS "Force enable assertion checking" OFF)
|
||||
option(MDBX_DISABLE_PAGECHECKS "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF)
|
||||
option(MDBX_DISABLE_VALIDATION "Disable some checks to reduce an overhead and detection probability of database corruption to a values closer to the LMDB" OFF)
|
||||
option(MDBX_ENABLE_REFUND "Zerocost auto-compactification during write-transactions" ON)
|
||||
option(MDBX_ENABLE_MADVISE "Using POSIX' madvise() and/or similar hints" ON)
|
||||
if (CMAKE_TARGET_BITNESS GREATER 32)
|
||||
set(MDBX_BIGFOOT_DEFAULT ON)
|
||||
else()
|
||||
set(MDBX_BIGFOOT_DEFAULT OFF)
|
||||
endif()
|
||||
option(MDBX_ENABLE_BIGFOOT "Chunking long list of retired pages during huge transactions commit to avoid use sequences of pages" ${MDBX_BIGFOOT_DEFAULT})
|
||||
option(MDBX_ENABLE_PGOP_STAT "Gathering statistics for page operations" ON)
|
||||
option(MDBX_ENABLE_PROFGC "Profiling of GC search and updates" OFF)
|
||||
|
||||
if(NOT MDBX_AMALGAMATED_SOURCE)
|
||||
if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "DEBUG")
|
||||
@ -966,6 +985,7 @@ if (NOT SUBPROJECT)
|
||||
set(CPACK_PACKAGE_VERSION_COMMIT ${MDBX_VERSION_REVISION})
|
||||
set(PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}.${CPACK_PACKAGE_VERSION_COMMIT}")
|
||||
message(STATUS "libmdbx package version is ${PACKAGE_VERSION}")
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/VERSION.txt" "${MDBX_VERSION_MAJOR}.${MDBX_VERSION_MINOR}.${MDBX_VERSION_RELEASE}.${MDBX_VERSION_REVISION}")
|
||||
endif()
|
||||
|
||||
cmake_policy(POP)
|
||||
|
@ -1,4 +1,4 @@
|
||||
Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
Copyright 2011-2015 Howard Chu, Symas Corp.
|
||||
Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
All rights reserved.
|
||||
|
480
ChangeLog.md
480
ChangeLog.md
@ -1,53 +1,447 @@
|
||||
ChangeLog
|
||||
---------
|
||||
|
||||
## v0.11.14 (Sergey Kapitsa) at 2023-02-14
|
||||
English version [by Google](https://gitflic-ru.translate.goog/project/erthink/libmdbx/blob?file=ChangeLog.md&_x_tr_sl=ru&_x_tr_tl=en)
|
||||
and [by Yandex](https://translated.turbopages.org/proxy_u/ru-en.en/https/gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md).
|
||||
|
||||
The stable bugfix release in memory of [Sergey Kapitsa](https://en.wikipedia.org/wiki/Sergey_Kapitsa) on his 95th birthday.
|
||||
## v0.12.4 (Арта-333) от 2023-03-03
|
||||
|
||||
Стабилизирующий выпуск с исправлением обнаруженных ошибок, устранением
|
||||
недочетов и технических долгов. Ветка 0.12 считается готовой к
|
||||
продуктовому использованию, получает статус стабильной и далее будет
|
||||
получать только исправление ошибок. Разработка будет продолжена в ветке
|
||||
0.13, а ветка 0.11 становится архивной.
|
||||
|
||||
```
|
||||
22 files changed, 250 insertions(+), 174 deletions(-)
|
||||
63 files changed, 1161 insertions(+), 569 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Благодарности:
|
||||
|
||||
- Max <maxc0d3r@protonmail.com> за сообщение о проблеме ERROR_SHARING_VIOLATION
|
||||
в режиме MDBX_EXCLUSIVE на Windows.
|
||||
- Alisher Ashyrov <https://t.me/a1is43ras4> за сообщение о проблеме
|
||||
с assert-проверкой и содействие в отладке.
|
||||
- Masatoshi Fukunaga <https://gitflic.ru/user/mah0x211> за сообщение о проблеме
|
||||
`put(MDBX_UPSERT+MDBX_ALLDUPS)` для случая замены всех значений в subDb.
|
||||
|
||||
Исправления (без корректировок новых функций):
|
||||
|
||||
- Устранен регресс после коммита 474391c83c5f81def6fdf3b0b6f5716a87b78fbf,
|
||||
приводящий к возврату ERROR_SHARING_VIOLATION в Windows при открытии БД
|
||||
в режиме MDBX_EXCLUSIVE для чтения-записи.
|
||||
|
||||
- Добавлено ограничение размера отображения при коротком read-only файле, для
|
||||
предотвращения ошибки ERROR_NOT_ENOUGH_MEMORY в Windows, которая возникает
|
||||
в этом случае и совсем не информативна для пользователя.
|
||||
|
||||
- Произведен рефакторинг `dxb_resize()`, в том числе, для устранения срабатывания
|
||||
assert-проверки `size_bytes == env->me_dxb_mmap.current` в специфических
|
||||
многопоточных сценариях использования. Проверка срабатывала только в
|
||||
отладочных сборках, при специфическом наложении во времени читающей и
|
||||
пишущей транзакции в разных потоках, одновременно с изменением размера БД.
|
||||
Кроме срабатывание проверки, каких-либо других последствий не возникало.
|
||||
|
||||
- Устранена проблема в `put(MDBX_UPSERT+MDBX_ALLDUPS)` для случая замены
|
||||
всех значений единственного ключа в subDb. В ходе этой операции subDb
|
||||
становится полностью пустой, без каких-либо страниц и именно эта
|
||||
ситуация не была учтена в коде, что приводило к повреждению БД
|
||||
при фиксации такой транзакции.
|
||||
|
||||
- Устранена излишняя assert-проверка внутри `override_meta()`.
|
||||
Что в отладочных сборках могло приводить к ложным срабатываниям
|
||||
при восстановлении БД, в том числе при автоматическом откате слабых
|
||||
мета-страниц.
|
||||
|
||||
- Скорректированы макросы `__cold`/`__hot`, в том числе для устранения проблемы
|
||||
`error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch`
|
||||
при сборке посредством GCC >10.x для SH4.
|
||||
|
||||
Ликвидация технических долгов и мелочи:
|
||||
|
||||
- Исправлены многочисленные опечатки в документации.
|
||||
- Доработан тест для полной стохастической проверки `MDBX_EKEYMISMATCH` в режиме `MDBX_APPEND`.
|
||||
- Расширены сценарии запуска `mdbx_chk` из CMake-тестов для проверки как в обычном,
|
||||
так и эксклюзивном режимах чтения-записи.
|
||||
- Уточнены спецификаторы `const` и `noexcept` для нескольких методов в C++ API.
|
||||
- Устранено использование стека под буферы для `wchar`-преобразования путей.
|
||||
- Для Windows добавлена функция `mdbx_env_get_path()` для получения пути к БД
|
||||
в формате многобайтных символов.
|
||||
- Добавлены doxygen-описания для API с широкими символами.
|
||||
- Устранены предупреждения статического анализатора MSVC,
|
||||
все они были несущественные, либо ложные.
|
||||
- Устранено ложное предупреждение GCC при сборке для SH4.
|
||||
- Добавлена поддержка ASAN (Address Sanitizer) при сборке посредством MSVC.
|
||||
- Расширен набор перебираемых режимов в скрипте `test/long_stochastic.sh`,
|
||||
добавлена опция `--extra`.
|
||||
- В C++ API добавлена поддержка расширенных опций времени выполнения `mdbx::extra_runtime_option`,
|
||||
аналогично `enum MDBX_option_t` из C API.
|
||||
- Вывод всех счетчиков page-operations в `mdbx_stat`.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.3 (Акула) от 2023-01-07
|
||||
|
||||
Выпуск с существенными доработками и новой функциональностью в память о закрытом open-source
|
||||
[проекте "Акула"](https://erigon.substack.com/p/winding-down-support-for-akula-project).
|
||||
|
||||
Добавлена prefault-запись, переделан контроль “некогерентности” unified page/buffer cache, изменена тактика слияния страниц и т.д.
|
||||
Стало ещё быстрее, в некоторых сценариях вдвое.
|
||||
|
||||
```
|
||||
20 files changed, 4508 insertions(+), 2928 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Благодарности:
|
||||
|
||||
- [Alex Sharov](https://t.me/AskAlexSharov) и команде [Erigon](https://github.com/ledgerwatch/erigon) за тестирование.
|
||||
- [Simon Leier](https://t.me/leisim) за сообщение о сбоях и тестирование.
|
||||
|
||||
Новое:
|
||||
|
||||
- Использование адреса [https://libmdbx.dqdkfa.ru/dead-github](https://libmdbx.dqdkfa.ru/dead-github)
|
||||
для отсылки к сохранённым в web.archive.org копиям ресурсов, уничтоженных администрацией Github.
|
||||
|
||||
- Реализована prefault-запись при выделении страниц для read-write отображений.
|
||||
Это приводит к кратному снижению системных издержек и существенному увеличению
|
||||
производительности в соответствующих сценариях использования, когда:
|
||||
- размер БД и объём данных существенно больше ОЗУ;
|
||||
- используется режим `MDBX_WRITEMAP`;
|
||||
- не-мелкие транзакции (по ходу транзакции выделяется многие сотни или тысячи страниц).
|
||||
|
||||
В режиме `MDBX_WRITEMAP` выделение/переиспользование страниц приводит
|
||||
к page-fault и чтению страницы с диска, даже если содержимое страницы
|
||||
не нужно (будет перезаписано). Это является следствием работы подсистемы
|
||||
виртуальной памяти, а штатный способ лечения через `MADV_REMOVE`
|
||||
работает не на всех ФС и обычно дороже получаемой экономии.
|
||||
|
||||
Теперь в libmdbx используется "упреждающая запись" таких страниц,
|
||||
которая на системах с [unified page cache](https://www.opennet.ru/base/dev/ubc.txt.html)
|
||||
приводит к "вталкиванию" данных, устраняя необходимость чтения с диска при
|
||||
обращении к такой странице памяти.
|
||||
|
||||
Новый функционал работает в согласованности с автоматическим управлением read-ahead
|
||||
и кэшем статуса присутствия страниц в ОЗУ, посредством [mincore()](https://man7.org/linux/man-pages/man2/mincore.2.html).
|
||||
|
||||
- Добавлена опция `MDBX_opt_prefault_write_enable` для возможности принудительного
|
||||
включения/выключения prefault-записи.
|
||||
|
||||
- Реализован динамический выбор между сквозной записью на диск и обычной записью
|
||||
с последующим [fdatasync()](https://man7.org/linux/man-pages/man3/fdatasync.3p.html)
|
||||
управляемый опцией `MDBX_opt_writethrough_threshold`.
|
||||
|
||||
В долговечных (durable) режимах данные на диск могут быть сброшены двумя способами:
|
||||
- сквозной записью через файловый дескриптор открытый с `O_DSYNC`;
|
||||
- обычной записью с последующим вызовом `fdatasync()`.
|
||||
|
||||
Первый способ выгоднее при записи малого количества страниц и/или если
|
||||
канал взаимодействия с диском/носителем имеет близкую к нулю задержку.
|
||||
Второй способ выгоднее если требуется записать много страниц и/или канал
|
||||
взаимодействия имеет весомую задержку (датацентры, облака). Добавленная
|
||||
опция `MDBX_opt_writethrough_threshold` позволяет во время выполнения
|
||||
задать порог для динамического выбора способа записи в зависимости от
|
||||
объема и конкретных условия использования.
|
||||
|
||||
- Автоматическая установка `MDBX_opt_rp_augment_limit` в зависимости от размера БД.
|
||||
|
||||
- Запрещение разного режима `MDBX_WRITEMAP` между процессами в режимах
|
||||
с отложенной/ленивой записью, так как в этом случае невозможно
|
||||
обеспечить сброс данных на диск во всех случаях на всех поддерживаемых платформах.
|
||||
|
||||
- Добавлена опция сборки `MDBX_MMAP_USE_MS_ASYNC` позволяющая отключить
|
||||
использование системного вызова `msync(MS_ASYNC)`, в использовании
|
||||
которого нет необходимости на подавляющем большинстве актуальных ОС.
|
||||
По-умолчанию `MDBX_MMAP_USE_MS_ASYNC=0` (выключено) на Linux и других
|
||||
системах с unified page cache. Такое поведение (без использования
|
||||
`msync(MS_ASYNC)`) соответствует неизменяемой (hardcoded) логике LMDB. В
|
||||
результате, в простых/наивных бенчмарках, libmdbx опережает LMDB
|
||||
примерно также как при реальном применении.
|
||||
|
||||
На всякий случай стоит еще раз отметить/напомнить, что на Windows
|
||||
предположительно libmdbx будет отставать от LMDB в сценариях с
|
||||
множеством мелких транзакций, так как libmdbx осознанно использует на
|
||||
Windows файловые блокировки, которые медленные (плохо реализованы в ядре
|
||||
ОС), но позволяют застраховать пользователей от массы неверных действий
|
||||
приводящих к повреждению БД.
|
||||
|
||||
- Поддержка не-печатных имен для subDb.
|
||||
|
||||
- Добавлен явный выбор `tls_model("local-dynamic")` для обхода проблемы
|
||||
`relocation R_X86_64_TPOFF32 against FOO cannot be used with -shared`
|
||||
из-за ошибки в CLANG приводящей к использованию неверного режима `ls_model`.
|
||||
|
||||
- Изменение тактики слияния страниц при удалении.
|
||||
Теперь слияние выполняется преимущественно с уже измененной/грязной страницей.
|
||||
Если же справа и слева обе страницы с одинаковым статусом,
|
||||
то с наименее заполненной, как прежде. В сценариях с массивным удалением
|
||||
это позволяет увеличить производительность до 50%.
|
||||
|
||||
- Добавлен контроль отсутствия LCK-файлов с альтернативным именованием.
|
||||
|
||||
Исправления (без корректировок новых функций):
|
||||
|
||||
- Изменение размера отображения если это требуется для сброса данных на
|
||||
диск при вызове `mdbx_env_sync()` из параллельного потока выполнения вне
|
||||
работающей транзакции.
|
||||
|
||||
- Исправление регресса после коммита db72763de049d6e4546f838277fe83b9081ad1de от 2022-10-08
|
||||
в логике возврата грязных страниц в режиме `MDBX_WRITEMAP`, из-за чего
|
||||
освободившиеся страницы использовались не немедленно, а попадали в
|
||||
retired-список совершаемой транзакции и происходил необоснованный рост
|
||||
размера транзакции.
|
||||
|
||||
- Устранение SIGSEGV или ошибочного вызова `free()` в ситуациях
|
||||
повторного открытия среды посредством `mdbx_env_open()`.
|
||||
|
||||
- Устранение ошибки совершенной в коммите fe20de136c22ed3bc4c6d3f673e79c106e824f60 от 2022-09-18,
|
||||
в результате чего на Linux в режиме `MDBX_WRITEMAP` никогда не вызывался `msync()`.
|
||||
Проблема существует только в релизе 0.12.2.
|
||||
|
||||
- Добавление подсчета грязных страниц в `MDBX_WRITEMAP` для предоставления посредством `mdbx_txn_info()`
|
||||
актуальной информации об объеме изменений в процессе транзакций чтения-записи.
|
||||
|
||||
- Исправление несущественной опечатки в условиях `#if` определения порядка байт.
|
||||
|
||||
- Исправление сборки для случая `MDBX_PNL_ASCENDING=1`.
|
||||
|
||||
Ликвидация технических долгов и мелочи:
|
||||
|
||||
- Доработка поддержки авто-слияния записей GC внутри `page_alloc_slowpath()`.
|
||||
- Устранение несущественных предупреждений Coverity.
|
||||
- Использование единого курсора для поиска в GC.
|
||||
- Переработка внутренних флагов связанных с выделением страниц из GC.
|
||||
- Доработка подготовки резерва перед обновлением GC при включенном BigFoot.
|
||||
- Оптимизация `pnl_merge()` для случаев неперекрывающихся объединяемых списков.
|
||||
- Оптимизация поддержки отсортированного списка страниц в `dpl_append()`.
|
||||
- Ускорение работы `mdbx_chk` при обработке пользовательских записей в `@MAIN`.
|
||||
- Переработка LRU-отметок для спиллинга.
|
||||
- Переработка контроля "некогерентности" Unified page cache для уменьшения накладных расходов.
|
||||
- Рефакторинг и микрооптимизация.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.2 (Иван Ярыгин) от 2022-11-11
|
||||
|
||||
Выпуск с существенными доработками и новой функциональностью
|
||||
в память о российском борце [Иване Сергеевиче Ярыгине](https://ru.wikipedia.org/wiki/Ярыгин,_Иван_Сергеевич).
|
||||
|
||||
На Олимпийских играх в Мюнхене в 1972 году Иван Ярыгин уложил всех соперников на лопатки,
|
||||
суммарно затратив менее 9 минут. Этот рекорд никем не побит до сих пор.
|
||||
|
||||
```
|
||||
64 files changed, 5573 insertions(+), 2510 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
Новое:
|
||||
|
||||
- Поддержка всех основных опций при сборке посредством CMake.
|
||||
|
||||
- Требования к CMake понижены до версии 3.0.2 для возможности сборки для устаревших платформ.
|
||||
|
||||
- Добавлена возможность профилирования работы GC в сложных и/или нагруженных
|
||||
сценариях (например Ethereum/Erigon). По-умолчанию соответствующий код отключен,
|
||||
а для его активации необходимо указать опцию сборки `MDBX_ENABLE_PROFGC=1`.
|
||||
|
||||
- Добавлена функция `mdbx_env_warmup()` для "прогрева" БД с возможностью
|
||||
закрепления страниц в памяти.
|
||||
В утилиты `mdbx_chk`, `mdbx_copy` и `mdbx_dump` добавлены опции `-u` и `-U`
|
||||
для активации соответствующего функционала.
|
||||
|
||||
- Отключение учета «грязных» страниц в не требующих этого режимах
|
||||
(`MDBX_WRITEMAP` при `MDBX_AVOID_MSYNC=0`). Доработка позволяет снизить
|
||||
накладные расходы и была запланирована давно, но откладывалась так как
|
||||
требовала других изменений.
|
||||
|
||||
- Вытеснение из памяти (спиллинг) «грязных» страниц с учетом размера
|
||||
large/overflow-страниц. Доработка позволяет корректно соблюдать политику
|
||||
задаваемую опциями `MDBX_opt_txn_dp_limit`,
|
||||
`MDBX_opt_spill_max_denominator`, `MDBX_opt_spill_min_denominator` и
|
||||
была запланирована давно, но откладывалась так как требовала других
|
||||
изменений.
|
||||
|
||||
- Для Windows в API добавлены UNICODE-зависимые определения макросов
|
||||
`MDBX_DATANAME`, `MDBX_LOCKNAME` и `MDBX_LOCK_SUFFIX`.
|
||||
|
||||
- Переход на преимущественное использование типа `size_t` для
|
||||
уменьшения накладных расходов на платформе Эльбрус.
|
||||
|
||||
- В API добавлены функции `mdbx_limits_valsize4page_max()` и
|
||||
`mdbx_env_get_valsize4page_max()` возвращающие максимальный размер в
|
||||
байтах значения, которое может быть размещена в одной
|
||||
large/overflow-странице, а не последовательности из двух или более таких
|
||||
страниц. Для таблиц с поддержкой дубликатов вынос значений на
|
||||
large/overflow-страницы не поддерживается, поэтому результат совпадает с
|
||||
`mdbx_limits_valsize_max()`.
|
||||
|
||||
- В API добавлены функции `mdbx_limits_pairsize4page_max()`и
|
||||
`mdbx_env_get_pairsize4page_max()` возвращающие в байтах максимальный
|
||||
суммарный размер пары ключ-значение для их размещения на одной листовой
|
||||
страницы, без выноса значения на отдельную large/overflow-страницу. Для
|
||||
таблиц с поддержкой дубликатов вынос значений на large/overflow-страницы
|
||||
не поддерживается, поэтому результат определяет максимальный/допустимый
|
||||
суммарный размер пары ключ-значение.
|
||||
|
||||
- Реализовано использование асинхронной (overlapped) записи в Windows,
|
||||
включая использования небуфферизированного ввода-вывода и `WriteGather()`.
|
||||
Это позволяет сократить накладные расходы и частично обойти проблемы
|
||||
Windows с низкой производительностью ввода-вывода, включая большие
|
||||
задержки `FlushFileBuffers()`. Новый код также обеспечивает консолидацию
|
||||
записываемых регионов на всех платформах, а на Windows использование
|
||||
событий (events) сведено к минимум, одновременно с автоматических
|
||||
использованием `WriteGather()`. Поэтому ожидается существенное снижение
|
||||
накладных расходов взаимодействия с ОС, а в Windows это ускорение, в
|
||||
некоторых сценариях, может быть кратным в сравнении с LMDB.
|
||||
|
||||
- Добавлена опция сборки `MDBX_AVOID_MSYNC`, которая определяет
|
||||
поведение libmdbx в режиме `MDBX_WRITE_MAP` (когда данные изменяются
|
||||
непосредственно в отображенных в ОЗУ страницах БД):
|
||||
|
||||
* Если `MDBX_AVOID_MSYNC=0` (по умолчанию на всех системах кроме Windows),
|
||||
то (как прежде) сохранение данных выполняется посредством `msync()`,
|
||||
либо `FlushViewOfFile()` на Windows. На платформах с полноценной
|
||||
подсистемой виртуальной памяти и адекватным файловым вводом-выводом
|
||||
это обеспечивает минимум накладных расходов (один системный вызов)
|
||||
и максимальную производительность. Однако, на Windows приводит
|
||||
к значительной деградации, в том числе из-за того что после
|
||||
`FlushViewOfFile()` требуется также вызов `FlushFileBuffers()`
|
||||
с массой проблем и суеты внутри ядра ОС.
|
||||
|
||||
* Если `MDBX_AVOID_MSYNC=1` (по умолчанию только на Windows), то
|
||||
сохранение данных выполняется явной записью в файл каждой измененной
|
||||
страницы БД. Это требует дополнительных накладных расходов, как
|
||||
на отслеживание измененных страниц (ведение списков "грязных"
|
||||
страниц), так и на системные вызовы для их записи.
|
||||
Кроме этого, с точки зрения подсистемы виртуальной памяти ядра ОС,
|
||||
страницы БД измененные в ОЗУ и явно записанные в файл, могут либо
|
||||
оставаться "грязными" и быть повторно записаны ядром ОС позже,
|
||||
либо требовать дополнительных накладных расходов для отслеживания
|
||||
PTE (Page Table Entries), их модификации и дополнительного копирования
|
||||
данных. Тем не менее, по имеющейся информации, на Windows такой путь
|
||||
записи данных в целом обеспечивает более высокую производительность.
|
||||
|
||||
- Улучшение эвристики включения авто-слияния записей GC.
|
||||
|
||||
- Изменение формата LCK и семантики некоторых внутренних полей. Версии
|
||||
libmdbx использующие разный формат не смогут работать с одной БД
|
||||
одновременно, а только поочередно (LCK-файл переписывается при открытии
|
||||
первым открывающим БД процессом).
|
||||
|
||||
- В `C++` API добавлены методы фиксации транзакции с получением информации
|
||||
о задержках.
|
||||
|
||||
- Added `MDBX_HAVE_BUILT IN_CPU_SUPPORTS` build option to control use GCC's
|
||||
`__builtin_cpu_supports()` function, which could be unavailable on a fake
|
||||
OSes (macos, ios, android, etc).
|
||||
|
||||
Исправления (без корректировок вышеперечисленных новых функций):
|
||||
|
||||
- Устранения ряда предупреждений при сборке посредством MinGW.
|
||||
- Устранение ложно-положительных сообщений от Valgrind об использовании
|
||||
не инициализированных данных из-за выравнивающих зазоров в `struct troika`.
|
||||
- Исправлен возврат неожиданной ошибки `MDBX_BUSY` из функций `mdbx_env_set_option()`,
|
||||
`mdbx_env_set_syncbytes()` и `mdbx_env_set_syncperiod()`.
|
||||
- Небольшие исправления для совместимости с CMake 3.8
|
||||
- Больше контроля и осторожности (паранойи) для страховки от дефектов `mremap()`.
|
||||
- Костыль для починки сборки со старыми версиями `stdatomic.h` из GNU Lib C,
|
||||
где макросы `ATOMIC_*_LOCK_FREE` ошибочно переопределяются через функции.
|
||||
- Использование `fcntl64(F_GETLK64/F_SETLK64/F_SETLKW64)` при наличии.
|
||||
Это решает проблему срабатывания проверочного утверждения при сборке для
|
||||
платформ где тип `off_t` шире соответствующих полей `структуры flock`,
|
||||
используемой для блокировки файлов.
|
||||
- Доработан сбор информации о задержках при фиксации транзакций:
|
||||
* Устранено искажение замеров длительности обновления GC
|
||||
при включении отладочного внутреннего аудита;
|
||||
* Защита от undeflow-нуля только общей задержки в метриках,
|
||||
чтобы исключить ситуации, когда сумма отдельных стадий
|
||||
больше общей длительности.
|
||||
- Ряд исправлений для устранения срабатываний проверочных утверждения в
|
||||
отладочных сборках.
|
||||
- Более осторожное преобразование к типу `mdbx_tid_t` для устранения
|
||||
предупреждений.
|
||||
- Исправление лишнего сброса данных на диск в режиме `MDBX_SAFE_NOSYNC`
|
||||
при обновлении GC.
|
||||
- Fixed an extra check for `MDBX_APPENDDUP` inside `mdbx_cursor_put()`
|
||||
which could result in returning `MDBX_EKEYMISMATCH` for valid cases.
|
||||
- Fixed nasty `clz()` bug (by using `_BitScanReverse()`, only MSVC builds affected).
|
||||
|
||||
Мелочи:
|
||||
|
||||
- Исторические ссылки cвязанные с удалённым на ~~github~~ проектом перенаправлены на [web.archive.org](https://web.archive.org/web/https://github.com/erthink/libmdbx).
|
||||
- Синхронизированны конструкции CMake между проектами.
|
||||
- Добавлено предупреждение о небезопасности RISC-V.
|
||||
- Добавлено описание параметров `MDBX_debug_func` и `MDBX_debug_func`.
|
||||
- Добавлено обходное решение для минимизации ложно-положительных
|
||||
конфликтов при использовании файловых блокировок в Windows.
|
||||
- Проверка атомарности C11-операций c 32/64-битными данными.
|
||||
- Уменьшение в 42 раза значения по-умолчанию для `me_options.dp_limit`
|
||||
в отладочных сборках.
|
||||
- Добавление платформы `gcc-riscv64-linux-gnu` в список для цели `cross-gcc`.
|
||||
- Небольшие правки скрипта `long_stochastic.sh` для работы в Windows.
|
||||
- Удаление ненужного вызова `LockFileEx()` внутри `mdbx_env_copy()`.
|
||||
- Добавлено описание использования файловых дескрипторов в различных режимах.
|
||||
- Добавлено использование `_CrtDbgReport()` в отладочных сборках.
|
||||
- Fixed an extra ensure/assertion check of `oldest_reader` inside `txn_end()`.
|
||||
- Removed description of deprecated usage of `MDBX_NODUPDATA`.
|
||||
- Fixed regression ASAN/Valgring-enabled builds.
|
||||
- Fixed minor MingGW warning.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.12.1 (Positive Proxima) at 2022-08-24
|
||||
|
||||
The planned frontward release with new superior features on the day of 20 anniversary of [Positive Technologies](https://ptsecurty.com).
|
||||
|
||||
```
|
||||
37 files changed, 7604 insertions(+), 7417 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
- The `Big Foot` feature which significantly reduces GC overhead for processing large lists of retired pages from huge transactions.
|
||||
Now _libmdbx_ avoid creating large chunks of PNLs (page number lists) which required a long sequences of free pages, aka large/overflow pages.
|
||||
Thus avoiding searching, allocating and storing such sequences inside GC.
|
||||
- Improved hot/online validation and checking of database pages both for more robustness and performance.
|
||||
- New solid and fast method to latch meta-pages called `Troika`.
|
||||
The minimum of memory barriers, reads, comparisons and conditional transitions are used.
|
||||
- New `MDBX_VALIDATION` environment options to extra validation of DB structure and pages content for carefully/safe handling damaged or untrusted DB.
|
||||
- Accelerated ×16/×8/×4 by AVX512/AVX2/SSE2/Neon implementations of search page sequences.
|
||||
- Added the `gcrtime_seconds16dot16` counter to the "Page Operation Statistics" that accumulates time spent for GC searching and reclaiming.
|
||||
- Copy-with-compactification now clears/zeroes unused gaps inside database pages.
|
||||
- The `C` and `C++` APIs has been extended and/or refined to simplify using `wchar_t` pathnames.
|
||||
On Windows the `mdbx_env_openW()`, ``mdbx_env_get_pathW()`()`, `mdbx_env_copyW()`, `mdbx_env_open_for_recoveryW()` are available for now,
|
||||
but the `mdbx_env_get_path()` has been replaced in favor of `mdbx_env_get_pathW()`.
|
||||
- Added explicit error message for Buildroot's Microblaze toolchain maintainers.
|
||||
- Added `MDBX_MANAGE_BUILD_FLAGS` build options for CMake.
|
||||
- Speed-up internal `bsearch`/`lower_bound` implementation using branchless tactic, including workaround for CLANG x86 optimiser bug.
|
||||
- A lot internal refinement and micro-optimisations.
|
||||
- Internally counted volume of dirty pages (unused for now but for coming features).
|
||||
|
||||
Fixes:
|
||||
|
||||
- backport: Fixed insignificant typo of `||` inside `#if` byte-order condition.
|
||||
|
||||
- backport: Fixed `SIGSEGV` or an erroneous call to `free()` in situations where
|
||||
errors occur when reopening by `mdbx_env_open()` of a previously used
|
||||
environment.
|
||||
|
||||
- backport: Fixed `cursor_put_nochecklen()` internals for case when dupsort'ed named subDb
|
||||
contains a single key with multiple values (aka duplicates), which are replaced
|
||||
with a single value by put-operation with the `MDBX_UPSERT+MDBX_ALLDUPS` flags.
|
||||
In this case, the database becomes completely empty, without any pages.
|
||||
However exactly this condition was not considered and thus wasn't handled correctly.
|
||||
See [issue#8](https://gitflic.ru/project/erthink/libmdbx/issue/8) for more information.
|
||||
|
||||
- backport: Fixed extra assertion inside `override_meta()`, which could
|
||||
lead to false-positive failing of the assertion in a debug builds during
|
||||
DB recovery and auto-rollback.
|
||||
|
||||
- backport: Refined the `__cold`/`__hot` macros to avoid the
|
||||
`error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch`
|
||||
issue during build using GCC >10.x for SH4 arch.
|
||||
|
||||
Minors:
|
||||
|
||||
- backport: Using the https://libmdbx.dqdkfa.ru/dead-github
|
||||
for resources deleted by the Github' administration.
|
||||
- backport: Fixed English typos.
|
||||
- backport: Fixed proto of `__asan_default_options()`.
|
||||
- backport: Fixed doxygen-description of C++ API, especially of C++20 concepts.
|
||||
- backport: Refined `const` and `noexcept` for few C++ API methods.
|
||||
- backport: Fixed copy&paste typo of "Getting started".
|
||||
- backport: Update MithrilDB status.
|
||||
- backport: Resolve false-posirive `used uninitialized` warning from GCC >10.x
|
||||
while build for SH4 arch.
|
||||
- Never use modern `__cxa_thread_atexit()` on Apple's OSes.
|
||||
- Don't check owner for finished transactions.
|
||||
- Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG.
|
||||
|
||||
|
||||
## v0.11.13 (Swashplate) at 2022-11-10
|
||||
## v0.12.0 at 2022-06-19
|
||||
|
||||
Not a release but preparation for changing feature set and API.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.11.13 at (Swashplate) 2022-11-10
|
||||
|
||||
The stable bugfix release in memory of [Boris Yuryev](https://ru.wikipedia.org/wiki/Юрьев,_Борис_Николаевич) on his 133rd birthday.
|
||||
|
||||
@ -113,13 +507,15 @@ Fixes:
|
||||
- Fixed derived C++ builds by removing `MDBX_INTERNAL_FUNC` for `mdbx_w2mb()` and `mdbx_mb2w()`.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.11.10 (the TriColor) at 2022-08-22
|
||||
|
||||
The stable bugfix release.
|
||||
|
||||
```
|
||||
14 files changed, 263 insertions(+), 252 deletions(-)
|
||||
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
|
||||
```
|
||||
|
||||
New:
|
||||
|
||||
- The C++ API has been refined to simplify support for `wchar_t` in path names.
|
||||
@ -141,8 +537,6 @@ Minors:
|
||||
- Minor clarified `iov_page()` failure case.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## v0.11.9 (Чирчик-1992) at 2022-08-02
|
||||
|
||||
@ -259,7 +653,7 @@ New:
|
||||
- Support build by MinGW' make from command line without CMake.
|
||||
- Added `mdbx::filesystem` C++ API namespace that corresponds to `std::filesystem` or `std::experimental::filesystem`.
|
||||
- Created [website](https://libmdbx.dqdkfa.ru/) for online auto-generated documentation.
|
||||
- Used `https://web.archive.org/web/20220414235959/https://github.com/erthink/` for dead (or temporarily lost) resources deleted by ~~Github~~.
|
||||
- Used `https://web.archive.org/web/https://github.com/erthink/libmdbx` for dead (or temporarily lost) resources deleted by ~~Github~~.
|
||||
- Added `--loglevel=` command-line option to the `mdbx_test` tool.
|
||||
- Added few fast smoke-like tests into CMake builds.
|
||||
|
||||
|
87
GNUmakefile
87
GNUmakefile
@ -53,8 +53,9 @@ CFLAGS_EXTRA ?=
|
||||
LD ?= ld
|
||||
|
||||
# build options
|
||||
MDBX_BUILD_OPTIONS ?=-DNDEBUG=1
|
||||
MDBX_BUILD_OPTIONS ?=-DNDEBUG=1
|
||||
MDBX_BUILD_TIMESTAMP ?=$(shell date +%Y-%m-%dT%H:%M:%S%z)
|
||||
MDBX_BUILD_CXX ?= YES
|
||||
|
||||
# probe and compose common compiler flags with variable expansion trick (seems this work two times per session for GNU Make 3.81)
|
||||
CFLAGS ?= $(strip $(eval CFLAGS := -std=gnu11 -O2 -g -Wall -Werror -Wextra -Wpedantic -ffunction-sections -fPIC -fvisibility=hidden -pthread -Wno-error=attributes $$(shell for opt in -fno-semantic-interposition -Wno-unused-command-line-argument -Wno-tautological-compare; do [ -z "$$$$($(CC) '-DMDBX_BUILD_FLAGS="probe"' $$$${opt} -c $(SRC_PROBE_C) -o /dev/null >/dev/null 2>&1 || echo failed)" ] && echo "$$$${opt} "; done)$(CFLAGS_EXTRA))$(CFLAGS))
|
||||
@ -127,6 +128,9 @@ TIP := // TIP:
|
||||
.PHONY: all help options lib libs tools clean install uninstall check_buildflags_tag tools-static
|
||||
.PHONY: install-strip install-no-strip strip libmdbx mdbx show-options lib-static lib-shared
|
||||
|
||||
boolean = $(if $(findstring $(strip $($1)),YES Yes yes y ON On on 1 true True TRUE),1,$(if $(findstring $(strip $($1)),NO No no n OFF Off off 0 false False FALSE),,$(error Wrong value `$($1)` of $1 for YES/NO option)))
|
||||
select_by = $(if $(call boolean,$(1)),$(2),$(3))
|
||||
|
||||
ifeq ("$(origin V)", "command line")
|
||||
MDBX_BUILD_VERBOSE := $(V)
|
||||
endif
|
||||
@ -134,7 +138,7 @@ ifndef MDBX_BUILD_VERBOSE
|
||||
MDBX_BUILD_VERBOSE := 0
|
||||
endif
|
||||
|
||||
ifeq ($(MDBX_BUILD_VERBOSE),1)
|
||||
ifeq ($(call boolean,MDBX_BUILD_VERBOSE),1)
|
||||
QUIET :=
|
||||
HUSH :=
|
||||
$(info $(TIP) Use `make V=0` for quiet.)
|
||||
@ -193,12 +197,12 @@ help:
|
||||
|
||||
show-options:
|
||||
@echo " MDBX_BUILD_OPTIONS = $(MDBX_BUILD_OPTIONS)"
|
||||
@echo " MDBX_BUILD_CXX = $(MDBX_BUILD_CXX)"
|
||||
@echo " MDBX_BUILD_TIMESTAMP = $(MDBX_BUILD_TIMESTAMP)"
|
||||
@echo '$(TIP) Use `make options` to listing available build options.'
|
||||
@echo " CC =`which $(CC)` | `$(CC) --version | head -1`"
|
||||
@echo " CFLAGS =$(CFLAGS)"
|
||||
@echo " CXXFLAGS =$(CXXFLAGS)"
|
||||
@echo " LDFLAGS =$(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) $(EXE_LDFLAGS)"
|
||||
@echo $(call select_by,MDBX_BUILD_CXX," CXX =`which $(CXX)` | `$(CXX) --version | head -1`"," CC =`which $(CC)` | `$(CC) --version | head -1`")
|
||||
@echo $(call select_by,MDBX_BUILD_CXX," CXXFLAGS =$(CXXFLAGS)"," CFLAGS =$(CFLAGS)")
|
||||
@echo $(call select_by,MDBX_BUILD_CXX," LDFLAGS =$(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) $(EXE_LDFLAGS)"," LDFLAGS =$(LDFLAGS) $(LIBS) $(EXE_LDFLAGS)")
|
||||
@echo '$(TIP) Use `make help` to listing available targets.'
|
||||
|
||||
options:
|
||||
@ -254,7 +258,7 @@ clean:
|
||||
config.h src/config.h src/version.c *.tar* buildflags.tag \
|
||||
mdbx_*.static mdbx_*.static-lto
|
||||
|
||||
MDBX_BUILD_FLAGS =$(strip $(MDBX_BUILD_OPTIONS) $(CXXSTD) $(CFLAGS) $(LDFLAGS) $(LIBS))
|
||||
MDBX_BUILD_FLAGS =$(strip MDBX_BUILD_CXX=$(MDBX_BUILD_CXX) $(MDBX_BUILD_OPTIONS) $(call select_by,MDBX_BUILD_CXX,$(CXXFLAGS) $(LDFLAGS) $(LIB_STDCXXFS) $(LIBS),$(CFLAGS) $(LDFLAGS) $(LIBS)))
|
||||
check_buildflags_tag:
|
||||
$(QUIET)if [ "$(MDBX_BUILD_FLAGS)" != "$$(cat buildflags.tag 2>&1)" ]; then \
|
||||
echo -n " CLEAN for build with specified flags..." && \
|
||||
@ -264,13 +268,13 @@ check_buildflags_tag:
|
||||
|
||||
buildflags.tag: check_buildflags_tag
|
||||
|
||||
lib-static libmdbx.a: mdbx-static.o mdbx++-static.o
|
||||
lib-static libmdbx.a: mdbx-static.o $(call select_by,MDBX_BUILD_CXX,mdbx++-static.o)
|
||||
@echo ' AR $@'
|
||||
$(QUIET)$(AR) rcs $@ $? $(HUSH)
|
||||
|
||||
lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o mdbx++-dylib.o
|
||||
lib-shared libmdbx.$(SO_SUFFIX): mdbx-dylib.o $(call select_by,MDBX_BUILD_CXX,mdbx++-dylib.o)
|
||||
@echo ' LD $@'
|
||||
$(QUIET)$(CXX) $(CXXFLAGS) $^ -pthread -shared $(LDFLAGS) $(LIB_STDCXXFS) $(LIBS) -o $@
|
||||
$(QUIET)$(call select_by,MDBX_BUILD_CXX,$(CXX) $(CXXFLAGS),$(CC) $(CFLAGS)) $^ -pthread -shared $(LDFLAGS) $(call select_by,MDBX_BUILD_CXX,$(LIB_STDCXXFS)) $(LIBS) -o $@
|
||||
|
||||
#> dist-cutoff-begin
|
||||
ifeq ($(wildcard mdbx.c),mdbx.c)
|
||||
@ -349,9 +353,9 @@ TEST_DB ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.d
|
||||
TEST_LOG ?= $(shell [ -d /dev/shm ] && echo /dev/shm || echo /tmp)/mdbx-test.log
|
||||
TEST_OSAL := $(shell $(uname2osal))
|
||||
TEST_ITER := $(shell $(uname2titer))
|
||||
TEST_SRC := test/osal-$(TEST_OSAL).cc $(filter-out $(wildcard test/osal-*.cc), $(wildcard test/*.cc))
|
||||
TEST_INC := $(wildcard test/*.h)
|
||||
TEST_OBJ := $(patsubst %.cc,%.o,$(TEST_SRC))
|
||||
TEST_SRC := test/osal-$(TEST_OSAL).c++ $(filter-out $(wildcard test/osal-*.c++),$(wildcard test/*.c++)) $(call select_by,MDBX_BUILD_CXX,,src/mdbx.c++)
|
||||
TEST_INC := $(wildcard test/*.h++)
|
||||
TEST_OBJ := $(patsubst %.c++,%.o,$(TEST_SRC))
|
||||
TAR ?= $(shell which gnu-tar || echo tar)
|
||||
ZIP ?= $(shell which zip || echo "echo 'Please install zip'")
|
||||
CLANG_FORMAT ?= $(shell (which clang-format-14 || which clang-format-13 || which clang-format) 2>/dev/null)
|
||||
@ -359,7 +363,7 @@ CLANG_FORMAT ?= $(shell (which clang-format-14 || which clang-format-13 || which
|
||||
reformat:
|
||||
@echo ' RUNNING clang-format...'
|
||||
$(QUIET)if [ -n "$(CLANG_FORMAT)" ]; then \
|
||||
git ls-files | grep -E '\.(c|cxx|cc|cpp|h|hxx|hpp)(\.in)?$$' | xargs -r $(CLANG_FORMAT) -i --style=file; \
|
||||
git ls-files | grep -E '\.(c|c++|h|h++)(\.in)?$$' | xargs -r $(CLANG_FORMAT) -i --style=file; \
|
||||
else \
|
||||
echo "clang-format version 13..14 not found for 'reformat'"; \
|
||||
fi
|
||||
@ -382,11 +386,11 @@ MDBX_SMOKE_EXTRA ?=
|
||||
check: DESTDIR = $(shell pwd)/@check-install
|
||||
check: test dist install
|
||||
|
||||
smoke-assertion: MDBX_BUILD_OPTIONS=-DMDBX_FORCE_ASSERTIONS=1
|
||||
smoke-assertion: MDBX_BUILD_OPTIONS:=$(strip $(MDBX_BUILD_OPTIONS) -DMDBX_FORCE_ASSERTIONS=1)
|
||||
smoke-assertion: smoke
|
||||
test-assertion: MDBX_BUILD_OPTIONS=-DMDBX_FORCE_ASSERTIONS=1
|
||||
test-assertion: MDBX_BUILD_OPTIONS:=$(strip $(MDBX_BUILD_OPTIONS) -DMDBX_FORCE_ASSERTIONS=1)
|
||||
test-assertion: smoke
|
||||
long-test-assertion: MDBX_BUILD_OPTIONS=-DMDBX_FORCE_ASSERTIONS=1
|
||||
long-test-assertion: MDBX_BUILD_OPTIONS:=$(strip $(MDBX_BUILD_OPTIONS) -DMDBX_FORCE_ASSERTIONS=1)
|
||||
long-test-assertion: smoke
|
||||
|
||||
smoke: build-test
|
||||
@ -414,7 +418,7 @@ smoke-fault: build-test
|
||||
|
||||
test: build-test
|
||||
@echo ' RUNNING `test/long_stochastic.sh --loops 2`...'
|
||||
$(QUIET)test/long_stochastic.sh --dont-check-ram-size --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
|
||||
$(QUIET)test/long_stochastic.sh --dont-check-ram-size --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG) || (cat $(TEST_LOG) && false)
|
||||
|
||||
long-test: build-test
|
||||
@echo ' RUNNING `test/long_stochastic.sh --loops 42`...'
|
||||
@ -422,12 +426,12 @@ long-test: build-test
|
||||
|
||||
test-singleprocess: build-test
|
||||
@echo ' RUNNING `test/long_stochastic.sh --single --loops 2`...'
|
||||
$(QUIET)test/long_stochastic.sh --dont-check-ram-size --single --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
|
||||
$(QUIET)test/long_stochastic.sh --dont-check-ram-size --single --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG) || (cat $(TEST_LOG) && false)
|
||||
|
||||
test-valgrind: CFLAGS_EXTRA=-Ofast -DMDBX_USE_VALGRIND
|
||||
test-valgrind: build-test
|
||||
@echo ' RUNNING `test/long_stochastic.sh --with-valgrind --loops 2`...'
|
||||
$(QUIET)test/long_stochastic.sh --with-valgrind --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG)
|
||||
$(QUIET)test/long_stochastic.sh --with-valgrind --loops 2 --db-upto-mb 256 --skip-make >$(TEST_LOG) || (cat $(TEST_LOG) && false)
|
||||
|
||||
memcheck: VALGRIND=valgrind --trace-children=yes --log-file=valgrind-%p.log --leak-check=full --track-origins=yes --error-exitcode=42 --suppressions=test/valgrind_suppress.txt
|
||||
memcheck: CFLAGS_EXTRA=-Ofast -DMDBX_USE_VALGRIND
|
||||
@ -448,7 +452,7 @@ gcc-analyzer:
|
||||
|
||||
test-ubsan:
|
||||
@echo ' RE-TEST with `-fsanitize=undefined` option...'
|
||||
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-Ofast -fsanitize=undefined -fsanitize-undefined-trap-on-error" test
|
||||
$(QUIET)$(MAKE) IOARENA=false CXXSTD=$(CXXSTD) CFLAGS_EXTRA="-DENABLE_UBSAN -Ofast -fsanitize=undefined -fsanitize-undefined-trap-on-error" test
|
||||
|
||||
test-asan:
|
||||
@echo ' RE-TEST with `-fsanitize=address` option...'
|
||||
@ -465,7 +469,7 @@ mdbx_example: mdbx.h example/example-mdbx.c libmdbx.$(SO_SUFFIX)
|
||||
build-test: all mdbx_example mdbx_test
|
||||
|
||||
define test-rule
|
||||
$(patsubst %.cc,%.o,$(1)): $(1) $(TEST_INC) $(HEADERS) $(lastword $(MAKEFILE_LIST))
|
||||
$(patsubst %.c++,%.o,$(1)): $(1) $(TEST_INC) $(HEADERS) $(lastword $(MAKEFILE_LIST))
|
||||
@echo ' CC $$@'
|
||||
$(QUIET)$$(CXX) $$(CXXFLAGS) $$(MDBX_BUILD_OPTIONS) -c $(1) -o $$@
|
||||
|
||||
@ -711,23 +715,23 @@ endif
|
||||
################################################################################
|
||||
# Cross-compilation simple test
|
||||
|
||||
CROSS_LIST = mips-linux-gnu-gcc \
|
||||
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 \
|
||||
sh4-linux-gnu-gcc mips64-linux-gnuabi64-gcc \
|
||||
hppa-linux-gnu-gcc s390x-linux-gnu-gcc
|
||||
arm-linux-gnueabihf-gcc aarch64-linux-gnu-gcc
|
||||
|
||||
## On Ubuntu Focal (20.04) with QEMU 4.2 (1:4.2-3ubuntu6.6) & GCC 9.3 (9.3.0-17ubuntu1~20.04)
|
||||
# hppa-linux-gnu-gcc - works (previously: don't supported by qemu)
|
||||
# s390x-linux-gnu-gcc - works (previously: qemu hang/abort)
|
||||
## 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)
|
||||
CROSS_LIST_NOQEMU = sparc64-linux-gnu-gcc alpha-linux-gnu-gcc
|
||||
# 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
|
||||
|
||||
cross-gcc:
|
||||
@echo ' Re-building by cross-compiler for: $(CROSS_LIST_NOQEMU) $(CROSS_LIST)'
|
||||
@echo "CORRESPONDING CROSS-COMPILERs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu g++-sparc64-linux-gnu"
|
||||
@echo "FOR INSTANCE: sudo apt install \$$(apt list 'g++-*' | grep 'g++-[a-z0-9]\+-linux-gnu/' | cut -f 1 -d / | sort -u)"
|
||||
$(QUIET)for CC in $(CROSS_LIST_NOQEMU) $(CROSS_LIST); do \
|
||||
echo "===================== $$CC"; \
|
||||
$(MAKE) IOARENA=false CXXSTD= clean && CC=$$CC CXX=$$(echo $$CC | sed 's/-gcc/-g++/') EXE_LDFLAGS=-static $(MAKE) IOARENA=false all || exit $$?; \
|
||||
@ -739,8 +743,8 @@ cross-qemu:
|
||||
@echo ' Re-building by cross-compiler and re-check by QEMU for: $(CROSS_LIST)'
|
||||
@echo "CORRESPONDING CROSS-COMPILERs AND QEMUs ARE REQUIRED."
|
||||
@echo "FOR INSTANCE: "
|
||||
@echo " 1) apt install g++-aarch64-linux-gnu g++-alpha-linux-gnu g++-arm-linux-gnueabihf g++-hppa-linux-gnu g++-mips-linux-gnu g++-mips64-linux-gnuabi64 g++-powerpc-linux-gnu g++-powerpc64-linux-gnu g++-s390x-linux-gnu g++-sh4-linux-gnu g++-sparc64-linux-gnu"
|
||||
@echo " 2) apt install binfmt-support qemu-user-static qemu-user qemu-system-arm qemu-system-mips qemu-system-misc qemu-system-ppc qemu-system-sparc"
|
||||
@echo " 1) sudo apt install \$$(apt list 'g++-*' | grep 'g++-[a-z0-9]\+-linux-gnu/' | cut -f 1 -d / | sort -u)"
|
||||
@echo " 2) sudo apt install binfmt-support qemu-user-static qemu-user \$$(apt list 'qemu-system-*' | grep 'qemu-system-[a-z0-9]\+/' | cut -f 1 -d / | sort -u)"
|
||||
$(QUIET)for CC in $(CROSS_LIST); do \
|
||||
echo "===================== $$CC + qemu"; \
|
||||
$(MAKE) IOARENA=false CXXSTD= clean && \
|
||||
@ -784,7 +788,7 @@ IOARENA := $(shell \
|
||||
(test -x ../ioarena/@BUILD/src/ioarena && echo ../ioarena/@BUILD/src/ioarena) || \
|
||||
(test -x ../../@BUILD/src/ioarena && echo ../../@BUILD/src/ioarena) || \
|
||||
(test -x ../../src/ioarena && echo ../../src/ioarena) || which ioarena 2>&- || \
|
||||
(echo false && echo '$(TIP) Clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2))
|
||||
(echo false && echo '$(TIP) Clone and build the https://abf.io/erthink/ioarena.git within a neighbouring directory for availability of benchmarking.' >&2))
|
||||
endif
|
||||
NN ?= 25000000
|
||||
BENCH_CRUD_MODE ?= nosync
|
||||
@ -798,7 +802,7 @@ re-bench: bench-clean bench
|
||||
ifeq ($(or $(IOARENA),false),false)
|
||||
bench bench-quartet bench-triplet bench-couple:
|
||||
$(QUIET)echo 'The `ioarena` benchmark is required.' >&2 && \
|
||||
echo 'Please clone and build the https://github.com/pmwkaa/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \
|
||||
echo 'Please clone and build the https://abf.io/erthink/ioarena.git within a neighbouring `ioarena` directory.' >&2 && \
|
||||
false
|
||||
|
||||
else
|
||||
@ -809,15 +813,20 @@ define bench-rule
|
||||
bench-$(1)_$(2).txt: $(3) $(IOARENA) $(lastword $(MAKEFILE_LIST))
|
||||
@echo ' RUNNING ioarena for $1/$2...'
|
||||
$(QUIET)(export LD_LIBRARY_PATH="./:$$$${LD_LIBRARY_PATH}"; \
|
||||
ldd $(IOARENA) && \
|
||||
ldd $(IOARENA) | grep -i $(1) && \
|
||||
$(IOARENA) -D $(1) -B batch -m $(BENCH_CRUD_MODE) -n $(2) \
|
||||
| tee $$@ | grep throughput | sed 's/throughput/batch×N/' && \
|
||||
$(IOARENA) -D $(1) -B crud -m $(BENCH_CRUD_MODE) -n $(2) \
|
||||
| tee $$@ | grep throughput && \
|
||||
| tee -a $$@ | grep throughput | sed 's/throughput/ crud/' && \
|
||||
$(IOARENA) -D $(1) -B iterate,get,iterate,get,iterate -m $(BENCH_CRUD_MODE) -r 4 -n $(2) \
|
||||
| tee -a $$@ | grep throughput \
|
||||
) || mv -f $$@ $$@.error
|
||||
| tee -a $$@ | grep throughput | sed '0,/throughput/{s/throughput/iterate/};s/throughput/ get/' && \
|
||||
$(IOARENA) -D $(1) -B delete -m $(BENCH_CRUD_MODE) -n $(2) \
|
||||
| tee -a $$@ | grep throughput | sed 's/throughput/ delete/' && \
|
||||
true) || mv -f $$@ $$@.error
|
||||
|
||||
endef
|
||||
|
||||
|
||||
$(eval $(call bench-rule,mdbx,$(NN),libmdbx.$(SO_SUFFIX)))
|
||||
|
||||
$(eval $(call bench-rule,sophia,$(NN)))
|
||||
|
@ -277,7 +277,7 @@ the user's point of view.
|
||||
> and up to 30% faster when _libmdbx_ compiled with specific build options
|
||||
> which downgrades several runtime checks to be match with LMDB behaviour.
|
||||
>
|
||||
> These and other results could be easily reproduced with [ioArena](https://github.com/pmwkaa/ioarena) just by `make bench-quartet` command,
|
||||
> These and other results could be easily reproduced with [ioArena](https://abf.io/erthink/ioarena.git) just by `make bench-quartet` command,
|
||||
> including comparisons with [RockDB](https://en.wikipedia.org/wiki/RocksDB)
|
||||
> and [WiredTiger](https://en.wikipedia.org/wiki/WiredTiger).
|
||||
|
||||
@ -382,7 +382,7 @@ named mutexes are used.
|
||||
Historically, _libmdbx_ is a deeply revised and extended descendant of the
|
||||
[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||
At first the development was carried out within the
|
||||
[ReOpenLDAP](https://web.archive.org/web/20220414235959/https://github.com/erthink/ReOpenLDAP) project. About a
|
||||
[ReOpenLDAP](https://web.archive.org/web/https://github.com/erthink/ReOpenLDAP) project. About a
|
||||
year later _libmdbx_ was separated into a standalone project, which was
|
||||
[presented at Highload++ 2015
|
||||
conference](http://www.highload.ru/2015/abstracts/1831.html).
|
||||
@ -659,7 +659,7 @@ Bindings
|
||||
Performance comparison
|
||||
======================
|
||||
|
||||
All benchmarks were done in 2015 by [IOArena](https://github.com/pmwkaa/ioarena)
|
||||
All benchmarks were done in 2015 by [IOArena](https://abf.io/erthink/ioarena.git)
|
||||
and multiple [scripts](https://github.com/pmwkaa/ioarena/tree/HL%2B%2B2015)
|
||||
runs on Lenovo Carbon-2 laptop, i7-4600U 2.1 GHz (2 physical cores, 4 HyperThreading cores), 8 Gb RAM,
|
||||
SSD SAMSUNG MZNTD512HAGL-000L1 (DXT23L0Q) 512 Gb.
|
||||
|
12
TODO.md
12
TODO.md
@ -11,15 +11,19 @@ For the same reason ~~Github~~ is blacklisted forever.
|
||||
|
||||
So currently most of the links are broken due to noted malicious ~~Github~~ sabotage.
|
||||
|
||||
- [Engage an "overlapped I/O" on Windows](https://libmdbx.dqdkfa.ru/dead-github/issues/224).
|
||||
- [Simple careful mode for working with corrupted DB](https://libmdbx.dqdkfa.ru/dead-github/issues/223).
|
||||
- [Move most of `mdbx_chk` functional to the library API](https://libmdbx.dqdkfa.ru/dead-github/issues/204).
|
||||
- [Replace SRW-lock on Windows to allow shrink DB with `MDBX_NOTLS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/210).
|
||||
- [More flexible support of asynchronous runtime/framework(s)](https://libmdbx.dqdkfa.ru/dead-github/issues/200).
|
||||
- [Migration guide from LMDB to MDBX](https://libmdbx.dqdkfa.ru/dead-github/issues/199).
|
||||
- [Get rid of dirty-pages list in MDBX_WRITEMAP mode](https://libmdbx.dqdkfa.ru/dead-github/issues/193).
|
||||
- [Large/Overflow pages accounting for dirty-room](https://libmdbx.dqdkfa.ru/dead-github/issues/192).
|
||||
- [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).
|
||||
- [Engage new terminology](https://libmdbx.dqdkfa.ru/dead-github/issues/137).
|
||||
- Packages for [Astra Linux](https://astralinux.ru/), [ALT Linux](https://www.altlinux.org/), [ROSA Linux](https://www.rosalinux.ru/), etc.
|
||||
|
||||
Done
|
||||
----
|
||||
|
||||
- [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).
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
@ -348,6 +348,8 @@ endif()
|
||||
|
||||
if(MSVC)
|
||||
check_compiler_flag("/WX" CC_HAS_WERROR)
|
||||
check_compiler_flag("/fsanitize=address" CC_HAS_ASAN)
|
||||
check_compiler_flag("/fsanitize=undefined" CC_HAS_UBSAN)
|
||||
else()
|
||||
#
|
||||
# GCC started to warn for unused result starting from 4.2, and
|
||||
@ -839,19 +841,26 @@ macro(setup_compile_flags)
|
||||
endif()
|
||||
|
||||
if(ENABLE_ASAN)
|
||||
add_compile_flags("C;CXX" "-fsanitize=address")
|
||||
if(NOT MSVC)
|
||||
add_compile_flags("C;CXX" "-fsanitize=address")
|
||||
else()
|
||||
add_compile_flags("C;CXX" "/fsanitize=address")
|
||||
endif()
|
||||
add_definitions(-DASAN_ENABLED=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_UBSAN)
|
||||
add_compile_flags("C;CXX" "-fsanitize=undefined" "-fsanitize-undefined-trap-on-error")
|
||||
if(NOT MSVC)
|
||||
add_compile_flags("C;CXX" "-fsanitize=undefined" "-fsanitize-undefined-trap-on-error")
|
||||
else()
|
||||
add_compile_flags("C;CXX" "/fsanitize=undefined")
|
||||
endif()
|
||||
add_definitions(-DUBSAN_ENABLED=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_GCOV)
|
||||
if(NOT HAVE_GCOV)
|
||||
message(FATAL_ERROR
|
||||
"ENABLE_GCOV option requested but gcov library is not found")
|
||||
message(FATAL_ERROR "ENABLE_GCOV option requested but gcov library is not found")
|
||||
endif()
|
||||
|
||||
add_compile_flags("C;CXX" "-fprofile-arcs" "-ftest-coverage")
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Copyright (c) 2012-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
## Copyright (c) 2012-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
##
|
||||
## Licensed under the Apache License, Version 2.0 (the "License");
|
||||
## you may not use this file except in compliance with the License.
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2017 Ilya Shipitsin <chipitsine@gmail.com>.
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2012-2015 Howard Chu, Symas Corp.
|
||||
* Copyright 2015,2016 Peter-Service R&D LLC.
|
||||
* All rights reserved.
|
||||
|
663
mdbx.h
663
mdbx.h
@ -25,7 +25,7 @@ _The Future will (be) [Positive](https://www.ptsecurity.com). Всё будет
|
||||
|
||||
\section copyright LICENSE & COPYRIGHT
|
||||
|
||||
\authors Copyright (c) 2015-2022, Leonid Yuriev <leo@yuriev.ru>
|
||||
\authors Copyright (c) 2015-2023, Leonid Yuriev <leo@yuriev.ru>
|
||||
and other _libmdbx_ authors: please see [AUTHORS](./AUTHORS) file.
|
||||
|
||||
\copyright Redistribution and use in source and binary forms, with or without
|
||||
@ -77,10 +77,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#if defined(__riscv) || defined(__riscv__) || defined(__RISCV) || \
|
||||
defined(__RISCV__)
|
||||
#warning The RISC-V architecture is intentionally insecure by design. \
|
||||
#warning "The RISC-V architecture is intentionally insecure by design. \
|
||||
Please delete this admonition at your own risk, \
|
||||
if you make such decision informed and consciously. \
|
||||
Refer to https://clck.ru/32d9xH for more information.
|
||||
Refer to https://clck.ru/32d9xH for more information."
|
||||
#endif /* RISC-V */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -634,9 +634,9 @@ typedef mode_t mdbx_mode_t;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MDBX version 0.11.x */
|
||||
/* MDBX version 0.12.x */
|
||||
#define MDBX_VERSION_MAJOR 0
|
||||
#define MDBX_VERSION_MINOR 11
|
||||
#define MDBX_VERSION_MINOR 12
|
||||
|
||||
#ifndef LIBMDBX_API
|
||||
#if defined(LIBMDBX_EXPORTS)
|
||||
@ -835,18 +835,48 @@ enum MDBX_constants {
|
||||
#ifndef MDBX_LOCKNAME
|
||||
/** \brief The name of the lock file in the environment
|
||||
* without using \ref MDBX_NOSUBDIR */
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
#define MDBX_LOCKNAME "/mdbx.lck"
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_LOCKNAME_W L"\\mdbx.lck"
|
||||
#define MDBX_LOCKNAME_A "\\mdbx.lck"
|
||||
#ifdef UNICODE
|
||||
#define MDBX_LOCKNAME MDBX_LOCKNAME_W
|
||||
#else
|
||||
#define MDBX_LOCKNAME MDBX_LOCKNAME_A
|
||||
#endif /* UNICODE */
|
||||
#endif /* Windows */
|
||||
#endif /* MDBX_LOCKNAME */
|
||||
#ifndef MDBX_DATANAME
|
||||
/** \brief The name of the data file in the environment
|
||||
* without using \ref MDBX_NOSUBDIR */
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
#define MDBX_DATANAME "/mdbx.dat"
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_DATANAME_W L"\\mdbx.dat"
|
||||
#define MDBX_DATANAME_A "\\mdbx.dat"
|
||||
#ifdef UNICODE
|
||||
#define MDBX_DATANAME MDBX_DATANAME_W
|
||||
#else
|
||||
#define MDBX_DATANAME MDBX_DATANAME_A
|
||||
#endif /* UNICODE */
|
||||
#endif /* Windows */
|
||||
#endif /* MDBX_DATANAME */
|
||||
|
||||
#ifndef MDBX_LOCK_SUFFIX
|
||||
/** \brief The suffix of the lock file when \ref MDBX_NOSUBDIR is used */
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
#define MDBX_LOCK_SUFFIX "-lck"
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_LOCK_SUFFIX_W L"-lck"
|
||||
#define MDBX_LOCK_SUFFIX_A "-lck"
|
||||
#ifdef UNICODE
|
||||
#define MDBX_LOCK_SUFFIX MDBX_LOCK_SUFFIX_W
|
||||
#else
|
||||
#define MDBX_LOCK_SUFFIX MDBX_LOCK_SUFFIX_A
|
||||
#endif /* UNICODE */
|
||||
#endif /* Windows */
|
||||
#endif /* MDBX_LOCK_SUFFIX */
|
||||
|
||||
/* DEBUG & LOGGING ************************************************************/
|
||||
|
||||
@ -1028,12 +1058,15 @@ LIBMDBX_API const char *mdbx_dump_val(const MDBX_val *key, char *const buf,
|
||||
const size_t bufsize);
|
||||
|
||||
/** \brief Panics with message and causes abnormal process termination. */
|
||||
LIBMDBX_API void mdbx_panic(const char *fmt, ...) MDBX_PRINTF_ARGS(1, 2);
|
||||
MDBX_NORETURN LIBMDBX_API void mdbx_panic(const char *fmt, ...)
|
||||
MDBX_PRINTF_ARGS(1, 2);
|
||||
|
||||
/** \brief Panics with asserton failed message and causes abnormal process
|
||||
* termination. */
|
||||
LIBMDBX_API void mdbx_assert_fail(const MDBX_env *env, const char *msg,
|
||||
const char *func, unsigned line);
|
||||
MDBX_NORETURN LIBMDBX_API void mdbx_assert_fail(const MDBX_env *env,
|
||||
const char *msg,
|
||||
const char *func,
|
||||
unsigned line);
|
||||
/** end of c_debug @} */
|
||||
|
||||
/** \brief Environment flags
|
||||
@ -1043,6 +1076,13 @@ LIBMDBX_API void mdbx_assert_fail(const MDBX_env *env, const char *msg,
|
||||
enum MDBX_env_flags_t {
|
||||
MDBX_ENV_DEFAULTS = 0,
|
||||
|
||||
/** Extra validation of DB structure and pages content.
|
||||
*
|
||||
* The `MDBX_VALIDATION` enabled the simple safe/careful mode for working
|
||||
* with damaged or untrusted DB. However, a notable performance
|
||||
* degradation should be expected. */
|
||||
MDBX_VALIDATION = UINT32_C(0x00002000),
|
||||
|
||||
/** No environment directory.
|
||||
*
|
||||
* By default, MDBX creates its environment in a directory whose pathname is
|
||||
@ -1115,8 +1155,8 @@ enum MDBX_env_flags_t {
|
||||
* while opening the database/environment which is already used by another
|
||||
* process(es) with unknown mode/flags. In such cases, if there is a
|
||||
* difference in the specified flags (\ref MDBX_NOMETASYNC,
|
||||
* \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC, \ref MDBX_LIFORECLAIM,
|
||||
* \ref MDBX_COALESCE and \ref MDBX_NORDAHEAD), instead of returning an error,
|
||||
* \ref MDBX_SAFE_NOSYNC, \ref MDBX_UTTERLY_NOSYNC, \ref MDBX_LIFORECLAIM
|
||||
* and \ref MDBX_NORDAHEAD), instead of returning an error,
|
||||
* the database will be opened in a compatibility with the already used mode.
|
||||
*
|
||||
* `MDBX_ACCEDE` has no effect if the current process is the only one either
|
||||
@ -1223,6 +1263,7 @@ enum MDBX_env_flags_t {
|
||||
MDBX_NOMEMINIT = UINT32_C(0x1000000),
|
||||
|
||||
/** Aims to coalesce a Garbage Collection items.
|
||||
* \note Always enabled since v0.12
|
||||
*
|
||||
* With `MDBX_COALESCE` flag MDBX will aims to coalesce items while recycling
|
||||
* a Garbage Collection. Technically, when possible short lists of pages
|
||||
@ -1593,8 +1634,7 @@ enum MDBX_put_flags_t {
|
||||
MDBX_NOOVERWRITE = UINT32_C(0x10),
|
||||
|
||||
/** Has effect only for \ref MDBX_DUPSORT databases.
|
||||
* For upsertion: don't write if the key-value pair already exist.
|
||||
* For deletion: remove all values for key. */
|
||||
* For upsertion: don't write if the key-value pair already exist. */
|
||||
MDBX_NODUPDATA = UINT32_C(0x20),
|
||||
|
||||
/** For upsertion: overwrite the current key/data pair.
|
||||
@ -1886,6 +1926,15 @@ enum MDBX_error_t {
|
||||
/** Overlapping read and write transactions for the current thread */
|
||||
MDBX_TXN_OVERLAPPING = -30415,
|
||||
|
||||
/** Внутренняя ошибка возвращаемая в случае нехватки запаса свободных страниц
|
||||
* при обновлении GC. Используется как вспомогательное средство для отладки.
|
||||
* \note С точки зрения пользователя семантически
|
||||
* равнозначна \ref MDBX_PROBLEM. */
|
||||
MDBX_BACKLOG_DEPLETED = -30414,
|
||||
|
||||
/** Alternative/Duplicate LCK-file is exists and should be removed manually */
|
||||
MDBX_DUPLICATED_CLK = -30413,
|
||||
|
||||
/* The last of MDBX-added error codes */
|
||||
MDBX_LAST_ADDED_ERRCODE = MDBX_TXN_OVERLAPPING,
|
||||
|
||||
@ -2011,7 +2060,9 @@ LIBMDBX_API const char *mdbx_strerror_r_ANSI2OEM(int errnum, char *buf,
|
||||
* \returns a non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_env_create(MDBX_env **penv);
|
||||
|
||||
/** \brief MDBX environment options. */
|
||||
/** \brief MDBX environment extra runtime options.
|
||||
* \ingroup c_settings
|
||||
* \see mdbx_env_set_option() \see mdbx_env_get_option() */
|
||||
enum MDBX_option_t {
|
||||
/** \brief Controls the maximum number of named databases for the environment.
|
||||
*
|
||||
@ -2180,13 +2231,46 @@ enum MDBX_option_t {
|
||||
* to 50% (half empty) which corresponds to the range from 8192 and to 32768
|
||||
* in units respectively. */
|
||||
MDBX_opt_merge_threshold_16dot16_percent,
|
||||
|
||||
/** \brief Controls the choosing between use write-through disk writes and
|
||||
* usual ones with followed flush by the `fdatasync()` syscall.
|
||||
* \details Depending on the operating system, storage subsystem
|
||||
* characteristics and the use case, higher performance can be achieved by
|
||||
* either using write-through or a serie of usual/lazy writes followed by
|
||||
* the flush-to-disk.
|
||||
*
|
||||
* Basically for N chunks the latency/cost of write-through is:
|
||||
* latency = N * (emit + round-trip-to-storage + storage-execution);
|
||||
* And for serie of lazy writes with flush is:
|
||||
* latency = N * (emit + storage-execution) + flush + round-trip-to-storage.
|
||||
*
|
||||
* So, for large N and/or noteable round-trip-to-storage the write+flush
|
||||
* approach is win. But for small N and/or near-zero NVMe-like latency
|
||||
* the write-through is better.
|
||||
*
|
||||
* To solve this issue libmdbx provide `MDBX_opt_writethrough_threshold`:
|
||||
* - when N described above less or equal specified threshold,
|
||||
* a write-through approach will be used;
|
||||
* - otherwise, when N great than specified threshold,
|
||||
* a write-and-flush approach will be used.
|
||||
*
|
||||
* \note MDBX_opt_writethrough_threshold affects only \ref MDBX_SYNC_DURABLE
|
||||
* mode without \ref MDBX_WRITEMAP, and not supported on Windows.
|
||||
* On Windows a write-through is used always but \ref MDBX_NOMETASYNC could
|
||||
* be used for switching to write-and-flush. */
|
||||
MDBX_opt_writethrough_threshold,
|
||||
|
||||
/** \brief Controls prevention of page-faults of reclaimed and allocated pages
|
||||
* in the \ref MDBX_WRITEMAP mode by clearing ones through file handle before
|
||||
* touching. */
|
||||
MDBX_opt_prefault_write_enable,
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
/** \ingroup c_settings */
|
||||
typedef enum MDBX_option_t MDBX_option_t;
|
||||
#endif
|
||||
|
||||
/** \brief Sets the value of a runtime options for an environment.
|
||||
/** \brief Sets the value of a extra runtime options for an environment.
|
||||
* \ingroup c_settings
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
@ -2199,7 +2283,7 @@ typedef enum MDBX_option_t MDBX_option_t;
|
||||
LIBMDBX_API int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option,
|
||||
uint64_t value);
|
||||
|
||||
/** \brief Gets the value of runtime options from an environment.
|
||||
/** \brief Gets the value of extra runtime options from an environment.
|
||||
* \ingroup c_settings
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
@ -2220,6 +2304,8 @@ LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env,
|
||||
* be called later to discard the \ref MDBX_env handle and release associated
|
||||
* resources.
|
||||
*
|
||||
* \note On Windows the \ref mdbx_env_openW() is recommended to use.
|
||||
*
|
||||
* \param [in] env An environment handle returned
|
||||
* by \ref mdbx_env_create()
|
||||
*
|
||||
@ -2287,6 +2373,14 @@ LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env,
|
||||
LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname,
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** \copydoc mdbx_env_open()
|
||||
* \note Available only on Windows.
|
||||
* \see mdbx_env_open() */
|
||||
LIBMDBX_API int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname,
|
||||
MDBX_env_flags_t flags, mdbx_mode_t mode);
|
||||
#endif /* Windows */
|
||||
|
||||
/** \brief Deletion modes for \ref mdbx_env_delete().
|
||||
* \ingroup c_extra
|
||||
* \see mdbx_env_delete() */
|
||||
@ -2313,6 +2407,8 @@ typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t;
|
||||
/** \brief Delete the environment's files in a proper and multiprocess-safe way.
|
||||
* \ingroup c_extra
|
||||
*
|
||||
* \note On Windows the \ref mdbx_env_deleteW() is recommended to use.
|
||||
*
|
||||
* \param [in] pathname The pathname for the database or the directory in which
|
||||
* the database files reside.
|
||||
*
|
||||
@ -2330,6 +2426,14 @@ typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t;
|
||||
LIBMDBX_API int mdbx_env_delete(const char *pathname,
|
||||
MDBX_env_delete_mode_t mode);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** \copydoc mdbx_env_delete()
|
||||
* \note Available only on Windows.
|
||||
* \see mdbx_env_delete() */
|
||||
LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathname,
|
||||
MDBX_env_delete_mode_t mode);
|
||||
#endif /* Windows */
|
||||
|
||||
/** \brief Copy an MDBX environment to the specified path, with options.
|
||||
* \ingroup c_extra
|
||||
*
|
||||
@ -2339,6 +2443,8 @@ LIBMDBX_API int mdbx_env_delete(const char *pathname,
|
||||
* parallel with write transactions, because it employs a read-only
|
||||
* transaction. See long-lived transactions under \ref restrictions section.
|
||||
*
|
||||
* \note On Windows the \ref mdbx_env_copyW() is recommended to use.
|
||||
*
|
||||
* \param [in] env An environment handle returned by mdbx_env_create().
|
||||
* It must have already been opened successfully.
|
||||
* \param [in] dest The pathname of a file in which the copy will reside.
|
||||
@ -2364,6 +2470,14 @@ LIBMDBX_API int mdbx_env_delete(const char *pathname,
|
||||
LIBMDBX_API int mdbx_env_copy(MDBX_env *env, const char *dest,
|
||||
MDBX_copy_flags_t flags);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** \copydoc mdbx_env_copy()
|
||||
* \note Available only on Windows.
|
||||
* \see mdbx_env_copy() */
|
||||
LIBMDBX_API int mdbx_env_copyW(MDBX_env *env, const wchar_t *dest,
|
||||
MDBX_copy_flags_t flags);
|
||||
#endif /* Windows */
|
||||
|
||||
/** \brief Copy an environment to the specified file descriptor, with
|
||||
* options.
|
||||
* \ingroup c_extra
|
||||
@ -2482,7 +2596,9 @@ struct MDBX_envinfo {
|
||||
uint64_t mi_unsync_volume;
|
||||
/** Current auto-sync threshold, see \ref mdbx_env_set_syncbytes(). */
|
||||
uint64_t mi_autosync_threshold;
|
||||
/** Time since the last steady sync in 1/65536 of second */
|
||||
/** Time since entering to a "dirty" out-of-sync state in units of 1/65536 of
|
||||
* second. In other words, this is the time since the last non-steady commit
|
||||
* or zero if it was steady. */
|
||||
uint32_t mi_since_sync_seconds16dot16;
|
||||
/** Current auto-sync period in 1/65536 of second,
|
||||
* see \ref mdbx_env_set_syncperiod(). */
|
||||
@ -2500,16 +2616,22 @@ struct MDBX_envinfo {
|
||||
* first process opened the database after everyone had previously closed it).
|
||||
*/
|
||||
struct {
|
||||
uint64_t newly; /**< Quantity of a new pages added */
|
||||
uint64_t cow; /**< Quantity of pages copied for update */
|
||||
uint64_t clone; /**< Quantity of parent's dirty pages clones
|
||||
for nested transactions */
|
||||
uint64_t split; /**< Page splits */
|
||||
uint64_t merge; /**< Page merges */
|
||||
uint64_t spill; /**< Quantity of spilled dirty pages */
|
||||
uint64_t unspill; /**< Quantity of unspilled/reloaded pages */
|
||||
uint64_t wops; /**< Number of explicit write operations (not a pages)
|
||||
to a disk */
|
||||
uint64_t newly; /**< Quantity of a new pages added */
|
||||
uint64_t cow; /**< Quantity of pages copied for update */
|
||||
uint64_t clone; /**< Quantity of parent's dirty pages clones
|
||||
for nested transactions */
|
||||
uint64_t split; /**< Page splits */
|
||||
uint64_t merge; /**< Page merges */
|
||||
uint64_t spill; /**< Quantity of spilled dirty pages */
|
||||
uint64_t unspill; /**< Quantity of unspilled/reloaded pages */
|
||||
uint64_t wops; /**< Number of explicit write operations (not a pages)
|
||||
to a disk */
|
||||
uint64_t prefault; /**< Number of prefault write operations (not a pages) */
|
||||
uint64_t mincore; /**< Number of mincore() calls */
|
||||
uint64_t
|
||||
msync; /**< Number of explicit msync-to-disk operations (not a pages) */
|
||||
uint64_t
|
||||
fsync; /**< Number of explicit fsync-to-disk operations (not a pages) */
|
||||
} mi_pgop_stat;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
@ -2766,6 +2888,94 @@ LIBMDBX_INLINE_API(int, mdbx_env_close, (MDBX_env * env)) {
|
||||
return mdbx_env_close_ex(env, false);
|
||||
}
|
||||
|
||||
/** \brief Warming up options
|
||||
* \ingroup c_settings
|
||||
* \anchor warmup_flags
|
||||
* \see mdbx_env_warmup() */
|
||||
enum MDBX_warmup_flags_t {
|
||||
/** By default \ref mdbx_env_warmup() just ask OS kernel to asynchronously
|
||||
* prefetch database pages. */
|
||||
MDBX_warmup_default = 0,
|
||||
|
||||
/** Peeking all pages of allocated portion of the database
|
||||
* to force ones to be loaded into memory. However, the pages are just peeks
|
||||
* sequentially, so unused pages that are in GC will be loaded in the same
|
||||
* way as those that contain payload. */
|
||||
MDBX_warmup_force = 1,
|
||||
|
||||
/** Using system calls to peeks pages instead of directly accessing ones,
|
||||
* which at the cost of additional overhead avoids killing the current
|
||||
* process by OOM-killer in a lack of memory condition.
|
||||
* \note Has effect only on POSIX (non-Windows) systems with conjunction
|
||||
* to \ref MDBX_warmup_force option. */
|
||||
MDBX_warmup_oomsafe = 2,
|
||||
|
||||
/** Try to lock database pages in memory by `mlock()` on POSIX-systems
|
||||
* or `VirtualLock()` on Windows. Please refer to description of these
|
||||
* functions for reasonability of such locking and the information of
|
||||
* effects, including the system as a whole.
|
||||
*
|
||||
* Such locking in memory requires that the corresponding resource limits
|
||||
* (e.g. `RLIMIT_RSS`, `RLIMIT_MEMLOCK` or process working set size)
|
||||
* and the availability of system RAM are sufficiently high.
|
||||
*
|
||||
* On successful, all currently allocated pages, both unused in GC and
|
||||
* containing payload, will be locked in memory until the environment closes,
|
||||
* or explicitly unblocked by using \ref MDBX_warmup_release, or the
|
||||
* database geomenry will changed, including its auto-shrinking. */
|
||||
MDBX_warmup_lock = 4,
|
||||
|
||||
/** Alters corresponding current resource limits to be enough for lock pages
|
||||
* by \ref MDBX_warmup_lock. However, this option should be used in simpler
|
||||
* applications since takes into account only current size of this environment
|
||||
* disregarding all other factors. For real-world database application you
|
||||
* will need full-fledged management of resources and their limits with
|
||||
* respective engineering. */
|
||||
MDBX_warmup_touchlimit = 8,
|
||||
|
||||
/** Release the lock that was performed before by \ref MDBX_warmup_lock. */
|
||||
MDBX_warmup_release = 16,
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
typedef enum MDBX_warmup_flags_t MDBX_warmup_flags_t;
|
||||
#else
|
||||
DEFINE_ENUM_FLAG_OPERATORS(MDBX_warmup_flags_t)
|
||||
#endif
|
||||
|
||||
/** \brief Warms up the database by loading pages into memory, optionally lock
|
||||
* ones. \ingroup c_settings
|
||||
*
|
||||
* Depending on the specified flags, notifies OS kernel about following access,
|
||||
* force loads the database pages, including locks ones in memory or releases
|
||||
* such a lock. However, the function does not analyze the b-tree nor the GC.
|
||||
* Therefore an unused pages that are in GC handled (i.e. will be loaded) in
|
||||
* the same way as those that contain payload.
|
||||
*
|
||||
* At least one of `env` or `txn` argument must be non-null.
|
||||
*
|
||||
* \param [in] env An environment handle returned
|
||||
* by \ref mdbx_env_create().
|
||||
* \param [in] txn A transaction handle returned
|
||||
* by \ref mdbx_txn_begin().
|
||||
* \param [in] flags The \ref warmup_flags, bitwise OR'ed together.
|
||||
*
|
||||
* \param [in] timeout_seconds_16dot16 Optional timeout which checking only
|
||||
* during explicitly peeking database pages
|
||||
* for loading ones if the \ref MDBX_warmup_force
|
||||
* option was specified.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success.
|
||||
* Some possible errors are:
|
||||
*
|
||||
* \retval MDBX_ENOSYS The system does not support requested
|
||||
* operation(s).
|
||||
*
|
||||
* \retval MDBX_RESULT_TRUE The specified timeout is reached during load
|
||||
* data into memory. */
|
||||
LIBMDBX_API int mdbx_env_warmup(const MDBX_env *env, const MDBX_txn *txn,
|
||||
MDBX_warmup_flags_t flags,
|
||||
unsigned timeout_seconds_16dot16);
|
||||
|
||||
/** \brief Set environment flags.
|
||||
* \ingroup c_settings
|
||||
*
|
||||
@ -2804,6 +3014,8 @@ LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags);
|
||||
/** \brief Return the path that was used in mdbx_env_open().
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
* \note On Windows the \ref mdbx_env_get_pathW() is recommended to use.
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create()
|
||||
* \param [out] dest Address of a string pointer to contain the path.
|
||||
* This is the actual string in the environment, not a
|
||||
@ -2814,6 +3026,13 @@ LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags);
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** \copydoc mdbx_env_get_path()
|
||||
* \note Available only on Windows.
|
||||
* \see mdbx_env_get_path() */
|
||||
LIBMDBX_API int mdbx_env_get_pathW(const MDBX_env *env, const wchar_t **dest);
|
||||
#endif /* Windows */
|
||||
|
||||
/** \brief Return the file descriptor for the given environment.
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
@ -3093,6 +3312,21 @@ mdbx_limits_keysize_max(intptr_t pagesize, MDBX_db_flags_t flags);
|
||||
MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
|
||||
mdbx_limits_valsize_max(intptr_t pagesize, MDBX_db_flags_t flags);
|
||||
|
||||
/** \brief Returns maximal size of key-value pair to fit in a single page with
|
||||
* the given size and database flags, or -1 if pagesize is invalid.
|
||||
* \ingroup c_statinfo
|
||||
* \see db_flags */
|
||||
MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
|
||||
mdbx_limits_pairsize4page_max(intptr_t pagesize, MDBX_db_flags_t flags);
|
||||
|
||||
/** \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
* single overflow/large-page with the given page size and database flags,
|
||||
* or -1 if pagesize is invalid.
|
||||
* \ingroup c_statinfo
|
||||
* \see db_flags */
|
||||
MDBX_NOTHROW_CONST_FUNCTION LIBMDBX_API intptr_t
|
||||
mdbx_limits_valsize4page_max(intptr_t pagesize, MDBX_db_flags_t flags);
|
||||
|
||||
/** \brief Returns maximal write transaction size (i.e. limit for summary volume
|
||||
* of dirty pages) in bytes for given page size, or -1 if pagesize is invalid.
|
||||
* \ingroup c_statinfo */
|
||||
@ -3248,6 +3482,32 @@ mdbx_env_get_maxvalsize_ex(const MDBX_env *env, MDBX_db_flags_t flags);
|
||||
MDBX_DEPRECATED MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
|
||||
mdbx_env_get_maxkeysize(const MDBX_env *env);
|
||||
|
||||
/** \brief Returns maximal size of key-value pair to fit in a single page
|
||||
* for specified database flags.
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
* \param [in] flags Database options (\ref MDBX_DUPSORT, \ref MDBX_INTEGERKEY
|
||||
* and so on). \see db_flags
|
||||
*
|
||||
* \returns The maximum size of a data can write,
|
||||
* or -1 if something is wrong. */
|
||||
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
|
||||
mdbx_env_get_pairsize4page_max(const MDBX_env *env, MDBX_db_flags_t flags);
|
||||
|
||||
/** \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
* single overflow/large-page for specified database flags.
|
||||
* \ingroup c_statinfo
|
||||
*
|
||||
* \param [in] env An environment handle returned by \ref mdbx_env_create().
|
||||
* \param [in] flags Database options (\ref MDBX_DUPSORT, \ref MDBX_INTEGERKEY
|
||||
* and so on). \see db_flags
|
||||
*
|
||||
* \returns The maximum size of a data can write,
|
||||
* or -1 if something is wrong. */
|
||||
MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int
|
||||
mdbx_env_get_valsize4page_max(const MDBX_env *env, MDBX_db_flags_t flags);
|
||||
|
||||
/** \brief Sets application information (a context pointer) associated with
|
||||
* the environment.
|
||||
* \see mdbx_env_get_userctx()
|
||||
@ -3526,8 +3786,8 @@ struct MDBX_commit_latency {
|
||||
/** \brief Duration of preparation (commit child transactions, update
|
||||
* sub-databases records and cursors destroying). */
|
||||
uint32_t preparation;
|
||||
/** \brief Duration of GC/freeDB handling & updation. */
|
||||
uint32_t gc;
|
||||
/** \brief Duration of GC update by wall clock. */
|
||||
uint32_t gc_wallclock;
|
||||
/** \brief Duration of internal audit if enabled. */
|
||||
uint32_t audit;
|
||||
/** \brief Duration of writing dirty/modified data pages to a filesystem,
|
||||
@ -3540,6 +3800,74 @@ struct MDBX_commit_latency {
|
||||
uint32_t ending;
|
||||
/** \brief The total duration of a commit. */
|
||||
uint32_t whole;
|
||||
/** \brief User-mode CPU time spent on GC update. */
|
||||
uint32_t gc_cputime;
|
||||
|
||||
/** \brief Информация для профилирования работы GC.
|
||||
* \note Статистика является общей для всех процессов работающих с одним
|
||||
* файлом БД и хранится в LCK-файле. Данные аккумулируются при фиксации всех
|
||||
* транзакций, но только в сборках libmdbx c установленной опцией
|
||||
* \ref MDBX_ENABLE_PROFGC. Собранная статистика возвращаются любому процессу
|
||||
* при использовании \ref mdbx_txn_commit_ex() и одновременно обнуляется
|
||||
* при завершении транзакций верхнего уровня (не вложенных). */
|
||||
struct {
|
||||
/** \brief Количество итераций обновления GC,
|
||||
* больше 1 если были повторы/перезапуски. */
|
||||
uint32_t wloops;
|
||||
/** \brief Количество итераций слияния записей GC. */
|
||||
uint32_t coalescences;
|
||||
/** \brief Количество уничтожений предыдущих надежных/устойчивых
|
||||
* точек фиксации при работе в режиме \ref MDBX_UTTERLY_NOSYNC. */
|
||||
uint32_t wipes;
|
||||
/** \brief Количество принудительных фиксаций на диск
|
||||
* во избежания приращения БД при работе вне режима
|
||||
* \ref MDBX_UTTERLY_NOSYNC. */
|
||||
uint32_t flushes;
|
||||
/** \brief Количество обращений к механизму Handle-Slow-Readers
|
||||
* во избежания приращения БД.
|
||||
* \see MDBX_hsr_func */
|
||||
uint32_t kicks;
|
||||
|
||||
/** \brief Счетчик выполнения по медленному пути (slow path execution count)
|
||||
* GC ради данных пользователя. */
|
||||
uint32_t work_counter;
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC ради данных пользователя. */
|
||||
uint32_t work_rtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное
|
||||
* на подготовку страниц извлекаемых из GC для данных пользователя,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t work_xtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* ради данных пользователя. */
|
||||
uint32_t work_rsteps;
|
||||
/** \brief Количество запросов на выделение последовательностей страниц
|
||||
* ради данных пользователя. */
|
||||
uint32_t work_xpages;
|
||||
/** \brief Количество страничных промахов (page faults) внутри GC
|
||||
* при выделении и подготовки страниц для данных пользователя. */
|
||||
uint32_t work_majflt;
|
||||
|
||||
/** \brief Счетчик выполнения по медленному пути (slow path execution count)
|
||||
* GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_counter;
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на подготовку
|
||||
* страниц извлекаемых из GC для целей поддержки и обновления самой GC,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t self_xtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rsteps;
|
||||
/** \brief Количество запросов на выделение последовательностей страниц
|
||||
* для самой GC. */
|
||||
uint32_t self_xpages;
|
||||
/** \brief Количество страничных промахов (page faults) внутри GC
|
||||
* при выделении и подготовки страниц для самой GC. */
|
||||
uint32_t self_majflt;
|
||||
} gc_prof;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
/** \ingroup c_statinfo */
|
||||
@ -3862,6 +4190,8 @@ typedef int(MDBX_cmp_func)(const MDBX_val *a,
|
||||
* by current thread. */
|
||||
LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name,
|
||||
MDBX_db_flags_t flags, MDBX_dbi *dbi);
|
||||
LIBMDBX_API int mdbx_dbi_open2(MDBX_txn *txn, const MDBX_val *name,
|
||||
MDBX_db_flags_t flags, MDBX_dbi *dbi);
|
||||
|
||||
/** \deprecated Please
|
||||
* \ref avoid_custom_comparators "avoid using custom comparators" and use
|
||||
@ -3881,6 +4211,9 @@ LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name,
|
||||
MDBX_DEPRECATED LIBMDBX_API int
|
||||
mdbx_dbi_open_ex(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags,
|
||||
MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
|
||||
MDBX_DEPRECATED LIBMDBX_API int
|
||||
mdbx_dbi_open_ex2(MDBX_txn *txn, const MDBX_val *name, MDBX_db_flags_t flags,
|
||||
MDBX_dbi *dbi, MDBX_cmp_func *keycmp, MDBX_cmp_func *datacmp);
|
||||
|
||||
/** \defgroup value2key Value-to-Key functions
|
||||
* \brief Value-to-Key functions to
|
||||
@ -5083,11 +5416,12 @@ LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env);
|
||||
* this value into account to evaluate the impact that
|
||||
* a long-running transaction has.
|
||||
* \param [in] retry A retry number starting from 0.
|
||||
* If callback has returned 0 at least once, then at end
|
||||
* of current handling loop the callback function will be
|
||||
* called additionally with negative value to notify about
|
||||
* the end of loop. The callback function can use this value
|
||||
* to implement timeout logic while waiting for readers.
|
||||
* If callback has returned 0 at least once, then at end of
|
||||
* current handling loop the callback function will be
|
||||
* called additionally with negative `retry` value to notify
|
||||
* about the end of loop. The callback function can use this
|
||||
* fact to implement timeout reset logic while waiting for
|
||||
* a readers.
|
||||
*
|
||||
* \returns The RETURN CODE determines the further actions libmdbx and must
|
||||
* match the action which was executed by the callback:
|
||||
@ -5110,7 +5444,7 @@ LIBMDBX_API int mdbx_thread_unregister(const MDBX_env *env);
|
||||
* \retval 1 Transaction aborted asynchronous and reader slot
|
||||
* should be cleared immediately, i.e. read transaction
|
||||
* will not continue but \ref mdbx_txn_abort()
|
||||
* or \ref mdbx_txn_reset() will be called later.
|
||||
* nor \ref mdbx_txn_reset() will be called later.
|
||||
*
|
||||
* \retval 2 or great The reader process was terminated or killed,
|
||||
* and libmdbx should entirely reset reader registration.
|
||||
@ -5177,18 +5511,20 @@ typedef enum MDBX_page_type_t MDBX_page_type_t;
|
||||
#endif
|
||||
|
||||
/** \brief Pseudo-name for MainDB */
|
||||
#define MDBX_PGWALK_MAIN ((const char *)((ptrdiff_t)0))
|
||||
#define MDBX_PGWALK_MAIN ((void *)((ptrdiff_t)0))
|
||||
/** \brief Pseudo-name for GarbageCollectorDB */
|
||||
#define MDBX_PGWALK_GC ((const char *)((ptrdiff_t)-1))
|
||||
#define MDBX_PGWALK_GC ((void *)((ptrdiff_t)-1))
|
||||
/** \brief Pseudo-name for MetaPages */
|
||||
#define MDBX_PGWALK_META ((const char *)((ptrdiff_t)-2))
|
||||
#define MDBX_PGWALK_META ((void *)((ptrdiff_t)-2))
|
||||
|
||||
/** \brief Callback function for traverse the b-tree. \see mdbx_env_pgwalk() */
|
||||
typedef int MDBX_pgvisitor_func(
|
||||
const uint64_t pgno, const unsigned number, void *const ctx, const int deep,
|
||||
const char *const dbi, const size_t page_size, const MDBX_page_type_t type,
|
||||
const MDBX_error_t err, const size_t nentries, const size_t payload_bytes,
|
||||
const size_t header_bytes, const size_t unused_bytes) MDBX_CXX17_NOEXCEPT;
|
||||
typedef int
|
||||
MDBX_pgvisitor_func(const uint64_t pgno, const unsigned number, void *const ctx,
|
||||
const int deep, const MDBX_val *dbi_name,
|
||||
const size_t page_size, const MDBX_page_type_t type,
|
||||
const MDBX_error_t err, const size_t nentries,
|
||||
const size_t payload_bytes, const size_t header_bytes,
|
||||
const size_t unused_bytes) MDBX_CXX17_NOEXCEPT;
|
||||
|
||||
/** \brief B-tree traversal function. */
|
||||
LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
@ -5199,11 +5535,24 @@ LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor,
|
||||
*
|
||||
* This function mostly of internal API for `mdbx_chk` utility and subject to
|
||||
* change at any time. Do not use this function to avoid shooting your own
|
||||
* leg(s). */
|
||||
* leg(s).
|
||||
*
|
||||
* \note On Windows the \ref mdbx_env_open_for_recoveryW() is recommended
|
||||
* to use. */
|
||||
LIBMDBX_API int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname,
|
||||
unsigned target_meta,
|
||||
bool writeable);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
/** \copydoc mdbx_env_open_for_recovery()
|
||||
* \note Available only on Windows.
|
||||
* \see mdbx_env_open_for_recovery() */
|
||||
LIBMDBX_API int mdbx_env_open_for_recoveryW(MDBX_env *env,
|
||||
const wchar_t *pathname,
|
||||
unsigned target_meta,
|
||||
bool writeable);
|
||||
#endif /* Windows */
|
||||
|
||||
/** \brief Turn database to the specified meta-page.
|
||||
*
|
||||
* This function mostly of internal API for `mdbx_chk` utility and subject to
|
||||
@ -5213,230 +5562,8 @@ LIBMDBX_API int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target_meta);
|
||||
|
||||
/** end of btree_traversal @} */
|
||||
|
||||
/**** Attribute support functions for Nexenta (scheduled for removal)
|
||||
* *****************************************************************/
|
||||
#if defined(MDBX_NEXENTA_ATTRS) || defined(DOXYGEN)
|
||||
/** \defgroup nexenta Attribute support functions for Nexenta
|
||||
* \ingroup c_crud
|
||||
* @{ */
|
||||
typedef uint_fast64_t mdbx_attr_t;
|
||||
|
||||
/** Store by cursor with attribute.
|
||||
*
|
||||
* This function stores key/data pairs into the database. The cursor is
|
||||
* positioned at the new item, or on failure usually near it.
|
||||
*
|
||||
* \note Internally based on \ref MDBX_RESERVE feature,
|
||||
* therefore doesn't support \ref MDBX_DUPSORT.
|
||||
*
|
||||
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open()
|
||||
* \param [in] key The key operated on.
|
||||
* \param [in] data The data operated on.
|
||||
* \param [in] attr The attribute.
|
||||
* \param [in] flags Options for this operation. This parameter must be set
|
||||
* to 0 or one of the values described here:
|
||||
* - \ref MDBX_CURRENT
|
||||
* Replace the item at the current cursor position. The key parameter
|
||||
* must still be provided, and must match it, otherwise the function
|
||||
* return \ref MDBX_EKEYMISMATCH.
|
||||
*
|
||||
* - \ref MDBX_APPEND
|
||||
* Append the given key/data pair to the end of the database. No key
|
||||
* comparisons are performed. This option allows fast bulk loading when
|
||||
* keys are already known to be in the correct order. Loading unsorted
|
||||
* keys with this flag will cause a \ref MDBX_KEYEXIST error.
|
||||
*
|
||||
* \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_EKEYMISMATCH
|
||||
* \retval MDBX_MAP_FULL The database is full, see \ref mdbx_env_set_mapsize().
|
||||
* \retval MDBX_TXN_FULL The transaction has too many dirty pages.
|
||||
* \retval MDBX_EACCES An attempt was made to write in a read-only
|
||||
* transaction.
|
||||
* \retval MDBX_EINVAL an invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_put_attr(MDBX_cursor *cursor, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t attr,
|
||||
MDBX_put_flags_t flags);
|
||||
|
||||
/** Store items and attributes into a database.
|
||||
*
|
||||
* This function stores key/data pairs in the database. The default behavior
|
||||
* is to enter the new key/data pair, replacing any previously existing key
|
||||
* if duplicates are disallowed.
|
||||
*
|
||||
* \note Internally based on \ref MDBX_RESERVE feature,
|
||||
* therefore doesn't support \ref MDBX_DUPSORT.
|
||||
*
|
||||
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
||||
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
||||
* \param [in] key The key to store in the database.
|
||||
* \param [in] attr The attribute to store in the database.
|
||||
* \param [in,out] data The data to store.
|
||||
* \param [in] flags Special options for this operation. This parameter
|
||||
* must be set to 0 or by bitwise OR'ing together one or
|
||||
* more of the values described here:
|
||||
* - \ref MDBX_NOOVERWRITE
|
||||
* Enter the new key/data pair only if the key does not already appear
|
||||
* in the database. The function will return \ref MDBX_KEYEXIST if the key
|
||||
* already appears in the database. The data parameter will be set to
|
||||
* point to the existing item.
|
||||
*
|
||||
* - \ref MDBX_CURRENT
|
||||
* Update an single existing entry, but not add new ones. The function
|
||||
* will return \ref MDBX_NOTFOUND if the given key not exist in the
|
||||
* database. Or the \ref MDBX_EMULTIVAL in case duplicates for the given
|
||||
* key.
|
||||
*
|
||||
* - \ref MDBX_APPEND
|
||||
* Append the given key/data pair to the end of the database. This option
|
||||
* allows fast bulk loading when keys are already known to be in the
|
||||
* correct order. Loading unsorted keys with this flag will cause
|
||||
* a \ref MDBX_EKEYMISMATCH error.
|
||||
*
|
||||
* \see \ref c_crud_hints "Quick reference for Insert/Update/Delete operations"
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_KEYEXIST
|
||||
* \retval MDBX_MAP_FULL The database is full, see \ref mdbx_env_set_mapsize().
|
||||
* \retval MDBX_TXN_FULL The transaction has too many dirty pages.
|
||||
* \retval MDBX_EACCES An attempt was made to write
|
||||
* in a read-only transaction.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_put_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t attr,
|
||||
MDBX_put_flags_t flags);
|
||||
|
||||
/** Set items attribute from a database.
|
||||
*
|
||||
* This function stores key/data pairs attribute to the database.
|
||||
*
|
||||
* \note Internally based on \ref MDBX_RESERVE feature,
|
||||
* therefore doesn't support \ref MDBX_DUPSORT.
|
||||
*
|
||||
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
||||
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
||||
* \param [in] key The key to search for in the database.
|
||||
* \param [in] data The data to be stored or NULL to save previous value.
|
||||
* \param [in] attr The attribute to be stored.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_NOTFOUND The key-value pair was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_set_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t attr);
|
||||
|
||||
/** Get items attribute from a database cursor.
|
||||
*
|
||||
* This function retrieves key/data pairs from the database. The address and
|
||||
* length of the key are returned in the object to which key refers (except
|
||||
* for the case of the \ref MDBX_SET option, in which the key object is
|
||||
* unchanged), and the address and length of the data are returned in the object
|
||||
* to which data refers.
|
||||
* \see mdbx_get()
|
||||
*
|
||||
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open().
|
||||
* \param [in,out] key The key for a retrieved item.
|
||||
* \param [in,out] data The data of a retrieved item.
|
||||
* \param [out] pattr The pointer to retrieve attribute.
|
||||
* \param [in] op A cursor operation MDBX_cursor_op.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_NOTFOUND No matching key found.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_cursor_get_attr(MDBX_cursor *cursor, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t *pattr,
|
||||
MDBX_cursor_op op);
|
||||
|
||||
/** Get items attribute from a database.
|
||||
*
|
||||
* This function retrieves key/data pairs from the database. The address
|
||||
* and length of the data associated with the specified key are returned
|
||||
* in the structure to which data refers.
|
||||
* If the database supports duplicate keys (see \ref MDBX_DUPSORT) then the
|
||||
* first data item for the key will be returned. Retrieval of other
|
||||
* items requires the use of \ref mdbx_cursor_get().
|
||||
*
|
||||
* \note The memory pointed to by the returned values is owned by the
|
||||
* database. The caller need not dispose of the memory, and may not
|
||||
* modify it in any way. For values returned in a read-only transaction
|
||||
* any modification attempts will cause a `SIGSEGV`.
|
||||
*
|
||||
* \note Values returned from the database are valid only until a
|
||||
* subsequent update operation, or the end of the transaction.
|
||||
*
|
||||
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin().
|
||||
* \param [in] dbi A database handle returned by \ref mdbx_dbi_open().
|
||||
* \param [in] key The key to search for in the database.
|
||||
* \param [in,out] data The data corresponding to the key.
|
||||
* \param [out] pattr The pointer to retrieve attribute.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_NOTFOUND The key was not in the database.
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
LIBMDBX_API int mdbx_get_attr(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key,
|
||||
MDBX_val *data, mdbx_attr_t *pattr);
|
||||
/** end of nexenta @} */
|
||||
#endif /* MDBX_NEXENTA_ATTRS */
|
||||
|
||||
/** end of c_api @} */
|
||||
|
||||
/*******************************************************************************
|
||||
* Workaround for mmaped-lookahead-cross-page-boundary bug
|
||||
* in an obsolete versions of Elbrus's libc and kernels. */
|
||||
#if defined(__e2k__) && defined(MDBX_E2K_MLHCPB_WORKAROUND) && \
|
||||
MDBX_E2K_MLHCPB_WORKAROUND
|
||||
LIBMDBX_API int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
|
||||
size_t n);
|
||||
LIBMDBX_API int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2);
|
||||
LIBMDBX_API int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
size_t n);
|
||||
LIBMDBX_API size_t mdbx_e2k_strlen_bug_workaround(const char *s);
|
||||
LIBMDBX_API size_t mdbx_e2k_strnlen_bug_workaround(const char *s,
|
||||
size_t maxlen);
|
||||
#ifdef __cplusplus
|
||||
namespace std {
|
||||
inline int mdbx_e2k_memcmp_bug_workaround(const void *s1, const void *s2,
|
||||
size_t n) {
|
||||
return ::mdbx_e2k_memcmp_bug_workaround(s1, s2, n);
|
||||
}
|
||||
inline int mdbx_e2k_strcmp_bug_workaround(const char *s1, const char *s2) {
|
||||
return ::mdbx_e2k_strcmp_bug_workaround(s1, s2);
|
||||
}
|
||||
inline int mdbx_e2k_strncmp_bug_workaround(const char *s1, const char *s2,
|
||||
size_t n) {
|
||||
return ::mdbx_e2k_strncmp_bug_workaround(s1, s2, n);
|
||||
}
|
||||
inline size_t mdbx_e2k_strlen_bug_workaround(const char *s) {
|
||||
return ::mdbx_e2k_strlen_bug_workaround(s);
|
||||
}
|
||||
inline size_t mdbx_e2k_strnlen_bug_workaround(const char *s, size_t maxlen) {
|
||||
return ::mdbx_e2k_strnlen_bug_workaround(s, maxlen);
|
||||
}
|
||||
} // namespace std
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#undef memcmp
|
||||
#define memcmp mdbx_e2k_memcmp_bug_workaround
|
||||
#undef bcmp
|
||||
#define bcmp mdbx_e2k_memcmp_bug_workaround
|
||||
#undef strcmp
|
||||
#define strcmp mdbx_e2k_strcmp_bug_workaround
|
||||
#undef strncmp
|
||||
#define strncmp mdbx_e2k_strncmp_bug_workaround
|
||||
#undef strlen
|
||||
#define strlen mdbx_e2k_strlen_bug_workaround
|
||||
#undef strnlen
|
||||
#define strnlen mdbx_e2k_strnlen_bug_workaround
|
||||
#endif /* MDBX_E2K_MLHCPB_WORKAROUND */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
311
mdbx.h++
311
mdbx.h++
@ -1,7 +1,7 @@
|
||||
/// \file mdbx.h++
|
||||
/// \brief The libmdbx C++ API header file.
|
||||
///
|
||||
/// \author Copyright (c) 2020-2022, Leonid Yuriev <leo@yuriev.ru>.
|
||||
/// \author Copyright (c) 2020-2023, Leonid Yuriev <leo@yuriev.ru>.
|
||||
/// \copyright SPDX-License-Identifier: Apache-2.0
|
||||
///
|
||||
/// Tested with:
|
||||
@ -84,6 +84,11 @@
|
||||
#include <experimental/filesystem>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#include <chrono>
|
||||
#include <ratio>
|
||||
#endif
|
||||
|
||||
#include "mdbx.h"
|
||||
|
||||
#if (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L) || \
|
||||
@ -386,6 +391,11 @@ using path = ::std::wstring;
|
||||
using path = ::std::string;
|
||||
#endif /* mdbx::path */
|
||||
|
||||
#if __cplusplus >= 201103L || defined(DOXYGEN)
|
||||
/// \brief Duration in 1/65536 units of second.
|
||||
using duration = ::std::chrono::duration<unsigned, ::std::ratio<1, 65536>>;
|
||||
#endif /* Duration for C++11 */
|
||||
|
||||
/// \defgroup cxx_exceptions exceptions and errors
|
||||
/// @{
|
||||
|
||||
@ -3189,6 +3199,7 @@ public:
|
||||
/// \brief Returns the minimal values size in bytes for specified values
|
||||
/// mode.
|
||||
static inline size_t value_min(value_mode) noexcept;
|
||||
|
||||
/// \brief Returns the maximal value size in bytes for specified page size
|
||||
/// and database flags.
|
||||
static inline size_t value_max(intptr_t pagesize, MDBX_db_flags_t flags);
|
||||
@ -3201,6 +3212,35 @@ public:
|
||||
/// \brief Returns the maximal value size in bytes for specified page size
|
||||
/// and values mode.
|
||||
static inline size_t value_max(const env &, value_mode);
|
||||
|
||||
/// \brief Returns maximal size of key-value pair to fit in a single page
|
||||
/// for specified size and database flags.
|
||||
static inline size_t pairsize4page_max(intptr_t pagesize,
|
||||
MDBX_db_flags_t flags);
|
||||
/// \brief Returns maximal size of key-value pair to fit in a single page
|
||||
/// for specified page size and values mode.
|
||||
static inline size_t pairsize4page_max(intptr_t pagesize, value_mode);
|
||||
/// \brief Returns maximal size of key-value pair to fit in a single page
|
||||
/// for given environment and database flags.
|
||||
static inline size_t pairsize4page_max(const env &, MDBX_db_flags_t flags);
|
||||
/// \brief Returns maximal size of key-value pair to fit in a single page
|
||||
/// for specified page size and values mode.
|
||||
static inline size_t pairsize4page_max(const env &, value_mode);
|
||||
|
||||
/// \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
/// single overflow/large-page for specified size and database flags.
|
||||
static inline size_t valsize4page_max(intptr_t pagesize,
|
||||
MDBX_db_flags_t flags);
|
||||
/// \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
/// single overflow/large-page for specified page size and values mode.
|
||||
static inline size_t valsize4page_max(intptr_t pagesize, value_mode);
|
||||
/// \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
/// single overflow/large-page for given environment and database flags.
|
||||
static inline size_t valsize4page_max(const env &, MDBX_db_flags_t flags);
|
||||
/// \brief Returns maximal data size in bytes to fit in a leaf-page or
|
||||
/// single overflow/large-page for specified page size and values mode.
|
||||
static inline size_t valsize4page_max(const env &, value_mode);
|
||||
|
||||
/// \brief Returns the maximal write transaction size (i.e. limit for
|
||||
/// summary volume of dirty pages) in bytes for specified page size.
|
||||
static inline size_t transaction_size_max(intptr_t pagesize);
|
||||
@ -3237,6 +3277,8 @@ public:
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
env ©(const ::std::wstring &destination, bool compactify,
|
||||
bool force_dynamic_size = false);
|
||||
env ©(const wchar_t *destination, bool compactify,
|
||||
bool force_dynamic_size = false);
|
||||
#endif /* Windows */
|
||||
env ©(const ::std::string &destination, bool compactify,
|
||||
bool force_dynamic_size = false);
|
||||
@ -3272,6 +3314,8 @@ public:
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
static bool remove(const ::std::wstring &pathname,
|
||||
const remove_mode mode = just_remove);
|
||||
static bool remove(const wchar_t *pathname,
|
||||
const remove_mode mode = just_remove);
|
||||
#endif /* Windows */
|
||||
static bool remove(const ::std::string &pathname,
|
||||
const remove_mode mode = just_remove);
|
||||
@ -3312,9 +3356,11 @@ public:
|
||||
|
||||
/// \brief Returns the maximum number of threads/reader slots for the
|
||||
/// environment.
|
||||
/// \see extra_runtime_option::max_readers
|
||||
inline unsigned max_readers() const;
|
||||
|
||||
/// \brief Returns the maximum number of named databases for the environment.
|
||||
/// \see extra_runtime_option::max_maps
|
||||
inline unsigned max_maps() const;
|
||||
|
||||
/// \brief Returns the application context associated with the environment.
|
||||
@ -3326,59 +3372,117 @@ public:
|
||||
/// \brief Sets threshold to force flush the data buffers to disk, for
|
||||
/// non-sync durability modes.
|
||||
///
|
||||
/// The threshold value affects all processes which operates with given
|
||||
/// environment until the last process close environment or a new value will
|
||||
/// be settled.
|
||||
/// Data is always written to disk when \ref txn_managed::commit() is called,
|
||||
/// but the operating system may keep it buffered. MDBX always flushes the OS
|
||||
/// buffers upon commit as well, unless the environment was opened with \ref
|
||||
/// whole_fragile, \ref lazy_weak_tail or in part \ref
|
||||
/// half_synchronous_weak_last. The default is 0, than mean no any threshold
|
||||
/// checked, and no additional flush will be made.
|
||||
/// \details The threshold value affects all processes which operates with
|
||||
/// given environment until the last process close environment or a new value
|
||||
/// will be settled. Data is always written to disk when \ref
|
||||
/// txn_managed::commit() is called, but the operating system may keep it
|
||||
/// buffered. MDBX always flushes the OS buffers upon commit as well, unless
|
||||
/// the environment was opened with \ref whole_fragile, \ref lazy_weak_tail or
|
||||
/// in part \ref half_synchronous_weak_last.
|
||||
///
|
||||
/// The default is 0, than mean no any threshold checked, and no additional
|
||||
/// flush will be made.
|
||||
/// \see extra_runtime_option::sync_bytes
|
||||
inline env &set_sync_threshold(size_t bytes);
|
||||
|
||||
/// \brief Gets threshold used to force flush the data buffers to disk, for
|
||||
/// non-sync durability modes.
|
||||
///
|
||||
/// \copydetails set_sync_threshold()
|
||||
/// \see extra_runtime_option::sync_bytes
|
||||
inline size_t sync_threshold() const;
|
||||
|
||||
#if __cplusplus >= 201103L || defined(DOXYGEN)
|
||||
/// \brief Sets relative period since the last unsteady commit to force flush
|
||||
/// the data buffers to disk, for non-sync durability modes.
|
||||
///
|
||||
/// The relative period value affects all processes which operates with given
|
||||
/// environment until the last process close environment or a new value will
|
||||
/// be settled.
|
||||
/// Data is always written to disk when \ref txn_managed::commit() is called,
|
||||
/// but the operating system may keep it buffered. MDBX always flushes the OS
|
||||
/// buffers upon commit as well, unless the environment was opened with \ref
|
||||
/// whole_fragile, \ref lazy_weak_tail or in part \ref
|
||||
/// half_synchronous_weak_last. Settled period don't checked asynchronously,
|
||||
/// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk()
|
||||
/// functions. Therefore, in cases where transactions are committed
|
||||
/// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk()
|
||||
/// may be a reasonable solution to timeout enforcement. The default is 0,
|
||||
/// than mean no any timeout checked, and no additional flush will be made.
|
||||
/// \details The relative period value affects all processes which operates
|
||||
/// with given environment until the last process close environment or a new
|
||||
/// value will be settled. Data is always written to disk when \ref
|
||||
/// txn_managed::commit() is called, but the operating system may keep it
|
||||
/// buffered. MDBX always flushes the OS buffers upon commit as well, unless
|
||||
/// the environment was opened with \ref whole_fragile, \ref lazy_weak_tail or
|
||||
/// in part \ref half_synchronous_weak_last. Settled period don't checked
|
||||
/// asynchronously, but only by the \ref txn_managed::commit() and \ref
|
||||
/// env::sync_to_disk() functions. Therefore, in cases where transactions are
|
||||
/// committed infrequently and/or irregularly, polling by \ref
|
||||
/// env::poll_sync_to_disk() may be a reasonable solution to timeout
|
||||
/// enforcement.
|
||||
///
|
||||
/// The default is 0, than mean no any timeout checked, and no additional
|
||||
/// flush will be made.
|
||||
/// \see extra_runtime_option::sync_period
|
||||
inline env &set_sync_period(const duration &period);
|
||||
|
||||
/// \brief Gets relative period since the last unsteady commit that used to
|
||||
/// force flush the data buffers to disk, for non-sync durability modes.
|
||||
/// \copydetails set_sync_period(const duration&)
|
||||
/// \see set_sync_period(const duration&)
|
||||
/// \see extra_runtime_option::sync_period
|
||||
inline duration sync_period() const;
|
||||
#endif
|
||||
|
||||
/// \copydoc set_sync_period(const duration&)
|
||||
/// \param [in] seconds_16dot16 The period in 1/65536 of second when a
|
||||
/// synchronous flush would be made since the last unsteady commit.
|
||||
inline env &set_sync_period(unsigned seconds_16dot16);
|
||||
inline env &set_sync_period__seconds_16dot16(unsigned seconds_16dot16);
|
||||
|
||||
/// \brief Sets relative period since the last unsteady commit to force flush
|
||||
/// the data buffers to disk, for non-sync durability modes.
|
||||
///
|
||||
/// The relative period value affects all processes which operates with given
|
||||
/// environment until the last process close environment or a new value will
|
||||
/// be settled.
|
||||
/// Data is always written to disk when \ref txn_managed::commit() is called,
|
||||
/// but the operating system may keep it buffered. MDBX always flushes the OS
|
||||
/// buffers upon commit as well, unless the environment was opened with \ref
|
||||
/// whole_fragile, \ref lazy_weak_tail or in part \ref
|
||||
/// half_synchronous_weak_last. Settled period don't checked asynchronously,
|
||||
/// but only by the \ref txn_managed::commit() and \ref env::sync_to_disk()
|
||||
/// functions. Therefore, in cases where transactions are committed
|
||||
/// infrequently and/or irregularly, polling by \ref env::poll_sync_to_disk()
|
||||
/// may be a reasonable solution to timeout enforcement. The default is 0,
|
||||
/// than mean no any timeout checked, and no additional flush will be made.
|
||||
///
|
||||
/// \copydoc sync_period()
|
||||
/// \see sync_period__seconds_16dot16(unsigned)
|
||||
inline unsigned sync_period__seconds_16dot16() const;
|
||||
|
||||
/// \copydoc set_sync_period(const duration&)
|
||||
/// \param [in] seconds The period in second when a synchronous flush would
|
||||
/// be made since the last unsteady commit.
|
||||
inline env &set_sync_period(double seconds);
|
||||
inline env &set_sync_period__seconds_double(double seconds);
|
||||
|
||||
/// \copydoc sync_period()
|
||||
/// \see set_sync_period__seconds_double(double)
|
||||
inline double sync_period__seconds_double() const;
|
||||
|
||||
/// \copydoc MDBX_option_t
|
||||
enum class extra_runtime_option {
|
||||
/// \copydoc MDBX_opt_max_db
|
||||
/// \see max_maps() \see env::operate_parameters::max_maps
|
||||
max_maps = MDBX_opt_max_db,
|
||||
/// \copydoc MDBX_opt_max_readers
|
||||
/// \see max_readers() \see env::operate_parameters::max_readers
|
||||
max_readers = MDBX_opt_max_readers,
|
||||
/// \copydoc MDBX_opt_sync_bytes
|
||||
/// \see sync_threshold() \see set_sync_threshold()
|
||||
sync_bytes = MDBX_opt_sync_bytes,
|
||||
/// \copydoc MDBX_opt_sync_period
|
||||
/// \see sync_period() \see set_sync_period()
|
||||
sync_period = MDBX_opt_sync_period,
|
||||
/// \copydoc MDBX_opt_rp_augment_limit
|
||||
rp_augment_limit = MDBX_opt_rp_augment_limit,
|
||||
/// \copydoc MDBX_opt_loose_limit
|
||||
loose_limit = MDBX_opt_loose_limit,
|
||||
/// \copydoc MDBX_opt_dp_reserve_limit
|
||||
dp_reserve_limit = MDBX_opt_dp_reserve_limit,
|
||||
/// \copydoc MDBX_opt_txn_dp_limit
|
||||
dp_limit = MDBX_opt_txn_dp_limit,
|
||||
/// \copydoc MDBX_opt_txn_dp_initial
|
||||
dp_initial = MDBX_opt_txn_dp_initial,
|
||||
/// \copydoc MDBX_opt_spill_max_denominator
|
||||
spill_max_denominator = MDBX_opt_spill_max_denominator,
|
||||
/// \copydoc MDBX_opt_spill_min_denominator
|
||||
spill_min_denominator = MDBX_opt_spill_min_denominator,
|
||||
/// \copydoc MDBX_opt_spill_parent4child_denominator
|
||||
spill_parent4child_denominator = MDBX_opt_spill_parent4child_denominator,
|
||||
/// \copydoc MDBX_opt_merge_threshold_16dot16_percent
|
||||
merge_threshold_16dot16_percent = MDBX_opt_merge_threshold_16dot16_percent,
|
||||
/// \copydoc MDBX_opt_writethrough_threshold
|
||||
writethrough_threshold = MDBX_opt_writethrough_threshold,
|
||||
/// \copydoc MDBX_opt_prefault_write_enable
|
||||
prefault_write_enable = MDBX_opt_prefault_write_enable,
|
||||
};
|
||||
|
||||
/// \copybrief mdbx_env_set_option()
|
||||
inline env &set_extra_option(extra_runtime_option option, uint64_t value);
|
||||
|
||||
/// \copybrief mdbx_env_get_option()
|
||||
inline uint64_t extra_option(extra_runtime_option option) const;
|
||||
|
||||
/// \brief Alter environment flags.
|
||||
inline env &alter_flags(MDBX_env_flags_t flags, bool on_off);
|
||||
@ -3519,6 +3623,8 @@ public:
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
env_managed(const ::std::wstring &pathname, const operate_parameters &,
|
||||
bool accede = true);
|
||||
explicit env_managed(const wchar_t *pathname, const operate_parameters &,
|
||||
bool accede = true);
|
||||
#endif /* Windows */
|
||||
env_managed(const ::std::string &pathname, const operate_parameters &,
|
||||
bool accede = true);
|
||||
@ -3543,6 +3649,8 @@ public:
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN)
|
||||
env_managed(const ::std::wstring &pathname, const create_parameters &,
|
||||
const operate_parameters &, bool accede = true);
|
||||
explicit env_managed(const wchar_t *pathname, const create_parameters &,
|
||||
const operate_parameters &, bool accede = true);
|
||||
#endif /* Windows */
|
||||
env_managed(const ::std::string &pathname, const create_parameters &,
|
||||
const operate_parameters &, bool accede = true);
|
||||
@ -3879,12 +3987,31 @@ public:
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/// \brief Abandon all the operations of the transaction instead of saving
|
||||
/// them.
|
||||
/// \brief Abandon all the operations of the transaction
|
||||
/// instead of saving ones.
|
||||
void abort();
|
||||
|
||||
/// \brief Commit all the operations of a transaction into the database.
|
||||
void commit();
|
||||
|
||||
using commit_latency = MDBX_commit_latency;
|
||||
|
||||
/// \brief Commit all the operations of a transaction into the database
|
||||
/// and collect latency information.
|
||||
void commit(commit_latency *);
|
||||
|
||||
/// \brief Commit all the operations of a transaction into the database
|
||||
/// and collect latency information.
|
||||
void commit(commit_latency &latency) { return commit(&latency); }
|
||||
|
||||
/// \brief Commit all the operations of a transaction into the database
|
||||
/// and return latency information.
|
||||
/// \returns latency information of commit stages.
|
||||
commit_latency commit_get_latency() {
|
||||
commit_latency result;
|
||||
commit(&result);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Unmanaged cursor.
|
||||
@ -4867,6 +4994,56 @@ inline size_t env::limits::value_max(const env &env, value_mode mode) {
|
||||
return value_max(env, MDBX_db_flags_t(mode));
|
||||
}
|
||||
|
||||
inline size_t env::limits::pairsize4page_max(intptr_t pagesize,
|
||||
MDBX_db_flags_t flags) {
|
||||
const intptr_t result = mdbx_limits_pairsize4page_max(pagesize, flags);
|
||||
if (result < 0)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
|
||||
return static_cast<size_t>(result);
|
||||
}
|
||||
|
||||
inline size_t env::limits::pairsize4page_max(intptr_t pagesize,
|
||||
value_mode mode) {
|
||||
return pairsize4page_max(pagesize, MDBX_db_flags_t(mode));
|
||||
}
|
||||
|
||||
inline size_t env::limits::pairsize4page_max(const env &env,
|
||||
MDBX_db_flags_t flags) {
|
||||
const intptr_t result = mdbx_env_get_pairsize4page_max(env, flags);
|
||||
if (result < 0)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
|
||||
return static_cast<size_t>(result);
|
||||
}
|
||||
|
||||
inline size_t env::limits::pairsize4page_max(const env &env, value_mode mode) {
|
||||
return pairsize4page_max(env, MDBX_db_flags_t(mode));
|
||||
}
|
||||
|
||||
inline size_t env::limits::valsize4page_max(intptr_t pagesize,
|
||||
MDBX_db_flags_t flags) {
|
||||
const intptr_t result = mdbx_limits_valsize4page_max(pagesize, flags);
|
||||
if (result < 0)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
|
||||
return static_cast<size_t>(result);
|
||||
}
|
||||
|
||||
inline size_t env::limits::valsize4page_max(intptr_t pagesize,
|
||||
value_mode mode) {
|
||||
return valsize4page_max(pagesize, MDBX_db_flags_t(mode));
|
||||
}
|
||||
|
||||
inline size_t env::limits::valsize4page_max(const env &env,
|
||||
MDBX_db_flags_t flags) {
|
||||
const intptr_t result = mdbx_env_get_valsize4page_max(env, flags);
|
||||
if (result < 0)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_EINVAL);
|
||||
return static_cast<size_t>(result);
|
||||
}
|
||||
|
||||
inline size_t env::limits::valsize4page_max(const env &env, value_mode mode) {
|
||||
return valsize4page_max(env, MDBX_db_flags_t(mode));
|
||||
}
|
||||
|
||||
inline size_t env::limits::transaction_size_max(intptr_t pagesize) {
|
||||
const intptr_t result = mdbx_limits_txnsize_max(pagesize);
|
||||
if (result < 0)
|
||||
@ -4961,13 +5138,53 @@ inline env &env::set_sync_threshold(size_t bytes) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline env &env::set_sync_period(unsigned seconds_16dot16) {
|
||||
inline size_t env::sync_threshold() const {
|
||||
size_t bytes;
|
||||
error::success_or_throw(::mdbx_env_get_syncbytes(handle_, &bytes));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
inline env &env::set_sync_period__seconds_16dot16(unsigned seconds_16dot16) {
|
||||
error::success_or_throw(::mdbx_env_set_syncperiod(handle_, seconds_16dot16));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline env &env::set_sync_period(double seconds) {
|
||||
return set_sync_period(unsigned(seconds * 65536));
|
||||
inline unsigned env::sync_period__seconds_16dot16() const {
|
||||
unsigned seconds_16dot16;
|
||||
error::success_or_throw(::mdbx_env_get_syncperiod(handle_, &seconds_16dot16));
|
||||
return seconds_16dot16;
|
||||
}
|
||||
|
||||
inline env &env::set_sync_period__seconds_double(double seconds) {
|
||||
return set_sync_period__seconds_16dot16(unsigned(seconds * 65536));
|
||||
}
|
||||
|
||||
inline double env::sync_period__seconds_double() const {
|
||||
return sync_period__seconds_16dot16() / 65536.0;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
inline env &env::set_sync_period(const duration &period) {
|
||||
return set_sync_period__seconds_16dot16(period.count());
|
||||
}
|
||||
|
||||
inline duration env::sync_period() const {
|
||||
return duration(sync_period__seconds_16dot16());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline env &env::set_extra_option(enum env::extra_runtime_option option,
|
||||
uint64_t value) {
|
||||
error::success_or_throw(
|
||||
::mdbx_env_set_option(handle_, ::MDBX_option_t(option), value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint64_t env::extra_option(enum env::extra_runtime_option option) const {
|
||||
uint64_t value;
|
||||
error::success_or_throw(
|
||||
::mdbx_env_get_option(handle_, ::MDBX_option_t(option), &value));
|
||||
return value;
|
||||
}
|
||||
|
||||
inline env &env::alter_flags(MDBX_env_flags_t flags, bool on_off) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
79
src/base.h
79
src/base.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -63,7 +63,7 @@
|
||||
#define SSIZE_MAX INTPTR_MAX
|
||||
#endif
|
||||
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul
|
||||
#if UINTPTR_MAX > 0xffffFFFFul || ULONG_MAX > 0xffffFFFFul || defined(_WIN64)
|
||||
#define MDBX_WORDBITS 64
|
||||
#else
|
||||
#define MDBX_WORDBITS 32
|
||||
@ -259,8 +259,10 @@ __extern_C key_t ftok(const char *, int);
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#endif /*---------------------------------------------------------------------*/
|
||||
@ -302,8 +304,9 @@ __extern_C key_t ftok(const char *, int);
|
||||
/* LY: define neutral __ia32__ for x86 and x86-64 */
|
||||
#define __ia32__ 1
|
||||
#endif /* __ia32__ */
|
||||
#if !defined(__amd64__) && (defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(__amd64) || defined(_M_X64))
|
||||
#if !defined(__amd64__) && \
|
||||
(defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || \
|
||||
defined(_M_X64) || defined(_M_AMD64))
|
||||
/* LY: define trusty __amd64__ for all AMD64/x86-64 arch */
|
||||
#define __amd64__ 1
|
||||
#endif /* __amd64__ */
|
||||
@ -371,18 +374,50 @@ __extern_C key_t ftok(const char *, int);
|
||||
#endif
|
||||
#endif /* __BYTE_ORDER__ || __ORDER_LITTLE_ENDIAN__ || __ORDER_BIG_ENDIAN__ */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Availability of CMOV or equivalent */
|
||||
|
||||
#ifndef MDBX_HAVE_CMOV
|
||||
#if defined(__e2k__)
|
||||
#define MDBX_HAVE_CMOV 1
|
||||
#elif defined(__thumb2__) || defined(__thumb2)
|
||||
#define MDBX_HAVE_CMOV 1
|
||||
#elif defined(__thumb__) || defined(__thumb) || defined(__TARGET_ARCH_THUMB)
|
||||
#define MDBX_HAVE_CMOV 0
|
||||
#elif defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || \
|
||||
defined(__aarch64) || defined(__arm__) || defined(__arm) || \
|
||||
defined(__CC_ARM)
|
||||
#define MDBX_HAVE_CMOV 1
|
||||
#elif (defined(__riscv__) || defined(__riscv64)) && \
|
||||
(defined(__riscv_b) || defined(__riscv_bitmanip))
|
||||
#define MDBX_HAVE_CMOV 1
|
||||
#elif defined(i686) || defined(__i686) || defined(__i686__) || \
|
||||
(defined(_M_IX86) && _M_IX86 > 600) || defined(__x86_64) || \
|
||||
defined(__x86_64__) || defined(__amd64__) || defined(__amd64) || \
|
||||
defined(_M_X64) || defined(_M_AMD64)
|
||||
#define MDBX_HAVE_CMOV 1
|
||||
#else
|
||||
#define MDBX_HAVE_CMOV 0
|
||||
#endif
|
||||
#endif /* MDBX_HAVE_CMOV */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Compiler's includes for builtins/intrinsics */
|
||||
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
#include <intrin.h>
|
||||
#elif __GNUC_PREREQ(4, 4) || defined(__clang__)
|
||||
#if defined(__ia32__) || defined(__e2k__)
|
||||
#if defined(__e2k__)
|
||||
#include <e2kintrin.h>
|
||||
#include <x86intrin.h>
|
||||
#endif /* __ia32__ */
|
||||
#endif /* __e2k__ */
|
||||
#if defined(__ia32__)
|
||||
#include <cpuid.h>
|
||||
#include <x86intrin.h>
|
||||
#endif /* __ia32__ */
|
||||
#ifdef __ARM_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#elif defined(__SUNPRO_C) || defined(__sun) || defined(sun)
|
||||
#include <mbarrier.h>
|
||||
#elif (defined(_HPUX_SOURCE) || defined(__hpux) || defined(__HP_aCC)) && \
|
||||
@ -603,6 +638,16 @@ __extern_C key_t ftok(const char *, int);
|
||||
#endif
|
||||
#endif /* __anonymous_struct_extension__ */
|
||||
|
||||
#ifndef expect_with_probability
|
||||
#if defined(__builtin_expect_with_probability) || \
|
||||
__has_builtin(__builtin_expect_with_probability) || __GNUC_PREREQ(9, 0)
|
||||
#define expect_with_probability(expr, value, prob) \
|
||||
__builtin_expect_with_probability(expr, value, prob)
|
||||
#else
|
||||
#define expect_with_probability(expr, value, prob) (expr)
|
||||
#endif
|
||||
#endif /* expect_with_probability */
|
||||
|
||||
#ifndef MDBX_WEAK_IMPORT_ATTRIBUTE
|
||||
#ifdef WEAK_IMPORT_ATTRIBUTE
|
||||
#define MDBX_WEAK_IMPORT_ATTRIBUTE WEAK_IMPORT_ATTRIBUTE
|
||||
@ -616,6 +661,28 @@ __extern_C key_t ftok(const char *, int);
|
||||
#endif
|
||||
#endif /* MDBX_WEAK_IMPORT_ATTRIBUTE */
|
||||
|
||||
#ifndef MDBX_GOOFY_MSVC_STATIC_ANALYZER
|
||||
#ifdef _PREFAST_
|
||||
#define MDBX_GOOFY_MSVC_STATIC_ANALYZER 1
|
||||
#else
|
||||
#define MDBX_GOOFY_MSVC_STATIC_ANALYZER 0
|
||||
#endif
|
||||
#endif /* MDBX_GOOFY_MSVC_STATIC_ANALYZER */
|
||||
|
||||
#if MDBX_GOOFY_MSVC_STATIC_ANALYZER || (defined(_MSC_VER) && _MSC_VER > 1919)
|
||||
#define MDBX_ANALYSIS_ASSUME(expr) __analysis_assume(expr)
|
||||
#ifdef _PREFAST_
|
||||
#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id) \
|
||||
__pragma(prefast(suppress : warn_id))
|
||||
#else
|
||||
#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id) \
|
||||
__pragma(warning(suppress : warn_id))
|
||||
#endif
|
||||
#else
|
||||
#define MDBX_ANALYSIS_ASSUME(expr) assert(expr)
|
||||
#define MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(warn_id)
|
||||
#endif /* MDBX_GOOFY_MSVC_STATIC_ANALYZER */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(MDBX_USE_VALGRIND)
|
||||
|
16
src/bits.md
16
src/bits.md
@ -1,11 +1,11 @@
|
||||
N | MASK | ENV | TXN | DB | PUT | DBI | NODE | PAGE | MRESIZE |
|
||||
--|---------|-----------|--------------|----------|-----------|------------|---------|----------|---------|
|
||||
0 |0000 0001|ALLOC_CACHE|TXN_FINISHED | | |DBI_DIRTY |F_BIGDATA|P_BRANCH | |
|
||||
1 |0000 0002|ALLOC_GC |TXN_ERROR |REVERSEKEY|F_SUBDATA |DBI_STALE |F_SUBDATA|P_LEAF | |
|
||||
2 |0000 0004|ALLOC_NEW |TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW| |
|
||||
3 |0000 0008|ALLOC_SLOT |TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META | |
|
||||
4 |0000 0010|ALLOC_FAKE |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_BAD | |
|
||||
5 |0000 0020| | |INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 | |
|
||||
0 |0000 0001|ALLOC_RSRV |TXN_FINISHED | | |DBI_DIRTY |F_BIGDATA|P_BRANCH | |
|
||||
1 |0000 0002|ALLOC_UNIMP|TXN_ERROR |REVERSEKEY|F_SUBDATA |DBI_STALE |F_SUBDATA|P_LEAF | |
|
||||
2 |0000 0004|ALLOC_COLSC|TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW| |
|
||||
3 |0000 0008|ALLOC_SSCAN|TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META | |
|
||||
4 |0000 0010|ALLOC_FIFO |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_BAD | |
|
||||
5 |0000 0020| |TXN_DRAINED_GC|INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 | |
|
||||
6 |0000 0040| | |REVERSEDUP|CURRENT |DBI_DUPDATA | |P_SUBP | |
|
||||
7 |0000 0080| | | |ALLDUPS |DBI_AUDITED | | | |
|
||||
8 |0000 0100| _MAY_MOVE | | | | | | | <= |
|
||||
@ -13,9 +13,9 @@ N | MASK | ENV | TXN | DB | PUT | DBI | NOD
|
||||
10|0000 0400| | | | | | | | |
|
||||
11|0000 0800| | | | | | | | |
|
||||
12|0000 1000| | | | | | | | |
|
||||
13|0000 2000| | | | | | |P_SPILLED | |
|
||||
13|0000 2000|VALIDATION | | | | | |P_SPILLED | |
|
||||
14|0000 4000|NOSUBDIR | | | | | |P_LOOSE | |
|
||||
15|0000 8000| | |DB_VALID |NOSPILL | | |P_FROZEN | |
|
||||
15|0000 8000| | |DB_VALID | | | |P_FROZEN | |
|
||||
16|0001 0000|SAFE_NOSYNC|TXN_NOSYNC | |RESERVE | |RESERVE | | |
|
||||
17|0002 0000|RDONLY |TXN_RDONLY | |APPEND | |APPEND | | <= |
|
||||
18|0004 0000|NOMETASYNC |TXN_NOMETASYNC|CREATE |APPENDDUP | | | | |
|
||||
|
@ -26,7 +26,13 @@
|
||||
#ifndef MDBX_TRUST_RTC_AUTO
|
||||
#cmakedefine01 MDBX_TRUST_RTC
|
||||
#endif
|
||||
#cmakedefine01 MDBX_DISABLE_PAGECHECKS
|
||||
#cmakedefine01 MDBX_DISABLE_VALIDATION
|
||||
#cmakedefine01 MDBX_AVOID_MSYNC
|
||||
#cmakedefine01 MDBX_ENABLE_REFUND
|
||||
#cmakedefine01 MDBX_ENABLE_MADVISE
|
||||
#cmakedefine01 MDBX_ENABLE_BIGFOOT
|
||||
#cmakedefine01 MDBX_ENABLE_PGOP_STAT
|
||||
#cmakedefine01 MDBX_ENABLE_PROFGC
|
||||
|
||||
/* Windows */
|
||||
#cmakedefine01 MDBX_WITHOUT_MSVC_CRT
|
||||
|
19309
src/core.c
19309
src/core.c
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,42 @@
|
||||
#if defined(__GNUC__) && !defined(__LCC__)
|
||||
|
||||
#pragma push_macro("mdbx_trace")
|
||||
#pragma push_macro("mdbx_debug")
|
||||
#pragma push_macro("mdbx_verbose")
|
||||
#pragma push_macro("mdbx_notice")
|
||||
#pragma push_macro("mdbx_warning")
|
||||
#pragma push_macro("mdbx_error")
|
||||
#pragma push_macro("mdbx_assert")
|
||||
#pragma push_macro("TRACE")
|
||||
#pragma push_macro("DEBUG")
|
||||
#pragma push_macro("VERBOSE")
|
||||
#pragma push_macro("NOTICE")
|
||||
#pragma push_macro("WARNING")
|
||||
#pragma push_macro("ERROR")
|
||||
#pragma push_macro("eASSERT")
|
||||
|
||||
#undef mdbx_trace
|
||||
#define mdbx_trace(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef TRACE
|
||||
#define TRACE(fmt, ...) \
|
||||
debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_debug
|
||||
#define mdbx_debug(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef DEBUG
|
||||
#define DEBUG(fmt, ...) \
|
||||
debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_verbose
|
||||
#define mdbx_verbose(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef VERBOSE
|
||||
#define VERBOSE(fmt, ...) \
|
||||
debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_notice
|
||||
#define mdbx_notice(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef NOTICE
|
||||
#define NOTICE(fmt, ...) \
|
||||
debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_warning
|
||||
#define mdbx_warning(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef WARNING
|
||||
#define WARNING(fmt, ...) \
|
||||
debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_error
|
||||
#define mdbx_error(fmt, ...) \
|
||||
mdbx_debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
#undef ERROR
|
||||
#define ERROR(fmt, ...) \
|
||||
debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__)
|
||||
|
||||
#undef mdbx_assert
|
||||
#define mdbx_assert(env, expr) mdbx_ensure(env, expr)
|
||||
#undef eASSERT
|
||||
#define eASSERT(env, expr) ENSURE(env, expr)
|
||||
|
||||
#if !defined(__clang__)
|
||||
#pragma GCC optimize("-O0")
|
||||
#pragma GCC optimize("-Og")
|
||||
#endif
|
||||
|
||||
#endif /* GCC only */
|
||||
|
@ -1,12 +1,12 @@
|
||||
#if defined(__GNUC__) && !defined(__LCC__)
|
||||
|
||||
#pragma pop_macro("mdbx_trace")
|
||||
#pragma pop_macro("mdbx_debug")
|
||||
#pragma pop_macro("mdbx_verbose")
|
||||
#pragma pop_macro("mdbx_notice")
|
||||
#pragma pop_macro("mdbx_warning")
|
||||
#pragma pop_macro("mdbx_error")
|
||||
#pragma pop_macro("mdbx_assert")
|
||||
#pragma pop_macro("TRACE")
|
||||
#pragma pop_macro("DEBUG")
|
||||
#pragma pop_macro("VERBOSE")
|
||||
#pragma pop_macro("NOTICE")
|
||||
#pragma pop_macro("WARNING")
|
||||
#pragma pop_macro("ERROR")
|
||||
#pragma pop_macro("eASSERT")
|
||||
|
||||
#if !defined(__clang__)
|
||||
#pragma GCC reset_options
|
||||
|
756
src/internals.h
756
src/internals.h
File diff suppressed because it is too large
Load Diff
216
src/lck-posix.c
216
src/lck-posix.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -28,10 +28,11 @@
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifndef xMDBX_ALLOY
|
||||
uint32_t mdbx_linux_kernel_version;
|
||||
uint32_t linux_kernel_version;
|
||||
bool mdbx_RunningOnWSL1;
|
||||
#endif /* xMDBX_ALLOY */
|
||||
|
||||
MDBX_EXCLUDE_FOR_GPROF
|
||||
__cold static uint8_t probe_for_WSL(const char *tag) {
|
||||
const char *const WSL = strstr(tag, "WSL");
|
||||
if (WSL && WSL[3] >= '2' && WSL[3] <= '9')
|
||||
@ -42,14 +43,28 @@ __cold static uint8_t probe_for_WSL(const char *tag) {
|
||||
if (WSL || wsl || strcasestr(tag, "Microsoft"))
|
||||
/* Expecting no new kernel within WSL1, either it will explicitly
|
||||
* marked by an appropriate WSL-version hint. */
|
||||
return (mdbx_linux_kernel_version < /* 4.19.x */ 0x04130000) ? 1 : 2;
|
||||
return (linux_kernel_version < /* 4.19.x */ 0x04130000) ? 1 : 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* Linux */
|
||||
|
||||
#ifdef ENABLE_GPROF
|
||||
extern void _mcleanup(void);
|
||||
extern void monstartup(unsigned long, unsigned long);
|
||||
extern void _init(void);
|
||||
extern void _fini(void);
|
||||
extern void __gmon_start__(void) __attribute__((__weak__));
|
||||
#endif /* ENABLE_GPROF */
|
||||
|
||||
MDBX_EXCLUDE_FOR_GPROF
|
||||
__cold static __attribute__((__constructor__)) void
|
||||
mdbx_global_constructor(void) {
|
||||
#ifdef ENABLE_GPROF
|
||||
if (!&__gmon_start__)
|
||||
monstartup((uintptr_t)&_init, (uintptr_t)&_fini);
|
||||
#endif /* ENABLE_GPROF */
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
struct utsname buffer;
|
||||
if (uname(&buffer) == 0) {
|
||||
@ -61,7 +76,7 @@ mdbx_global_constructor(void) {
|
||||
if (number > 0) {
|
||||
if (number > 255)
|
||||
number = 255;
|
||||
mdbx_linux_kernel_version += number << (24 - i * 8);
|
||||
linux_kernel_version += number << (24 - i * 8);
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
@ -81,12 +96,17 @@ mdbx_global_constructor(void) {
|
||||
}
|
||||
#endif /* Linux */
|
||||
|
||||
mdbx_rthc_global_init();
|
||||
global_ctor();
|
||||
}
|
||||
|
||||
MDBX_EXCLUDE_FOR_GPROF
|
||||
__cold static __attribute__((__destructor__)) void
|
||||
mdbx_global_destructor(void) {
|
||||
mdbx_rthc_global_dtor();
|
||||
global_dtor();
|
||||
#ifdef ENABLE_GPROF
|
||||
if (!&__gmon_start__)
|
||||
_mcleanup();
|
||||
#endif /* ENABLE_GPROF */
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@ -98,15 +118,15 @@ mdbx_global_destructor(void) {
|
||||
* размещаются совместно используемые posix-мьютексы (futex). Посредством
|
||||
* этих мьютексов (см struct MDBX_lockinfo) реализуются:
|
||||
* - Блокировка таблицы читателей для регистрации,
|
||||
* т.е. функции mdbx_rdt_lock() и mdbx_rdt_unlock().
|
||||
* т.е. функции osal_rdt_lock() и osal_rdt_unlock().
|
||||
* - Блокировка БД для пишущих транзакций,
|
||||
* т.е. функции mdbx_txn_lock() и mdbx_txn_unlock().
|
||||
*
|
||||
* Остальной функционал реализуется отдельно посредством файловых блокировок:
|
||||
* - Первоначальный захват БД в режиме exclusive/shared и последующий перевод
|
||||
* в операционный режим, функции mdbx_lck_seize() и mdbx_lck_downgrade().
|
||||
* в операционный режим, функции osal_lck_seize() и osal_lck_downgrade().
|
||||
* - Проверка присутствие процессов-читателей,
|
||||
* т.е. функции mdbx_rpid_set(), mdbx_rpid_clear() и mdbx_rpid_check().
|
||||
* т.е. функции osal_rpid_set(), osal_rpid_clear() и osal_rpid_check().
|
||||
*
|
||||
* Для блокировки файлов используется fcntl(F_SETLK), так как:
|
||||
* - lockf() оперирует только эксклюзивной блокировкой и требует
|
||||
@ -150,9 +170,9 @@ mdbx_global_destructor(void) {
|
||||
static int op_setlk, op_setlkw, op_getlk;
|
||||
__cold static void choice_fcntl(void) {
|
||||
assert(!op_setlk && !op_setlkw && !op_getlk);
|
||||
if ((mdbx_runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0
|
||||
if ((runtime_flags & MDBX_DBG_LEGACY_MULTIOPEN) == 0
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
&& mdbx_linux_kernel_version >
|
||||
&& linux_kernel_version >
|
||||
0x030f0000 /* OFD locks are available since 3.15, but engages here
|
||||
only for 3.16 and later kernels (i.e. LTS) because
|
||||
of reliability reasons */
|
||||
@ -182,7 +202,7 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck,
|
||||
"The bitness of system `off_t` type is mismatch. Please "
|
||||
"fix build and/or NDK configuration.");
|
||||
#endif /* Android */
|
||||
mdbx_jitter4testing(true);
|
||||
jitter4testing(true);
|
||||
assert(offset >= 0 && len > 0);
|
||||
assert((uint64_t)offset < (uint64_t)INT64_MAX &&
|
||||
(uint64_t)len < (uint64_t)INT64_MAX &&
|
||||
@ -208,7 +228,7 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck,
|
||||
lock_op.l_start = offset;
|
||||
lock_op.l_len = len;
|
||||
int rc = MDBX_FCNTL(fd, cmd, &lock_op);
|
||||
mdbx_jitter4testing(true);
|
||||
jitter4testing(true);
|
||||
if (rc != -1) {
|
||||
if (cmd == op_getlk) {
|
||||
/* Checks reader by pid. Returns:
|
||||
@ -243,7 +263,7 @@ static int lck_op(const mdbx_filehandle_t fd, int cmd, const int lck,
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
MDBX_INTERNAL_FUNC int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (unlikely(op_setlk == 0))
|
||||
choice_fcntl();
|
||||
@ -251,21 +271,21 @@ MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return lck_op(fd, wait ? op_setlkw : op_setlk, F_WRLCK, 0, OFF_T_MAX);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_set(MDBX_env *env) {
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_pid > 0);
|
||||
if (unlikely(mdbx_getpid() != env->me_pid))
|
||||
if (unlikely(osal_getpid() != env->me_pid))
|
||||
return MDBX_PANIC;
|
||||
return lck_op(env->me_lfd, op_setlk, F_WRLCK, env->me_pid, 1);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env) {
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_pid > 0);
|
||||
return lck_op(env->me_lfd, op_setlk, F_UNLCK, env->me_pid, 1);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
assert(pid > 0);
|
||||
return lck_op(env->me_lfd, op_getlk, F_WRLCK, pid, 1);
|
||||
@ -274,7 +294,7 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#if MDBX_LOCKING > MDBX_LOCKING_SYSV
|
||||
MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc) {
|
||||
MDBX_INTERNAL_FUNC int osal_ipclock_stub(osal_ipclock_t *ipc) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
return sem_init(ipc, false, 1) ? errno : 0;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \
|
||||
@ -285,7 +305,7 @@ MDBX_INTERNAL_FUNC int mdbx_ipclock_stub(mdbx_ipclock_t *ipc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_ipclock_destroy(mdbx_ipclock_t *ipc) {
|
||||
MDBX_INTERNAL_FUNC int osal_ipclock_destroy(osal_ipclock_t *ipc) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX1988
|
||||
return sem_destroy(ipc) ? errno : 0;
|
||||
#elif MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \
|
||||
@ -303,7 +323,7 @@ static int check_fstat(MDBX_env *env) {
|
||||
int rc = MDBX_SUCCESS;
|
||||
if (fstat(env->me_lazy_fd, &st)) {
|
||||
rc = errno;
|
||||
mdbx_error("fstat(%s), err %d", "DXB", rc);
|
||||
ERROR("fstat(%s), err %d", "DXB", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -313,15 +333,14 @@ static int check_fstat(MDBX_env *env) {
|
||||
#else
|
||||
rc = EPERM;
|
||||
#endif
|
||||
mdbx_error("%s %s, err %d", "DXB",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file",
|
||||
rc);
|
||||
ERROR("%s %s, err %d", "DXB",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (st.st_size < (off_t)(MDBX_MIN_PAGESIZE * NUM_METAS)) {
|
||||
mdbx_verbose("dxb-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
VERBOSE("dxb-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
@ -329,7 +348,7 @@ static int check_fstat(MDBX_env *env) {
|
||||
|
||||
if (fstat(env->me_lfd, &st)) {
|
||||
rc = errno;
|
||||
mdbx_error("fstat(%s), err %d", "LCK", rc);
|
||||
ERROR("fstat(%s), err %d", "LCK", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -339,26 +358,25 @@ static int check_fstat(MDBX_env *env) {
|
||||
#else
|
||||
rc = EPERM;
|
||||
#endif
|
||||
mdbx_error("%s %s, err %d", "LCK",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file",
|
||||
rc);
|
||||
ERROR("%s %s, err %d", "LCK",
|
||||
(st.st_nlink < 1) ? "file was removed" : "not a regular file", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Checking file size for detect the situation when we got the shared lock
|
||||
* immediately after mdbx_lck_destroy(). */
|
||||
* immediately after osal_lck_destroy(). */
|
||||
if (st.st_size < (off_t)(sizeof(MDBX_lockinfo) + sizeof(MDBX_reader))) {
|
||||
mdbx_verbose("lck-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
VERBOSE("lck-file is too short (%u), exclusive-lock needed",
|
||||
(unsigned)st.st_size);
|
||||
rc = MDBX_RESULT_TRUE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
__cold MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(mdbx_getpid() != env->me_pid))
|
||||
if (unlikely(osal_getpid() != env->me_pid))
|
||||
return MDBX_PANIC;
|
||||
#if MDBX_USE_OFDLOCKS
|
||||
if (unlikely(op_setlk == 0))
|
||||
@ -369,10 +387,10 @@ __cold MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
if (unlikely(mdbx_RunningOnWSL1)) {
|
||||
rc = ENOLCK /* No record locks available */;
|
||||
mdbx_error("%s, err %u",
|
||||
"WSL1 (Windows Subsystem for Linux) is mad and trouble-full, "
|
||||
"injecting failure to avoid data loss",
|
||||
rc);
|
||||
ERROR("%s, err %u",
|
||||
"WSL1 (Windows Subsystem for Linux) is mad and trouble-full, "
|
||||
"injecting failure to avoid data loss",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
#endif /* Linux */
|
||||
@ -383,8 +401,8 @@ __cold MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
lck_op(env->me_lazy_fd, op_setlk,
|
||||
(env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0, OFF_T_MAX);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "without-lck", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "without-lck", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
return MDBX_RESULT_TRUE /* Done: return with exclusive locking. */;
|
||||
@ -397,8 +415,8 @@ retry:
|
||||
if (rc == MDBX_RESULT_TRUE) {
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_UNLCK, 0, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "unlock-before-retry", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "unlock-before-retry", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@ -424,23 +442,23 @@ retry:
|
||||
/* the cause may be a collision with POSIX's file-lock recovery. */
|
||||
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK ||
|
||||
rc == EDEADLK)) {
|
||||
mdbx_error("%s, err %u", "dxb-exclusive", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "dxb-exclusive", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Fallback to lck-shared */
|
||||
} else if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY ||
|
||||
rc == EWOULDBLOCK || rc == EDEADLK)) {
|
||||
mdbx_error("%s, err %u", "try-exclusive", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "try-exclusive", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Here could be one of two:
|
||||
* - mdbx_lck_destroy() from the another process was hold the lock
|
||||
* - osal_lck_destroy() from the another process was hold the lock
|
||||
* during a destruction.
|
||||
* - either mdbx_lck_seize() from the another process was got the exclusive
|
||||
* - either osal_lck_seize() from the another process was got the exclusive
|
||||
* lock and doing initialization.
|
||||
* For distinguish these cases will use size of the lck-file later. */
|
||||
|
||||
@ -449,8 +467,8 @@ retry:
|
||||
* competing process doesn't call lck_downgrade(). */
|
||||
rc = lck_op(env->me_lfd, op_setlkw, F_RDLCK, 0, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "try-shared", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "try-shared", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -458,7 +476,7 @@ retry:
|
||||
if (rc == MDBX_RESULT_TRUE)
|
||||
goto retry;
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "lck_fstat", rc);
|
||||
ERROR("%s, err %u", "lck_fstat", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -469,8 +487,8 @@ retry:
|
||||
|
||||
if (!(rc == EAGAIN || rc == EACCES || rc == EBUSY || rc == EWOULDBLOCK ||
|
||||
rc == EDEADLK)) {
|
||||
mdbx_error("%s, err %u", "try-exclusive", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "try-exclusive", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -479,8 +497,8 @@ retry:
|
||||
lck_op(env->me_lazy_fd, op_setlk,
|
||||
(env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, env->me_pid, 1);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
mdbx_error("%s, err %u", "lock-against-without-lck", rc);
|
||||
mdbx_assert(env, MDBX_IS_ERROR(rc));
|
||||
ERROR("%s, err %u", "lock-against-without-lck", rc);
|
||||
eASSERT(env, MDBX_IS_ERROR(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -488,9 +506,9 @@ retry:
|
||||
return MDBX_RESULT_FALSE;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env) {
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
if (unlikely(mdbx_getpid() != env->me_pid))
|
||||
if (unlikely(osal_getpid() != env->me_pid))
|
||||
return MDBX_PANIC;
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
@ -503,15 +521,15 @@ MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
|
||||
if (rc == MDBX_SUCCESS)
|
||||
rc = lck_op(env->me_lfd, op_setlk, F_RDLCK, 0, 1);
|
||||
if (unlikely(rc != 0)) {
|
||||
mdbx_error("%s, err %u", "lck", rc);
|
||||
ERROR("%s, err %u", "lck", rc);
|
||||
assert(MDBX_IS_ERROR(rc));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
__cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
__cold MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor) {
|
||||
if (unlikely(mdbx_getpid() != env->me_pid))
|
||||
if (unlikely(osal_getpid() != env->me_pid))
|
||||
return MDBX_PANIC;
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
@ -526,25 +544,25 @@ __cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
(env->me_flags & MDBX_RDONLY) ? F_RDLCK : F_WRLCK, 0,
|
||||
OFF_T_MAX) == 0) {
|
||||
|
||||
mdbx_verbose("%p got exclusive, drown locks", (void *)env);
|
||||
VERBOSE("%p got exclusive, drown locks", (void *)env);
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
if (env->me_sysv_ipc.semid != -1)
|
||||
rc = semctl(env->me_sysv_ipc.semid, 2, IPC_RMID) ? errno : 0;
|
||||
#else
|
||||
rc = mdbx_ipclock_destroy(&lck->mti_rlock);
|
||||
rc = osal_ipclock_destroy(&lck->mti_rlock);
|
||||
if (rc == 0)
|
||||
rc = mdbx_ipclock_destroy(&lck->mti_wlock);
|
||||
rc = osal_ipclock_destroy(&lck->mti_wlock);
|
||||
#endif /* MDBX_LOCKING */
|
||||
|
||||
mdbx_assert(env, rc == 0);
|
||||
eASSERT(env, rc == 0);
|
||||
if (rc == 0) {
|
||||
const bool synced = lck->mti_unsynced_pages.weak == 0;
|
||||
mdbx_munmap(&env->me_lck_mmap);
|
||||
osal_munmap(&env->me_lck_mmap);
|
||||
if (synced)
|
||||
rc = ftruncate(env->me_lfd, 0) ? errno : 0;
|
||||
}
|
||||
|
||||
mdbx_jitter4testing(false);
|
||||
jitter4testing(false);
|
||||
}
|
||||
|
||||
/* 1) POSIX's fcntl() locks (i.e. when op_setlk == F_SETLK) should be restored
|
||||
@ -585,7 +603,7 @@ __cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
/* restore file-locks */
|
||||
rc = lck_op(inprocess_neighbor->me_lfd, F_SETLKW, F_RDLCK, 0, 1);
|
||||
if (rc == MDBX_SUCCESS && inprocess_neighbor->me_live_reader)
|
||||
rc = mdbx_rpid_set(inprocess_neighbor);
|
||||
rc = osal_rpid_set(inprocess_neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,7 +614,7 @@ __cold MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
__cold MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
|
||||
__cold MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor,
|
||||
int global_uniqueness_flag) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
@ -743,7 +761,7 @@ bailout:
|
||||
#endif /* MDBX_LOCKING > 0 */
|
||||
}
|
||||
|
||||
__cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
__cold static int mdbx_ipclock_failed(MDBX_env *env, osal_ipclock_t *ipc,
|
||||
const int err) {
|
||||
int rc = err;
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2008 || MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
@ -760,10 +778,10 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
rc = MDBX_PANIC;
|
||||
}
|
||||
}
|
||||
mdbx_warning("%clock owner died, %s", (rlocked ? 'r' : 'w'),
|
||||
(rc ? "this process' env is hosed" : "recovering"));
|
||||
WARNING("%clock owner died, %s", (rlocked ? 'r' : 'w'),
|
||||
(rc ? "this process' env is hosed" : "recovering"));
|
||||
|
||||
int check_rc = mdbx_cleanup_dead_readers(env, rlocked, NULL);
|
||||
int check_rc = cleanup_dead_readers(env, rlocked, NULL);
|
||||
check_rc = (check_rc == MDBX_SUCCESS) ? MDBX_RESULT_TRUE : check_rc;
|
||||
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_SYSV
|
||||
@ -781,7 +799,7 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
check_rc = (mreco_rc == 0) ? check_rc : mreco_rc;
|
||||
|
||||
if (unlikely(mreco_rc))
|
||||
mdbx_error("lock recovery failed, %s", mdbx_strerror(mreco_rc));
|
||||
ERROR("lock recovery failed, %s", mdbx_strerror(mreco_rc));
|
||||
|
||||
rc = (rc == MDBX_SUCCESS) ? check_rc : rc;
|
||||
if (MDBX_IS_ERROR(rc))
|
||||
@ -804,24 +822,24 @@ __cold static int mdbx_ipclock_failed(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
#error "FIXME"
|
||||
#endif /* MDBX_LOCKING */
|
||||
|
||||
mdbx_error("mutex (un)lock failed, %s", mdbx_strerror(err));
|
||||
ERROR("mutex (un)lock failed, %s", mdbx_strerror(err));
|
||||
if (rc != EDEADLK)
|
||||
env->me_flags |= MDBX_FATAL_ERROR;
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
|
||||
MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void) {
|
||||
MDBX_INTERNAL_FUNC 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();
|
||||
if (unlikely(tid > 0xffff)) {
|
||||
mdbx_fatal("Raise the ENOSYS(%d) error to avoid hang due "
|
||||
"the 32-bit Bionic/Android bug with tid/thread_id 0x%08x(%i) "
|
||||
"that don’t fit in 16 bits, see "
|
||||
"https://android.googlesource.com/platform/bionic/+/master/"
|
||||
"docs/32-bit-abi.md#is-too-small-for-large-pids",
|
||||
ENOSYS, tid, tid);
|
||||
FATAL("Raise the ENOSYS(%d) error to avoid hang due "
|
||||
"the 32-bit Bionic/Android bug with tid/thread_id 0x%08x(%i) "
|
||||
"that don’t fit in 16 bits, see "
|
||||
"https://android.googlesource.com/platform/bionic/+/master/"
|
||||
"docs/32-bit-abi.md#is-too-small-for-large-pids",
|
||||
ENOSYS, tid, tid);
|
||||
return ENOSYS;
|
||||
}
|
||||
}
|
||||
@ -829,11 +847,11 @@ MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void) {
|
||||
}
|
||||
#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
|
||||
|
||||
static int mdbx_ipclock_lock(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
static int mdbx_ipclock_lock(MDBX_env *env, osal_ipclock_t *ipc,
|
||||
const bool dont_wait) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \
|
||||
MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
int rc = mdbx_check_tid4bionic();
|
||||
int rc = osal_check_tid4bionic();
|
||||
if (likely(rc == 0))
|
||||
rc = dont_wait ? pthread_mutex_trylock(ipc) : pthread_mutex_lock(ipc);
|
||||
rc = (rc == EBUSY && dont_wait) ? MDBX_BUSY : rc;
|
||||
@ -869,7 +887,7 @@ static int mdbx_ipclock_lock(MDBX_env *env, mdbx_ipclock_t *ipc,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdbx_ipclock_unlock(MDBX_env *env, mdbx_ipclock_t *ipc) {
|
||||
static int mdbx_ipclock_unlock(MDBX_env *env, osal_ipclock_t *ipc) {
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_POSIX2001 || \
|
||||
MDBX_LOCKING == MDBX_LOCKING_POSIX2008
|
||||
int rc = pthread_mutex_unlock(ipc);
|
||||
@ -891,38 +909,38 @@ static int mdbx_ipclock_unlock(MDBX_env *env, mdbx_ipclock_t *ipc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env) {
|
||||
mdbx_trace("%s", ">>");
|
||||
mdbx_jitter4testing(true);
|
||||
MDBX_INTERNAL_FUNC int osal_rdt_lock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
jitter4testing(true);
|
||||
int rc = mdbx_ipclock_lock(env, &env->me_lck->mti_rlock, false);
|
||||
mdbx_trace("<< rc %d", rc);
|
||||
TRACE("<< rc %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
|
||||
mdbx_trace("%s", ">>");
|
||||
MDBX_INTERNAL_FUNC void osal_rdt_unlock(MDBX_env *env) {
|
||||
TRACE("%s", ">>");
|
||||
int rc = mdbx_ipclock_unlock(env, &env->me_lck->mti_rlock);
|
||||
mdbx_trace("<< rc %d", rc);
|
||||
TRACE("<< rc %d", rc);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
mdbx_panic("%s() failed: err %d\n", __func__, rc);
|
||||
mdbx_jitter4testing(true);
|
||||
jitter4testing(true);
|
||||
}
|
||||
|
||||
int mdbx_txn_lock(MDBX_env *env, bool dont_wait) {
|
||||
mdbx_trace("%swait %s", dont_wait ? "dont-" : "", ">>");
|
||||
mdbx_jitter4testing(true);
|
||||
TRACE("%swait %s", dont_wait ? "dont-" : "", ">>");
|
||||
jitter4testing(true);
|
||||
int rc = mdbx_ipclock_lock(env, &env->me_lck->mti_wlock, dont_wait);
|
||||
mdbx_trace("<< rc %d", rc);
|
||||
TRACE("<< rc %d", rc);
|
||||
return MDBX_IS_ERROR(rc) ? rc : MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
void mdbx_txn_unlock(MDBX_env *env) {
|
||||
mdbx_trace("%s", ">>");
|
||||
TRACE("%s", ">>");
|
||||
int rc = mdbx_ipclock_unlock(env, &env->me_lck->mti_wlock);
|
||||
mdbx_trace("<< rc %d", rc);
|
||||
TRACE("<< rc %d", rc);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
mdbx_panic("%s() failed: err %d\n", __func__, rc);
|
||||
mdbx_jitter4testing(true);
|
||||
jitter4testing(true);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -48,16 +48,16 @@ static
|
||||
switch (reason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
mdbx_winnt_import();
|
||||
mdbx_rthc_global_init();
|
||||
global_ctor();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
mdbx_rthc_global_dtor();
|
||||
global_dtor();
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
mdbx_rthc_thread_dtor(module);
|
||||
thread_dtor(module);
|
||||
break;
|
||||
}
|
||||
#if MDBX_BUILD_SHARED_LIBRARY
|
||||
@ -112,32 +112,71 @@ static
|
||||
#define LCK_WAITFOR 0
|
||||
#define LCK_DONTWAIT LOCKFILE_FAIL_IMMEDIATELY
|
||||
|
||||
static __inline BOOL flock(mdbx_filehandle_t fd, DWORD flags, uint64_t offset,
|
||||
size_t bytes) {
|
||||
static int flock_with_event(HANDLE fd, HANDLE event, unsigned flags,
|
||||
size_t offset, size_t bytes) {
|
||||
TRACE("lock>>: fd %p, event %p, flags 0x%x offset %zu, bytes %zu >>", fd,
|
||||
event, flags, offset, bytes);
|
||||
OVERLAPPED ov;
|
||||
ov.hEvent = 0;
|
||||
ov.Internal = 0;
|
||||
ov.InternalHigh = 0;
|
||||
ov.hEvent = event;
|
||||
ov.Offset = (DWORD)offset;
|
||||
ov.OffsetHigh = HIGH_DWORD(offset);
|
||||
return LockFileEx(fd, flags, 0, (DWORD)bytes, HIGH_DWORD(bytes), &ov);
|
||||
if (LockFileEx(fd, flags, 0, (DWORD)bytes, HIGH_DWORD(bytes), &ov)) {
|
||||
TRACE("lock<<: fd %p, event %p, flags 0x%x offset %zu, bytes %zu << %s", fd,
|
||||
event, flags, offset, bytes, "done");
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD rc = GetLastError();
|
||||
if (rc == ERROR_IO_PENDING) {
|
||||
if (event) {
|
||||
if (GetOverlappedResult(fd, &ov, &rc, true)) {
|
||||
TRACE("lock<<: fd %p, event %p, flags 0x%x offset %zu, bytes %zu << %s",
|
||||
fd, event, flags, offset, bytes, "overlapped-done");
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
rc = GetLastError();
|
||||
} else
|
||||
CancelIo(fd);
|
||||
}
|
||||
TRACE("lock<<: fd %p, event %p, flags 0x%x offset %zu, bytes %zu << err %d",
|
||||
fd, event, flags, offset, bytes, (int)rc);
|
||||
return (int)rc;
|
||||
}
|
||||
|
||||
static __inline BOOL funlock(mdbx_filehandle_t fd, uint64_t offset,
|
||||
size_t bytes) {
|
||||
static __inline int flock(HANDLE fd, unsigned flags, size_t offset,
|
||||
size_t bytes) {
|
||||
return flock_with_event(fd, 0, flags, offset, bytes);
|
||||
}
|
||||
|
||||
static __inline int flock_data(const MDBX_env *env, unsigned flags,
|
||||
size_t offset, size_t bytes) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
return flock_with_event(fd4data, env->me_data_lock_event, flags, offset,
|
||||
bytes);
|
||||
}
|
||||
|
||||
static int funlock(mdbx_filehandle_t fd, size_t offset, size_t bytes) {
|
||||
TRACE("unlock: fd %p, offset %zu, bytes %zu", fd, offset, bytes);
|
||||
return UnlockFile(fd, (DWORD)offset, HIGH_DWORD(offset), (DWORD)bytes,
|
||||
HIGH_DWORD(bytes));
|
||||
HIGH_DWORD(bytes))
|
||||
? MDBX_SUCCESS
|
||||
: (int)GetLastError();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* global `write` lock for write-txt processing,
|
||||
* exclusive locking both meta-pages) */
|
||||
|
||||
#define LCK_MAXLEN (1u + ((~(size_t)0) >> 1))
|
||||
#define LCK_META_OFFSET 0
|
||||
#define LCK_META_LEN (MAX_PAGESIZE * NUM_METAS)
|
||||
#define LCK_BODY_OFFSET LCK_META_LEN
|
||||
#define LCK_BODY_LEN (LCK_MAXLEN - LCK_BODY_OFFSET)
|
||||
#define LCK_BODY LCK_BODY_OFFSET, LCK_BODY_LEN
|
||||
#define LCK_WHOLE 0, LCK_MAXLEN
|
||||
#ifdef _WIN64
|
||||
#define DXB_MAXLEN UINT64_C(0x7fffFFFFfff00000)
|
||||
#else
|
||||
#define DXB_MAXLEN UINT32_C(0x7ff00000)
|
||||
#endif
|
||||
#define DXB_BODY (env->me_psize * (size_t)NUM_METAS), DXB_MAXLEN
|
||||
#define DXB_WHOLE 0, DXB_MAXLEN
|
||||
|
||||
int mdbx_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
if (dontwait) {
|
||||
@ -155,38 +194,49 @@ int mdbx_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) ||
|
||||
flock(env->me_lazy_fd,
|
||||
dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT)
|
||||
: (LCK_EXCLUSIVE | LCK_WAITFOR),
|
||||
LCK_BODY))
|
||||
if (env->me_flags & MDBX_EXCLUSIVE) {
|
||||
/* Zap: Failing to release lock 'env->me_windowsbug_lock'
|
||||
* in function 'mdbx_txn_lock' */
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(26115);
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
int rc = (int)GetLastError();
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
int rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
dontwait ? (LCK_EXCLUSIVE | LCK_DONTWAIT)
|
||||
: (LCK_EXCLUSIVE | LCK_WAITFOR),
|
||||
DXB_BODY);
|
||||
if (rc == ERROR_LOCK_VIOLATION && dontwait) {
|
||||
SleepEx(0, true);
|
||||
if (flock(env->me_lazy_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY))
|
||||
return MDBX_SUCCESS;
|
||||
rc = (int)GetLastError();
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
if (rc == ERROR_LOCK_VIOLATION) {
|
||||
SleepEx(0, true);
|
||||
if (flock(env->me_lazy_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY))
|
||||
return MDBX_SUCCESS;
|
||||
rc = (int)GetLastError();
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
}
|
||||
}
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
/* Zap: Failing to release lock 'env->me_windowsbug_lock'
|
||||
* in function 'mdbx_txn_lock' */
|
||||
MDBX_SUPPRESS_GOOFY_MSVC_ANALYZER(26115);
|
||||
return rc;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&env->me_windowsbug_lock);
|
||||
return (!dontwait || rc != ERROR_LOCK_VIOLATION) ? rc : MDBX_BUSY;
|
||||
}
|
||||
|
||||
void mdbx_txn_unlock(MDBX_env *env) {
|
||||
int rc = (env->me_flags & MDBX_EXCLUSIVE)
|
||||
? TRUE
|
||||
: funlock(env->me_lazy_fd, LCK_BODY);
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) == 0) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
int err = funlock(fd4data, DXB_BODY);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
LeaveCriticalSection(&env->me_windowsbug_lock);
|
||||
if (!rc)
|
||||
mdbx_panic("%s failed: err %u", __func__, (int)GetLastError());
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@ -200,56 +250,57 @@ void mdbx_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_FUNC int mdbx_rdt_lock(MDBX_env *env) {
|
||||
mdbx_srwlock_AcquireShared(&env->me_remap_guard);
|
||||
MDBX_INTERNAL_FUNC int osal_rdt_lock(MDBX_env *env) {
|
||||
osal_srwlock_AcquireShared(&env->me_remap_guard);
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE)
|
||||
return MDBX_SUCCESS; /* readonly database in readonly filesystem */
|
||||
|
||||
/* transition from S-? (used) to S-E (locked),
|
||||
* e.g. exclusive lock upper-part */
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) ||
|
||||
flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER))
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS;
|
||||
|
||||
int rc = (int)GetLastError();
|
||||
mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
int rc = flock(env->me_lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
return MDBX_SUCCESS;
|
||||
|
||||
osal_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env) {
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE) {
|
||||
MDBX_INTERNAL_FUNC void osal_rdt_unlock(MDBX_env *env) {
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE &&
|
||||
(env->me_flags & MDBX_EXCLUSIVE) == 0) {
|
||||
/* transition from S-E (locked) to S-? (used), e.g. unlock upper-part */
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) == 0 &&
|
||||
!funlock(env->me_lfd, LCK_UPPER))
|
||||
mdbx_panic("%s failed: err %u", __func__, (int)GetLastError());
|
||||
int err = funlock(env->me_lfd, LCK_UPPER);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s failed: err %u", __func__, err);
|
||||
}
|
||||
mdbx_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
osal_srwlock_ReleaseShared(&env->me_remap_guard);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return flock(fd,
|
||||
wait ? LCK_EXCLUSIVE | LCK_WAITFOR
|
||||
: LCK_EXCLUSIVE | LCK_DONTWAIT,
|
||||
0, LCK_MAXLEN)
|
||||
? MDBX_SUCCESS
|
||||
: (int)GetLastError();
|
||||
MDBX_INTERNAL_FUNC int osal_lockfile(mdbx_filehandle_t fd, bool wait) {
|
||||
return flock(
|
||||
fd, wait ? LCK_EXCLUSIVE | LCK_WAITFOR : LCK_EXCLUSIVE | LCK_DONTWAIT, 0,
|
||||
DXB_MAXLEN);
|
||||
}
|
||||
|
||||
static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
const DWORD ThreadId) {
|
||||
const unsigned limit = (*array)->limit;
|
||||
if ((*array)->count == limit) {
|
||||
void *ptr = mdbx_realloc(
|
||||
(limit > ARRAY_LENGTH((*array)->handles))
|
||||
? *array
|
||||
: /* don't free initial array on the stack */ NULL,
|
||||
sizeof(mdbx_handle_array_t) +
|
||||
sizeof(HANDLE) * (limit * 2 - ARRAY_LENGTH((*array)->handles)));
|
||||
mdbx_handle_array_t *const ptr =
|
||||
osal_realloc((limit > ARRAY_LENGTH((*array)->handles))
|
||||
? *array
|
||||
: /* don't free initial array on the stack */ NULL,
|
||||
sizeof(mdbx_handle_array_t) +
|
||||
sizeof(HANDLE) * (limit * (size_t)2 -
|
||||
ARRAY_LENGTH((*array)->handles)));
|
||||
if (!ptr)
|
||||
return MDBX_ENOMEM;
|
||||
if (limit == ARRAY_LENGTH((*array)->handles))
|
||||
memcpy(ptr, *array, sizeof(mdbx_handle_array_t));
|
||||
*array = (mdbx_handle_array_t *)ptr;
|
||||
*ptr = **array;
|
||||
*array = ptr;
|
||||
(*array)->limit = limit * 2;
|
||||
}
|
||||
|
||||
@ -273,8 +324,8 @@ static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
mdbx_assert(env, (env->me_flags & MDBX_NOTLS) == 0);
|
||||
osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
eASSERT(env, (env->me_flags & MDBX_NOTLS) == 0);
|
||||
const uintptr_t CurrentTid = GetCurrentThreadId();
|
||||
int rc;
|
||||
if (env->me_lck_mmap.lck) {
|
||||
@ -296,7 +347,7 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
rc = suspend_and_append(array, (mdbx_tid_t)reader->mr_tid.weak);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
bailout_lck:
|
||||
(void)mdbx_resume_threads_after_remap(*array);
|
||||
(void)osal_resume_threads_after_remap(*array);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@ -308,7 +359,7 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
} else {
|
||||
/* Without LCK (i.e. read-only mode).
|
||||
* Walk through a snapshot of all running threads */
|
||||
mdbx_assert(env, env->me_flags & (MDBX_EXCLUSIVE | MDBX_RDONLY));
|
||||
eASSERT(env, env->me_flags & (MDBX_EXCLUSIVE | MDBX_RDONLY));
|
||||
const HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnapshot == INVALID_HANDLE_VALUE)
|
||||
return (int)GetLastError();
|
||||
@ -320,7 +371,7 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
rc = (int)GetLastError();
|
||||
bailout_toolhelp:
|
||||
CloseHandle(hSnapshot);
|
||||
(void)mdbx_resume_threads_after_remap(*array);
|
||||
(void)osal_resume_threads_after_remap(*array);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -345,7 +396,7 @@ mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array) {
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
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];
|
||||
@ -384,11 +435,11 @@ mdbx_resume_threads_after_remap(mdbx_handle_array_t *array) {
|
||||
* E-S
|
||||
* E-E = exclusive-write, i.e. exclusive due (re)initialization
|
||||
*
|
||||
* The mdbx_lck_seize() moves the locking-FSM from the initial free/unlocked
|
||||
* The osal_lck_seize() moves the locking-FSM from the initial free/unlocked
|
||||
* state to the "exclusive write" (and returns MDBX_RESULT_TRUE) if possible,
|
||||
* or to the "used" (and returns MDBX_RESULT_FALSE).
|
||||
*
|
||||
* The mdbx_lck_downgrade() moves the locking-FSM from "exclusive write"
|
||||
* The osal_lck_downgrade() moves the locking-FSM from "exclusive write"
|
||||
* state to the "used" (i.e. shared) state.
|
||||
*
|
||||
* The mdbx_lck_upgrade() moves the locking-FSM from "used" (i.e. shared)
|
||||
@ -400,40 +451,38 @@ static void lck_unlock(MDBX_env *env) {
|
||||
|
||||
if (env->me_lfd != INVALID_HANDLE_VALUE) {
|
||||
/* double `unlock` for robustly remove overlapped shared/exclusive locks */
|
||||
while (funlock(env->me_lfd, LCK_LOWER))
|
||||
;
|
||||
err = (int)GetLastError();
|
||||
do
|
||||
err = funlock(env->me_lfd, LCK_LOWER);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(void)err;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
while (funlock(env->me_lfd, LCK_UPPER))
|
||||
;
|
||||
err = (int)GetLastError();
|
||||
do
|
||||
err = funlock(env->me_lfd, LCK_UPPER);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(void)err;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
if (env->me_lazy_fd != INVALID_HANDLE_VALUE) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
if (fd4data != INVALID_HANDLE_VALUE) {
|
||||
/* explicitly unlock to avoid latency for other processes (windows kernel
|
||||
* releases such locks via deferred queues) */
|
||||
while (funlock(env->me_lazy_fd, LCK_BODY))
|
||||
;
|
||||
err = (int)GetLastError();
|
||||
do
|
||||
err = funlock(fd4data, DXB_BODY);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(void)err;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
while (funlock(env->me_lazy_fd, LCK_WHOLE))
|
||||
;
|
||||
err = (int)GetLastError();
|
||||
do
|
||||
err = funlock(fd4data, DXB_WHOLE);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
(void)err;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
}
|
||||
}
|
||||
@ -442,56 +491,57 @@ static void lck_unlock(MDBX_env *env) {
|
||||
* or as 'used' (S-? and returns MDBX_RESULT_FALSE).
|
||||
* Otherwise returns an error. */
|
||||
static int internal_seize_lck(HANDLE lfd) {
|
||||
int rc;
|
||||
assert(lfd != INVALID_HANDLE_VALUE);
|
||||
|
||||
/* 1) now on ?-? (free), get ?-E (middle) */
|
||||
mdbx_jitter4testing(false);
|
||||
if (!flock(lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER)) {
|
||||
rc = (int)GetLastError() /* 2) something went wrong, give up */;
|
||||
mdbx_error("%s, err %u", "?-?(free) >> ?-E(middle)", rc);
|
||||
jitter4testing(false);
|
||||
int rc = flock(lfd, LCK_EXCLUSIVE | LCK_WAITFOR, LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
/* 2) something went wrong, give up */;
|
||||
ERROR("%s, err %u", "?-?(free) >> ?-E(middle)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3) now on ?-E (middle), try E-E (exclusive-write) */
|
||||
mdbx_jitter4testing(false);
|
||||
if (flock(lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER))
|
||||
jitter4testing(false);
|
||||
rc = flock(lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
return MDBX_RESULT_TRUE /* 4) got E-E (exclusive-write), done */;
|
||||
|
||||
/* 5) still on ?-E (middle) */
|
||||
rc = (int)GetLastError();
|
||||
mdbx_jitter4testing(false);
|
||||
jitter4testing(false);
|
||||
if (rc != ERROR_SHARING_VIOLATION && rc != ERROR_LOCK_VIOLATION) {
|
||||
/* 6) something went wrong, give up */
|
||||
if (!funlock(lfd, LCK_UPPER))
|
||||
rc = funlock(lfd, LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "?-E(middle) >> ?-?(free)",
|
||||
(int)GetLastError());
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 7) still on ?-E (middle), try S-E (locked) */
|
||||
mdbx_jitter4testing(false);
|
||||
rc = flock(lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER) ? MDBX_RESULT_FALSE
|
||||
: (int)GetLastError();
|
||||
jitter4testing(false);
|
||||
rc = flock(lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER);
|
||||
|
||||
mdbx_jitter4testing(false);
|
||||
if (rc != MDBX_RESULT_FALSE)
|
||||
mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
jitter4testing(false);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
ERROR("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
|
||||
/* 8) now on S-E (locked) or still on ?-E (middle),
|
||||
* transition to S-? (used) or ?-? (free) */
|
||||
if (!funlock(lfd, LCK_UPPER))
|
||||
int err = funlock(lfd, LCK_UPPER);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"X-E(locked/middle) >> X-?(used/free)", (int)GetLastError());
|
||||
"X-E(locked/middle) >> X-?(used/free)", err);
|
||||
|
||||
/* 9) now on S-? (used, DONE) or ?-? (free, FAILURE) */
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
int rc;
|
||||
|
||||
assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
|
||||
MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_RESULT_TRUE /* nope since files were must be opened
|
||||
non-shareable */
|
||||
@ -499,17 +549,15 @@ MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
|
||||
if (env->me_lfd == INVALID_HANDLE_VALUE) {
|
||||
/* LY: without-lck mode (e.g. on read-only filesystem) */
|
||||
mdbx_jitter4testing(false);
|
||||
if (!flock(env->me_lazy_fd, LCK_SHARED | LCK_DONTWAIT, LCK_WHOLE)) {
|
||||
rc = (int)GetLastError();
|
||||
mdbx_error("%s, err %u", "without-lck", rc);
|
||||
return rc;
|
||||
}
|
||||
return MDBX_RESULT_FALSE;
|
||||
jitter4testing(false);
|
||||
int rc = flock_data(env, LCK_SHARED | LCK_DONTWAIT, DXB_WHOLE);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
ERROR("%s, err %u", "without-lck", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = internal_seize_lck(env->me_lfd);
|
||||
mdbx_jitter4testing(false);
|
||||
int rc = internal_seize_lck(env->me_lfd);
|
||||
jitter4testing(false);
|
||||
if (rc == MDBX_RESULT_TRUE && (env->me_flags & MDBX_RDONLY) == 0) {
|
||||
/* Check that another process don't operates in without-lck mode.
|
||||
* Doing such check by exclusive locking the body-part of db. Should be
|
||||
@ -517,46 +565,52 @@ MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env) {
|
||||
* - we need an exclusive lock for do so;
|
||||
* - we can't lock meta-pages, otherwise other process could get an error
|
||||
* while opening db in valid (non-conflict) mode. */
|
||||
if (!flock(env->me_lazy_fd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_BODY)) {
|
||||
rc = (int)GetLastError();
|
||||
mdbx_error("%s, err %u", "lock-against-without-lck", rc);
|
||||
mdbx_jitter4testing(false);
|
||||
int err = flock_data(env, LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_WHOLE);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
ERROR("%s, err %u", "lock-against-without-lck", err);
|
||||
jitter4testing(false);
|
||||
lck_unlock(env);
|
||||
} else {
|
||||
mdbx_jitter4testing(false);
|
||||
if (!funlock(env->me_lazy_fd, LCK_BODY))
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"unlock-against-without-lck", (int)GetLastError());
|
||||
return err;
|
||||
}
|
||||
jitter4testing(false);
|
||||
err = funlock(fd4data, DXB_WHOLE);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"unlock-against-without-lck", err);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env) {
|
||||
const HANDLE fd4data =
|
||||
env->me_overlapped_fd ? env->me_overlapped_fd : env->me_lazy_fd;
|
||||
/* Transite from exclusive-write state (E-E) to used (S-?) */
|
||||
assert(env->me_lazy_fd != INVALID_HANDLE_VALUE);
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
|
||||
;
|
||||
/* 1) now at E-E (exclusive-write), transition to ?_E (middle) */
|
||||
if (!funlock(env->me_lfd, LCK_LOWER))
|
||||
int rc = funlock(env->me_lfd, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"E-E(exclusive-write) >> ?-E(middle)", (int)GetLastError());
|
||||
"E-E(exclusive-write) >> ?-E(middle)", rc);
|
||||
|
||||
/* 2) now at ?-E (middle), transition to S-E (locked) */
|
||||
if (!flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER)) {
|
||||
int rc = (int)GetLastError() /* 3) something went wrong, give up */;
|
||||
mdbx_error("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
rc = flock(env->me_lfd, LCK_SHARED | LCK_DONTWAIT, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
/* 3) something went wrong, give up */;
|
||||
ERROR("%s, err %u", "?-E(middle) >> S-E(locked)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 4) got S-E (locked), continue transition to S-? (used) */
|
||||
if (!funlock(env->me_lfd, LCK_UPPER))
|
||||
rc = funlock(env->me_lfd, LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> S-?(used)",
|
||||
(int)GetLastError());
|
||||
rc);
|
||||
|
||||
return MDBX_SUCCESS /* 5) now at S-? (used), done */;
|
||||
}
|
||||
@ -569,53 +623,72 @@ MDBX_INTERNAL_FUNC int mdbx_lck_upgrade(MDBX_env *env) {
|
||||
return MDBX_SUCCESS /* nope since files were must be opened non-shareable */
|
||||
;
|
||||
|
||||
int rc;
|
||||
/* 1) now on S-? (used), try S-E (locked) */
|
||||
mdbx_jitter4testing(false);
|
||||
if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_UPPER)) {
|
||||
rc = (int)GetLastError() /* 2) something went wrong, give up */;
|
||||
mdbx_verbose("%s, err %u", "S-?(used) >> S-E(locked)", rc);
|
||||
jitter4testing(false);
|
||||
int rc = flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_UPPER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
/* 2) something went wrong, give up */;
|
||||
VERBOSE("%s, err %u", "S-?(used) >> S-E(locked)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3) now on S-E (locked), transition to ?-E (middle) */
|
||||
if (!funlock(env->me_lfd, LCK_LOWER))
|
||||
rc = funlock(env->me_lfd, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__, "S-E(locked) >> ?-E(middle)",
|
||||
(int)GetLastError());
|
||||
rc);
|
||||
|
||||
/* 4) now on ?-E (middle), try E-E (exclusive-write) */
|
||||
mdbx_jitter4testing(false);
|
||||
if (!flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER)) {
|
||||
rc = (int)GetLastError() /* 5) something went wrong, give up */;
|
||||
mdbx_verbose("%s, err %u", "?-E(middle) >> E-E(exclusive-write)", rc);
|
||||
jitter4testing(false);
|
||||
rc = flock(env->me_lfd, LCK_EXCLUSIVE | LCK_DONTWAIT, LCK_LOWER);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
/* 5) something went wrong, give up */;
|
||||
VERBOSE("%s, err %u", "?-E(middle) >> E-E(exclusive-write)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return MDBX_SUCCESS /* 6) now at E-E (exclusive-write), done */;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
|
||||
MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor,
|
||||
int global_uniqueness_flag) {
|
||||
(void)env;
|
||||
(void)inprocess_neighbor;
|
||||
(void)global_uniqueness_flag;
|
||||
if (mdbx_SetFileIoOverlappedRange && !(env->me_flags & MDBX_RDONLY)) {
|
||||
HANDLE token = INVALID_HANDLE_VALUE;
|
||||
TOKEN_PRIVILEGES privileges;
|
||||
privileges.PrivilegeCount = 1;
|
||||
privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
|
||||
&token) ||
|
||||
!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
|
||||
&privileges.Privileges[0].Luid) ||
|
||||
!AdjustTokenPrivileges(token, FALSE, &privileges, sizeof(privileges),
|
||||
nullptr, nullptr) ||
|
||||
GetLastError() != ERROR_SUCCESS)
|
||||
mdbx_SetFileIoOverlappedRange = NULL;
|
||||
|
||||
if (token != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(token);
|
||||
}
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor) {
|
||||
/* LY: should unmap before releasing the locks to avoid race condition and
|
||||
* STATUS_USER_MAPPED_FILE/ERROR_USER_MAPPED_FILE */
|
||||
if (env->me_map)
|
||||
mdbx_munmap(&env->me_dxb_mmap);
|
||||
osal_munmap(&env->me_dxb_mmap);
|
||||
if (env->me_lck_mmap.lck) {
|
||||
const bool synced = env->me_lck_mmap.lck->mti_unsynced_pages.weak == 0;
|
||||
mdbx_munmap(&env->me_lck_mmap);
|
||||
osal_munmap(&env->me_lck_mmap);
|
||||
if (synced && !inprocess_neighbor && env->me_lfd != INVALID_HANDLE_VALUE &&
|
||||
mdbx_lck_upgrade(env) == MDBX_SUCCESS)
|
||||
/* this will fail if LCK is used/mmapped by other process(es) */
|
||||
mdbx_ftruncate(env->me_lfd, 0);
|
||||
osal_ftruncate(env->me_lfd, 0);
|
||||
}
|
||||
lck_unlock(env);
|
||||
return MDBX_SUCCESS;
|
||||
@ -624,12 +697,12 @@ MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* reader checking (by pid) */
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_set(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env) {
|
||||
(void)env;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
@ -640,7 +713,7 @@ MDBX_INTERNAL_FUNC int mdbx_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_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
(void)env;
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
int rc;
|
||||
@ -677,18 +750,18 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid) {
|
||||
// Stub for slim read-write lock
|
||||
// Copyright (C) 1995-2002 Brad Wilson
|
||||
|
||||
static void WINAPI stub_srwlock_Init(MDBX_srwlock *srwl) {
|
||||
static void WINAPI stub_srwlock_Init(osal_srwlock_t *srwl) {
|
||||
srwl->readerCount = srwl->writerCount = 0;
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_AcquireShared(MDBX_srwlock *srwl) {
|
||||
static void WINAPI stub_srwlock_AcquireShared(osal_srwlock_t *srwl) {
|
||||
while (true) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -702,23 +775,23 @@ static void WINAPI stub_srwlock_AcquireShared(MDBX_srwlock *srwl) {
|
||||
|
||||
// Remove from the readers list, spin, try again
|
||||
_InterlockedDecrement(&srwl->readerCount);
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_ReleaseShared(MDBX_srwlock *srwl) {
|
||||
static void WINAPI stub_srwlock_ReleaseShared(osal_srwlock_t *srwl) {
|
||||
assert(srwl->readerCount > 0);
|
||||
_InterlockedDecrement(&srwl->readerCount);
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_AcquireExclusive(MDBX_srwlock *srwl) {
|
||||
static void WINAPI stub_srwlock_AcquireExclusive(osal_srwlock_t *srwl) {
|
||||
while (true) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -733,11 +806,11 @@ static void WINAPI stub_srwlock_AcquireExclusive(MDBX_srwlock *srwl) {
|
||||
// that we're the writer.
|
||||
while (srwl->readerCount != 0) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
static void WINAPI stub_srwlock_ReleaseExclusive(MDBX_srwlock *srwl) {
|
||||
static void WINAPI stub_srwlock_ReleaseExclusive(osal_srwlock_t *srwl) {
|
||||
assert(srwl->writerCount == 1 && srwl->readerCount >= 0);
|
||||
srwl->writerCount = 0;
|
||||
}
|
||||
@ -753,9 +826,9 @@ static uint64_t WINAPI stub_GetTickCount64(void) {
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef xMDBX_ALLOY
|
||||
MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared,
|
||||
mdbx_srwlock_ReleaseShared, mdbx_srwlock_AcquireExclusive,
|
||||
mdbx_srwlock_ReleaseExclusive;
|
||||
osal_srwlock_t_function osal_srwlock_Init, osal_srwlock_AcquireShared,
|
||||
osal_srwlock_ReleaseShared, osal_srwlock_AcquireExclusive,
|
||||
osal_srwlock_ReleaseExclusive;
|
||||
|
||||
MDBX_NtExtendSection mdbx_NtExtendSection;
|
||||
MDBX_GetFileInformationByHandleEx mdbx_GetFileInformationByHandleEx;
|
||||
@ -766,6 +839,7 @@ MDBX_NtFsControlFile mdbx_NtFsControlFile;
|
||||
MDBX_PrefetchVirtualMemory mdbx_PrefetchVirtualMemory;
|
||||
MDBX_GetTickCount64 mdbx_GetTickCount64;
|
||||
MDBX_RegGetValueA mdbx_RegGetValueA;
|
||||
MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange;
|
||||
#endif /* xMDBX_ALLOY */
|
||||
|
||||
#if __GNUC_PREREQ(8, 0)
|
||||
@ -774,54 +848,63 @@ MDBX_RegGetValueA mdbx_RegGetValueA;
|
||||
#endif /* GCC/MINGW */
|
||||
|
||||
static void mdbx_winnt_import(void) {
|
||||
const HINSTANCE hNtdll = GetModuleHandleA("ntdll.dll");
|
||||
|
||||
#define GET_PROC_ADDR(dll, ENTRY) \
|
||||
mdbx_##ENTRY = (MDBX_##ENTRY)GetProcAddress(dll, #ENTRY)
|
||||
|
||||
if (GetProcAddress(hNtdll, "wine_get_version")) {
|
||||
assert(mdbx_RunningUnderWine());
|
||||
} else {
|
||||
GET_PROC_ADDR(hNtdll, NtFsControlFile);
|
||||
GET_PROC_ADDR(hNtdll, NtExtendSection);
|
||||
assert(!mdbx_RunningUnderWine());
|
||||
const HINSTANCE hNtdll = GetModuleHandleA("ntdll.dll");
|
||||
if (hNtdll) {
|
||||
if (GetProcAddress(hNtdll, "wine_get_version")) {
|
||||
assert(mdbx_RunningUnderWine());
|
||||
} else {
|
||||
GET_PROC_ADDR(hNtdll, NtFsControlFile);
|
||||
GET_PROC_ADDR(hNtdll, NtExtendSection);
|
||||
assert(!mdbx_RunningUnderWine());
|
||||
}
|
||||
}
|
||||
|
||||
const HINSTANCE hKernel32dll = GetModuleHandleA("kernel32.dll");
|
||||
GET_PROC_ADDR(hKernel32dll, GetFileInformationByHandleEx);
|
||||
GET_PROC_ADDR(hKernel32dll, GetTickCount64);
|
||||
if (!mdbx_GetTickCount64)
|
||||
mdbx_GetTickCount64 = stub_GetTickCount64;
|
||||
if (!mdbx_RunningUnderWine()) {
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileInformationByHandle);
|
||||
GET_PROC_ADDR(hKernel32dll, GetVolumeInformationByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, GetFinalPathNameByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, PrefetchVirtualMemory);
|
||||
if (hKernel32dll) {
|
||||
GET_PROC_ADDR(hKernel32dll, GetFileInformationByHandleEx);
|
||||
GET_PROC_ADDR(hKernel32dll, GetTickCount64);
|
||||
if (!mdbx_GetTickCount64)
|
||||
mdbx_GetTickCount64 = stub_GetTickCount64;
|
||||
if (!mdbx_RunningUnderWine()) {
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileInformationByHandle);
|
||||
GET_PROC_ADDR(hKernel32dll, GetVolumeInformationByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, GetFinalPathNameByHandleW);
|
||||
GET_PROC_ADDR(hKernel32dll, PrefetchVirtualMemory);
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileIoOverlappedRange);
|
||||
}
|
||||
}
|
||||
|
||||
const osal_srwlock_t_function init =
|
||||
(osal_srwlock_t_function)(hKernel32dll
|
||||
? GetProcAddress(hKernel32dll,
|
||||
"InitializeSRWLock")
|
||||
: nullptr);
|
||||
if (init != NULL) {
|
||||
osal_srwlock_Init = init;
|
||||
osal_srwlock_AcquireShared = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockShared");
|
||||
osal_srwlock_ReleaseShared = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockShared");
|
||||
osal_srwlock_AcquireExclusive = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockExclusive");
|
||||
osal_srwlock_ReleaseExclusive = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockExclusive");
|
||||
} else {
|
||||
osal_srwlock_Init = stub_srwlock_Init;
|
||||
osal_srwlock_AcquireShared = stub_srwlock_AcquireShared;
|
||||
osal_srwlock_ReleaseShared = stub_srwlock_ReleaseShared;
|
||||
osal_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive;
|
||||
osal_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive;
|
||||
}
|
||||
|
||||
const HINSTANCE hAdvapi32dll = GetModuleHandleA("advapi32.dll");
|
||||
GET_PROC_ADDR(hAdvapi32dll, RegGetValueA);
|
||||
#undef GET_PROC_ADDR
|
||||
|
||||
const MDBX_srwlock_function init =
|
||||
(MDBX_srwlock_function)GetProcAddress(hKernel32dll, "InitializeSRWLock");
|
||||
if (init != NULL) {
|
||||
mdbx_srwlock_Init = init;
|
||||
mdbx_srwlock_AcquireShared = (MDBX_srwlock_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockShared");
|
||||
mdbx_srwlock_ReleaseShared = (MDBX_srwlock_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockShared");
|
||||
mdbx_srwlock_AcquireExclusive = (MDBX_srwlock_function)GetProcAddress(
|
||||
hKernel32dll, "AcquireSRWLockExclusive");
|
||||
mdbx_srwlock_ReleaseExclusive = (MDBX_srwlock_function)GetProcAddress(
|
||||
hKernel32dll, "ReleaseSRWLockExclusive");
|
||||
} else {
|
||||
mdbx_srwlock_Init = stub_srwlock_Init;
|
||||
mdbx_srwlock_AcquireShared = stub_srwlock_AcquireShared;
|
||||
mdbx_srwlock_ReleaseShared = stub_srwlock_ReleaseShared;
|
||||
mdbx_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive;
|
||||
mdbx_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive;
|
||||
if (hAdvapi32dll) {
|
||||
GET_PROC_ADDR(hAdvapi32dll, RegGetValueA);
|
||||
}
|
||||
#undef GET_PROC_ADDR
|
||||
}
|
||||
|
||||
#if __GNUC_PREREQ(8, 0)
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_CHK 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_CHK 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_chk \- MDBX checking tool
|
||||
.SH SYNOPSIS
|
||||
@ -81,6 +81,13 @@ Turn to a specified meta-page on successful check.
|
||||
.BR \-T
|
||||
Turn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!
|
||||
.TP
|
||||
.BR \-u
|
||||
Warms up the DB before checking via notifying OS kernel of subsequent access to the database pages.
|
||||
.TP
|
||||
.BR \-U
|
||||
Warms up the DB before checking, notifying the OS kernel of subsequent access to the database pages,
|
||||
then forcibly loads ones by sequential access and tries to lock database pages in memory.
|
||||
.TP
|
||||
.BR \-n
|
||||
Open MDBX environment(s) which do not use subdirectories.
|
||||
This is legacy option. For now MDBX handles this automatically.
|
||||
|
@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_COPY 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_COPY 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_copy \- MDBX environment copy tool
|
||||
.SH SYNOPSIS
|
||||
@ -45,6 +45,13 @@ or unused pages will be omitted from the copy. This option will
|
||||
slow down the backup process as it is more CPU-intensive.
|
||||
Currently it fails if the environment has suffered a page leak.
|
||||
.TP
|
||||
.BR \-u
|
||||
Warms up the DB before copying via notifying OS kernel of subsequent access to the database pages.
|
||||
.TP
|
||||
.BR \-U
|
||||
Warms up the DB before copying, notifying the OS kernel of subsequent access to the database pages,
|
||||
then forcibly loads ones by sequential access and tries to lock database pages in memory.
|
||||
.TP
|
||||
.BR \-n
|
||||
Open MDBX environment(s) which do not use subdirectories.
|
||||
This is legacy option. For now MDBX handles this automatically.
|
||||
|
@ -1,7 +1,7 @@
|
||||
.\" Copyright 2021-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2014-2021 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_DROP 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_DROP 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_drop \- MDBX database delete tool
|
||||
.SH SYNOPSIS
|
||||
|
@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_DUMP 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_DUMP 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_dump \- MDBX environment export tool
|
||||
.SH SYNOPSIS
|
||||
@ -66,6 +66,13 @@ Dump a specific subdatabase. If no database is specified, only the main database
|
||||
.BR \-r
|
||||
Rescure mode. Ignore some errors to dump corrupted DB.
|
||||
.TP
|
||||
.BR \-u
|
||||
Warms up the DB before dumping via notifying OS kernel of subsequent access to the database pages.
|
||||
.TP
|
||||
.BR \-U
|
||||
Warms up the DB before dumping, notifying the OS kernel of subsequent access to the database pages,
|
||||
then forcibly loads ones by sequential access and tries to lock database pages in memory.
|
||||
.TP
|
||||
.BR \-n
|
||||
Dump an MDBX database which does not use subdirectories.
|
||||
This is legacy option. For now MDBX handles this automatically.
|
||||
|
@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_LOAD 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_LOAD 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_load \- MDBX environment import tool
|
||||
.SH SYNOPSIS
|
||||
|
@ -1,8 +1,8 @@
|
||||
.\" Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
|
||||
.\" Copyright 2015,2016 Peter-Service R&D LLC <http://billing.ru/>.
|
||||
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
|
||||
.TH MDBX_STAT 1 "2023-02-14" "MDBX 0.11.14"
|
||||
.TH MDBX_STAT 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_stat \- MDBX environment status tool
|
||||
.SH SYNOPSIS
|
||||
|
152
src/mdbx.c++
152
src/mdbx.c++
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2020-2022, Leonid Yuriev <leo@yuriev.ru>.
|
||||
// Copyright (c) 2020-2023, Leonid Yuriev <leo@yuriev.ru>.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Non-inline part of the libmdbx C++ API
|
||||
@ -14,6 +14,12 @@
|
||||
#define __USE_MINGW_ANSI_STDIO 1
|
||||
#endif /* MinGW */
|
||||
|
||||
/* Workaround for MSVC' header `extern "C"` vs `std::` redefinition bug */
|
||||
#if defined(_MSC_VER) && defined(__SANITIZE_ADDRESS__) && \
|
||||
!defined(_DISABLE_VECTOR_ANNOTATION)
|
||||
#define _DISABLE_VECTOR_ANNOTATION
|
||||
#endif /* _DISABLE_VECTOR_ANNOTATION */
|
||||
|
||||
#include "../mdbx.h++"
|
||||
|
||||
#include "internals.h"
|
||||
@ -201,41 +207,6 @@ __cold bug::~bug() noexcept {}
|
||||
|
||||
#endif /* Unused*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
std::string w2mb(const std::wstring &in) {
|
||||
std::string out;
|
||||
if (!in.empty()) {
|
||||
const auto out_len = mdbx_w2mb(nullptr, 0, in.data(), in.size());
|
||||
if (out_len < 1)
|
||||
mdbx::error::throw_exception(GetLastError());
|
||||
out.append(out_len, '\0');
|
||||
if (out_len != mdbx_w2mb(const_cast<char *>(out.data()), out_len, in.data(),
|
||||
in.size()))
|
||||
mdbx::error::throw_exception(GetLastError());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::wstring mb2w(const char *in) {
|
||||
std::wstring out;
|
||||
if (in && *in) {
|
||||
const auto in_len = strlen(in);
|
||||
const auto out_len = mdbx_mb2w(nullptr, 0, in, in_len);
|
||||
if (out_len < 1)
|
||||
mdbx::error::throw_exception(GetLastError());
|
||||
out.append(out_len, '\0');
|
||||
if (out_len !=
|
||||
mdbx_mb2w(const_cast<wchar_t *>(out.data()), out_len, in, in_len))
|
||||
mdbx::error::throw_exception(GetLastError());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* Windows */
|
||||
|
||||
} // namespace
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -1240,6 +1211,23 @@ env &env::copy(const ::std::string &destination, bool compactify,
|
||||
return copy(destination.c_str(), compactify, force_dynamic_size);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
env &env::copy(const wchar_t *destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
error::success_or_throw(
|
||||
::mdbx_env_copyW(handle_, destination,
|
||||
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
|
||||
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
|
||||
: MDBX_CP_DEFAULTS)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
env &env::copy(const ::std::wstring &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
return copy(destination.c_str(), compactify, force_dynamic_size);
|
||||
}
|
||||
#endif /* Windows */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
@ -1247,20 +1235,15 @@ env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify,
|
||||
}
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
env &env::copy(const ::std::wstring &destination, bool compactify,
|
||||
bool force_dynamic_size) {
|
||||
return copy(w2mb(destination), compactify, force_dynamic_size);
|
||||
}
|
||||
#endif /* Windows */
|
||||
|
||||
path env::get_path() const {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const wchar_t *c_wstr;
|
||||
error::success_or_throw(::mdbx_env_get_pathW(handle_, &c_wstr));
|
||||
static_assert(sizeof(path::value_type) == sizeof(wchar_t), "Oops");
|
||||
return path(c_wstr);
|
||||
#else
|
||||
const char *c_str;
|
||||
error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
static_assert(sizeof(path::value_type) == sizeof(wchar_t), "Oops");
|
||||
return path(mb2w(c_str));
|
||||
#else
|
||||
static_assert(sizeof(path::value_type) == sizeof(char), "Oops");
|
||||
return path(c_str);
|
||||
#endif
|
||||
@ -1275,6 +1258,17 @@ bool env::remove(const ::std::string &pathname, const remove_mode mode) {
|
||||
return remove(pathname.c_str(), mode);
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
bool env::remove(const wchar_t *pathname, const remove_mode mode) {
|
||||
return error::boolean_or_throw(
|
||||
::mdbx_env_deleteW(pathname, MDBX_env_delete_mode_t(mode)));
|
||||
}
|
||||
|
||||
bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
|
||||
return remove(pathname.c_str(), mode);
|
||||
}
|
||||
#endif /* Windows */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
const remove_mode mode) {
|
||||
@ -1282,12 +1276,6 @@ bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
}
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
|
||||
return remove(w2mb(pathname), mode);
|
||||
}
|
||||
#endif /* Windows */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static inline MDBX_env *create_env() {
|
||||
@ -1360,6 +1348,44 @@ __cold env_managed::env_managed(const ::std::string &pathname,
|
||||
const env::operate_parameters &op, bool accede)
|
||||
: env_managed(pathname.c_str(), cp, op, accede) {}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
__cold env_managed::env_managed(const wchar_t *pathname,
|
||||
const operate_parameters &op, bool accede)
|
||||
: env_managed(create_env()) {
|
||||
setup(op.max_maps, op.max_readers);
|
||||
error::success_or_throw(
|
||||
::mdbx_env_openW(handle_, pathname, op.make_flags(accede), 0));
|
||||
|
||||
if (op.options.nested_write_transactions &&
|
||||
!get_options().nested_write_transactions)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
|
||||
}
|
||||
|
||||
__cold env_managed::env_managed(const wchar_t *pathname,
|
||||
const env_managed::create_parameters &cp,
|
||||
const env::operate_parameters &op, bool accede)
|
||||
: env_managed(create_env()) {
|
||||
setup(op.max_maps, op.max_readers);
|
||||
set_geometry(cp.geometry);
|
||||
error::success_or_throw(::mdbx_env_openW(
|
||||
handle_, pathname, op.make_flags(accede, cp.use_subdirectory),
|
||||
cp.file_mode_bits));
|
||||
|
||||
if (op.options.nested_write_transactions &&
|
||||
!get_options().nested_write_transactions)
|
||||
MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
|
||||
}
|
||||
|
||||
__cold env_managed::env_managed(const ::std::wstring &pathname,
|
||||
const operate_parameters &op, bool accede)
|
||||
: env_managed(pathname.c_str(), op, accede) {}
|
||||
|
||||
__cold env_managed::env_managed(const ::std::wstring &pathname,
|
||||
const env_managed::create_parameters &cp,
|
||||
const env::operate_parameters &op, bool accede)
|
||||
: env_managed(pathname.c_str(), cp, op, accede) {}
|
||||
#endif /* Windows */
|
||||
|
||||
#ifdef MDBX_STD_FILESYSTEM_PATH
|
||||
__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
const operate_parameters &op, bool accede)
|
||||
@ -1371,17 +1397,6 @@ __cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname,
|
||||
: env_managed(pathname.native(), cp, op, accede) {}
|
||||
#endif /* MDBX_STD_FILESYSTEM_PATH */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
__cold env_managed::env_managed(const ::std::wstring &pathname,
|
||||
const operate_parameters &op, bool accede)
|
||||
: env_managed(w2mb(pathname), op, accede) {}
|
||||
|
||||
__cold env_managed::env_managed(const ::std::wstring &pathname,
|
||||
const env_managed::create_parameters &cp,
|
||||
const env::operate_parameters &op, bool accede)
|
||||
: env_managed(w2mb(pathname), cp, op, accede) {}
|
||||
#endif /* Windows */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
txn_managed txn::start_nested() {
|
||||
@ -1415,6 +1430,15 @@ void txn_managed::commit() {
|
||||
MDBX_CXX20_UNLIKELY err.throw_exception();
|
||||
}
|
||||
|
||||
void txn_managed::commit(commit_latency *latency) {
|
||||
const error err =
|
||||
static_cast<MDBX_error_t>(::mdbx_txn_commit_ex(handle_, latency));
|
||||
if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
|
||||
MDBX_CXX20_LIKELY handle_ = nullptr;
|
||||
if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
|
||||
MDBX_CXX20_UNLIKELY err.throw_exception();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool txn::drop_map(const char *name, bool throw_if_absent) {
|
||||
|
536
src/mdbx_chk.c
536
src/mdbx_chk.c
@ -1,7 +1,7 @@
|
||||
/* mdbx_chk.c - memory-mapped database check tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -20,9 +20,11 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct flagbit {
|
||||
int bit;
|
||||
const char *name;
|
||||
@ -71,7 +73,7 @@ static void signal_handler(int sig) {
|
||||
#define EXIT_FAILURE_CHECK_MINOR EXIT_FAILURE
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
MDBX_val name;
|
||||
struct {
|
||||
uint64_t branch, large_count, large_volume, leaf;
|
||||
uint64_t subleaf_dupsort, leaf_dupfixed, subleaf_dupfixed;
|
||||
@ -93,7 +95,7 @@ struct {
|
||||
#define dbi_main walk.dbi[MAIN_DBI]
|
||||
#define dbi_meta walk.dbi[CORE_DBS]
|
||||
|
||||
int envflags = MDBX_RDONLY | MDBX_EXCLUSIVE;
|
||||
int envflags = MDBX_RDONLY | MDBX_EXCLUSIVE | MDBX_VALIDATION;
|
||||
MDBX_env *env;
|
||||
MDBX_txn *txn;
|
||||
MDBX_envinfo envinfo;
|
||||
@ -102,7 +104,7 @@ uint64_t total_unused_bytes, reclaimable_pages, gc_pages, alloc_pages,
|
||||
unused_pages, backed_pages;
|
||||
unsigned verbose;
|
||||
bool ignore_wrong_order, quiet, dont_traversal;
|
||||
const char *only_subdb;
|
||||
MDBX_val only_subdb;
|
||||
int stuck_meta = -1;
|
||||
|
||||
struct problem {
|
||||
@ -125,7 +127,99 @@ static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
static void va_log(MDBX_log_level_t level, const char *msg, va_list args) {
|
||||
static MDBX_val printable_buf;
|
||||
static void free_printable_buf(void) { osal_free(printable_buf.iov_base); }
|
||||
|
||||
static const char *sdb_name(const MDBX_val *val) {
|
||||
if (val == MDBX_PGWALK_MAIN)
|
||||
return "@MAIN";
|
||||
if (val == MDBX_PGWALK_GC)
|
||||
return "@GC";
|
||||
if (val == MDBX_PGWALK_META)
|
||||
return "@META";
|
||||
|
||||
const unsigned char *const data = val->iov_base;
|
||||
const size_t len = val->iov_len;
|
||||
if (data == MDBX_PGWALK_MAIN)
|
||||
return "@MAIN";
|
||||
if (data == MDBX_PGWALK_GC)
|
||||
return "@GC";
|
||||
if (data == MDBX_PGWALK_META)
|
||||
return "@META";
|
||||
|
||||
if (!len)
|
||||
return "<zero-length>";
|
||||
if (!data)
|
||||
return "<nullptr>";
|
||||
if (len > 65536) {
|
||||
static char buf[64];
|
||||
/* NOTE: There is MSYS2 MinGW bug if you here got
|
||||
* the "unknown conversion type character ‘z’ in format [-Werror=format=]"
|
||||
* https://stackoverflow.com/questions/74504432/whats-the-proper-way-to-tell-mingw-based-gcc-to-use-ansi-stdio-output-on-windo
|
||||
*/
|
||||
snprintf(buf, sizeof(buf), "<too-long-%zu>", len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool printable = true;
|
||||
bool quoting = false;
|
||||
size_t xchars = 0;
|
||||
for (size_t i = 0; i < val->iov_len && printable; ++i) {
|
||||
quoting |= data[i] != '_' && isalnum(data[i]) == 0;
|
||||
printable = isprint(data[i]) != 0 ||
|
||||
(data[i] < ' ' && ++xchars < 4 && len > xchars * 4);
|
||||
}
|
||||
|
||||
size_t need = len + 1;
|
||||
if (quoting || !printable)
|
||||
need += len + /* quotes */ 2 + 2 * /* max xchars */ 4;
|
||||
if (need > printable_buf.iov_len) {
|
||||
void *ptr = osal_realloc(printable_buf.iov_base, need);
|
||||
if (!ptr)
|
||||
return "<out-of-memory>";
|
||||
if (!printable_buf.iov_base)
|
||||
atexit(free_printable_buf);
|
||||
printable_buf.iov_base = ptr;
|
||||
printable_buf.iov_len = need;
|
||||
}
|
||||
|
||||
char *out = printable_buf.iov_base;
|
||||
if (!quoting) {
|
||||
memcpy(out, data, len);
|
||||
out += len;
|
||||
} else if (printable) {
|
||||
*out++ = '\'';
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (data[i] < ' ') {
|
||||
assert((char *)printable_buf.iov_base + printable_buf.iov_len >
|
||||
out + 4);
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
out[0] = '\\';
|
||||
out[1] = 'x';
|
||||
out[2] = hex[data[i] >> 4];
|
||||
out[3] = hex[data[i] & 15];
|
||||
out += 4;
|
||||
} else if (strchr("\"'`\\", data[i])) {
|
||||
assert((char *)printable_buf.iov_base + printable_buf.iov_len >
|
||||
out + 2);
|
||||
out[0] = '\\';
|
||||
out[1] = data[i];
|
||||
out += 2;
|
||||
} else {
|
||||
assert((char *)printable_buf.iov_base + printable_buf.iov_len >
|
||||
out + 1);
|
||||
*out++ = data[i];
|
||||
}
|
||||
}
|
||||
*out++ = '\'';
|
||||
}
|
||||
assert((char *)printable_buf.iov_base + printable_buf.iov_len > out);
|
||||
*out = 0;
|
||||
return printable_buf.iov_base;
|
||||
}
|
||||
|
||||
static void va_log(MDBX_log_level_t level, const char *function, int line,
|
||||
const char *msg, va_list args) {
|
||||
static const char *const prefixes[] = {
|
||||
"!!!fatal: ", " ! " /* error */, " ~ " /* warning */,
|
||||
" " /* notice */, " // " /* verbose */, " //// " /* debug */,
|
||||
@ -143,13 +237,20 @@ static void va_log(MDBX_log_level_t level, const char *msg, va_list args) {
|
||||
fflush(nullptr);
|
||||
fputs(prefixes[level], out);
|
||||
vfprintf(out, msg, args);
|
||||
if (msg[strlen(msg) - 1] != '\n')
|
||||
|
||||
const bool have_lf = msg[strlen(msg) - 1] == '\n';
|
||||
if (level == MDBX_LOG_FATAL && function && line)
|
||||
fprintf(out, have_lf ? " %s(), %u\n" : " (%s:%u)\n",
|
||||
function + (strncmp(function, "mdbx_", 5) ? 5 : 0), line);
|
||||
else if (!have_lf)
|
||||
fputc('\n', out);
|
||||
fflush(nullptr);
|
||||
}
|
||||
|
||||
if (level == MDBX_LOG_FATAL) {
|
||||
#if !MDBX_DEBUG && !MDBX_FORCE_ASSERTIONS
|
||||
exit(EXIT_FAILURE_MDBX);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
}
|
||||
@ -157,7 +258,7 @@ static void va_log(MDBX_log_level_t level, const char *msg, va_list args) {
|
||||
static void MDBX_PRINTF_ARGS(1, 2) error(const char *msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
va_log(MDBX_LOG_ERROR, msg, args);
|
||||
va_log(MDBX_LOG_ERROR, nullptr, 0, msg, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -166,7 +267,7 @@ static void logger(MDBX_log_level_t level, const char *function, int line,
|
||||
(void)line;
|
||||
(void)function;
|
||||
if (level < MDBX_LOG_EXTRA)
|
||||
va_log(level, msg, args);
|
||||
va_log(level, function, line, msg, args);
|
||||
}
|
||||
|
||||
static int check_user_break(void) {
|
||||
@ -182,19 +283,17 @@ static int check_user_break(void) {
|
||||
}
|
||||
|
||||
static void pagemap_cleanup(void) {
|
||||
for (size_t i = CORE_DBS + /* account pseudo-entry for meta */ 1;
|
||||
i < ARRAY_LENGTH(walk.dbi); ++i) {
|
||||
if (walk.dbi[i].name) {
|
||||
mdbx_free((void *)walk.dbi[i].name);
|
||||
walk.dbi[i].name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
mdbx_free(walk.pagemap);
|
||||
osal_free(walk.pagemap);
|
||||
walk.pagemap = nullptr;
|
||||
}
|
||||
|
||||
static walk_dbi_t *pagemap_lookup_dbi(const char *dbi_name, bool silent) {
|
||||
static bool eq(const MDBX_val a, const MDBX_val b) {
|
||||
return a.iov_len == b.iov_len &&
|
||||
(a.iov_base == b.iov_base || a.iov_len == 0 ||
|
||||
!memcmp(a.iov_base, b.iov_base, a.iov_len));
|
||||
}
|
||||
|
||||
static walk_dbi_t *pagemap_lookup_dbi(const MDBX_val *dbi_name, bool silent) {
|
||||
static walk_dbi_t *last;
|
||||
|
||||
if (dbi_name == MDBX_PGWALK_MAIN)
|
||||
@ -204,24 +303,24 @@ static walk_dbi_t *pagemap_lookup_dbi(const char *dbi_name, bool silent) {
|
||||
if (dbi_name == MDBX_PGWALK_META)
|
||||
return &dbi_meta;
|
||||
|
||||
if (last && strcmp(last->name, dbi_name) == 0)
|
||||
if (last && eq(last->name, *dbi_name))
|
||||
return last;
|
||||
|
||||
walk_dbi_t *dbi = walk.dbi + CORE_DBS + /* account pseudo-entry for meta */ 1;
|
||||
for (; dbi < ARRAY_END(walk.dbi) && dbi->name; ++dbi) {
|
||||
if (strcmp(dbi->name, dbi_name) == 0)
|
||||
for (; dbi < ARRAY_END(walk.dbi) && dbi->name.iov_base; ++dbi) {
|
||||
if (eq(dbi->name, *dbi_name))
|
||||
return last = dbi;
|
||||
}
|
||||
|
||||
if (verbose > 0 && !silent) {
|
||||
print(" - found '%s' area\n", dbi_name);
|
||||
print(" - found %s area\n", sdb_name(dbi_name));
|
||||
fflush(nullptr);
|
||||
}
|
||||
|
||||
if (dbi == ARRAY_END(walk.dbi))
|
||||
return nullptr;
|
||||
|
||||
dbi->name = mdbx_strdup(dbi_name);
|
||||
dbi->name = *dbi_name;
|
||||
return last = dbi;
|
||||
}
|
||||
|
||||
@ -239,7 +338,7 @@ static void MDBX_PRINTF_ARGS(4, 5)
|
||||
break;
|
||||
|
||||
if (!p) {
|
||||
p = mdbx_calloc(1, sizeof(*p));
|
||||
p = osal_calloc(1, sizeof(*p));
|
||||
if (unlikely(!p))
|
||||
return;
|
||||
p->caption = msg;
|
||||
@ -284,7 +383,7 @@ static size_t problems_pop(struct problem *list) {
|
||||
count += problems_list->count;
|
||||
print("%s%s (%" PRIuPTR ")", i ? ", " : "", problems_list->caption,
|
||||
problems_list->count);
|
||||
mdbx_free(problems_list);
|
||||
osal_free(problems_list);
|
||||
problems_list = p;
|
||||
}
|
||||
print("\n");
|
||||
@ -296,13 +395,13 @@ static size_t problems_pop(struct problem *list) {
|
||||
}
|
||||
|
||||
static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
void *const ctx, const int deep,
|
||||
const char *const dbi_name_or_tag, const size_t page_size,
|
||||
const MDBX_page_type_t pagetype, const MDBX_error_t err,
|
||||
const size_t nentries, const size_t payload_bytes,
|
||||
const size_t header_bytes, const size_t unused_bytes) {
|
||||
void *const ctx, const int deep, const MDBX_val *dbi_name,
|
||||
const size_t page_size, const MDBX_page_type_t pagetype,
|
||||
const MDBX_error_t err, const size_t nentries,
|
||||
const size_t payload_bytes, const size_t header_bytes,
|
||||
const size_t unused_bytes) {
|
||||
(void)ctx;
|
||||
const bool is_gc_tree = dbi_name_or_tag == MDBX_PGWALK_GC;
|
||||
const bool is_gc_tree = dbi_name == MDBX_PGWALK_GC;
|
||||
if (deep > 42) {
|
||||
problem_add("deep", deep, "too large", nullptr);
|
||||
data_tree_problems += !is_gc_tree;
|
||||
@ -310,7 +409,7 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
return MDBX_CORRUPTED /* avoid infinite loop/recursion */;
|
||||
}
|
||||
|
||||
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name_or_tag, false);
|
||||
walk_dbi_t *dbi = pagemap_lookup_dbi(dbi_name, false);
|
||||
if (!dbi) {
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
@ -375,14 +474,14 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
}
|
||||
|
||||
if (pgnumber) {
|
||||
if (verbose > 3 && (!only_subdb || strcmp(only_subdb, dbi->name) == 0)) {
|
||||
if (verbose > 3 && (!only_subdb.iov_base || eq(only_subdb, dbi->name))) {
|
||||
if (pgnumber == 1)
|
||||
print(" %s-page %" PRIu64, pagetype_caption, pgno);
|
||||
else
|
||||
print(" %s-span %" PRIu64 "[%u]", pagetype_caption, pgno, pgnumber);
|
||||
print(" of %s: header %" PRIiPTR ", %s %" PRIiPTR ", payload %" PRIiPTR
|
||||
", unused %" PRIiPTR ", deep %i\n",
|
||||
dbi->name, header_bytes,
|
||||
sdb_name(&dbi->name), header_bytes,
|
||||
(pagetype == MDBX_page_branch) ? "keys" : "entries", nentries,
|
||||
payload_bytes, unused_bytes, deep);
|
||||
}
|
||||
@ -400,8 +499,8 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
walk_dbi_t *coll_dbi = &walk.dbi[walk.pagemap[spanpgno] - 1];
|
||||
problem_add("page", spanpgno,
|
||||
(branch && coll_dbi == dbi) ? "loop" : "already used",
|
||||
"%s-page: by %s, deep %i", pagetype_caption, coll_dbi->name,
|
||||
deep);
|
||||
"%s-page: by %s, deep %i", pagetype_caption,
|
||||
sdb_name(&coll_dbi->name), deep);
|
||||
already_used = true;
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
@ -472,8 +571,8 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
data_tree_problems += !is_gc_tree;
|
||||
gc_tree_problems += is_gc_tree;
|
||||
} else {
|
||||
dbi->payload_bytes += payload_bytes + header_bytes;
|
||||
walk.total_payload_bytes += payload_bytes + header_bytes;
|
||||
dbi->payload_bytes += (uint64_t)payload_bytes + header_bytes;
|
||||
walk.total_payload_bytes += (uint64_t)payload_bytes + header_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -483,8 +582,8 @@ static int pgvisitor(const uint64_t pgno, const unsigned pgnumber,
|
||||
|
||||
typedef int(visitor)(const uint64_t record_number, const MDBX_val *key,
|
||||
const MDBX_val *data);
|
||||
static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
bool silent);
|
||||
static int process_db(MDBX_dbi dbi_handle, const MDBX_val *dbi_name,
|
||||
visitor *handler);
|
||||
|
||||
static int handle_userdb(const uint64_t record_number, const MDBX_val *key,
|
||||
const MDBX_val *data) {
|
||||
@ -521,7 +620,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
number = data->iov_len / sizeof(pgno_t) - 1;
|
||||
} else if (data->iov_len - (number + 1) * sizeof(pgno_t) >=
|
||||
/* LY: allow gap up to one page. it is ok
|
||||
* and better than shink-and-retry inside mdbx_update_gc() */
|
||||
* and better than shink-and-retry inside update_gc() */
|
||||
envinfo.mi_dxb_pagesize)
|
||||
problem_add("entry", txnid, "extra idl space",
|
||||
"%" PRIuSIZE " < %" PRIuSIZE " (minor, not a trouble)",
|
||||
@ -533,7 +632,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
|
||||
pgno_t prev = MDBX_PNL_ASCENDING ? NUM_METAS - 1 : txn->mt_next_pgno;
|
||||
pgno_t span = 1;
|
||||
for (unsigned i = 0; i < number; ++i) {
|
||||
for (size_t i = 0; i < number; ++i) {
|
||||
if (check_user_break())
|
||||
return MDBX_EINTR;
|
||||
const pgno_t pgno = iptr[i];
|
||||
@ -552,7 +651,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
if (MDBX_PNL_DISORDERED(prev, pgno)) {
|
||||
bad = " [bad sequence]";
|
||||
problem_add("entry", txnid, "bad sequence",
|
||||
"%" PRIaPGNO " %c [%u].%" PRIaPGNO, prev,
|
||||
"%" PRIaPGNO " %c [%zu].%" PRIaPGNO, prev,
|
||||
(prev == pgno) ? '=' : (MDBX_PNL_ASCENDING ? '>' : '<'),
|
||||
i, pgno);
|
||||
}
|
||||
@ -562,7 +661,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
walk.pagemap[pgno] = -1;
|
||||
else if (idx > 0)
|
||||
problem_add("page", pgno, "already used", "by %s",
|
||||
walk.dbi[idx - 1].name);
|
||||
sdb_name(&walk.dbi[idx - 1].name));
|
||||
else
|
||||
problem_add("page", pgno, "already listed in GC", nullptr);
|
||||
}
|
||||
@ -573,12 +672,12 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
: pgno_sub(pgno, span)))
|
||||
++span;
|
||||
}
|
||||
if (verbose > 3 && !only_subdb) {
|
||||
if (verbose > 3 && !only_subdb.iov_base) {
|
||||
print(" transaction %" PRIaTXN ", %" PRIuPTR
|
||||
" pages, maxspan %" PRIaPGNO "%s\n",
|
||||
txnid, number, span, bad);
|
||||
if (verbose > 4) {
|
||||
for (unsigned i = 0; i < number; i += span) {
|
||||
for (size_t i = 0; i < number; i += span) {
|
||||
const pgno_t pgno = iptr[i];
|
||||
for (span = 1;
|
||||
i + span < number &&
|
||||
@ -600,36 +699,18 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
|
||||
}
|
||||
|
||||
static int equal_or_greater(const MDBX_val *a, const MDBX_val *b) {
|
||||
return (a->iov_len == b->iov_len &&
|
||||
memcmp(a->iov_base, b->iov_base, a->iov_len) == 0)
|
||||
? 0
|
||||
: 1;
|
||||
return eq(*a, *b) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int handle_maindb(const uint64_t record_number, const MDBX_val *key,
|
||||
const MDBX_val *data) {
|
||||
char *name;
|
||||
int rc;
|
||||
size_t i;
|
||||
|
||||
name = key->iov_base;
|
||||
for (i = 0; i < key->iov_len; ++i) {
|
||||
if (name[i] < ' ')
|
||||
return handle_userdb(record_number, key, data);
|
||||
if (data->iov_len == sizeof(MDBX_db)) {
|
||||
int rc = process_db(~0u, key, handle_userdb);
|
||||
if (rc != MDBX_INCOMPATIBLE) {
|
||||
userdb_count++;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
name = mdbx_malloc(key->iov_len + 1);
|
||||
if (unlikely(!name))
|
||||
return MDBX_ENOMEM;
|
||||
memcpy(name, key->iov_base, key->iov_len);
|
||||
name[key->iov_len] = '\0';
|
||||
userdb_count++;
|
||||
|
||||
rc = process_db(~0u, name, handle_userdb, false);
|
||||
mdbx_free(name);
|
||||
if (rc != MDBX_INCOMPATIBLE)
|
||||
return rc;
|
||||
|
||||
return handle_userdb(record_number, key, data);
|
||||
}
|
||||
|
||||
@ -683,8 +764,8 @@ static const char *db_flags2valuemode(unsigned flags) {
|
||||
}
|
||||
}
|
||||
|
||||
static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
bool silent) {
|
||||
static int process_db(MDBX_dbi dbi_handle, const MDBX_val *dbi_name,
|
||||
visitor *handler) {
|
||||
MDBX_cursor *mc;
|
||||
MDBX_stat ms;
|
||||
MDBX_val key, data;
|
||||
@ -693,18 +774,19 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
int rc, i;
|
||||
struct problem *saved_list;
|
||||
uint64_t problems_count;
|
||||
const bool second_pass = dbi_handle == MAIN_DBI;
|
||||
|
||||
uint64_t record_count = 0, dups = 0;
|
||||
uint64_t key_bytes = 0, data_bytes = 0;
|
||||
|
||||
if ((MDBX_TXN_FINISHED | MDBX_TXN_ERROR) & mdbx_txn_flags(txn)) {
|
||||
print(" ! abort processing '%s' due to a previous error\n",
|
||||
dbi_name ? dbi_name : "@MAIN");
|
||||
print(" ! abort processing %s due to a previous error\n",
|
||||
sdb_name(dbi_name));
|
||||
return MDBX_BAD_TXN;
|
||||
}
|
||||
|
||||
if (dbi_handle == ~0u) {
|
||||
rc = mdbx_dbi_open_ex(
|
||||
rc = mdbx_dbi_open_ex2(
|
||||
txn, dbi_name, MDBX_DB_ACCEDE, &dbi_handle,
|
||||
(dbi_name && ignore_wrong_order) ? equal_or_greater : nullptr,
|
||||
(dbi_name && ignore_wrong_order) ? equal_or_greater : nullptr);
|
||||
@ -712,27 +794,26 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
if (!dbi_name ||
|
||||
rc !=
|
||||
MDBX_INCOMPATIBLE) /* LY: mainDB's record is not a user's DB. */ {
|
||||
error("mdbx_dbi_open('%s') failed, error %d %s\n",
|
||||
dbi_name ? dbi_name : "main", rc, mdbx_strerror(rc));
|
||||
error("mdbx_dbi_open(%s) failed, error %d %s\n", sdb_name(dbi_name), rc,
|
||||
mdbx_strerror(rc));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (dbi_handle >= CORE_DBS && dbi_name && only_subdb &&
|
||||
strcmp(only_subdb, dbi_name) != 0) {
|
||||
if (dbi_handle >= CORE_DBS && dbi_name && only_subdb.iov_base &&
|
||||
!eq(only_subdb, *dbi_name)) {
|
||||
if (verbose) {
|
||||
print("Skip processing '%s'...\n", dbi_name);
|
||||
print("Skip processing %s...\n", sdb_name(dbi_name));
|
||||
fflush(nullptr);
|
||||
}
|
||||
skipped_subdb++;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
if (!silent && verbose) {
|
||||
print("Processing '%s'...\n", dbi_name ? dbi_name : "@MAIN");
|
||||
fflush(nullptr);
|
||||
}
|
||||
if (!second_pass && verbose)
|
||||
print("Processing %s...\n", sdb_name(dbi_name));
|
||||
fflush(nullptr);
|
||||
|
||||
rc = mdbx_dbi_flags(txn, dbi_handle, &flags);
|
||||
if (rc) {
|
||||
@ -746,7 +827,7 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!silent && verbose) {
|
||||
if (!second_pass && verbose) {
|
||||
print(" - key-value kind: %s-key => %s-value", db_flags2keymode(flags),
|
||||
db_flags2valuemode(flags));
|
||||
if (verbose > 1) {
|
||||
@ -805,9 +886,9 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
}
|
||||
|
||||
if (ignore_wrong_order) { /* for debugging with enabled assertions */
|
||||
mc->mc_flags |= C_SKIPORD;
|
||||
mc->mc_checking |= CC_SKIPORD;
|
||||
if (mc->mc_xcursor)
|
||||
mc->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
|
||||
mc->mc_xcursor->mx_cursor.mc_checking |= CC_SKIPORD;
|
||||
}
|
||||
|
||||
const size_t maxkeysize = mdbx_env_get_maxkeysize_ex(env, flags);
|
||||
@ -822,57 +903,75 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
if (rc)
|
||||
goto bailout;
|
||||
|
||||
bool bad_key = false;
|
||||
if (key.iov_len > maxkeysize) {
|
||||
problem_add("entry", record_count, "key length exceeds max-key-size",
|
||||
"%" PRIuPTR " > %" PRIuPTR, key.iov_len, maxkeysize);
|
||||
bad_key = true;
|
||||
} else if ((flags & MDBX_INTEGERKEY) && key.iov_len != sizeof(uint64_t) &&
|
||||
key.iov_len != sizeof(uint32_t)) {
|
||||
problem_add("entry", record_count, "wrong key length",
|
||||
"%" PRIuPTR " != 4or8", key.iov_len);
|
||||
bad_key = true;
|
||||
}
|
||||
if (!second_pass) {
|
||||
bool bad_key = false;
|
||||
if (key.iov_len > maxkeysize) {
|
||||
problem_add("entry", record_count, "key length exceeds max-key-size",
|
||||
"%" PRIuPTR " > %" PRIuPTR, key.iov_len, maxkeysize);
|
||||
bad_key = true;
|
||||
} else if ((flags & MDBX_INTEGERKEY) && key.iov_len != sizeof(uint64_t) &&
|
||||
key.iov_len != sizeof(uint32_t)) {
|
||||
problem_add("entry", record_count, "wrong key length",
|
||||
"%" PRIuPTR " != 4or8", key.iov_len);
|
||||
bad_key = true;
|
||||
}
|
||||
|
||||
bool bad_data = false;
|
||||
if ((flags & MDBX_INTEGERDUP) && data.iov_len != sizeof(uint64_t) &&
|
||||
data.iov_len != sizeof(uint32_t)) {
|
||||
problem_add("entry", record_count, "wrong data length",
|
||||
"%" PRIuPTR " != 4or8", data.iov_len);
|
||||
bad_data = true;
|
||||
}
|
||||
|
||||
if (prev_key.iov_base) {
|
||||
if (prev_data.iov_base && !bad_data && (flags & MDBX_DUPFIXED) &&
|
||||
prev_data.iov_len != data.iov_len) {
|
||||
problem_add("entry", record_count, "different data length",
|
||||
"%" PRIuPTR " != %" PRIuPTR, prev_data.iov_len,
|
||||
data.iov_len);
|
||||
bool bad_data = false;
|
||||
if ((flags & MDBX_INTEGERDUP) && data.iov_len != sizeof(uint64_t) &&
|
||||
data.iov_len != sizeof(uint32_t)) {
|
||||
problem_add("entry", record_count, "wrong data length",
|
||||
"%" PRIuPTR " != 4or8", data.iov_len);
|
||||
bad_data = true;
|
||||
}
|
||||
|
||||
if (!bad_key) {
|
||||
int cmp = mdbx_cmp(txn, dbi_handle, &key, &prev_key);
|
||||
if (cmp == 0) {
|
||||
++dups;
|
||||
if ((flags & MDBX_DUPSORT) == 0) {
|
||||
problem_add("entry", record_count, "duplicated entries", nullptr);
|
||||
if (prev_data.iov_base && data.iov_len == prev_data.iov_len &&
|
||||
memcmp(data.iov_base, prev_data.iov_base, data.iov_len) == 0) {
|
||||
problem_add("entry", record_count, "complete duplicate", nullptr);
|
||||
}
|
||||
} else if (!bad_data && prev_data.iov_base) {
|
||||
cmp = mdbx_dcmp(txn, dbi_handle, &data, &prev_data);
|
||||
if (cmp == 0) {
|
||||
problem_add("entry", record_count, "complete duplicate", nullptr);
|
||||
} else if (cmp < 0 && !ignore_wrong_order) {
|
||||
problem_add("entry", record_count, "wrong order of multi-values",
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
} else if (cmp < 0 && !ignore_wrong_order) {
|
||||
problem_add("entry", record_count, "wrong order of entries", nullptr);
|
||||
if (prev_key.iov_base) {
|
||||
if (prev_data.iov_base && !bad_data && (flags & MDBX_DUPFIXED) &&
|
||||
prev_data.iov_len != data.iov_len) {
|
||||
problem_add("entry", record_count, "different data length",
|
||||
"%" PRIuPTR " != %" PRIuPTR, prev_data.iov_len,
|
||||
data.iov_len);
|
||||
bad_data = true;
|
||||
}
|
||||
|
||||
if (!bad_key) {
|
||||
int cmp = mdbx_cmp(txn, dbi_handle, &key, &prev_key);
|
||||
if (cmp == 0) {
|
||||
++dups;
|
||||
if ((flags & MDBX_DUPSORT) == 0) {
|
||||
problem_add("entry", record_count, "duplicated entries", nullptr);
|
||||
if (prev_data.iov_base && data.iov_len == prev_data.iov_len &&
|
||||
memcmp(data.iov_base, prev_data.iov_base, data.iov_len) ==
|
||||
0) {
|
||||
problem_add("entry", record_count, "complete duplicate",
|
||||
nullptr);
|
||||
}
|
||||
} else if (!bad_data && prev_data.iov_base) {
|
||||
cmp = mdbx_dcmp(txn, dbi_handle, &data, &prev_data);
|
||||
if (cmp == 0) {
|
||||
problem_add("entry", record_count, "complete duplicate",
|
||||
nullptr);
|
||||
} else if (cmp < 0 && !ignore_wrong_order) {
|
||||
problem_add("entry", record_count,
|
||||
"wrong order of multi-values", nullptr);
|
||||
}
|
||||
}
|
||||
} else if (cmp < 0 && !ignore_wrong_order) {
|
||||
problem_add("entry", record_count, "wrong order of entries",
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bad_key) {
|
||||
if (verbose && (flags & MDBX_INTEGERKEY) && !prev_key.iov_base)
|
||||
print(" - fixed key-size %" PRIuPTR "\n", key.iov_len);
|
||||
prev_key = key;
|
||||
}
|
||||
if (!bad_data) {
|
||||
if (verbose && (flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) &&
|
||||
!prev_data.iov_base)
|
||||
print(" - fixed data-size %" PRIuPTR "\n", data.iov_len);
|
||||
prev_data = data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -886,17 +985,6 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
key_bytes += key.iov_len;
|
||||
data_bytes += data.iov_len;
|
||||
|
||||
if (!bad_key) {
|
||||
if (verbose && (flags & MDBX_INTEGERKEY) && !prev_key.iov_base)
|
||||
print(" - fixed key-size %" PRIuPTR "\n", key.iov_len);
|
||||
prev_key = key;
|
||||
}
|
||||
if (!bad_data) {
|
||||
if (verbose && (flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) &&
|
||||
!prev_data.iov_base)
|
||||
print(" - fixed data-size %" PRIuPTR "\n", data.iov_len);
|
||||
prev_data = data;
|
||||
}
|
||||
rc = mdbx_cursor_get(mc, &key, &data, MDBX_NEXT);
|
||||
}
|
||||
if (rc != MDBX_NOTFOUND)
|
||||
@ -909,7 +997,7 @@ static int process_db(MDBX_dbi dbi_handle, char *dbi_name, visitor *handler,
|
||||
"%" PRIu64 " != %" PRIu64, record_count, ms.ms_entries);
|
||||
bailout:
|
||||
problems_count = problems_pop(saved_list);
|
||||
if (!silent && verbose) {
|
||||
if (!second_pass && verbose) {
|
||||
print(" - summary: %" PRIu64 " records, %" PRIu64 " dups, %" PRIu64
|
||||
" key's bytes, %" PRIu64 " data's "
|
||||
"bytes, %" PRIu64 " problems\n",
|
||||
@ -922,21 +1010,24 @@ bailout:
|
||||
}
|
||||
|
||||
static void usage(char *prog) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s subdb] "
|
||||
"dbpath\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -v\t\tmore verbose, could be used multiple times\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -c\t\tforce cooperative mode (don't try exclusive)\n"
|
||||
" -w\t\twrite-mode checking\n"
|
||||
" -d\t\tdisable page-by-page traversal of B-tree\n"
|
||||
" -i\t\tignore wrong order errors (for custom comparators case)\n"
|
||||
" -s subdb\tprocess a specific subdatabase only\n"
|
||||
" -0|1|2\tforce using specific meta-page 0, or 2 for checking\n"
|
||||
" -t\t\tturn to a specified meta-page on successful check\n"
|
||||
" -T\t\tturn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!\n",
|
||||
prog);
|
||||
fprintf(
|
||||
stderr,
|
||||
"usage: %s "
|
||||
"[-V] [-v] [-q] [-c] [-0|1|2] [-w] [-d] [-i] [-s subdb] [-u|U] dbpath\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -v\t\tmore verbose, could be used multiple times\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -c\t\tforce cooperative mode (don't try exclusive)\n"
|
||||
" -w\t\twrite-mode checking\n"
|
||||
" -d\t\tdisable page-by-page traversal of B-tree\n"
|
||||
" -i\t\tignore wrong order errors (for custom comparators case)\n"
|
||||
" -s subdb\tprocess a specific subdatabase only\n"
|
||||
" -u\t\twarmup database before checking\n"
|
||||
" -U\t\twarmup and try lock database pages in memory before checking\n"
|
||||
" -0|1|2\tforce using specific meta-page 0, or 2 for checking\n"
|
||||
" -t\t\tturn to a specified meta-page on successful check\n"
|
||||
" -T\t\tturn to a specified meta-page EVEN ON UNSUCCESSFUL CHECK!\n",
|
||||
prog);
|
||||
exit(EXIT_INTERRUPTED);
|
||||
}
|
||||
|
||||
@ -1075,6 +1166,8 @@ int main(int argc, char *argv[]) {
|
||||
bool write_locked = false;
|
||||
bool turn_meta = false;
|
||||
bool force_turn_meta = false;
|
||||
bool warmup = false;
|
||||
MDBX_warmup_flags_t warmup_flags = MDBX_warmup_default;
|
||||
|
||||
double elapsed;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@ -1089,15 +1182,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
|
||||
dbi_meta.name = "@META";
|
||||
dbi_free.name = "@GC";
|
||||
dbi_main.name = "@MAIN";
|
||||
dbi_meta.name.iov_base = MDBX_PGWALK_META;
|
||||
dbi_free.name.iov_base = MDBX_PGWALK_GC;
|
||||
dbi_main.name.iov_base = MDBX_PGWALK_MAIN;
|
||||
atexit(pagemap_cleanup);
|
||||
|
||||
if (argc < 2)
|
||||
usage(prog);
|
||||
|
||||
for (int i; (i = getopt(argc, argv,
|
||||
"uU"
|
||||
"0"
|
||||
"1"
|
||||
"2"
|
||||
@ -1168,13 +1262,22 @@ int main(int argc, char *argv[]) {
|
||||
dont_traversal = true;
|
||||
break;
|
||||
case 's':
|
||||
if (only_subdb && strcmp(only_subdb, optarg))
|
||||
if (only_subdb.iov_base && strcmp(only_subdb.iov_base, optarg))
|
||||
usage(prog);
|
||||
only_subdb = optarg;
|
||||
only_subdb.iov_base = optarg;
|
||||
only_subdb.iov_len = strlen(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
ignore_wrong_order = true;
|
||||
break;
|
||||
case 'u':
|
||||
warmup = true;
|
||||
break;
|
||||
case 'U':
|
||||
warmup = true;
|
||||
warmup_flags =
|
||||
MDBX_warmup_force | MDBX_warmup_touchlimit | MDBX_warmup_lock;
|
||||
break;
|
||||
default:
|
||||
usage(prog);
|
||||
}
|
||||
@ -1200,9 +1303,10 @@ int main(int argc, char *argv[]) {
|
||||
error("write-mode must be enabled to turn to the specified meta-page.\n");
|
||||
rc = EXIT_INTERRUPTED;
|
||||
}
|
||||
if (only_subdb || dont_traversal) {
|
||||
error("whole database checking with tree-traversal are required to turn "
|
||||
"to the specified meta-page.\n");
|
||||
if (only_subdb.iov_base || dont_traversal) {
|
||||
error(
|
||||
"whole database checking with b-tree traversal are required to turn "
|
||||
"to the specified meta-page.\n");
|
||||
rc = EXIT_INTERRUPTED;
|
||||
}
|
||||
}
|
||||
@ -1231,7 +1335,9 @@ int main(int argc, char *argv[]) {
|
||||
mdbx_setup_debug((verbose < MDBX_LOG_TRACE - 1)
|
||||
? (MDBX_log_level_t)(verbose + 1)
|
||||
: MDBX_LOG_TRACE,
|
||||
MDBX_DBG_LEGACY_OVERLAP | MDBX_DBG_DONT_UPGRADE, logger);
|
||||
MDBX_DBG_DUMP | MDBX_DBG_ASSERT | MDBX_DBG_AUDIT |
|
||||
MDBX_DBG_LEGACY_OVERLAP | MDBX_DBG_DONT_UPGRADE,
|
||||
logger);
|
||||
|
||||
rc = mdbx_env_create(&env);
|
||||
if (rc) {
|
||||
@ -1274,14 +1380,35 @@ int main(int argc, char *argv[]) {
|
||||
(envflags & MDBX_EXCLUSIVE) ? "monopolistic" : "cooperative");
|
||||
|
||||
if ((envflags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == 0) {
|
||||
if (verbose) {
|
||||
print(" - taking write lock...");
|
||||
fflush(nullptr);
|
||||
}
|
||||
rc = mdbx_txn_lock(env, false);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
error("mdbx_txn_lock() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
if (verbose)
|
||||
print(" done\n");
|
||||
write_locked = true;
|
||||
}
|
||||
|
||||
if (warmup) {
|
||||
if (verbose) {
|
||||
print(" - warming up...");
|
||||
fflush(nullptr);
|
||||
}
|
||||
rc = mdbx_env_warmup(env, nullptr, warmup_flags, 3600 * 65536);
|
||||
if (MDBX_IS_ERROR(rc)) {
|
||||
error("mdbx_env_warmup(flags %u) failed, error %d %s\n", warmup_flags, rc,
|
||||
mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
if (verbose)
|
||||
print(" %s\n", rc ? "timeout" : "done");
|
||||
}
|
||||
|
||||
rc = mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &txn);
|
||||
if (rc) {
|
||||
error("mdbx_txn_begin() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
@ -1330,7 +1457,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#endif
|
||||
if (rc) {
|
||||
error("mdbx_filesize() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
error("osal_filesize() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
@ -1494,7 +1621,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
print("Traversal b-tree by txn#%" PRIaTXN "...\n", txn->mt_txnid);
|
||||
fflush(nullptr);
|
||||
walk.pagemap = mdbx_calloc((size_t)backed_pages, sizeof(*walk.pagemap));
|
||||
walk.pagemap = osal_calloc((size_t)backed_pages, sizeof(*walk.pagemap));
|
||||
if (!walk.pagemap) {
|
||||
rc = errno ? errno : MDBX_ENOMEM;
|
||||
error("calloc() failed, error %d %s\n", rc, mdbx_strerror(rc));
|
||||
@ -1518,8 +1645,8 @@ int main(int argc, char *argv[]) {
|
||||
unused_pages += 1;
|
||||
|
||||
empty_pages = lost_bytes = 0;
|
||||
for (walk_dbi_t *dbi = &dbi_main; dbi < ARRAY_END(walk.dbi) && dbi->name;
|
||||
++dbi) {
|
||||
for (walk_dbi_t *dbi = &dbi_main;
|
||||
dbi < ARRAY_END(walk.dbi) && dbi->name.iov_base; ++dbi) {
|
||||
empty_pages += dbi->pages.empty;
|
||||
lost_bytes += dbi->lost_bytes;
|
||||
}
|
||||
@ -1529,9 +1656,10 @@ int main(int argc, char *argv[]) {
|
||||
print(" - pages: walked %" PRIu64 ", left/unused %" PRIu64 "\n",
|
||||
walk.pgcount, unused_pages);
|
||||
if (verbose > 1) {
|
||||
for (walk_dbi_t *dbi = walk.dbi; dbi < ARRAY_END(walk.dbi) && dbi->name;
|
||||
++dbi) {
|
||||
print(" %s: subtotal %" PRIu64, dbi->name, dbi->pages.total);
|
||||
for (walk_dbi_t *dbi = walk.dbi;
|
||||
dbi < ARRAY_END(walk.dbi) && dbi->name.iov_base; ++dbi) {
|
||||
print(" %s: subtotal %" PRIu64, sdb_name(&dbi->name),
|
||||
dbi->pages.total);
|
||||
if (dbi->pages.other && dbi->pages.other != dbi->pages.total)
|
||||
print(", other %" PRIu64, dbi->pages.other);
|
||||
if (dbi->pages.branch)
|
||||
@ -1563,14 +1691,15 @@ int main(int argc, char *argv[]) {
|
||||
(total_page_bytes - walk.total_payload_bytes) * 100.0 /
|
||||
total_page_bytes);
|
||||
if (verbose > 2) {
|
||||
for (walk_dbi_t *dbi = walk.dbi; dbi < ARRAY_END(walk.dbi) && dbi->name;
|
||||
++dbi)
|
||||
for (walk_dbi_t *dbi = walk.dbi;
|
||||
dbi < ARRAY_END(walk.dbi) && dbi->name.iov_base; ++dbi)
|
||||
if (dbi->pages.total) {
|
||||
uint64_t dbi_bytes = dbi->pages.total * envinfo.mi_dxb_pagesize;
|
||||
print(" %s: subtotal %" PRIu64 " bytes (%.1f%%),"
|
||||
" payload %" PRIu64 " (%.1f%%), unused %" PRIu64 " (%.1f%%)",
|
||||
dbi->name, dbi_bytes, dbi_bytes * 100.0 / total_page_bytes,
|
||||
dbi->payload_bytes, dbi->payload_bytes * 100.0 / dbi_bytes,
|
||||
sdb_name(&dbi->name), dbi_bytes,
|
||||
dbi_bytes * 100.0 / total_page_bytes, dbi->payload_bytes,
|
||||
dbi->payload_bytes * 100.0 / dbi_bytes,
|
||||
dbi_bytes - dbi->payload_bytes,
|
||||
(dbi_bytes - dbi->payload_bytes) * 100.0 / dbi_bytes);
|
||||
if (dbi->pages.empty)
|
||||
@ -1579,7 +1708,7 @@ int main(int argc, char *argv[]) {
|
||||
print(", %" PRIu64 " bytes lost", dbi->lost_bytes);
|
||||
print("\n");
|
||||
} else
|
||||
print(" %s: empty\n", dbi->name);
|
||||
print(" %s: empty\n", sdb_name(&dbi->name));
|
||||
}
|
||||
print(" - summary: average fill %.1f%%",
|
||||
walk.total_payload_bytes * 100.0 / total_page_bytes);
|
||||
@ -1594,21 +1723,12 @@ int main(int argc, char *argv[]) {
|
||||
fflush(nullptr);
|
||||
}
|
||||
|
||||
if (!verbose)
|
||||
print("Iterating DBIs...\n");
|
||||
if (data_tree_problems) {
|
||||
print("Skip processing %s since tree is corrupted (%u problems)\n", "@MAIN",
|
||||
data_tree_problems);
|
||||
problems_maindb = data_tree_problems;
|
||||
} else
|
||||
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr, false);
|
||||
|
||||
if (gc_tree_problems) {
|
||||
print("Skip processing %s since tree is corrupted (%u problems)\n", "@GC",
|
||||
gc_tree_problems);
|
||||
print("Skip processing %s since %s is corrupted (%u problems)\n", "@GC",
|
||||
"b-tree", gc_tree_problems);
|
||||
problems_freedb = gc_tree_problems;
|
||||
} else
|
||||
problems_freedb = process_db(FREE_DBI, "@GC", handle_freedb, false);
|
||||
problems_freedb = process_db(FREE_DBI, MDBX_PGWALK_GC, handle_freedb);
|
||||
|
||||
if (verbose) {
|
||||
uint64_t value = envinfo.mi_mapsize / envinfo.mi_dxb_pagesize;
|
||||
@ -1640,7 +1760,7 @@ int main(int argc, char *argv[]) {
|
||||
print(", available %" PRIu64 " (%.1f%%)\n", value, value / percent);
|
||||
}
|
||||
|
||||
if (problems_maindb == 0 && problems_freedb == 0) {
|
||||
if ((problems_maindb = data_tree_problems) == 0 && problems_freedb == 0) {
|
||||
if (!dont_traversal &&
|
||||
(envflags & (MDBX_EXCLUSIVE | MDBX_RDONLY)) != MDBX_RDONLY) {
|
||||
if (walk.pgcount != alloc_pages - gc_pages) {
|
||||
@ -1649,22 +1769,32 @@ int main(int argc, char *argv[]) {
|
||||
walk.pgcount, alloc_pages - gc_pages);
|
||||
}
|
||||
if (unused_pages != gc_pages) {
|
||||
error("gc pages mismatch (%" PRIu64 "(expected) != %" PRIu64 "(GC))\n",
|
||||
error("GC pages mismatch (%" PRIu64 "(expected) != %" PRIu64 "(GC))\n",
|
||||
unused_pages, gc_pages);
|
||||
}
|
||||
} else if (verbose) {
|
||||
print(" - skip check used and gc pages (btree-traversal with "
|
||||
print(" - skip check used and GC pages (btree-traversal with "
|
||||
"monopolistic or read-write mode only)\n");
|
||||
}
|
||||
|
||||
if (!process_db(MAIN_DBI, nullptr, handle_maindb, true)) {
|
||||
if (!userdb_count && verbose)
|
||||
print(" - does not contain multiple databases\n");
|
||||
problems_maindb = process_db(~0u, /* MAIN_DBI */ nullptr, nullptr);
|
||||
if (problems_maindb == 0) {
|
||||
print("Scanning %s for %s...\n", "@MAIN", "sub-database(s)");
|
||||
if (!process_db(MAIN_DBI, nullptr, handle_maindb)) {
|
||||
if (!userdb_count && verbose)
|
||||
print(" - does not contain multiple databases\n");
|
||||
}
|
||||
} else {
|
||||
print("Skip processing %s since %s is corrupted (%u problems)\n",
|
||||
"sub-database(s)", "@MAIN", problems_maindb);
|
||||
}
|
||||
} else {
|
||||
print("Skip processing %s since %s is corrupted (%u problems)\n", "@MAIN",
|
||||
"b-tree", data_tree_problems);
|
||||
}
|
||||
|
||||
if (rc == 0 && total_problems == 1 && problems_meta == 1 && !dont_traversal &&
|
||||
(envflags & MDBX_RDONLY) == 0 && !only_subdb && stuck_meta < 0 &&
|
||||
(envflags & MDBX_RDONLY) == 0 && !only_subdb.iov_base && stuck_meta < 0 &&
|
||||
get_meta_txnid(meta_recent(true)) < envinfo.mi_recent_txnid) {
|
||||
print("Perform sync-to-disk for make steady checkpoint at txn-id #%" PRIi64
|
||||
"\n",
|
||||
@ -1683,7 +1813,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (turn_meta && stuck_meta >= 0 && !dont_traversal && !only_subdb &&
|
||||
if (turn_meta && stuck_meta >= 0 && !dont_traversal && !only_subdb.iov_base &&
|
||||
(envflags & (MDBX_RDONLY | MDBX_EXCLUSIVE)) == MDBX_EXCLUSIVE) {
|
||||
const bool successful_check = (rc | total_problems | problems_meta) == 0;
|
||||
if (successful_check || force_turn_meta) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* mdbx_copy.c - memory-mapped database backup tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -20,7 +20,7 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@ -44,14 +44,17 @@ static void signal_handler(int sig) {
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
static void usage(const char *prog) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [-V] [-q] [-c] src_path [dest_path]\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -c\t\tenable compactification (skip unused pages)\n"
|
||||
" src_path\tsource database\n"
|
||||
" dest_path\tdestination (stdout if not specified)\n",
|
||||
prog);
|
||||
fprintf(
|
||||
stderr,
|
||||
"usage: %s [-V] [-q] [-c] [-u|U] src_path [dest_path]\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -c\t\tenable compactification (skip unused pages)\n"
|
||||
" -u\t\twarmup database before copying\n"
|
||||
" -U\t\twarmup and try lock database pages in memory before copying\n"
|
||||
" src_path\tsource database\n"
|
||||
" dest_path\tdestination (stdout if not specified)\n",
|
||||
prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -62,6 +65,8 @@ int main(int argc, char *argv[]) {
|
||||
unsigned flags = MDBX_RDONLY;
|
||||
unsigned cpflags = 0;
|
||||
bool quiet = false;
|
||||
bool warmup = false;
|
||||
MDBX_warmup_flags_t warmup_flags = MDBX_warmup_default;
|
||||
|
||||
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
|
||||
if (argv[1][1] == 'n' && argv[1][2] == '\0')
|
||||
@ -70,8 +75,14 @@ int main(int argc, char *argv[]) {
|
||||
cpflags |= MDBX_CP_COMPACT;
|
||||
else if (argv[1][1] == 'q' && argv[1][2] == '\0')
|
||||
quiet = true;
|
||||
else if ((argv[1][1] == 'h' && argv[1][2] == '\0') ||
|
||||
strcmp(argv[1], "--help") == 0)
|
||||
else if (argv[1][1] == 'u' && argv[1][2] == '\0')
|
||||
warmup = true;
|
||||
else if (argv[1][1] == 'U' && argv[1][2] == '\0') {
|
||||
warmup = true;
|
||||
warmup_flags =
|
||||
MDBX_warmup_force | MDBX_warmup_touchlimit | MDBX_warmup_lock;
|
||||
} else if ((argv[1][1] == 'h' && argv[1][2] == '\0') ||
|
||||
strcmp(argv[1], "--help") == 0)
|
||||
usage(progname);
|
||||
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
|
||||
printf("mdbx_copy version %d.%d.%d.%d\n"
|
||||
@ -120,7 +131,12 @@ int main(int argc, char *argv[]) {
|
||||
if (rc == MDBX_SUCCESS)
|
||||
rc = mdbx_env_open(env, argv[1], flags, 0);
|
||||
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
if (rc == MDBX_SUCCESS && warmup) {
|
||||
act = "warming up";
|
||||
rc = mdbx_env_warmup(env, nullptr, warmup_flags, 3600 * 65536);
|
||||
}
|
||||
|
||||
if (!MDBX_IS_ERROR(rc)) {
|
||||
act = "copying";
|
||||
if (argc == 2) {
|
||||
mdbx_filehandle_t fd;
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* mdbx_drop.c - memory-mapped database delete tool */
|
||||
|
||||
/*
|
||||
* Copyright 2021 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2021-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
*
|
||||
* Copyright 2016-2022 Howard Chu, Symas Corp.
|
||||
* Copyright 2016-2021 Howard Chu, Symas Corp.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -22,7 +22,7 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* mdbx_dump.c - memory-mapped database dump tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -20,7 +20,7 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#include <ctype.h>
|
||||
@ -66,7 +66,7 @@ static const char hexc[] = "0123456789abcdef";
|
||||
|
||||
static void dumpbyte(unsigned char c) {
|
||||
putchar(hexc[c >> 4]);
|
||||
putchar(hexc[c & 0xf]);
|
||||
putchar(hexc[c & 15]);
|
||||
}
|
||||
|
||||
static void text(MDBX_val *v) {
|
||||
@ -186,10 +186,10 @@ static int dump_sdb(MDBX_txn *txn, MDBX_dbi dbi, char *name) {
|
||||
error("mdbx_cursor_open", rc);
|
||||
return rc;
|
||||
}
|
||||
if (MDBX_DEBUG > 0 && rescue) {
|
||||
cursor->mc_flags |= C_SKIPORD;
|
||||
if (rescue) {
|
||||
cursor->mc_checking |= CC_SKIPORD;
|
||||
if (cursor->mc_xcursor)
|
||||
cursor->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
|
||||
cursor->mc_xcursor->mx_cursor.mc_checking |= CC_SKIPORD;
|
||||
}
|
||||
|
||||
while ((rc = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) ==
|
||||
@ -217,19 +217,23 @@ static int dump_sdb(MDBX_txn *txn, MDBX_dbi dbi, char *name) {
|
||||
}
|
||||
|
||||
static void usage(void) {
|
||||
fprintf(stderr,
|
||||
"usage: %s [-V] [-q] [-f file] [-l] [-p] [-r] [-a|-s subdb] "
|
||||
"dbpath\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -f\t\twrite to file instead of stdout\n"
|
||||
" -l\t\tlist subDBs and exit\n"
|
||||
" -p\t\tuse printable characters\n"
|
||||
" -r\t\trescue mode (ignore errors to dump corrupted DB)\n"
|
||||
" -a\t\tdump main DB and all subDBs\n"
|
||||
" -s name\tdump only the specified named subDB\n"
|
||||
" \t\tby default dump only the main DB\n",
|
||||
prog);
|
||||
fprintf(
|
||||
stderr,
|
||||
"usage: %s "
|
||||
"[-V] [-q] [-f file] [-l] [-p] [-r] [-a|-s subdb] [-u|U] "
|
||||
"dbpath\n"
|
||||
" -V\t\tprint version and exit\n"
|
||||
" -q\t\tbe quiet\n"
|
||||
" -f\t\twrite to file instead of stdout\n"
|
||||
" -l\t\tlist subDBs and exit\n"
|
||||
" -p\t\tuse printable characters\n"
|
||||
" -r\t\trescue mode (ignore errors to dump corrupted DB)\n"
|
||||
" -a\t\tdump main DB and all subDBs\n"
|
||||
" -s name\tdump only the specified named subDB\n"
|
||||
" -u\t\twarmup database before dumping\n"
|
||||
" -U\t\twarmup and try lock database pages in memory before dumping\n"
|
||||
" \t\tby default dump only the main DB\n",
|
||||
prog);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -250,11 +254,14 @@ int main(int argc, char *argv[]) {
|
||||
char *subname = nullptr, *buf4free = nullptr;
|
||||
unsigned envflags = 0;
|
||||
bool alldbs = false, list = false;
|
||||
bool warmup = false;
|
||||
MDBX_warmup_flags_t warmup_flags = MDBX_warmup_default;
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
while ((i = getopt(argc, argv,
|
||||
"uU"
|
||||
"a"
|
||||
"f:"
|
||||
"l"
|
||||
@ -311,6 +318,14 @@ int main(int argc, char *argv[]) {
|
||||
case 'r':
|
||||
rescue = true;
|
||||
break;
|
||||
case 'u':
|
||||
warmup = true;
|
||||
break;
|
||||
case 'U':
|
||||
warmup = true;
|
||||
warmup_flags =
|
||||
MDBX_warmup_force | MDBX_warmup_touchlimit | MDBX_warmup_lock;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@ -356,12 +371,22 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
rc = mdbx_env_open(
|
||||
env, envname,
|
||||
envflags | (rescue ? MDBX_RDONLY | MDBX_EXCLUSIVE : MDBX_RDONLY), 0);
|
||||
envflags | (rescue ? MDBX_RDONLY | MDBX_EXCLUSIVE | MDBX_VALIDATION
|
||||
: MDBX_RDONLY),
|
||||
0);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
error("mdbx_env_open", rc);
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
if (warmup) {
|
||||
rc = mdbx_env_warmup(env, nullptr, warmup_flags, 3600 * 65536);
|
||||
if (MDBX_IS_ERROR(rc)) {
|
||||
error("mdbx_env_warmup", rc);
|
||||
goto env_close;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &txn);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
error("mdbx_txn_begin", rc);
|
||||
@ -383,10 +408,10 @@ int main(int argc, char *argv[]) {
|
||||
error("mdbx_cursor_open", rc);
|
||||
goto txn_abort;
|
||||
}
|
||||
if (MDBX_DEBUG > 0 && rescue) {
|
||||
cursor->mc_flags |= C_SKIPORD;
|
||||
if (rescue) {
|
||||
cursor->mc_checking |= CC_SKIPORD;
|
||||
if (cursor->mc_xcursor)
|
||||
cursor->mc_xcursor->mx_cursor.mc_flags |= C_SKIPORD;
|
||||
cursor->mc_xcursor->mx_cursor.mc_checking |= CC_SKIPORD;
|
||||
}
|
||||
|
||||
bool have_raw = false;
|
||||
@ -401,7 +426,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (memchr(key.iov_base, '\0', key.iov_len))
|
||||
continue;
|
||||
subname = mdbx_realloc(buf4free, key.iov_len + 1);
|
||||
subname = osal_realloc(buf4free, key.iov_len + 1);
|
||||
if (!subname) {
|
||||
rc = MDBX_ENOMEM;
|
||||
break;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* mdbx_load.c - memory-mapped database load tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -20,7 +20,7 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#include <ctype.h>
|
||||
@ -213,7 +213,7 @@ static int readhdr(void) {
|
||||
if (str) {
|
||||
if (*str) {
|
||||
free(subname);
|
||||
subname = mdbx_strdup(str);
|
||||
subname = osal_strdup(str);
|
||||
if (!subname) {
|
||||
if (!quiet)
|
||||
perror("strdup()");
|
||||
@ -421,7 +421,7 @@ __hot static int readline(MDBX_val *out, MDBX_val *buf) {
|
||||
|
||||
/* Is buffer too short? */
|
||||
while (c1[len - 1] != '\n') {
|
||||
buf->iov_base = mdbx_realloc(buf->iov_base, buf->iov_len * 2);
|
||||
buf->iov_base = osal_realloc(buf->iov_base, buf->iov_len * 2);
|
||||
if (!buf->iov_base) {
|
||||
if (!quiet)
|
||||
fprintf(stderr,
|
||||
@ -560,7 +560,7 @@ int main(int argc, char *argv[]) {
|
||||
envflags |= MDBX_NOSUBDIR;
|
||||
break;
|
||||
case 's':
|
||||
subname = mdbx_strdup(optarg);
|
||||
subname = osal_strdup(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
putflags |= MDBX_NOOVERWRITE | MDBX_NODUPDATA;
|
||||
@ -606,7 +606,7 @@ int main(int argc, char *argv[]) {
|
||||
fflush(nullptr);
|
||||
|
||||
dbuf.iov_len = 4096;
|
||||
dbuf.iov_base = mdbx_malloc(dbuf.iov_len);
|
||||
dbuf.iov_base = osal_malloc(dbuf.iov_len);
|
||||
if (!dbuf.iov_base) {
|
||||
rc = MDBX_ENOMEM;
|
||||
error("value-buffer", rc);
|
||||
@ -673,7 +673,7 @@ int main(int argc, char *argv[]) {
|
||||
goto env_close;
|
||||
}
|
||||
|
||||
kbuf.iov_len = mdbx_env_get_maxvalsize_ex(env, 0) + 1;
|
||||
kbuf.iov_len = mdbx_env_get_maxvalsize_ex(env, 0) + (size_t)1;
|
||||
if (kbuf.iov_len >= INTPTR_MAX / 2) {
|
||||
if (!quiet)
|
||||
fprintf(stderr, "mdbx_env_get_maxkeysize() failed, returns %zu\n",
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* mdbx_stat.c - memory-mapped database status tool */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -20,7 +20,7 @@
|
||||
#pragma warning(disable : 4996) /* The POSIX name is deprecated... */
|
||||
#endif /* _MSC_VER (warnings) */
|
||||
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "internals.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@ -256,6 +256,17 @@ int main(int argc, char *argv[]) {
|
||||
printf(" WOP: %8" PRIu64
|
||||
"\t// number of explicit write operations (not a pages) to a disk\n",
|
||||
mei.mi_pgop_stat.wops);
|
||||
printf(" PreFault: %8" PRIu64
|
||||
"\t// number of prefault write operations (not a pages)\n",
|
||||
mei.mi_pgop_stat.prefault);
|
||||
printf(" mInCore: %8" PRIu64 "\t// number of mincore() calls\n",
|
||||
mei.mi_pgop_stat.mincore);
|
||||
printf(" mSync: %8" PRIu64
|
||||
"\t// number of explicit msync-to-disk operations (not a pages)\n",
|
||||
mei.mi_pgop_stat.msync);
|
||||
printf(" fSync: %8" PRIu64
|
||||
"\t// number of explicit fsync-to-disk operations (not a pages)\n",
|
||||
mei.mi_pgop_stat.fsync);
|
||||
}
|
||||
|
||||
if (envinfo) {
|
||||
@ -469,13 +480,13 @@ int main(int argc, char *argv[]) {
|
||||
MDBX_dbi subdbi;
|
||||
if (memchr(key.iov_base, '\0', key.iov_len))
|
||||
continue;
|
||||
subname = mdbx_malloc(key.iov_len + 1);
|
||||
subname = osal_malloc(key.iov_len + 1);
|
||||
memcpy(subname, key.iov_base, key.iov_len);
|
||||
subname[key.iov_len] = '\0';
|
||||
rc = mdbx_dbi_open(txn, subname, MDBX_DB_ACCEDE, &subdbi);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
printf("Status of %s\n", subname);
|
||||
mdbx_free(subname);
|
||||
osal_free(subname);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
if (rc == MDBX_INCOMPATIBLE)
|
||||
continue;
|
||||
|
146
src/options.h
146
src/options.h
@ -40,6 +40,8 @@
|
||||
#define MDBX_ENV_CHECKPID 1
|
||||
#endif
|
||||
#define MDBX_ENV_CHECKPID_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
|
||||
#elif !(MDBX_ENV_CHECKPID == 0 || MDBX_ENV_CHECKPID == 1)
|
||||
#error MDBX_ENV_CHECKPID must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_ENV_CHECKPID_CONFIG MDBX_STRINGIFY(MDBX_ENV_CHECKPID)
|
||||
#endif /* MDBX_ENV_CHECKPID */
|
||||
@ -49,6 +51,8 @@
|
||||
#ifndef MDBX_TXN_CHECKOWNER
|
||||
#define MDBX_TXN_CHECKOWNER 1
|
||||
#define MDBX_TXN_CHECKOWNER_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
|
||||
#elif !(MDBX_TXN_CHECKOWNER == 0 || MDBX_TXN_CHECKOWNER == 1)
|
||||
#error MDBX_TXN_CHECKOWNER must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_TXN_CHECKOWNER_CONFIG MDBX_STRINGIFY(MDBX_TXN_CHECKOWNER)
|
||||
#endif /* MDBX_TXN_CHECKOWNER */
|
||||
@ -62,6 +66,8 @@
|
||||
#define MDBX_TRUST_RTC 1
|
||||
#endif
|
||||
#define MDBX_TRUST_RTC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_TRUST_RTC)
|
||||
#elif !(MDBX_TRUST_RTC == 0 || MDBX_TRUST_RTC == 1)
|
||||
#error MDBX_TRUST_RTC must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_TRUST_RTC_CONFIG MDBX_STRINGIFY(MDBX_TRUST_RTC)
|
||||
#endif /* MDBX_TRUST_RTC */
|
||||
@ -73,6 +79,13 @@
|
||||
#error MDBX_ENABLE_REFUND must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_REFUND */
|
||||
|
||||
/** Controls profiling of GC search and updates. */
|
||||
#ifndef MDBX_ENABLE_PROFGC
|
||||
#define MDBX_ENABLE_PROFGC 0
|
||||
#elif !(MDBX_ENABLE_PROFGC == 0 || MDBX_ENABLE_PROFGC == 1)
|
||||
#error MDBX_ENABLE_PROFGC must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_PROFGC */
|
||||
|
||||
/** Controls gathering statistics for page operations. */
|
||||
#ifndef MDBX_ENABLE_PGOP_STAT
|
||||
#define MDBX_ENABLE_PGOP_STAT 1
|
||||
@ -80,7 +93,32 @@
|
||||
#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_PGOP_STAT */
|
||||
|
||||
/** Controls use of POSIX madvise() hints and friends. */
|
||||
/** Controls using Unix' mincore() to determine whether DB-pages
|
||||
* are resident in memory. */
|
||||
#ifndef MDBX_ENABLE_MINCORE
|
||||
#if MDBX_ENABLE_PREFAULT && \
|
||||
(defined(MINCORE_INCORE) || !(defined(_WIN32) || defined(_WIN64)))
|
||||
#define MDBX_ENABLE_MINCORE 1
|
||||
#else
|
||||
#define MDBX_ENABLE_MINCORE 0
|
||||
#endif
|
||||
#elif !(MDBX_ENABLE_MINCORE == 0 || MDBX_ENABLE_MINCORE == 1)
|
||||
#error MDBX_ENABLE_MINCORE must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_MINCORE */
|
||||
|
||||
/** Enables chunking long list of retired pages during huge transactions commit
|
||||
* to avoid use sequences of pages. */
|
||||
#ifndef MDBX_ENABLE_BIGFOOT
|
||||
#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
|
||||
#define MDBX_ENABLE_BIGFOOT 1
|
||||
#else
|
||||
#define MDBX_ENABLE_BIGFOOT 0
|
||||
#endif
|
||||
#elif !(MDBX_ENABLE_BIGFOOT == 0 || MDBX_ENABLE_BIGFOOT == 1)
|
||||
#error MDBX_ENABLE_BIGFOOT must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_BIGFOOT */
|
||||
|
||||
/** Controls using of POSIX' madvise() and/or similar hints. */
|
||||
#ifndef MDBX_ENABLE_MADVISE
|
||||
#define MDBX_ENABLE_MADVISE 1
|
||||
#elif !(MDBX_ENABLE_MADVISE == 0 || MDBX_ENABLE_MADVISE == 1)
|
||||
@ -89,11 +127,11 @@
|
||||
|
||||
/** Disable some checks to reduce an overhead and detection probability of
|
||||
* database corruption to a values closer to the LMDB. */
|
||||
#ifndef MDBX_DISABLE_PAGECHECKS
|
||||
#define MDBX_DISABLE_PAGECHECKS 0
|
||||
#elif !(MDBX_DISABLE_PAGECHECKS == 0 || MDBX_DISABLE_PAGECHECKS == 1)
|
||||
#error MDBX_DISABLE_PAGECHECKS must be defined as 0 or 1
|
||||
#endif /* MDBX_DISABLE_PAGECHECKS */
|
||||
#ifndef MDBX_DISABLE_VALIDATION
|
||||
#define MDBX_DISABLE_VALIDATION 0
|
||||
#elif !(MDBX_DISABLE_VALIDATION == 0 || MDBX_DISABLE_VALIDATION == 1)
|
||||
#error MDBX_DISABLE_VALIDATION must be defined as 0 or 1
|
||||
#endif /* MDBX_DISABLE_VALIDATION */
|
||||
|
||||
#ifndef MDBX_PNL_PREALLOC_FOR_RADIXSORT
|
||||
#define MDBX_PNL_PREALLOC_FOR_RADIXSORT 1
|
||||
@ -109,23 +147,22 @@
|
||||
#error MDBX_DPL_PREALLOC_FOR_RADIXSORT must be defined as 0 or 1
|
||||
#endif /* MDBX_DPL_PREALLOC_FOR_RADIXSORT */
|
||||
|
||||
/** Basically, this build-option is for TODO. Guess it should be replaced
|
||||
* with MDBX_ENABLE_WRITEMAP_SPILLING with the three variants:
|
||||
* 0/OFF = Don't track dirty pages at all and don't spilling ones.
|
||||
* This should be by-default on Linux and may-be other systems
|
||||
* (not sure: Darwin/OSX, FreeBSD, Windows 10) where kernel provides
|
||||
* properly LRU tracking and async writing on-demand.
|
||||
* 1/ON = Lite tracking of dirty pages but with LRU labels and explicit
|
||||
* spilling with msync(MS_ASYNC). */
|
||||
#ifndef MDBX_FAKE_SPILL_WRITEMAP
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
#define MDBX_FAKE_SPILL_WRITEMAP 1 /* msync(MS_ASYNC) is no-op on Linux */
|
||||
/** Controls dirty pages tracking, spilling and persisting in MDBX_WRITEMAP
|
||||
* mode. 0/OFF = Don't track dirty pages at all, don't spill ones, and use
|
||||
* msync() to persist data. This is by-default on Linux and other systems where
|
||||
* kernel provides properly LRU tracking and effective flushing on-demand. 1/ON
|
||||
* = Tracking of dirty pages but with LRU labels for spilling and explicit
|
||||
* persist ones by write(). This may be reasonable for systems which low
|
||||
* performance of msync() and/or LRU tracking. */
|
||||
#ifndef MDBX_AVOID_MSYNC
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MDBX_AVOID_MSYNC 1
|
||||
#else
|
||||
#define MDBX_FAKE_SPILL_WRITEMAP 0
|
||||
#define MDBX_AVOID_MSYNC 0
|
||||
#endif
|
||||
#elif !(MDBX_FAKE_SPILL_WRITEMAP == 0 || MDBX_FAKE_SPILL_WRITEMAP == 1)
|
||||
#error MDBX_FAKE_SPILL_WRITEMAP must be defined as 0 or 1
|
||||
#endif /* MDBX_FAKE_SPILL_WRITEMAP */
|
||||
#elif !(MDBX_AVOID_MSYNC == 0 || MDBX_AVOID_MSYNC == 1)
|
||||
#error MDBX_AVOID_MSYNC must be defined as 0 or 1
|
||||
#endif /* MDBX_AVOID_MSYNC */
|
||||
|
||||
/** Controls sort order of internal page number lists.
|
||||
* This mostly experimental/advanced option with not for regular MDBX users.
|
||||
@ -182,6 +219,31 @@
|
||||
#ifndef MDBX_HAVE_C11ATOMICS
|
||||
#endif /* MDBX_HAVE_C11ATOMICS */
|
||||
|
||||
/** If defined then enables use the GCC's `__builtin_cpu_supports()`
|
||||
* for runtime dispatching depending on the CPU's capabilities.
|
||||
* \note Defining `MDBX_HAVE_BUILTIN_CPU_SUPPORTS` to `0` should avoided unless
|
||||
* build for particular single-target platform, since on AMD64/x86 this disables
|
||||
* dynamic choice (at runtime) of SSE2 / AVX2 / AVX512 instructions
|
||||
* with fallback to non-accelerated baseline code. */
|
||||
#ifndef MDBX_HAVE_BUILTIN_CPU_SUPPORTS
|
||||
#if defined(__APPLE__) || defined(BIONIC)
|
||||
/* Never use any modern features on Apple's or Google's OSes
|
||||
* since a lot of troubles with compatibility and/or performance */
|
||||
#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0
|
||||
#elif defined(__e2k__)
|
||||
#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0
|
||||
#elif __has_builtin(__builtin_cpu_supports) || \
|
||||
defined(__BUILTIN_CPU_SUPPORTS__) || \
|
||||
(defined(__ia32__) && __GNUC_PREREQ(4, 8) && __GLIBC_PREREQ(2, 23))
|
||||
#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 1
|
||||
#else
|
||||
#define MDBX_HAVE_BUILTIN_CPU_SUPPORTS 0
|
||||
#endif
|
||||
#elif !(MDBX_HAVE_BUILTIN_CPU_SUPPORTS == 0 || \
|
||||
MDBX_HAVE_BUILTIN_CPU_SUPPORTS == 1)
|
||||
#error MDBX_HAVE_BUILTIN_CPU_SUPPORTS must be defined as 0 or 1
|
||||
#endif /* MDBX_HAVE_BUILTIN_CPU_SUPPORTS */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Win32 File Locking API for \ref MDBX_LOCKING */
|
||||
@ -248,6 +310,8 @@
|
||||
#define MDBX_USE_OFDLOCKS 0
|
||||
#endif
|
||||
#define MDBX_USE_OFDLOCKS_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
|
||||
#elif !(MDBX_USE_OFDLOCKS == 0 || MDBX_USE_OFDLOCKS == 1)
|
||||
#error MDBX_USE_OFDLOCKS must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_USE_OFDLOCKS_CONFIG MDBX_STRINGIFY(MDBX_USE_OFDLOCKS)
|
||||
#endif /* MDBX_USE_OFDLOCKS */
|
||||
@ -261,6 +325,8 @@
|
||||
#else
|
||||
#define MDBX_USE_SENDFILE 0
|
||||
#endif
|
||||
#elif !(MDBX_USE_SENDFILE == 0 || MDBX_USE_SENDFILE == 1)
|
||||
#error MDBX_USE_SENDFILE must be defined as 0 or 1
|
||||
#endif /* MDBX_USE_SENDFILE */
|
||||
|
||||
/** Advanced: Using copy_file_range() syscall (autodetection by default). */
|
||||
@ -270,6 +336,8 @@
|
||||
#else
|
||||
#define MDBX_USE_COPYFILERANGE 0
|
||||
#endif
|
||||
#elif !(MDBX_USE_COPYFILERANGE == 0 || MDBX_USE_COPYFILERANGE == 1)
|
||||
#error MDBX_USE_COPYFILERANGE must be defined as 0 or 1
|
||||
#endif /* MDBX_USE_COPYFILERANGE */
|
||||
|
||||
/** Advanced: Using sync_file_range() syscall (autodetection by default). */
|
||||
@ -281,6 +349,8 @@
|
||||
#else
|
||||
#define MDBX_USE_SYNCFILERANGE 0
|
||||
#endif
|
||||
#elif !(MDBX_USE_SYNCFILERANGE == 0 || MDBX_USE_SYNCFILERANGE == 1)
|
||||
#error MDBX_USE_SYNCFILERANGE must be defined as 0 or 1
|
||||
#endif /* MDBX_USE_SYNCFILERANGE */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -292,6 +362,9 @@
|
||||
#else
|
||||
#define MDBX_CPU_WRITEBACK_INCOHERENT 1
|
||||
#endif
|
||||
#elif !(MDBX_CPU_WRITEBACK_INCOHERENT == 0 || \
|
||||
MDBX_CPU_WRITEBACK_INCOHERENT == 1)
|
||||
#error MDBX_CPU_WRITEBACK_INCOHERENT must be defined as 0 or 1
|
||||
#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
|
||||
|
||||
#ifndef MDBX_MMAP_INCOHERENT_FILE_WRITE
|
||||
@ -300,6 +373,9 @@
|
||||
#else
|
||||
#define MDBX_MMAP_INCOHERENT_FILE_WRITE 0
|
||||
#endif
|
||||
#elif !(MDBX_MMAP_INCOHERENT_FILE_WRITE == 0 || \
|
||||
MDBX_MMAP_INCOHERENT_FILE_WRITE == 1)
|
||||
#error MDBX_MMAP_INCOHERENT_FILE_WRITE must be defined as 0 or 1
|
||||
#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
|
||||
|
||||
#ifndef MDBX_MMAP_INCOHERENT_CPU_CACHE
|
||||
@ -312,8 +388,21 @@
|
||||
/* LY: assume no relevant mmap/dcache issues. */
|
||||
#define MDBX_MMAP_INCOHERENT_CPU_CACHE 0
|
||||
#endif
|
||||
#elif !(MDBX_MMAP_INCOHERENT_CPU_CACHE == 0 || \
|
||||
MDBX_MMAP_INCOHERENT_CPU_CACHE == 1)
|
||||
#error MDBX_MMAP_INCOHERENT_CPU_CACHE must be defined as 0 or 1
|
||||
#endif /* MDBX_MMAP_INCOHERENT_CPU_CACHE */
|
||||
|
||||
#ifndef MDBX_MMAP_USE_MS_ASYNC
|
||||
#if MDBX_MMAP_INCOHERENT_FILE_WRITE || MDBX_MMAP_INCOHERENT_CPU_CACHE
|
||||
#define MDBX_MMAP_USE_MS_ASYNC 1
|
||||
#else
|
||||
#define MDBX_MMAP_USE_MS_ASYNC 0
|
||||
#endif
|
||||
#elif !(MDBX_MMAP_USE_MS_ASYNC == 0 || MDBX_MMAP_USE_MS_ASYNC == 1)
|
||||
#error MDBX_MMAP_USE_MS_ASYNC must be defined as 0 or 1
|
||||
#endif /* MDBX_MMAP_USE_MS_ASYNC */
|
||||
|
||||
#ifndef MDBX_64BIT_ATOMIC
|
||||
#if MDBX_WORDBITS >= 64 || defined(DOXYGEN)
|
||||
#define MDBX_64BIT_ATOMIC 1
|
||||
@ -321,6 +410,8 @@
|
||||
#define MDBX_64BIT_ATOMIC 0
|
||||
#endif
|
||||
#define MDBX_64BIT_ATOMIC_CONFIG "AUTO=" MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
|
||||
#elif !(MDBX_64BIT_ATOMIC == 0 || MDBX_64BIT_ATOMIC == 1)
|
||||
#error MDBX_64BIT_ATOMIC must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_64BIT_ATOMIC_CONFIG MDBX_STRINGIFY(MDBX_64BIT_ATOMIC)
|
||||
#endif /* MDBX_64BIT_ATOMIC */
|
||||
@ -346,6 +437,8 @@
|
||||
#endif
|
||||
#elif defined(_MSC_VER) || defined(__APPLE__) || defined(DOXYGEN)
|
||||
#define MDBX_64BIT_CAS 1
|
||||
#elif !(MDBX_64BIT_CAS == 0 || MDBX_64BIT_CAS == 1)
|
||||
#error MDBX_64BIT_CAS must be defined as 0 or 1
|
||||
#else
|
||||
#define MDBX_64BIT_CAS MDBX_64BIT_ATOMIC
|
||||
#endif
|
||||
@ -355,14 +448,11 @@
|
||||
#endif /* MDBX_64BIT_CAS */
|
||||
|
||||
#ifndef MDBX_UNALIGNED_OK
|
||||
#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__)
|
||||
#if defined(__ALIGNED__) || defined(__SANITIZE_UNDEFINED__) || \
|
||||
defined(ENABLE_UBSAN)
|
||||
#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
|
||||
#elif defined(__ARM_FEATURE_UNALIGNED)
|
||||
#define MDBX_UNALIGNED_OK 4 /* ok unaligned for 32-bit words */
|
||||
#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
|
||||
/* expecting an optimization will well done, also this
|
||||
* hushes false-positives from UBSAN (undefined behaviour sanitizer) */
|
||||
#define MDBX_UNALIGNED_OK 0
|
||||
#elif defined(__e2k__) || defined(__elbrus__)
|
||||
#if __iset__ > 4
|
||||
#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
|
||||
@ -371,6 +461,10 @@
|
||||
#endif
|
||||
#elif defined(__ia32__)
|
||||
#define MDBX_UNALIGNED_OK 8 /* ok unaligned for 64-bit words */
|
||||
#elif __CLANG_PREREQ(5, 0) || __GNUC_PREREQ(5, 0)
|
||||
/* expecting an optimization will well done, also this
|
||||
* hushes false-positives from UBSAN (undefined behaviour sanitizer) */
|
||||
#define MDBX_UNALIGNED_OK 0
|
||||
#else
|
||||
#define MDBX_UNALIGNED_OK 0 /* no unaligned access allowed */
|
||||
#endif
|
||||
|
1461
src/osal.c
1461
src/osal.c
File diff suppressed because it is too large
Load Diff
513
src/osal.h
513
src/osal.h
@ -1,7 +1,7 @@
|
||||
/* https://en.wikipedia.org/wiki/Operating_system_abstraction_layer */
|
||||
|
||||
/*
|
||||
* Copyright 2015-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2015-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -58,7 +58,7 @@
|
||||
#include <sys/cachectl.h>
|
||||
#endif
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
|
||||
MDBX_MAYBE_UNUSED static __inline void osal_compiler_barrier(void) {
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
@ -78,7 +78,7 @@ MDBX_MAYBE_UNUSED static __inline void mdbx_compiler_barrier(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
|
||||
MDBX_MAYBE_UNUSED static __inline void osal_memory_barrier(void) {
|
||||
#ifdef MDBX_HAVE_C11ATOMICS
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
#elif defined(__ATOMIC_SEQ_CST)
|
||||
@ -116,8 +116,8 @@ MDBX_MAYBE_UNUSED static __inline void mdbx_memory_barrier(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define HAVE_SYS_STAT_H
|
||||
#define HAVE_SYS_TYPES_H
|
||||
typedef HANDLE mdbx_thread_t;
|
||||
typedef unsigned mdbx_thread_key_t;
|
||||
typedef HANDLE osal_thread_t;
|
||||
typedef unsigned osal_thread_key_t;
|
||||
#define MAP_FAILED NULL
|
||||
#define HIGH_DWORD(v) ((DWORD)((sizeof(v) > 4) ? ((uint64_t)(v) >> 32) : 0))
|
||||
#define THREAD_CALL WINAPI
|
||||
@ -125,8 +125,8 @@ typedef unsigned mdbx_thread_key_t;
|
||||
typedef struct {
|
||||
HANDLE mutex;
|
||||
HANDLE event[2];
|
||||
} mdbx_condpair_t;
|
||||
typedef CRITICAL_SECTION mdbx_fastmutex_t;
|
||||
} osal_condpair_t;
|
||||
typedef CRITICAL_SECTION osal_fastmutex_t;
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__try)
|
||||
/* *INDENT-OFF* */
|
||||
@ -139,36 +139,36 @@ typedef CRITICAL_SECTION mdbx_fastmutex_t;
|
||||
|
||||
#if MDBX_WITHOUT_MSVC_CRT
|
||||
|
||||
#ifndef mdbx_malloc
|
||||
static inline void *mdbx_malloc(size_t bytes) {
|
||||
#ifndef osal_malloc
|
||||
static inline void *osal_malloc(size_t bytes) {
|
||||
return HeapAlloc(GetProcessHeap(), 0, bytes);
|
||||
}
|
||||
#endif /* mdbx_malloc */
|
||||
#endif /* osal_malloc */
|
||||
|
||||
#ifndef mdbx_calloc
|
||||
static inline void *mdbx_calloc(size_t nelem, size_t size) {
|
||||
#ifndef osal_calloc
|
||||
static inline void *osal_calloc(size_t nelem, size_t size) {
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nelem * size);
|
||||
}
|
||||
#endif /* mdbx_calloc */
|
||||
#endif /* osal_calloc */
|
||||
|
||||
#ifndef mdbx_realloc
|
||||
static inline void *mdbx_realloc(void *ptr, size_t bytes) {
|
||||
#ifndef osal_realloc
|
||||
static inline void *osal_realloc(void *ptr, size_t bytes) {
|
||||
return ptr ? HeapReAlloc(GetProcessHeap(), 0, ptr, bytes)
|
||||
: HeapAlloc(GetProcessHeap(), 0, bytes);
|
||||
}
|
||||
#endif /* mdbx_realloc */
|
||||
#endif /* osal_realloc */
|
||||
|
||||
#ifndef mdbx_free
|
||||
static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
|
||||
#endif /* mdbx_free */
|
||||
#ifndef osal_free
|
||||
static inline void osal_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
|
||||
#endif /* osal_free */
|
||||
|
||||
#else /* MDBX_WITHOUT_MSVC_CRT */
|
||||
|
||||
#define mdbx_malloc malloc
|
||||
#define mdbx_calloc calloc
|
||||
#define mdbx_realloc realloc
|
||||
#define mdbx_free free
|
||||
#define mdbx_strdup _strdup
|
||||
#define osal_malloc malloc
|
||||
#define osal_calloc calloc
|
||||
#define osal_realloc realloc
|
||||
#define osal_free free
|
||||
#define osal_strdup _strdup
|
||||
|
||||
#endif /* MDBX_WITHOUT_MSVC_CRT */
|
||||
|
||||
@ -180,26 +180,23 @@ static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); }
|
||||
#define vsnprintf _vsnprintf /* ntdll */
|
||||
#endif
|
||||
|
||||
size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src, size_t src_n);
|
||||
size_t mdbx_w2mb(char *dst, size_t dst_n, const wchar_t *src, size_t src_n);
|
||||
|
||||
#else /*----------------------------------------------------------------------*/
|
||||
|
||||
typedef pthread_t mdbx_thread_t;
|
||||
typedef pthread_key_t mdbx_thread_key_t;
|
||||
typedef pthread_t osal_thread_t;
|
||||
typedef pthread_key_t osal_thread_key_t;
|
||||
#define INVALID_HANDLE_VALUE (-1)
|
||||
#define THREAD_CALL
|
||||
#define THREAD_RESULT void *
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond[2];
|
||||
} mdbx_condpair_t;
|
||||
typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
#define mdbx_malloc malloc
|
||||
#define mdbx_calloc calloc
|
||||
#define mdbx_realloc realloc
|
||||
#define mdbx_free free
|
||||
#define mdbx_strdup strdup
|
||||
} osal_condpair_t;
|
||||
typedef pthread_mutex_t osal_fastmutex_t;
|
||||
#define osal_malloc malloc
|
||||
#define osal_calloc calloc
|
||||
#define osal_realloc realloc
|
||||
#define osal_free free
|
||||
#define osal_strdup strdup
|
||||
#endif /* Platform */
|
||||
|
||||
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
|
||||
@ -213,24 +210,30 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* OS abstraction layer stuff */
|
||||
|
||||
MDBX_INTERNAL_VAR unsigned sys_pagesize;
|
||||
MDBX_MAYBE_UNUSED MDBX_INTERNAL_VAR unsigned sys_pagesize_ln2,
|
||||
sys_allocation_granularity;
|
||||
|
||||
/* Get the size of a memory page for the system.
|
||||
* This is the basic size that the platform's memory manager uses, and is
|
||||
* fundamental to the use of memory-mapped files. */
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline size_t
|
||||
mdbx_syspagesize(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
return si.dwPageSize;
|
||||
#else
|
||||
return sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
osal_syspagesize(void) {
|
||||
assert(sys_pagesize > 0 && (sys_pagesize & (sys_pagesize - 1)) == 0);
|
||||
return sys_pagesize;
|
||||
}
|
||||
|
||||
typedef struct mdbx_mmap_param {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef wchar_t pathchar_t;
|
||||
#define MDBX_PRIsPATH "ls"
|
||||
#else
|
||||
typedef char pathchar_t;
|
||||
#define MDBX_PRIsPATH "s"
|
||||
#endif
|
||||
|
||||
typedef struct osal_mmap {
|
||||
union {
|
||||
void *address;
|
||||
uint8_t *dxb;
|
||||
void *base;
|
||||
struct MDBX_lockinfo *lck;
|
||||
};
|
||||
mdbx_filehandle_t fd;
|
||||
@ -240,7 +243,7 @@ typedef struct mdbx_mmap_param {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE section; /* memory-mapped section handle */
|
||||
#endif
|
||||
} mdbx_mmap_t;
|
||||
} osal_mmap_t;
|
||||
|
||||
typedef union bin128 {
|
||||
__anonymous_struct_extension__ struct { uint64_t x, y; };
|
||||
@ -248,28 +251,162 @@ typedef union bin128 {
|
||||
} bin128_t;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef union MDBX_srwlock {
|
||||
typedef union osal_srwlock {
|
||||
__anonymous_struct_extension__ struct {
|
||||
long volatile readerCount;
|
||||
long volatile writerCount;
|
||||
};
|
||||
RTL_SRWLOCK native;
|
||||
} MDBX_srwlock;
|
||||
} osal_srwlock_t;
|
||||
#endif /* Windows */
|
||||
|
||||
#ifndef MDBX_HAVE_PWRITEV
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
|
||||
#elif defined(__ANDROID_API__)
|
||||
|
||||
#if __ANDROID_API__ < 24
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
#else
|
||||
#define MDBX_HAVE_PWRITEV 1
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__) || defined(__MACH__) || defined(_DARWIN_C_SOURCE)
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && defined(MAC_OS_VERSION_11_0) && \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
|
||||
/* FIXME: add checks for IOS versions, etc */
|
||||
#define MDBX_HAVE_PWRITEV 1
|
||||
#else
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
#endif
|
||||
|
||||
#elif defined(_SC_IOV_MAX) || (defined(IOV_MAX) && IOV_MAX > 1)
|
||||
#define MDBX_HAVE_PWRITEV 1
|
||||
#else
|
||||
#define MDBX_HAVE_PWRITEV 0
|
||||
#endif
|
||||
#endif /* MDBX_HAVE_PWRITEV */
|
||||
|
||||
typedef struct ior_item {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
OVERLAPPED ov;
|
||||
#define ior_svg_gap4terminator 1
|
||||
#define ior_sgv_element FILE_SEGMENT_ELEMENT
|
||||
#else
|
||||
size_t offset;
|
||||
#if MDBX_HAVE_PWRITEV
|
||||
size_t sgvcnt;
|
||||
#define ior_svg_gap4terminator 0
|
||||
#define ior_sgv_element struct iovec
|
||||
#endif /* MDBX_HAVE_PWRITEV */
|
||||
#endif /* !Windows */
|
||||
union {
|
||||
MDBX_val single;
|
||||
#if defined(ior_sgv_element)
|
||||
ior_sgv_element sgv[1 + ior_svg_gap4terminator];
|
||||
#endif /* ior_sgv_element */
|
||||
};
|
||||
} ior_item_t;
|
||||
|
||||
typedef struct osal_ioring {
|
||||
unsigned slots_left;
|
||||
unsigned allocated;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define IOR_STATE_LOCKED 1
|
||||
HANDLE overlapped_fd;
|
||||
unsigned pagesize;
|
||||
unsigned last_sgvcnt;
|
||||
size_t last_bytes;
|
||||
uint8_t direct, state, pagesize_ln2;
|
||||
unsigned event_stack;
|
||||
HANDLE *event_pool;
|
||||
volatile LONG async_waiting;
|
||||
volatile LONG async_completed;
|
||||
HANDLE async_done;
|
||||
|
||||
#define ior_last_sgvcnt(ior, item) (ior)->last_sgvcnt
|
||||
#define ior_last_bytes(ior, item) (ior)->last_bytes
|
||||
#elif MDBX_HAVE_PWRITEV
|
||||
unsigned last_bytes;
|
||||
#define ior_last_sgvcnt(ior, item) (item)->sgvcnt
|
||||
#define ior_last_bytes(ior, item) (ior)->last_bytes
|
||||
#else
|
||||
#define ior_last_sgvcnt(ior, item) (1)
|
||||
#define ior_last_bytes(ior, item) (item)->single.iov_len
|
||||
#endif /* !Windows */
|
||||
ior_item_t *last;
|
||||
ior_item_t *pool;
|
||||
char *boundary;
|
||||
} osal_ioring_t;
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
/* Actually this is not ioring for now, but on the way. */
|
||||
MDBX_INTERNAL_FUNC int osal_ioring_create(osal_ioring_t *
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
,
|
||||
bool enable_direct,
|
||||
mdbx_filehandle_t overlapped_fd
|
||||
#endif /* Windows */
|
||||
);
|
||||
MDBX_INTERNAL_FUNC int osal_ioring_resize(osal_ioring_t *, size_t items);
|
||||
MDBX_INTERNAL_FUNC void osal_ioring_destroy(osal_ioring_t *);
|
||||
MDBX_INTERNAL_FUNC void osal_ioring_reset(osal_ioring_t *);
|
||||
MDBX_INTERNAL_FUNC int osal_ioring_add(osal_ioring_t *ctx, const size_t offset,
|
||||
void *data, const size_t bytes);
|
||||
typedef struct osal_ioring_write_result {
|
||||
int err;
|
||||
unsigned wops;
|
||||
} osal_ioring_write_result_t;
|
||||
MDBX_INTERNAL_FUNC osal_ioring_write_result_t
|
||||
osal_ioring_write(osal_ioring_t *ior, mdbx_filehandle_t fd);
|
||||
|
||||
typedef struct iov_ctx iov_ctx_t;
|
||||
MDBX_INTERNAL_FUNC 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));
|
||||
|
||||
MDBX_MAYBE_UNUSED static inline unsigned
|
||||
osal_ioring_left(const osal_ioring_t *ior) {
|
||||
return ior->slots_left;
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED static inline unsigned
|
||||
osal_ioring_used(const osal_ioring_t *ior) {
|
||||
return ior->allocated - ior->slots_left;
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED static inline int
|
||||
osal_ioring_prepare(osal_ioring_t *ior, size_t items, size_t bytes) {
|
||||
items = (items > 32) ? items : 32;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (ior->direct) {
|
||||
const size_t npages = bytes >> ior->pagesize_ln2;
|
||||
items = (items > npages) ? items : npages;
|
||||
}
|
||||
#else
|
||||
(void)bytes;
|
||||
#endif
|
||||
items = (items < 65536) ? items : 65536;
|
||||
if (likely(ior->allocated >= items))
|
||||
return MDBX_SUCCESS;
|
||||
return osal_ioring_resize(ior, items);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* libc compatibility stuff */
|
||||
|
||||
#if (!defined(__GLIBC__) && __GLIBC_PREREQ(2, 1)) && \
|
||||
(defined(_GNU_SOURCE) || defined(_BSD_SOURCE))
|
||||
#define mdbx_asprintf asprintf
|
||||
#define mdbx_vasprintf vasprintf
|
||||
#define osal_asprintf asprintf
|
||||
#define osal_vasprintf vasprintf
|
||||
#else
|
||||
MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC
|
||||
MDBX_PRINTF_ARGS(2, 3) int mdbx_asprintf(char **strp, const char *fmt, ...);
|
||||
MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
MDBX_PRINTF_ARGS(2, 3) int osal_asprintf(char **strp, const char *fmt, ...);
|
||||
MDBX_INTERNAL_FUNC int osal_vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
#endif
|
||||
|
||||
#if !defined(MADV_DODUMP) && defined(MADV_CORE)
|
||||
@ -280,12 +417,14 @@ MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
#define MADV_DONTDUMP MADV_NOCORE
|
||||
#endif /* MADV_NOCORE -> MADV_DONTDUMP */
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void mdbx_osal_jitter(bool tiny);
|
||||
MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
|
||||
MDBX_MAYBE_UNUSED MDBX_INTERNAL_FUNC void osal_jitter(bool tiny);
|
||||
MDBX_MAYBE_UNUSED static __inline void jitter4testing(bool tiny);
|
||||
|
||||
/* max bytes to write in one call */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MAX_WRITE UINT32_C(0x01000000)
|
||||
#if defined(_WIN64)
|
||||
#define MAX_WRITE UINT32_C(0x10000000)
|
||||
#elif defined(_WIN32)
|
||||
#define MAX_WRITE UINT32_C(0x04000000)
|
||||
#else
|
||||
#define MAX_WRITE UINT32_C(0x3f000000)
|
||||
|
||||
@ -332,15 +471,15 @@ MDBX_MAYBE_UNUSED static __inline void mdbx_jitter4testing(bool tiny);
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
|
||||
MDBX_INTERNAL_VAR uint32_t linux_kernel_version;
|
||||
MDBX_INTERNAL_VAR bool mdbx_RunningOnWSL1 /* Windows Subsystem 1 for Linux */;
|
||||
#endif /* Linux */
|
||||
|
||||
#ifndef mdbx_strdup
|
||||
LIBMDBX_API char *mdbx_strdup(const char *str);
|
||||
#ifndef osal_strdup
|
||||
LIBMDBX_API char *osal_strdup(const char *str);
|
||||
#endif
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
|
||||
MDBX_MAYBE_UNUSED static __inline int osal_get_errno(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD rc = GetLastError();
|
||||
#else
|
||||
@ -349,84 +488,101 @@ MDBX_MAYBE_UNUSED static __inline int mdbx_get_errno(void) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifndef mdbx_memalign_alloc
|
||||
MDBX_INTERNAL_FUNC int mdbx_memalign_alloc(size_t alignment, size_t bytes,
|
||||
#ifndef osal_memalign_alloc
|
||||
MDBX_INTERNAL_FUNC int osal_memalign_alloc(size_t alignment, size_t bytes,
|
||||
void **result);
|
||||
#endif
|
||||
#ifndef mdbx_memalign_free
|
||||
MDBX_INTERNAL_FUNC void mdbx_memalign_free(void *ptr);
|
||||
#ifndef osal_memalign_free
|
||||
MDBX_INTERNAL_FUNC void osal_memalign_free(void *ptr);
|
||||
#endif
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_init(mdbx_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_lock(mdbx_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_unlock(mdbx_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_signal(mdbx_condpair_t *condpair,
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_init(osal_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_lock(osal_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_unlock(osal_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_signal(osal_condpair_t *condpair,
|
||||
bool part);
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_wait(mdbx_condpair_t *condpair, bool part);
|
||||
MDBX_INTERNAL_FUNC int mdbx_condpair_destroy(mdbx_condpair_t *condpair);
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_wait(osal_condpair_t *condpair, bool part);
|
||||
MDBX_INTERNAL_FUNC int osal_condpair_destroy(osal_condpair_t *condpair);
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_fastmutex_init(mdbx_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int mdbx_fastmutex_acquire(mdbx_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int mdbx_fastmutex_destroy(mdbx_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int osal_fastmutex_init(osal_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int osal_fastmutex_acquire(osal_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int osal_fastmutex_release(osal_fastmutex_t *fastmutex);
|
||||
MDBX_INTERNAL_FUNC int osal_fastmutex_destroy(osal_fastmutex_t *fastmutex);
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
|
||||
int iovcnt, uint64_t offset,
|
||||
size_t expected_written);
|
||||
MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
|
||||
MDBX_INTERNAL_FUNC int osal_pwritev(mdbx_filehandle_t fd, struct iovec *iov,
|
||||
size_t sgvcnt, uint64_t offset);
|
||||
MDBX_INTERNAL_FUNC int osal_pread(mdbx_filehandle_t fd, void *buf, size_t count,
|
||||
uint64_t offset);
|
||||
MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
MDBX_INTERNAL_FUNC int osal_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
size_t count, uint64_t offset);
|
||||
MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
|
||||
MDBX_INTERNAL_FUNC int osal_write(mdbx_filehandle_t fd, const void *buf,
|
||||
size_t count);
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_thread_create(mdbx_thread_t *thread,
|
||||
osal_thread_create(osal_thread_t *thread,
|
||||
THREAD_RESULT(THREAD_CALL *start_routine)(void *),
|
||||
void *arg);
|
||||
MDBX_INTERNAL_FUNC int mdbx_thread_join(mdbx_thread_t thread);
|
||||
MDBX_INTERNAL_FUNC int osal_thread_join(osal_thread_t thread);
|
||||
|
||||
enum mdbx_syncmode_bits {
|
||||
enum osal_syncmode_bits {
|
||||
MDBX_SYNC_NONE = 0,
|
||||
MDBX_SYNC_DATA = 1,
|
||||
MDBX_SYNC_SIZE = 2,
|
||||
MDBX_SYNC_IODQ = 4
|
||||
MDBX_SYNC_KICK = 1,
|
||||
MDBX_SYNC_DATA = 2,
|
||||
MDBX_SYNC_SIZE = 4,
|
||||
MDBX_SYNC_IODQ = 8
|
||||
};
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_fsync(mdbx_filehandle_t fd,
|
||||
const enum mdbx_syncmode_bits mode_bits);
|
||||
MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
|
||||
MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
|
||||
MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
|
||||
MDBX_INTERNAL_FUNC int osal_fsync(mdbx_filehandle_t fd,
|
||||
const enum osal_syncmode_bits mode_bits);
|
||||
MDBX_INTERNAL_FUNC int osal_ftruncate(mdbx_filehandle_t fd, uint64_t length);
|
||||
MDBX_INTERNAL_FUNC int osal_fseek(mdbx_filehandle_t fd, uint64_t pos);
|
||||
MDBX_INTERNAL_FUNC int osal_filesize(mdbx_filehandle_t fd, uint64_t *length);
|
||||
|
||||
enum mdbx_openfile_purpose {
|
||||
MDBX_OPEN_DXB_READ = 0,
|
||||
MDBX_OPEN_DXB_LAZY = 1,
|
||||
MDBX_OPEN_DXB_DSYNC = 2,
|
||||
MDBX_OPEN_LCK = 3,
|
||||
MDBX_OPEN_COPY = 4,
|
||||
MDBX_OPEN_DELETE = 5
|
||||
enum osal_openfile_purpose {
|
||||
MDBX_OPEN_DXB_READ,
|
||||
MDBX_OPEN_DXB_LAZY,
|
||||
MDBX_OPEN_DXB_DSYNC,
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
MDBX_OPEN_DXB_OVERLAPPED,
|
||||
MDBX_OPEN_DXB_OVERLAPPED_DIRECT,
|
||||
#endif /* Windows */
|
||||
MDBX_OPEN_LCK,
|
||||
MDBX_OPEN_COPY,
|
||||
MDBX_OPEN_DELETE
|
||||
};
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
MDBX_MAYBE_UNUSED static __inline bool osal_isdirsep(pathchar_t c) {
|
||||
return
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
c == '\\' ||
|
||||
#endif
|
||||
c == '/';
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC bool osal_pathequal(const pathchar_t *l, const pathchar_t *r,
|
||||
size_t len);
|
||||
MDBX_INTERNAL_FUNC pathchar_t *osal_fileext(const pathchar_t *pathname,
|
||||
size_t len);
|
||||
MDBX_INTERNAL_FUNC int osal_fileexists(const pathchar_t *pathname);
|
||||
MDBX_INTERNAL_FUNC 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);
|
||||
MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait);
|
||||
MDBX_INTERNAL_FUNC int osal_closefile(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int osal_removefile(const pathchar_t *pathname);
|
||||
MDBX_INTERNAL_FUNC int osal_removedirectory(const pathchar_t *pathname);
|
||||
MDBX_INTERNAL_FUNC int osal_is_pipe(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int osal_lockfile(mdbx_filehandle_t fd, bool wait);
|
||||
|
||||
#define MMAP_OPTION_TRUNCATE 1
|
||||
#define MMAP_OPTION_SEMAPHORE 2
|
||||
MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
|
||||
const size_t must, const size_t limit,
|
||||
const unsigned options);
|
||||
MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map);
|
||||
MDBX_INTERNAL_FUNC int osal_mmap(const int flags, osal_mmap_t *map, size_t size,
|
||||
const size_t limit, const unsigned options);
|
||||
MDBX_INTERNAL_FUNC int osal_munmap(osal_mmap_t *map);
|
||||
#define MDBX_MRESIZE_MAY_MOVE 0x00000100
|
||||
#define MDBX_MRESIZE_MAY_UNMAP 0x00000200
|
||||
MDBX_INTERNAL_FUNC int mdbx_mresize(const int flags, mdbx_mmap_t *map,
|
||||
MDBX_INTERNAL_FUNC int osal_mresize(const int flags, osal_mmap_t *map,
|
||||
size_t size, size_t limit);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef struct {
|
||||
@ -434,17 +590,19 @@ typedef struct {
|
||||
HANDLE handles[31];
|
||||
} mdbx_handle_array_t;
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
|
||||
osal_suspend_threads_before_remap(MDBX_env *env, mdbx_handle_array_t **array);
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
|
||||
osal_resume_threads_after_remap(mdbx_handle_array_t *array);
|
||||
#endif /* Windows */
|
||||
MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
|
||||
MDBX_INTERNAL_FUNC int osal_msync(const osal_mmap_t *map, size_t offset,
|
||||
size_t length,
|
||||
enum mdbx_syncmode_bits mode_bits);
|
||||
MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
|
||||
const char *pathname, int err);
|
||||
enum osal_syncmode_bits mode_bits);
|
||||
MDBX_INTERNAL_FUNC int osal_check_fs_rdonly(mdbx_filehandle_t handle,
|
||||
const pathchar_t *pathname,
|
||||
int err);
|
||||
MDBX_INTERNAL_FUNC int osal_check_fs_incore(mdbx_filehandle_t handle);
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
|
||||
MDBX_MAYBE_UNUSED static __inline uint32_t osal_getpid(void) {
|
||||
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return GetCurrentProcessId();
|
||||
@ -454,7 +612,7 @@ MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
|
||||
MDBX_MAYBE_UNUSED static __inline uintptr_t osal_thread_self(void) {
|
||||
mdbx_tid_t thunk;
|
||||
STATIC_ASSERT(sizeof(uintptr_t) >= sizeof(thunk));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
@ -467,24 +625,30 @@ MDBX_MAYBE_UNUSED static __inline uintptr_t mdbx_thread_self(void) {
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#if defined(__ANDROID_API__) || defined(ANDROID) || defined(BIONIC)
|
||||
MDBX_INTERNAL_FUNC int mdbx_check_tid4bionic(void);
|
||||
MDBX_INTERNAL_FUNC int osal_check_tid4bionic(void);
|
||||
#else
|
||||
static __inline int mdbx_check_tid4bionic(void) { return 0; }
|
||||
static __inline int osal_check_tid4bionic(void) { return 0; }
|
||||
#endif /* __ANDROID_API__ || ANDROID) || BIONIC */
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline int
|
||||
mdbx_pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int err = mdbx_check_tid4bionic();
|
||||
osal_pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
int err = osal_check_tid4bionic();
|
||||
return unlikely(err) ? err : pthread_mutex_lock(mutex);
|
||||
}
|
||||
#endif /* !Windows */
|
||||
|
||||
MDBX_INTERNAL_FUNC uint64_t mdbx_osal_monotime(void);
|
||||
MDBX_INTERNAL_FUNC uint64_t
|
||||
mdbx_osal_16dot16_to_monotime(uint32_t seconds_16dot16);
|
||||
MDBX_INTERNAL_FUNC uint32_t mdbx_osal_monotime_to_16dot16(uint64_t monotime);
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_monotime(void);
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_cputime(size_t *optional_page_faults);
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16);
|
||||
MDBX_INTERNAL_FUNC uint32_t osal_monotime_to_16dot16(uint64_t monotime);
|
||||
|
||||
MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
|
||||
MDBX_MAYBE_UNUSED static inline uint32_t
|
||||
osal_monotime_to_16dot16_noUnderflow(uint64_t monotime) {
|
||||
uint32_t seconds_16dot16 = osal_monotime_to_16dot16(monotime);
|
||||
return seconds_16dot16 ? seconds_16dot16 : /* fix underflow */ (monotime > 0);
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC bin128_t osal_bootid(void);
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* lck stuff */
|
||||
|
||||
@ -500,7 +664,7 @@ MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void);
|
||||
/// MUST NOT initialize shared synchronization objects in memory-mapped
|
||||
/// LCK-file that are already in use.
|
||||
/// \return Error code or zero on success.
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
|
||||
MDBX_INTERNAL_FUNC int osal_lck_init(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor,
|
||||
int global_uniqueness_flag);
|
||||
|
||||
@ -521,7 +685,7 @@ MDBX_INTERNAL_FUNC int mdbx_lck_init(MDBX_env *env,
|
||||
/// of other instances of MDBX_env within the current process, e.g.
|
||||
/// restore POSIX-fcntl locks after the closing of file descriptors.
|
||||
/// \return Error code (MDBX_PANIC) or zero on success.
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
MDBX_INTERNAL_FUNC int osal_lck_destroy(MDBX_env *env,
|
||||
MDBX_env *inprocess_neighbor);
|
||||
|
||||
/// \brief Connects to shared interprocess locking objects and tries to acquire
|
||||
@ -529,14 +693,14 @@ MDBX_INTERNAL_FUNC int mdbx_lck_destroy(MDBX_env *env,
|
||||
/// Depending on implementation or/and platform (Windows) this function may
|
||||
/// acquire the non-OS super-level lock (e.g. for shared synchronization
|
||||
/// objects initialization), which will be downgraded to OS-exclusive or
|
||||
/// shared via explicit calling of mdbx_lck_downgrade().
|
||||
/// shared via explicit calling of osal_lck_downgrade().
|
||||
/// \return
|
||||
/// MDBX_RESULT_TRUE (-1) - if an exclusive lock was acquired and thus
|
||||
/// the current process is the first and only after the last use of DB.
|
||||
/// MDBX_RESULT_FALSE (0) - if a shared lock was acquired and thus
|
||||
/// DB has already been opened and now is used by other processes.
|
||||
/// Otherwise (not 0 and not -1) - error code.
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env);
|
||||
|
||||
/// \brief Downgrades the level of initially acquired lock to
|
||||
/// operational level specified by argument. The reason for such downgrade:
|
||||
@ -549,14 +713,14 @@ MDBX_INTERNAL_FUNC int mdbx_lck_seize(MDBX_env *env);
|
||||
/// (env->me_flags & MDBX_EXCLUSIVE) != 0 - downgrade to exclusive
|
||||
/// operational lock.
|
||||
/// \return Error code or zero on success
|
||||
MDBX_INTERNAL_FUNC int mdbx_lck_downgrade(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC int osal_lck_downgrade(MDBX_env *env);
|
||||
|
||||
/// \brief Locks LCK-file or/and table of readers for (de)registering.
|
||||
/// \return Error code or zero on success
|
||||
MDBX_INTERNAL_FUNC int mdbx_rdt_lock(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC int osal_rdt_lock(MDBX_env *env);
|
||||
|
||||
/// \brief Unlocks LCK-file or/and table of readers after (de)registering.
|
||||
MDBX_INTERNAL_FUNC void mdbx_rdt_unlock(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC void osal_rdt_unlock(MDBX_env *env);
|
||||
|
||||
/// \brief Acquires lock for DB change (on writing transaction start)
|
||||
/// Reading transactions will not be blocked.
|
||||
@ -571,15 +735,15 @@ LIBMDBX_API void mdbx_txn_unlock(MDBX_env *env);
|
||||
|
||||
/// \brief Sets alive-flag of reader presence (indicative lock) for PID of
|
||||
/// the current process. The function does no more than needed for
|
||||
/// the correct working of mdbx_rpid_check() in other processes.
|
||||
/// the correct working of osal_rpid_check() in other processes.
|
||||
/// \return Error code or zero on success
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_set(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_set(MDBX_env *env);
|
||||
|
||||
/// \brief Resets alive-flag of reader presence (indicative lock)
|
||||
/// for PID of the current process. The function does no more than needed
|
||||
/// for the correct working of mdbx_rpid_check() in other processes.
|
||||
/// for the correct working of osal_rpid_check() in other processes.
|
||||
/// \return Error code or zero on success
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_clear(MDBX_env *env);
|
||||
|
||||
/// \brief Checks for reading process status with the given pid with help of
|
||||
/// alive-flag of presence (indicative lock) or using another way.
|
||||
@ -589,28 +753,16 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_clear(MDBX_env *env);
|
||||
/// MDBX_RESULT_FALSE (0) - if the reader process with the given PID is absent
|
||||
/// or not working with DB (indicative lock is not present).
|
||||
/// Otherwise (not 0 and not -1) - error code.
|
||||
MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid);
|
||||
MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#define MUSTDIE_MB2WIDE(FROM, TO) \
|
||||
do { \
|
||||
const char *const from_tmp = (FROM); \
|
||||
const size_t from_mblen = strlen(from_tmp); \
|
||||
const size_t to_wlen = mdbx_mb2w(nullptr, 0, from_tmp, from_mblen); \
|
||||
if (to_wlen < 1 || to_wlen > /* MAX_PATH */ INT16_MAX) \
|
||||
return ERROR_INVALID_NAME; \
|
||||
wchar_t *const to_tmp = _alloca((to_wlen + 1) * sizeof(wchar_t)); \
|
||||
if (to_wlen + 1 != \
|
||||
mdbx_mb2w(to_tmp, to_wlen + 1, from_tmp, from_mblen + 1)) \
|
||||
return ERROR_INVALID_NAME; \
|
||||
(TO) = to_tmp; \
|
||||
} while (0)
|
||||
MDBX_INTERNAL_FUNC int osal_mb2w(const char *const src, wchar_t **const pdst);
|
||||
|
||||
typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *);
|
||||
MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init,
|
||||
mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,
|
||||
mdbx_srwlock_AcquireExclusive, mdbx_srwlock_ReleaseExclusive;
|
||||
typedef void(WINAPI *osal_srwlock_t_function)(osal_srwlock_t *);
|
||||
MDBX_INTERNAL_VAR osal_srwlock_t_function osal_srwlock_Init,
|
||||
osal_srwlock_AcquireShared, osal_srwlock_ReleaseShared,
|
||||
osal_srwlock_AcquireExclusive, osal_srwlock_ReleaseExclusive;
|
||||
|
||||
#if _WIN32_WINNT < 0x0600 /* prior to Windows Vista */
|
||||
typedef enum _FILE_INFO_BY_HANDLE_CLASS {
|
||||
@ -726,12 +878,57 @@ MDBX_INTERNAL_VAR MDBX_RegGetValueA mdbx_RegGetValueA;
|
||||
|
||||
NTSYSAPI ULONG RtlRandomEx(PULONG Seed);
|
||||
|
||||
typedef BOOL(WINAPI *MDBX_SetFileIoOverlappedRange)(HANDLE FileHandle,
|
||||
PUCHAR OverlappedRangeStart,
|
||||
ULONG Length);
|
||||
MDBX_INTERNAL_VAR MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange;
|
||||
|
||||
#endif /* Windows */
|
||||
|
||||
#endif /* !__cplusplus */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint64_t
|
||||
osal_bswap64(uint64_t v) {
|
||||
#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \
|
||||
__has_builtin(__builtin_bswap64)
|
||||
return __builtin_bswap64(v);
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
return _byteswap_uint64(v);
|
||||
#elif defined(__bswap_64)
|
||||
return __bswap_64(v);
|
||||
#elif defined(bswap_64)
|
||||
return bswap_64(v);
|
||||
#else
|
||||
return v << 56 | v >> 56 | ((v << 40) & UINT64_C(0x00ff000000000000)) |
|
||||
((v << 24) & UINT64_C(0x0000ff0000000000)) |
|
||||
((v << 8) & UINT64_C(0x000000ff00000000)) |
|
||||
((v >> 8) & UINT64_C(0x00000000ff000000)) |
|
||||
((v >> 24) & UINT64_C(0x0000000000ff0000)) |
|
||||
((v >> 40) & UINT64_C(0x000000000000ff00));
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_PURE_FUNCTION static __always_inline uint32_t
|
||||
osal_bswap32(uint32_t v) {
|
||||
#if __GNUC_PREREQ(4, 4) || __CLANG_PREREQ(4, 0) || \
|
||||
__has_builtin(__builtin_bswap32)
|
||||
return __builtin_bswap32(v);
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
return _byteswap_ulong(v);
|
||||
#elif defined(__bswap_32)
|
||||
return __bswap_32(v);
|
||||
#elif defined(bswap_32)
|
||||
return bswap_32(v);
|
||||
#else
|
||||
return v << 24 | v >> 24 | ((v << 8) & UINT32_C(0x00ff0000)) |
|
||||
((v >> 8) & UINT32_C(0x0000ff00));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
/* LY: MSVC 2015/2017/2019 has buggy/inconsistent PRIuPTR/PRIxPTR macros
|
||||
* for internal format-args checker. */
|
||||
|
@ -2,32 +2,32 @@ enable_language(CXX)
|
||||
include(../cmake/compiler.cmake)
|
||||
|
||||
set(LIBMDBX_TEST_SOURCES
|
||||
base.h
|
||||
cases.cc
|
||||
chrono.cc
|
||||
chrono.h
|
||||
config.cc
|
||||
config.h
|
||||
copy.cc
|
||||
dead.cc
|
||||
hill.cc
|
||||
jitter.cc
|
||||
keygen.cc
|
||||
keygen.h
|
||||
log.cc
|
||||
log.h
|
||||
main.cc
|
||||
osal.h
|
||||
osal-unix.cc
|
||||
osal-windows.cc
|
||||
test.cc
|
||||
test.h
|
||||
try.cc
|
||||
utils.cc
|
||||
utils.h
|
||||
append.cc
|
||||
ttl.cc
|
||||
nested.cc
|
||||
base.h++
|
||||
cases.c++
|
||||
chrono.c++
|
||||
chrono.h++
|
||||
config.c++
|
||||
config.h++
|
||||
copy.c++
|
||||
dead.c++
|
||||
hill.c++
|
||||
jitter.c++
|
||||
keygen.c++
|
||||
keygen.h++
|
||||
log.c++
|
||||
log.h++
|
||||
main.c++
|
||||
osal.h++
|
||||
osal-unix.c++
|
||||
osal-windows.c++
|
||||
test.c++
|
||||
test.h++
|
||||
try.c++
|
||||
utils.c++
|
||||
utils.h++
|
||||
append.c++
|
||||
ttl.c++
|
||||
nested.c++
|
||||
)
|
||||
|
||||
if(NOT MDBX_BUILD_CXX)
|
||||
@ -92,11 +92,13 @@ else()
|
||||
set_tests_properties(smoke_chk PROPERTIES
|
||||
DEPENDS smoke
|
||||
TIMEOUT 60
|
||||
FAIL_REGULAR_EXPRESSION "cooperative mode"
|
||||
REQUIRED_FILES smoke.db)
|
||||
add_test(NAME smoke_chk_copy COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvv smoke.db-copy)
|
||||
set_tests_properties(smoke_chk_copy PROPERTIES
|
||||
DEPENDS smoke
|
||||
TIMEOUT 60
|
||||
FAIL_REGULAR_EXPRESSION "cooperative mode"
|
||||
REQUIRED_FILES smoke.db-copy)
|
||||
endif()
|
||||
|
||||
@ -109,15 +111,16 @@ else()
|
||||
TIMEOUT 600
|
||||
RUN_SERIAL OFF)
|
||||
if(MDBX_BUILD_TOOLS)
|
||||
add_test(NAME dupsort_writemap_chk COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvv dupsort_writemap.db)
|
||||
add_test(NAME dupsort_writemap_chk COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvvwc dupsort_writemap.db)
|
||||
set_tests_properties(dupsort_writemap_chk PROPERTIES
|
||||
DEPENDS dupsort_writemap
|
||||
TIMEOUT 60
|
||||
REQUIRED_FILES dupsort_writemap.db)
|
||||
add_test(NAME dupsort_writemap_chk_copy COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvv dupsort_writemap.db-copy)
|
||||
add_test(NAME dupsort_writemap_chk_copy COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvvc dupsort_writemap.db-copy)
|
||||
set_tests_properties(dupsort_writemap_chk_copy PROPERTIES
|
||||
DEPENDS dupsort_writemap
|
||||
TIMEOUT 60
|
||||
FAIL_REGULAR_EXPRESSION "monopolistic mode"
|
||||
REQUIRED_FILES dupsort_writemap.db-copy)
|
||||
endif()
|
||||
|
||||
@ -128,15 +131,17 @@ else()
|
||||
TIMEOUT 1800
|
||||
RUN_SERIAL OFF)
|
||||
if(MDBX_BUILD_TOOLS)
|
||||
add_test(NAME uniq_nested_chk COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvv uniq_nested.db)
|
||||
add_test(NAME uniq_nested_chk COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvvw uniq_nested.db)
|
||||
set_tests_properties(uniq_nested_chk PROPERTIES
|
||||
DEPENDS uniq_nested
|
||||
TIMEOUT 60
|
||||
FAIL_REGULAR_EXPRESSION "cooperative mode"
|
||||
REQUIRED_FILES uniq_nested.db)
|
||||
add_test(NAME uniq_nested_chk_copy COMMAND ${MDBX_OUTPUT_DIR}/mdbx_chk -nvv uniq_nested.db-copy)
|
||||
set_tests_properties(uniq_nested_chk_copy PROPERTIES
|
||||
DEPENDS uniq_nested
|
||||
TIMEOUT 60
|
||||
FAIL_REGULAR_EXPRESSION "cooperative mode"
|
||||
REQUIRED_FILES uniq_nested.db-copy)
|
||||
endif()
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
class testcase_append : public testcase {
|
||||
public:
|
||||
@ -21,7 +21,14 @@ public:
|
||||
bool run() override;
|
||||
|
||||
static bool review_params(actor_params ¶ms) {
|
||||
return testcase::review_params(params) && params.make_keygen_linear();
|
||||
if (!testcase::review_params(params))
|
||||
return false;
|
||||
const bool ordered = !flipcoin_x3();
|
||||
log_notice("the '%s' key-generation mode is selected",
|
||||
ordered ? "ordered/linear" : "unordered/non-linear");
|
||||
if (ordered && !params.make_keygen_linear())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
REGISTER_TESTCASE(append);
|
||||
@ -133,8 +140,6 @@ bool testcase_append::run() {
|
||||
}
|
||||
} else
|
||||
failure_perror("mdbx_get_equal_or_great()", err);
|
||||
|
||||
assert(!expect_key_mismatch);
|
||||
}
|
||||
|
||||
err = mdbx_cursor_put(cursor_guard.get(), &key->value, &data->value, flags);
|
||||
@ -148,12 +153,25 @@ bool testcase_append::run() {
|
||||
|
||||
if (!expect_key_mismatch) {
|
||||
if (unlikely(err != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_cursor_put(insert-a)", err);
|
||||
failure_perror("mdbx_cursor_put(append)", err);
|
||||
++inserted_number;
|
||||
inserted_checksum.push((uint32_t)inserted_number, key->value);
|
||||
inserted_checksum.push(10639, data->value);
|
||||
|
||||
if (config.params.speculum) {
|
||||
Item item(iov2dataview(key), iov2dataview(data));
|
||||
const auto insertion_result = speculum.insert(item);
|
||||
if (!insertion_result.second) {
|
||||
char dump_key[32], dump_value[32];
|
||||
log_error(
|
||||
"speculum.append: unexpected %s {%s, %s}", "MDBX_SUCCESS",
|
||||
mdbx_dump_val(&key->value, dump_key, sizeof(dump_key)),
|
||||
mdbx_dump_val(&data->value, dump_value, sizeof(dump_value)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (unlikely(err != MDBX_EKEYMISMATCH))
|
||||
failure_perror("mdbx_cursor_put(insert-a) != MDBX_EKEYMISMATCH", err);
|
||||
failure_perror("mdbx_cursor_put(append) != MDBX_EKEYMISMATCH", err);
|
||||
|
||||
if (++txn_nops >= config.params.batch_write) {
|
||||
err = breakable_restart();
|
||||
@ -166,6 +184,10 @@ bool testcase_append::run() {
|
||||
committed_inserted_number = inserted_number;
|
||||
committed_inserted_checksum = inserted_checksum;
|
||||
txn_nops = 0;
|
||||
if (!speculum_verify()) {
|
||||
log_notice("append: bailout breakable_restart");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
report(1);
|
||||
@ -181,6 +203,10 @@ bool testcase_append::run() {
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
txn_begin(true);
|
||||
if (!speculum_verify()) {
|
||||
log_notice("append: bailout verify");
|
||||
return false;
|
||||
}
|
||||
cursor_renew();
|
||||
|
||||
MDBX_val check_key, check_data;
|
||||
@ -209,7 +235,8 @@ bool testcase_append::run() {
|
||||
failure("read_count(%" PRIu64 ") != inserted_number(%" PRIu64 ")",
|
||||
read_count, inserted_number);
|
||||
|
||||
if (unlikely(read_checksum.value != inserted_checksum.value))
|
||||
if (unlikely(read_checksum.value != inserted_checksum.value) &&
|
||||
!keyvalue_maker.is_unordered())
|
||||
failure("read_checksum(0x%016" PRIu64 ") "
|
||||
"!= inserted_checksum(0x%016" PRIu64 ")",
|
||||
read_checksum.value, inserted_checksum.value);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -30,6 +30,10 @@
|
||||
#define _WIN32_WINNT 0x0601 /* Windows 7 */
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
/* Workaround for MSVC' header `extern "C"` vs `std::` redefinition bug */
|
||||
#if defined(__SANITIZE_ADDRESS__) && !defined(_DISABLE_VECTOR_ANNOTATION)
|
||||
#define _DISABLE_VECTOR_ANNOTATION
|
||||
#endif /* _DISABLE_VECTOR_ANNOTATION */
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif /* _CRT_SECURE_NO_WARNINGS */
|
||||
@ -94,7 +98,7 @@
|
||||
|
||||
#define MDBX_INTERNAL_FUNC
|
||||
#define MDBX_INTERNAL_VAR extern
|
||||
#define xMDBX_TOOLS /* Avoid using internal mdbx_assert() */
|
||||
#define xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#include "../mdbx.h++"
|
||||
#include "../src/base.h"
|
||||
#include "../src/osal.h"
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
registry *registry::instance() {
|
||||
static registry *singleton;
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
namespace chrono {
|
||||
|
||||
@ -87,10 +87,11 @@ time from_ms(uint64_t ms) {
|
||||
time now_realtime() {
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS)
|
||||
static void(WINAPI * query_time)(LPFILETIME);
|
||||
if (!query_time) {
|
||||
query_time = (void(WINAPI *)(LPFILETIME))GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetSystemTimePreciseAsFileTime");
|
||||
if (unlikely(!query_time)) {
|
||||
HMODULE hModule = GetModuleHandle(TEXT("kernel32.dll"));
|
||||
if (hModule)
|
||||
query_time = (void(WINAPI *)(LPFILETIME))GetProcAddress(
|
||||
hModule, "GetSystemTimePreciseAsFileTime");
|
||||
if (!query_time)
|
||||
query_time = GetSystemTimeAsFileTime;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,8 +14,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "utils.h"
|
||||
#include "base.h++"
|
||||
#include "utils.h++"
|
||||
|
||||
namespace chrono {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(strcasecmp)
|
||||
#define strcasecmp(str, len) _stricmp(str, len)
|
||||
@ -369,7 +369,6 @@ const struct option_verb mode_bits[] = {
|
||||
{"notls", unsigned(MDBX_NOTLS)},
|
||||
{"nordahead", unsigned(MDBX_NORDAHEAD)},
|
||||
{"nomeminit", unsigned(MDBX_NOMEMINIT)},
|
||||
{"coalesce", unsigned(MDBX_COALESCE)},
|
||||
{"lifo", unsigned(MDBX_LIFORECLAIM)},
|
||||
{"perturb", unsigned(MDBX_PAGEPERTURB)},
|
||||
{"accede", unsigned(MDBX_ACCEDE)},
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,9 +14,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
#include "base.h++"
|
||||
#include "log.h++"
|
||||
#include "utils.h++"
|
||||
|
||||
#define ACTOR_ID_MAX INT16_MAX
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
class testcase_copy : public testcase {
|
||||
const std::string copy_pathname;
|
||||
@ -15,7 +15,7 @@ REGISTER_TESTCASE(copy);
|
||||
void testcase_copy::copy_db(const bool with_compaction) {
|
||||
int err = mdbx_env_delete(copy_pathname.c_str(), MDBX_ENV_JUST_DELETE);
|
||||
if (err != MDBX_SUCCESS && err != MDBX_RESULT_TRUE)
|
||||
failure_perror("mdbx_removefile()", err);
|
||||
failure_perror("osal_removefile()", err);
|
||||
|
||||
err = mdbx_env_copy(db_guard.get(), copy_pathname.c_str(),
|
||||
with_compaction ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
class testcase_deadread : public testcase {
|
||||
public:
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
/* LY: тест "холмиком":
|
||||
* - сначала наполняем таблицу циклическими CRUD-манипуляциями,
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
class testcase_jitter : public testcase {
|
||||
protected:
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
namespace keygen {
|
||||
|
||||
@ -227,7 +227,8 @@ void maker::setup(const config::actor_params_pod &actor, unsigned actor_id,
|
||||
|
||||
(void)thread_number;
|
||||
mapping = actor.keygen;
|
||||
salt = (actor.keygen.seed + actor_id) * UINT64_C(14653293970879851569);
|
||||
salt =
|
||||
(actor.keygen.seed + uint64_t(actor_id)) * UINT64_C(14653293970879851569);
|
||||
|
||||
base = actor.serial_base();
|
||||
}
|
||||
@ -315,11 +316,12 @@ void __hot maker::mk_begin(const serial_t serial, const essentials ¶ms,
|
||||
out.value.iov_len = std::max(unsigned(params.minlen), length(serial));
|
||||
const auto variation = params.maxlen - params.minlen;
|
||||
if (variation) {
|
||||
if (serial % (variation + 1)) {
|
||||
if (serial % (variation + serial_t(1))) {
|
||||
auto refix = serial * UINT64_C(48835288005252737);
|
||||
refix ^= refix >> 32;
|
||||
out.value.iov_len = std::max(
|
||||
out.value.iov_len, params.minlen + 1 + size_t(refix) % variation);
|
||||
out.value.iov_len =
|
||||
std::max(out.value.iov_len,
|
||||
params.minlen + size_t(1) + size_t(refix) % variation);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
#include "base.h++"
|
||||
#include "config.h++"
|
||||
#include "log.h++"
|
||||
#include "utils.h++"
|
||||
|
||||
namespace keygen {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
static void fflushall() { fflush(nullptr); }
|
||||
|
||||
@ -61,7 +61,8 @@ static FILE *last;
|
||||
void setlevel(loglevel priority) {
|
||||
level = priority;
|
||||
int rc = mdbx_setup_debug(MDBX_log_level_t(priority),
|
||||
MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER,
|
||||
MDBX_DBG_ASSERT | MDBX_DBG_AUDIT | MDBX_DBG_JITTER |
|
||||
MDBX_DBG_DUMP,
|
||||
mdbx_logger);
|
||||
log_trace("set mdbx debug-opts: 0x%02x", rc);
|
||||
}
|
||||
@ -141,7 +142,7 @@ void output_nocheckloglevel_ap(const logging::loglevel priority,
|
||||
prefix.c_str(), level2str(priority), suffix.c_str());
|
||||
|
||||
va_list ones;
|
||||
memset(&ones, 0, sizeof(ones)) /* zap MSVC and other stupid compilers */;
|
||||
memset(&ones, 0, sizeof(ones)) /* zap MSVC and other goofy compilers */;
|
||||
if (same_or_higher(priority, error))
|
||||
va_copy(ones, ap);
|
||||
vfprintf(last, format, ap);
|
||||
@ -152,11 +153,11 @@ void output_nocheckloglevel_ap(const logging::loglevel priority,
|
||||
switch (end) {
|
||||
default:
|
||||
putc('\n', last);
|
||||
// fall through
|
||||
MDBX_CXX17_FALLTHROUGH; // fall through
|
||||
case '\n':
|
||||
fflush(last);
|
||||
last = nullptr;
|
||||
// fall through
|
||||
MDBX_CXX17_FALLTHROUGH; // fall through
|
||||
case ' ':
|
||||
case '_':
|
||||
case ':':
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,8 +14,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "chrono.h"
|
||||
#include "base.h++"
|
||||
#include "chrono.h++"
|
||||
|
||||
MDBX_NORETURN void usage(void);
|
||||
MDBX_NORETURN void MDBX_PRINTF_ARGS(1, 2) failure(const char *fmt, ...);
|
@ -12,6 +12,7 @@ UNAME="$(uname -s 2>/dev/null || echo Unknown)"
|
||||
DB_UPTO_MB=17408
|
||||
PAGESIZE=min
|
||||
DONT_CHECK_RAM=no
|
||||
EXTRA=no
|
||||
|
||||
while [ -n "$1" ]
|
||||
do
|
||||
@ -31,8 +32,9 @@ do
|
||||
echo "--dir PATH Specifies directory for test DB and other files (it will be cleared)"
|
||||
echo "--db-upto-mb NN Limits upper size of test DB to the NN megabytes"
|
||||
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 "--dont-check-ram-size Don't check available RAM "
|
||||
echo "--pagesize NN Use specified page size (256 is minimal and used by default)"
|
||||
echo "--dont-check-ram-size Don't check available RAM"
|
||||
echo "--extra Iterate extra modes/flags"
|
||||
echo "--help Print this usage help and exit"
|
||||
exit -2
|
||||
;;
|
||||
@ -136,7 +138,7 @@ do
|
||||
PAGESIZE=$((1024*64))
|
||||
;;
|
||||
*)
|
||||
echo "Invalig page size '$2'"
|
||||
echo "Invalid page size '$2'"
|
||||
exit -2
|
||||
;;
|
||||
esac
|
||||
@ -145,6 +147,9 @@ do
|
||||
--dont-check-ram-size)
|
||||
DONT_CHECK_RAM=yes
|
||||
;;
|
||||
--extra)
|
||||
EXTRA=yes
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option '$1'"
|
||||
exit -2
|
||||
@ -350,9 +355,12 @@ else
|
||||
}
|
||||
fi
|
||||
|
||||
syncmodes=("" ,+nosync-safe ,+nosync-utterly)
|
||||
options=(writemap lifo notls perturb)
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
options=(writemap lifo notls perturb nomeminit nordahead)
|
||||
else
|
||||
options=(writemap lifo notls)
|
||||
fi
|
||||
syncmodes=("" ,+nosync-safe ,+nosync-utterly ,+nometasync)
|
||||
function join { local IFS="$1"; shift; echo "$*"; }
|
||||
|
||||
function bits2options {
|
||||
@ -414,65 +422,89 @@ for nops in 10 33 100 333 1000 3333 10000 33333 100000 333333 1000000 3333333 10
|
||||
split=30
|
||||
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
|
||||
split=24
|
||||
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
|
||||
split=16
|
||||
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
|
||||
if [ "$EXTRA" != "no" ]; then
|
||||
split=10
|
||||
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --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]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,+data.dups --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]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--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]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.dups --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]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) with-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+data.dups --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]} \
|
||||
--keygen.seed=${seed}
|
||||
fi
|
||||
|
||||
split=4
|
||||
caption="Probe #$((++count)) int-key,w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=+key.integer,-data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) int-key,int-data, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
caption="Probe #$((++count)) w/o-dups, split=${split}, case $((++subcase)) of ${cases}" probe \
|
||||
--pagesize=$PAGESIZE --size-upper-upto=${db_size_mb}M --table=-data.dups --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%3]} \
|
||||
--nops=$nops --batch.write=$wbatch --mode=$(bits2options $bits)${syncmodes[count%4]} \
|
||||
--keygen.seed=${seed}
|
||||
done # options
|
||||
loop=$((loop + 1))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
#include <sys/resource.h>
|
||||
@ -98,7 +98,6 @@ MDBX_NORETURN void usage(void) {
|
||||
" accede == MDBX_ACCEDE\n"
|
||||
" nometasync == MDBX_NOMETASYNC\n"
|
||||
" lifo == MDBX_LIFORECLAIM\n"
|
||||
" coalesce == MDBX_COALESCE\n"
|
||||
" nosync-safe == MDBX_SAFE_NOSYNC\n"
|
||||
" writemap == MDBX_WRITEMAP\n"
|
||||
" nosync-utterly == MDBX_UTTERLY_NOSYNC\n"
|
||||
@ -130,8 +129,7 @@ void actor_params::set_defaults(const std::string &tmpdir) {
|
||||
#endif
|
||||
|
||||
pathname_db = tmpdir + "mdbx-test.db";
|
||||
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_SAFE_NOSYNC |
|
||||
MDBX_NOMEMINIT | MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_ACCEDE;
|
||||
mode_flags = MDBX_NOSUBDIR | MDBX_WRITEMAP | MDBX_SYNC_DURABLE | MDBX_ACCEDE;
|
||||
table_flags = MDBX_DUPSORT;
|
||||
|
||||
size_lower = -1;
|
||||
@ -682,9 +680,9 @@ int main(int argc, char *const argv[]) {
|
||||
if (!actor)
|
||||
continue;
|
||||
|
||||
log_verbose("actor #%u, id %d, pid %ld: %s\n", actor->actor_id,
|
||||
actor->space_id, (long)pid, status2str(status));
|
||||
if (status > as_running) {
|
||||
log_notice("actor #%u, id %d, pid %ld: %s\n", actor->actor_id,
|
||||
actor->space_id, (long)pid, status2str(status));
|
||||
left -= 1;
|
||||
if (status != as_successful) {
|
||||
if (global::config::failfast && !failed) {
|
||||
@ -694,6 +692,9 @@ int main(int argc, char *const argv[]) {
|
||||
}
|
||||
failed = true;
|
||||
}
|
||||
} else {
|
||||
log_verbose("actor #%u, id %d, pid %ld: %s\n", actor->actor_id,
|
||||
actor->space_id, (long)pid, status2str(status));
|
||||
}
|
||||
} else {
|
||||
if (timeout_seconds_left == 0)
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
#include <cmath>
|
||||
|
||||
/* LY: тест "эмуляцией time-to-live" с вложенными транзакциями:
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
@ -71,7 +71,7 @@ void osal_setup(const std::vector<actor_config> &actors) {
|
||||
events.reserve(n);
|
||||
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
if (!hEvent)
|
||||
failure_perror("CreateEvent()", GetLastError());
|
||||
hEvent = make_inheritable(hEvent);
|
||||
@ -79,22 +79,22 @@ void osal_setup(const std::vector<actor_config> &actors) {
|
||||
events[i] = hEvent;
|
||||
}
|
||||
|
||||
hBarrierSemaphore = CreateSemaphore(NULL, 0, (LONG)actors.size(), NULL);
|
||||
hBarrierSemaphore = CreateSemaphoreW(NULL, 0, (LONG)actors.size(), NULL);
|
||||
if (!hBarrierSemaphore)
|
||||
failure_perror("CreateSemaphore(BarrierSemaphore)", GetLastError());
|
||||
hBarrierSemaphore = make_inheritable(hBarrierSemaphore);
|
||||
|
||||
hBarrierEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
hBarrierEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
if (!hBarrierEvent)
|
||||
failure_perror("CreateEvent(BarrierEvent)", GetLastError());
|
||||
hBarrierEvent = make_inheritable(hBarrierEvent);
|
||||
|
||||
hProgressActiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
hProgressActiveEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
if (!hProgressActiveEvent)
|
||||
failure_perror("CreateEvent(ProgressActiveEvent)", GetLastError());
|
||||
hProgressActiveEvent = make_inheritable(hProgressActiveEvent);
|
||||
|
||||
hProgressPassiveEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
hProgressPassiveEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
if (!hProgressPassiveEvent)
|
||||
failure_perror("CreateEvent(ProgressPassiveEvent)", GetLastError());
|
||||
hProgressPassiveEvent = make_inheritable(hProgressPassiveEvent);
|
||||
@ -248,7 +248,7 @@ Environment:
|
||||
CommandLine.push_back('"');
|
||||
|
||||
for (auto It = Argument.begin();; ++It) {
|
||||
unsigned NumberBackslashes = 0;
|
||||
size_t NumberBackslashes = 0;
|
||||
|
||||
while (It != Argument.end() && *It == '\\') {
|
||||
++It;
|
||||
@ -348,6 +348,7 @@ actor_status osal_actor_info(const mdbx_pid_t pid) {
|
||||
status = as_debugging;
|
||||
break;
|
||||
case STATUS_CONTROL_C_EXIT:
|
||||
case /* STATUS_INTERRUPTED */ 0xC0000515L:
|
||||
status = as_killed;
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
@ -357,6 +358,12 @@ actor_status osal_actor_info(const mdbx_pid_t pid) {
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
case /* STATUS_STACK_BUFFER_OVERRUN, STATUS_BUFFER_OVERFLOW_PREVENTED */
|
||||
0xC0000409L:
|
||||
case /* STATUS_ASSERTION_FAILURE */ 0xC0000420L:
|
||||
case /* STATUS_HEAP_CORRUPTION */ 0xC0000374L:
|
||||
case /* STATUS_CONTROL_STACK_VIOLATION */ 0xC00001B2L:
|
||||
log_error("pid %zu, exception 0x%x", (intptr_t)pid, (unsigned)ExitCode);
|
||||
status = as_coredump;
|
||||
break;
|
||||
default:
|
||||
@ -428,7 +435,7 @@ void osal_udelay(size_t us) {
|
||||
unsigned timeslice_ms = 1;
|
||||
while (timeBeginPeriod(timeslice_ms) == TIMERR_NOCANDO)
|
||||
++timeslice_ms;
|
||||
threshold_us = timeslice_ms * 1500u;
|
||||
threshold_us = timeslice_ms * size_t(1500);
|
||||
assert(threshold_us > 0);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "base.h++"
|
||||
|
||||
void osal_setup(const std::vector<actor_config> &actors);
|
||||
void osal_broadcast(unsigned id);
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2022 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2016-2023 Leonid Yuriev <leo@yuriev.ru>.
|
||||
* Copyright 2015 Vladimir Romanov
|
||||
* <https://www.linkedin.com/in/vladimirromanov>, Yota Lab.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
const char *testcase2str(const actor_testcase testcase) {
|
||||
switch (testcase) {
|
||||
@ -100,7 +100,7 @@ int testcase::hsr_callback(const MDBX_env *env, const MDBX_txn *txn,
|
||||
info.mi_geo.current >= info.mi_geo.upper)) {
|
||||
osal_yield();
|
||||
if (retry > 0)
|
||||
osal_udelay(retry * 100);
|
||||
osal_udelay(retry * size_t(100));
|
||||
return MDBX_RESULT_FALSE /* retry / wait until reader done */;
|
||||
}
|
||||
|
||||
@ -158,12 +158,17 @@ void testcase::db_open() {
|
||||
if (config.params.random_writemap && flipcoin())
|
||||
mode ^= MDBX_WRITEMAP;
|
||||
|
||||
actual_env_mode = mode;
|
||||
int rc = mdbx_env_open(db_guard.get(), config.params.pathname_db.c_str(),
|
||||
mode, 0640);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_env_open()", rc);
|
||||
|
||||
unsigned env_flags_proxy;
|
||||
rc = mdbx_env_get_flags(db_guard.get(), &env_flags_proxy);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
failure_perror("mdbx_env_get_flags()", rc);
|
||||
actual_env_mode = MDBX_env_flags_t(env_flags_proxy);
|
||||
|
||||
rc = mdbx_env_set_syncperiod(db_guard.get(), unsigned(0.042 * 65536));
|
||||
if (unlikely(rc != MDBX_SUCCESS) && rc != MDBX_BUSY)
|
||||
failure_perror("mdbx_env_set_syncperiod()", rc);
|
||||
@ -199,6 +204,19 @@ void testcase::txn_begin(bool readonly, MDBX_txn_flags_t flags) {
|
||||
|
||||
log_trace("<< txn_begin(%s, 0x%04X)", readonly ? "read-only" : "read-write",
|
||||
flags);
|
||||
|
||||
if (flipcoin_n(5)) {
|
||||
const unsigned mask =
|
||||
unsigned(MDBX_warmup_default | MDBX_warmup_force | MDBX_warmup_oomsafe |
|
||||
MDBX_warmup_lock | MDBX_warmup_touchlimit);
|
||||
static unsigned counter;
|
||||
MDBX_warmup_flags_t warmup_flags = MDBX_warmup_flags_t(
|
||||
(counter > MDBX_warmup_release) ? prng64() & mask : counter);
|
||||
counter += 1;
|
||||
int err = mdbx_env_warmup(db_guard.get(), txn, warmup_flags, 0);
|
||||
log_trace("== counter %u, env_warmup(flags %u), rc %d", counter,
|
||||
warmup_flags, err);
|
||||
}
|
||||
}
|
||||
|
||||
int testcase::breakable_commit() {
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -14,13 +14,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "chrono.h"
|
||||
#include "config.h"
|
||||
#include "keygen.h"
|
||||
#include "log.h"
|
||||
#include "osal.h"
|
||||
#include "utils.h"
|
||||
#include "base.h++"
|
||||
#include "chrono.h++"
|
||||
#include "config.h++"
|
||||
#include "keygen.h++"
|
||||
#include "log.h++"
|
||||
#include "osal.h++"
|
||||
#include "utils.h++"
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
@ -101,10 +101,10 @@ class testcase;
|
||||
|
||||
class registry {
|
||||
struct record {
|
||||
actor_testcase id;
|
||||
actor_testcase id = ac_none;
|
||||
std::string name;
|
||||
bool (*review_params)(actor_params &);
|
||||
testcase *(*constructor)(const actor_config &, const mdbx_pid_t);
|
||||
bool (*review_params)(actor_params &) = nullptr;
|
||||
testcase *(*constructor)(const actor_config &, const mdbx_pid_t) = nullptr;
|
||||
};
|
||||
std::unordered_map<std::string, const record *> name2id;
|
||||
std::unordered_map<int, const record *> id2record;
|
@ -1,4 +1,4 @@
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
|
||||
class testcase_try : public testcase {
|
||||
public:
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -12,7 +12,7 @@
|
||||
* <http://www.OpenLDAP.org/license.html>.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "test.h++"
|
||||
#include <float.h>
|
||||
#if defined(HAVE_IEEE754_H) || __has_include(<ieee754.h>)
|
||||
#include <ieee754.h>
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 Leonid Yuriev <leo@yuriev.ru>
|
||||
* Copyright 2017-2023 Leonid Yuriev <leo@yuriev.ru>
|
||||
* and other libmdbx authors: please see AUTHORS file.
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "base.h"
|
||||
#include "base.h++"
|
||||
|
||||
#if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
|
||||
!defined(__ORDER_BIG_ENDIAN__)
|
@ -4,7 +4,7 @@
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:mdbx_sync_locked*
|
||||
fun:sync_locked*
|
||||
}
|
||||
{
|
||||
msync-whole-mmap-2
|
||||
@ -12,7 +12,7 @@
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:mdbx_env_sync_internal*
|
||||
fun:env_sync*
|
||||
}
|
||||
{
|
||||
msync-whole-mmap-3
|
||||
@ -20,7 +20,7 @@
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:mdbx_mapresize*
|
||||
fun:map_resize*
|
||||
}
|
||||
{
|
||||
msync-wipe-steady
|
||||
@ -28,21 +28,43 @@
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:mdbx_wipe_steady*
|
||||
fun:wipe_steady*
|
||||
}
|
||||
{
|
||||
msync-meta
|
||||
Memcheck:Param
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:meta_sync*
|
||||
}
|
||||
{
|
||||
msync-spill
|
||||
Memcheck:Param
|
||||
msync(start)
|
||||
fun:msync
|
||||
...
|
||||
fun:txn_spill*
|
||||
}
|
||||
|
||||
# memcmp() inside mdbx_iov_write() as workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269
|
||||
# memcmp() inside iov_write() as workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269
|
||||
{
|
||||
write-page-check-bcmp
|
||||
iov-pagecheck-1
|
||||
Memcheck:Cond
|
||||
fun:bcmp
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_callback4dirtypages
|
||||
fun:osal_ioring_walk
|
||||
fun:iov_complete
|
||||
fun:iov_write
|
||||
}
|
||||
{
|
||||
write-page-check-memcmp
|
||||
iov-pagecheck-2
|
||||
Memcheck:Cond
|
||||
fun:memcmp*
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_callback4dirtypages
|
||||
fun:osal_ioring_walk
|
||||
fun:iov_complete
|
||||
fun:iov_write
|
||||
}
|
||||
|
||||
# single-page flush by pwrite()
|
||||
@ -52,7 +74,7 @@
|
||||
pwrite(buf)
|
||||
fun:pwrite
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwrite64-page-flush
|
||||
@ -60,7 +82,7 @@
|
||||
pwrite64(buf)
|
||||
fun:pwrite
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
|
||||
# modern Valgrind don't support the `vector[...]` pattern
|
||||
@ -70,16 +92,16 @@
|
||||
# pwritev(vector[...])
|
||||
# fun:pwritev
|
||||
# ...
|
||||
# fun:mdbx_iov_write*
|
||||
# fun:iov_write*
|
||||
#}
|
||||
# for((i=0;i<64;++i)); do echo -e "{\n pwritev-page-flush-$i\n Memcheck:Param\n pwritev(vector[$i])\n fun:pwritev\n ...\n fun:mdbx_iov_write*\n}"; done >> valgrind_suppress.txt
|
||||
# for((i=0;i<64;++i)); do echo -e "{\n pwritev-page-flush-$i\n Memcheck:Param\n pwritev(vector[$i])\n fun:pwritev\n ...\n fun:iov_write*\n}"; done >> valgrind_suppress.txt
|
||||
{
|
||||
pwritev-page-flush-0
|
||||
Memcheck:Param
|
||||
pwritev(vector[0])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-1
|
||||
@ -87,7 +109,7 @@
|
||||
pwritev(vector[1])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-2
|
||||
@ -95,7 +117,7 @@
|
||||
pwritev(vector[2])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-3
|
||||
@ -103,7 +125,7 @@
|
||||
pwritev(vector[3])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-4
|
||||
@ -111,7 +133,7 @@
|
||||
pwritev(vector[4])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-5
|
||||
@ -119,7 +141,7 @@
|
||||
pwritev(vector[5])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-6
|
||||
@ -127,7 +149,7 @@
|
||||
pwritev(vector[6])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-7
|
||||
@ -135,7 +157,7 @@
|
||||
pwritev(vector[7])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-8
|
||||
@ -143,7 +165,7 @@
|
||||
pwritev(vector[8])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-9
|
||||
@ -151,7 +173,7 @@
|
||||
pwritev(vector[9])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-10
|
||||
@ -159,7 +181,7 @@
|
||||
pwritev(vector[10])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-11
|
||||
@ -167,7 +189,7 @@
|
||||
pwritev(vector[11])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-12
|
||||
@ -175,7 +197,7 @@
|
||||
pwritev(vector[12])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-13
|
||||
@ -183,7 +205,7 @@
|
||||
pwritev(vector[13])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-14
|
||||
@ -191,7 +213,7 @@
|
||||
pwritev(vector[14])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-15
|
||||
@ -199,7 +221,7 @@
|
||||
pwritev(vector[15])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-16
|
||||
@ -207,7 +229,7 @@
|
||||
pwritev(vector[16])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-17
|
||||
@ -215,7 +237,7 @@
|
||||
pwritev(vector[17])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-18
|
||||
@ -223,7 +245,7 @@
|
||||
pwritev(vector[18])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-19
|
||||
@ -231,7 +253,7 @@
|
||||
pwritev(vector[19])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-20
|
||||
@ -239,7 +261,7 @@
|
||||
pwritev(vector[20])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-21
|
||||
@ -247,7 +269,7 @@
|
||||
pwritev(vector[21])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-22
|
||||
@ -255,7 +277,7 @@
|
||||
pwritev(vector[22])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-23
|
||||
@ -263,7 +285,7 @@
|
||||
pwritev(vector[23])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-24
|
||||
@ -271,7 +293,7 @@
|
||||
pwritev(vector[24])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-25
|
||||
@ -279,7 +301,7 @@
|
||||
pwritev(vector[25])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-26
|
||||
@ -287,7 +309,7 @@
|
||||
pwritev(vector[26])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-27
|
||||
@ -295,7 +317,7 @@
|
||||
pwritev(vector[27])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-28
|
||||
@ -303,7 +325,7 @@
|
||||
pwritev(vector[28])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-29
|
||||
@ -311,7 +333,7 @@
|
||||
pwritev(vector[29])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-30
|
||||
@ -319,7 +341,7 @@
|
||||
pwritev(vector[30])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-31
|
||||
@ -327,7 +349,7 @@
|
||||
pwritev(vector[31])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-32
|
||||
@ -335,7 +357,7 @@
|
||||
pwritev(vector[32])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-33
|
||||
@ -343,7 +365,7 @@
|
||||
pwritev(vector[33])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-34
|
||||
@ -351,7 +373,7 @@
|
||||
pwritev(vector[34])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-35
|
||||
@ -359,7 +381,7 @@
|
||||
pwritev(vector[35])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-36
|
||||
@ -367,7 +389,7 @@
|
||||
pwritev(vector[36])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-37
|
||||
@ -375,7 +397,7 @@
|
||||
pwritev(vector[37])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-38
|
||||
@ -383,7 +405,7 @@
|
||||
pwritev(vector[38])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-39
|
||||
@ -391,7 +413,7 @@
|
||||
pwritev(vector[39])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-40
|
||||
@ -399,7 +421,7 @@
|
||||
pwritev(vector[40])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-41
|
||||
@ -407,7 +429,7 @@
|
||||
pwritev(vector[41])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-42
|
||||
@ -415,7 +437,7 @@
|
||||
pwritev(vector[42])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-43
|
||||
@ -423,7 +445,7 @@
|
||||
pwritev(vector[43])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-44
|
||||
@ -431,7 +453,7 @@
|
||||
pwritev(vector[44])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-45
|
||||
@ -439,7 +461,7 @@
|
||||
pwritev(vector[45])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-46
|
||||
@ -447,7 +469,7 @@
|
||||
pwritev(vector[46])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-47
|
||||
@ -455,7 +477,7 @@
|
||||
pwritev(vector[47])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-48
|
||||
@ -463,7 +485,7 @@
|
||||
pwritev(vector[48])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-49
|
||||
@ -471,7 +493,7 @@
|
||||
pwritev(vector[49])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-50
|
||||
@ -479,7 +501,7 @@
|
||||
pwritev(vector[50])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-51
|
||||
@ -487,7 +509,7 @@
|
||||
pwritev(vector[51])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-52
|
||||
@ -495,7 +517,7 @@
|
||||
pwritev(vector[52])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-53
|
||||
@ -503,7 +525,7 @@
|
||||
pwritev(vector[53])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-54
|
||||
@ -511,7 +533,7 @@
|
||||
pwritev(vector[54])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-55
|
||||
@ -519,7 +541,7 @@
|
||||
pwritev(vector[55])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-56
|
||||
@ -527,7 +549,7 @@
|
||||
pwritev(vector[56])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-57
|
||||
@ -535,7 +557,7 @@
|
||||
pwritev(vector[57])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-58
|
||||
@ -543,7 +565,7 @@
|
||||
pwritev(vector[58])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-59
|
||||
@ -551,7 +573,7 @@
|
||||
pwritev(vector[59])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-60
|
||||
@ -559,7 +581,7 @@
|
||||
pwritev(vector[60])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-61
|
||||
@ -567,7 +589,7 @@
|
||||
pwritev(vector[61])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-62
|
||||
@ -575,7 +597,7 @@
|
||||
pwritev(vector[62])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
{
|
||||
pwritev-page-flush-63
|
||||
@ -583,5 +605,5 @@
|
||||
pwritev(vector[63])
|
||||
fun:pwritev
|
||||
...
|
||||
fun:mdbx_iov_write*
|
||||
fun:iov_write*
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user