mirror of
https://github.com/isar/libmdbx.git
synced 2025-12-15 04:32:21 +08:00
Compare commits
148 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53177e483c | ||
|
|
ad93633d10 | ||
|
|
f17c55a872 | ||
|
|
7db014c4fc | ||
|
|
22405885f6 | ||
|
|
2ae7bfd9be | ||
|
|
8f87ab252e | ||
|
|
800bd55ab9 | ||
|
|
5c52adf358 | ||
|
|
6d74b10db1 | ||
|
|
359489e271 | ||
|
|
5f690bbc4f | ||
|
|
1b6e32071c | ||
|
|
29d12f1fc3 | ||
|
|
2ea9fbe51b | ||
|
|
57ca0d6e1b | ||
|
|
b8092dd0db | ||
|
|
8fba5ac8d8 | ||
|
|
c9d11cbac1 | ||
|
|
25e958f081 | ||
|
|
7f5ea6d3b8 | ||
|
|
e51140fe48 | ||
|
|
bd35fe8970 | ||
|
|
1684d17b0f | ||
|
|
ebbe98afa5 | ||
|
|
351a30f186 | ||
|
|
2a41b24876 | ||
|
|
fb827959a9 | ||
|
|
209f784ee7 | ||
|
|
68ebbe1fde | ||
|
|
486711945d | ||
|
|
3ade7c7ba1 | ||
|
|
c01f025bfa | ||
|
|
a484a1f89b | ||
|
|
0979a93a78 | ||
|
|
a98c73f4f6 | ||
|
|
9e15bd9b29 | ||
|
|
0159f97e94 | ||
|
|
56050f201f | ||
|
|
525c4a55a4 | ||
|
|
702c67fc38 | ||
|
|
3da23da7b3 | ||
|
|
16cda5c2e8 | ||
|
|
f1fdb88938 | ||
|
|
68a8a15621 | ||
|
|
b86b71a948 | ||
|
|
61e77e7b70 | ||
|
|
08fb7d5838 | ||
|
|
f2a49b687a | ||
|
|
c6b73c8a24 | ||
|
|
24f2e878c1 | ||
|
|
2c8d3e1e12 | ||
|
|
ab55016599 | ||
|
|
f0c2927fc7 | ||
|
|
8519fde741 | ||
|
|
bcddeaba9f | ||
|
|
5317e516d2 | ||
|
|
be05037906 | ||
|
|
f53dc70038 | ||
|
|
2322138a8e | ||
|
|
37867a0b84 | ||
|
|
f0c43fb24a | ||
|
|
adf433a1bc | ||
|
|
48bd3fc4c8 | ||
|
|
7ffea70087 | ||
|
|
ef460a9229 | ||
|
|
df63ff0e7e | ||
|
|
66a5704949 | ||
|
|
61d21b0a02 | ||
|
|
0941319940 | ||
|
|
bb2e3967eb | ||
|
|
e458af602e | ||
|
|
d29acf4fdc | ||
|
|
a06fe4f168 | ||
|
|
0498114469 | ||
|
|
85828f677a | ||
|
|
9cbbdfa025 | ||
|
|
686145ec2e | ||
|
|
fe55f25665 | ||
|
|
e9a2042df1 | ||
|
|
fd98a635d9 | ||
|
|
722c6ecf43 | ||
|
|
44493c6448 | ||
|
|
7011743262 | ||
|
|
b247b081af | ||
|
|
bf2f3bfbbf | ||
|
|
ffdff3f831 | ||
|
|
07f2ccb752 | ||
|
|
23fedf6bba | ||
|
|
167011c2d5 | ||
|
|
245a782912 | ||
|
|
957c99d86f | ||
|
|
b959e217b1 | ||
|
|
54b15d7e41 | ||
|
|
69f7d6cdd8 | ||
|
|
0884f28f85 | ||
|
|
1c93cff825 | ||
|
|
1ae6a398ed | ||
|
|
cd0ed2f155 | ||
|
|
4ee8fff305 | ||
|
|
1bb41ee8fc | ||
|
|
a572902fde | ||
|
|
ebc4976acb | ||
|
|
fd7aaf5f35 | ||
|
|
4b27c4c7c9 | ||
|
|
3a77af7d8a | ||
|
|
a9163f6307 | ||
|
|
48eeb93628 | ||
|
|
a772a9d3e1 | ||
|
|
be3ff92772 | ||
|
|
dc27d5d30a | ||
|
|
48a56d1d05 | ||
|
|
db83bd34d2 | ||
|
|
23d236f70e | ||
|
|
822952ef01 | ||
|
|
9f2d30c1a9 | ||
|
|
163486fa3a | ||
|
|
512e6dbd08 | ||
|
|
2776480f18 | ||
|
|
b7734369a2 | ||
|
|
01a39e7dc2 | ||
|
|
d6b9a71825 | ||
|
|
9cee1ff799 | ||
|
|
8c74de57ea | ||
|
|
05804e2f30 | ||
|
|
7685b4080e | ||
|
|
c521a21f05 | ||
|
|
c5ddf12602 | ||
|
|
07674ada47 | ||
|
|
3757eb72f7 | ||
|
|
b324844296 | ||
|
|
30972102e5 | ||
|
|
61eafe80c1 | ||
|
|
a1333fc827 | ||
|
|
da023657f5 | ||
|
|
141cce0c0f | ||
|
|
12ed2bcfbd | ||
|
|
1f93dfe5fd | ||
|
|
543e52730d | ||
|
|
c46c03e7c8 | ||
|
|
4a257133cb | ||
|
|
f73cd7a491 | ||
|
|
3e05d1a427 | ||
|
|
e518edcfed | ||
|
|
3563ed00e3 | ||
|
|
0f92baaa5e | ||
|
|
eaf063ca9b | ||
|
|
6c840cf58e |
@@ -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.
|
||||
##
|
||||
|
||||
@@ -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.
|
||||
|
||||
354
ChangeLog.md
354
ChangeLog.md
@@ -4,6 +4,228 @@ ChangeLog
|
||||
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).
|
||||
|
||||
## v0.12.4 (Арта-333) от 2023-03-03
|
||||
|
||||
Стабилизирующий выпуск с исправлением обнаруженных ошибок, устранением
|
||||
недочетов и технических долгов. Ветка 0.12 считается готовой к
|
||||
продуктовому использованию, получает статус стабильной и далее будет
|
||||
получать только исправление ошибок. Разработка будет продолжена в ветке
|
||||
0.13, а ветка 0.11 становится архивной.
|
||||
|
||||
```
|
||||
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
|
||||
|
||||
Выпуск с существенными доработками и новой функциональностью
|
||||
@@ -471,7 +693,7 @@ Minors:
|
||||
|
||||
The stable release with the complete workaround for an incoherence flaw of Linux unified page/buffer cache.
|
||||
Nonetheless the cause for this trouble may be an issue of Intel CPU cache/MESI.
|
||||
See [issue#269](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/269) for more information.
|
||||
See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information.
|
||||
|
||||
Acknowledgements:
|
||||
|
||||
@@ -480,8 +702,8 @@ Acknowledgements:
|
||||
|
||||
Fixes:
|
||||
|
||||
- [Added complete workaround](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/269) for an incoherence flaw of Linux unified page/buffer cache.
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/272) cursor reusing for read-only transactions.
|
||||
- [Added complete workaround](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for an incoherence flaw of Linux unified page/buffer cache.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/272) cursor reusing for read-only transactions.
|
||||
- Fixed copy&paste typo inside `mdbx::cursor::find_multivalue()`.
|
||||
|
||||
Minors:
|
||||
@@ -496,7 +718,7 @@ Minors:
|
||||
## v0.11.5 at 2022-02-23
|
||||
|
||||
The release with the temporary hotfix for a flaw of Linux unified page/buffer cache.
|
||||
See [issue#269](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/269) for more information.
|
||||
See [issue#269](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for more information.
|
||||
|
||||
Acknowledgements:
|
||||
|
||||
@@ -506,10 +728,10 @@ Acknowledgements:
|
||||
|
||||
Fixes:
|
||||
|
||||
- [Added hotfix](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/269) for a flaw of Linux unified page/buffer cache.
|
||||
- [Fixed/Reworked](https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/270) move-assignment operators for "managed" classes of C++ API.
|
||||
- [Added hotfix](https://libmdbx.dqdkfa.ru/dead-github/issues/269) for a flaw of Linux unified page/buffer cache.
|
||||
- [Fixed/Reworked](https://libmdbx.dqdkfa.ru/dead-github/pull/270) move-assignment operators for "managed" classes of C++ API.
|
||||
- Fixed potential `SIGSEGV` while open DB with overrided non-default page size.
|
||||
- [Made](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/267) `mdbx_env_open()` idempotence in failure cases.
|
||||
- [Made](https://libmdbx.dqdkfa.ru/dead-github/issues/267) `mdbx_env_open()` idempotence in failure cases.
|
||||
- Refined/Fixed pages reservation inside `mdbx_update_gc()` to avoid non-reclamation in a rare cases.
|
||||
- Fixed typo in a retained space calculation for the hsr-callback.
|
||||
|
||||
@@ -542,15 +764,15 @@ New features, extensions and improvements:
|
||||
Fixes:
|
||||
|
||||
- Fixed handling `MDBX_opt_rp_augment_limit` for GC's records from huge transactions (Erigon/Akula/Ethereum).
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/258) build on Android (avoid including `sys/sem.h`).
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/261) missing copy assignment operator for `mdbx::move_result`.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/258) build on Android (avoid including `sys/sem.h`).
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/pull/261) missing copy assignment operator for `mdbx::move_result`.
|
||||
- Fixed missing `&` for `std::ostream &operator<<()` overloads.
|
||||
- Fixed unexpected `EXDEV` (Cross-device link) error from `mdbx_env_copy()`.
|
||||
- Fixed base64 encoding/decoding bugs in auxillary C++ API.
|
||||
- Fixed overflow of `pgno_t` during checking PNL on 64-bit platforms.
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/260) excessive PNL checking after sort for spilling.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/260) excessive PNL checking after sort for spilling.
|
||||
- Reworked checking `MAX_PAGENO` and DB upper-size geometry limit.
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/265) build for some combinations of versions of MSVC and Windows SDK.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/265) build for some combinations of versions of MSVC and Windows SDK.
|
||||
|
||||
Minors:
|
||||
|
||||
@@ -577,10 +799,10 @@ Acknowledgements:
|
||||
|
||||
New features, extensions and improvements:
|
||||
|
||||
- [Added](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/236) `mdbx_cursor_get_batch()`.
|
||||
- [Added](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/250) `MDBX_SET_UPPERBOUND`.
|
||||
- [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/236) `mdbx_cursor_get_batch()`.
|
||||
- [Added](https://libmdbx.dqdkfa.ru/dead-github/issues/250) `MDBX_SET_UPPERBOUND`.
|
||||
- C++ API is finalized now.
|
||||
- The GC update stage has been [significantly speeded](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem).
|
||||
- The GC update stage has been [significantly speeded](https://libmdbx.dqdkfa.ru/dead-github/issues/254) when fixing huge Erigon's transactions (Ethereum ecosystem).
|
||||
|
||||
Fixes:
|
||||
|
||||
@@ -591,12 +813,12 @@ Minors:
|
||||
|
||||
- Fixed returning `MDBX_RESULT_TRUE` (unexpected -1) from `mdbx_env_set_option()`.
|
||||
- Added `mdbx_env_get_syncbytes()` and `mdbx_env_get_syncperiod()`.
|
||||
- [Clarified](https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/249) description of `MDBX_INTEGERKEY`.
|
||||
- [Clarified](https://libmdbx.dqdkfa.ru/dead-github/pull/249) description of `MDBX_INTEGERKEY`.
|
||||
- Reworked/simplified `mdbx_env_sync_internal()`.
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/248) extra assertion inside `mdbx_cursor_put()` for `MDBX_DUPFIXED` cases.
|
||||
- Avoiding extra looping inside `mdbx_env_info_ex()`.
|
||||
- Explicitly enabled core dumps from stochastic tests scripts on Linux.
|
||||
- [Fixed](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/253) `mdbx_override_meta()` to avoid false-positive assertions.
|
||||
- [Fixed](https://libmdbx.dqdkfa.ru/dead-github/issues/253) `mdbx_override_meta()` to avoid false-positive assertions.
|
||||
- For compatibility reverted returning `MDBX_ENODATA`for some cases.
|
||||
|
||||
|
||||
@@ -612,10 +834,10 @@ Acknowledgements:
|
||||
|
||||
Fixes:
|
||||
|
||||
- [Fixed compilation](https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/239) with `devtoolset-9` on CentOS/RHEL 7.
|
||||
- [Fixed unexpected `MDBX_PROBLEM` error](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/242) because of update an obsolete meta-page.
|
||||
- [Fixed returning `MDBX_NOTFOUND` error](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation.
|
||||
- [Fixed compilation](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/245) without kernel/libc-devel headers.
|
||||
- [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/pull/239) with `devtoolset-9` on CentOS/RHEL 7.
|
||||
- [Fixed unexpected `MDBX_PROBLEM` error](https://libmdbx.dqdkfa.ru/dead-github/issues/242) because of update an obsolete meta-page.
|
||||
- [Fixed returning `MDBX_NOTFOUND` error](https://libmdbx.dqdkfa.ru/dead-github/issues/243) in case an inexact value found for `MDBX_GET_BOTH` operation.
|
||||
- [Fixed compilation](https://libmdbx.dqdkfa.ru/dead-github/issues/245) without kernel/libc-devel headers.
|
||||
|
||||
Minors:
|
||||
|
||||
@@ -632,7 +854,7 @@ Minors:
|
||||
|
||||
The database format signature has been changed to prevent
|
||||
forward-interoperability with an previous releases, which may lead to a
|
||||
[false positive diagnosis of database corruption](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/238)
|
||||
[false positive diagnosis of database corruption](https://libmdbx.dqdkfa.ru/dead-github/issues/238)
|
||||
due to flaws of an old library versions.
|
||||
|
||||
This change is mostly invisible:
|
||||
@@ -684,7 +906,7 @@ Acknowledgements:
|
||||
Fixes:
|
||||
|
||||
- Fixed possibility of looping update GC during transaction commit (no public issue since the problem was discovered inside [Positive Technologies](https://www.ptsecurity.ru)).
|
||||
- Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/235).
|
||||
- Fixed `#pragma pack` to avoid provoking some compilers to generate code with [unaligned access](https://libmdbx.dqdkfa.ru/dead-github/issues/235).
|
||||
- Fixed `noexcept` for potentially throwing `txn::put()` of C++ API.
|
||||
|
||||
Minors:
|
||||
@@ -710,7 +932,7 @@ Extensions and improvements:
|
||||
|
||||
Fixes:
|
||||
|
||||
- Always setup `madvise` while opening DB (fixes https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/231).
|
||||
- Always setup `madvise` while opening DB (fixes https://libmdbx.dqdkfa.ru/dead-github/issues/231).
|
||||
- Fixed checking legacy `P_DIRTY` flag (`0x10`) for nested/sub-pages.
|
||||
|
||||
Minors:
|
||||
@@ -731,11 +953,11 @@ Acknowledgements:
|
||||
- [Lionel Debroux](https://github.com/debrouxl) for fuzzing tests and reporting bugs.
|
||||
- [Sergey Fedotov](https://github.com/SergeyFromHell/) for [`node-mdbx` NodeJS bindings](https://www.npmjs.com/package/node-mdbx).
|
||||
- [Kris Zyp](https://github.com/kriszyp) for [`lmdbx-store` NodeJS bindings](https://github.com/kriszyp/lmdbx-store).
|
||||
- [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://web.archive.org/web/https://github.com/erthink/libmdbx/commits/python-bindings).
|
||||
- [Noel Kuntze](https://github.com/Thermi) for [draft Python bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings).
|
||||
|
||||
New features, extensions and improvements:
|
||||
|
||||
- [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/201).
|
||||
- [Allow to predefine/override `MDBX_BUILD_TIMESTAMP` for builds reproducibility](https://libmdbx.dqdkfa.ru/dead-github/issues/201).
|
||||
- Added options support for `long-stochastic` script.
|
||||
- Avoided `MDBX_TXN_FULL` error for large transactions when possible.
|
||||
- The `MDBX_READERS_LIMIT` increased to `32767`.
|
||||
@@ -743,7 +965,7 @@ New features, extensions and improvements:
|
||||
- Minimized the size of poisoned/unpoisoned regions to avoid Valgrind/ASAN stuck.
|
||||
- Added more workarounds for QEMU for testing builds for 32-bit platforms, Alpha and Sparc architectures.
|
||||
- `mdbx_chk` now skips iteration & checking of DB' records if corresponding page-tree is corrupted (to avoid `SIGSEGV`, ASAN failures, etc).
|
||||
- Added more checks for [rare/fuzzing corruption cases](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/217).
|
||||
- Added more checks for [rare/fuzzing corruption cases](https://libmdbx.dqdkfa.ru/dead-github/issues/217).
|
||||
|
||||
Backward compatibility break:
|
||||
|
||||
@@ -755,18 +977,18 @@ Backward compatibility break:
|
||||
Fixes:
|
||||
|
||||
- Fixed excess meta-pages checks in case `mdbx_chk` is called to check the DB for a specific meta page and thus could prevent switching to the selected meta page, even if the check passed without errors.
|
||||
- Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/203).
|
||||
- Fixed [log a warning during a new DB creation](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/205).
|
||||
- Fixed [false-negative `mdbx_cursor_eof()` result](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/207).
|
||||
- Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/208).
|
||||
- Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/209).
|
||||
- Fixed [C++ Buffer issue with `std::string` and alignment](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/191).
|
||||
- Fixed [recursive use of SRW-lock on Windows cause by `MDBX_NOTLS` option](https://libmdbx.dqdkfa.ru/dead-github/issues/203).
|
||||
- Fixed [log a warning during a new DB creation](https://libmdbx.dqdkfa.ru/dead-github/issues/205).
|
||||
- Fixed [false-negative `mdbx_cursor_eof()` result](https://libmdbx.dqdkfa.ru/dead-github/issues/207).
|
||||
- Fixed [`make install` with non-GNU `install` utility (OSX, BSD)](https://libmdbx.dqdkfa.ru/dead-github/issues/208).
|
||||
- Fixed [installation by `CMake` in special cases by complete use `GNUInstallDirs`'s variables](https://libmdbx.dqdkfa.ru/dead-github/issues/209).
|
||||
- Fixed [C++ Buffer issue with `std::string` and alignment](https://libmdbx.dqdkfa.ru/dead-github/issues/191).
|
||||
- Fixed `safe64_reset()` for platforms without atomic 64-bit compare-and-swap.
|
||||
- Fixed hang/shutdown on big-endian platforms without `__cxa_thread_atexit()`.
|
||||
- Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/217).
|
||||
- Fixed [using bad meta-pages if DB was partially/recoverable corrupted](https://libmdbx.dqdkfa.ru/dead-github/issues/217).
|
||||
- Fixed extra `noexcept` for `buffer::&assign_reference()`.
|
||||
- Fixed `bootid` generation on Windows for case of change system' time.
|
||||
- Fixed [test framework keygen-related issue](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/127).
|
||||
- Fixed [test framework keygen-related issue](https://libmdbx.dqdkfa.ru/dead-github/issues/127).
|
||||
|
||||
|
||||
## v0.10.1 at 2021-06-01
|
||||
@@ -787,10 +1009,10 @@ New features:
|
||||
Fixes:
|
||||
|
||||
- Fixed minor "foo not used" warnings from modern C++ compilers when building the C++ part of the library.
|
||||
- Fixed confusing/messy errors when build library from unfit github's archives (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/197).
|
||||
- Fixed confusing/messy errors when build library from unfit github's archives (https://libmdbx.dqdkfa.ru/dead-github/issues/197).
|
||||
- Fixed `#elsif` typo.
|
||||
- Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/195).
|
||||
- Re-Fixed WSL1/WSL2 detection with distinguishing (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/97).
|
||||
- Fixed rare unexpected `MDBX_PROBLEM` error during altering data in huge transactions due to wrong spilling/oust of dirty pages (https://libmdbx.dqdkfa.ru/dead-github/issues/195).
|
||||
- Re-Fixed WSL1/WSL2 detection with distinguishing (https://libmdbx.dqdkfa.ru/dead-github/issues/97).
|
||||
|
||||
|
||||
## v0.10.0 at 2021-05-09
|
||||
@@ -813,7 +1035,7 @@ New features:
|
||||
and conjointly with the `MDBX_ENV_CHECKPID=0` and `MDBX_TXN_CHECKOWNER=0` options can yield
|
||||
up to 30% more performance compared to LMDB.
|
||||
- Using float point (exponential quantized) representation for internal 16-bit values
|
||||
of grow step and shrink threshold when huge ones (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/166).
|
||||
of grow step and shrink threshold when huge ones (https://libmdbx.dqdkfa.ru/dead-github/issues/166).
|
||||
To minimize the impact on compatibility, only the odd values inside the upper half
|
||||
of the range (i.e. 32769..65533) are used for the new representation.
|
||||
- Added the `mdbx_drop` similar to LMDB command-line tool to purge or delete (sub)database(s).
|
||||
@@ -822,7 +1044,7 @@ New features:
|
||||
- The internal node sizes were refined, resulting in a reduction in large/overflow pages in some use cases
|
||||
and a slight increase in limits for a keys size to ≈½ of page size.
|
||||
- Added to `mdbx_chk` output number of keys/items on pages.
|
||||
- Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/180).
|
||||
- Added explicit `install-strip` and `install-no-strip` targets to the `Makefile` (https://libmdbx.dqdkfa.ru/dead-github/pull/180).
|
||||
- Major rework page splitting (af9b7b560505684249b76730997f9e00614b8113) for
|
||||
- An "auto-appending" feature upon insertion for both ascending and
|
||||
descending key sequences. As a result, the optimality of page filling
|
||||
@@ -830,7 +1052,7 @@ New features:
|
||||
inserting ordered sequences of keys,
|
||||
- A "splitting at middle" to make page tree more balanced on average.
|
||||
- Added `mdbx_get_sysraminfo()` to the API.
|
||||
- Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/183).
|
||||
- Added guessing a reasonable maximum DB size for the default upper limit of geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183).
|
||||
- Major rework internal labeling of a dirty pages (958fd5b9479f52f2124ab7e83c6b18b04b0e7dda) for
|
||||
a "transparent spilling" feature with the gist to make a dirty pages
|
||||
be ready to spilling (writing to a disk) without further altering ones.
|
||||
@@ -846,7 +1068,7 @@ New features:
|
||||
- Support `make help` to list available make targets.
|
||||
- Silently `make`'s build by default.
|
||||
- Preliminary [Python bindings](https://github.com/Thermi/libmdbx/tree/python-bindings) is available now
|
||||
by [Noel Kuntze](https://github.com/Thermi) (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/147).
|
||||
by [Noel Kuntze](https://github.com/Thermi) (https://libmdbx.dqdkfa.ru/dead-github/issues/147).
|
||||
|
||||
Backward compatibility break:
|
||||
|
||||
@@ -861,22 +1083,22 @@ Backward compatibility break:
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fixed performance regression due non-optimal C11 atomics usage (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/160).
|
||||
- Fixed "reincarnation" of subDB after it deletion (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/168).
|
||||
- Fixed performance regression due non-optimal C11 atomics usage (https://libmdbx.dqdkfa.ru/dead-github/issues/160).
|
||||
- Fixed "reincarnation" of subDB after it deletion (https://libmdbx.dqdkfa.ru/dead-github/issues/168).
|
||||
- Fixed (disallowing) implicit subDB deletion via operations on `@MAIN`'s DBI-handle.
|
||||
- Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/171).
|
||||
- Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/170).
|
||||
- Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/179).
|
||||
- Fixed an unreasonably huge default upper limit for DB geometry (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/183).
|
||||
- Fixed a crash of `mdbx_env_info_ex()` in case of a call for a non-open environment (https://libmdbx.dqdkfa.ru/dead-github/issues/171).
|
||||
- Fixed the selecting/adjustment values inside `mdbx_env_set_geometry()` for implicit out-of-range cases (https://libmdbx.dqdkfa.ru/dead-github/issues/170).
|
||||
- Fixed `mdbx_env_set_option()` for set initial and limit size of dirty page list ((https://libmdbx.dqdkfa.ru/dead-github/issues/179).
|
||||
- Fixed an unreasonably huge default upper limit for DB geometry (https://libmdbx.dqdkfa.ru/dead-github/issues/183).
|
||||
- Fixed `constexpr` specifier for the `slice::invalid()`.
|
||||
- Fixed (no)readahead auto-handling (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/164).
|
||||
- Fixed (no)readahead auto-handling (https://libmdbx.dqdkfa.ru/dead-github/issues/164).
|
||||
- Fixed non-alloy build for Windows.
|
||||
- Switched to using Heap-functions instead of LocalAlloc/LocalFree on Windows.
|
||||
- Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/190).
|
||||
- Fixed `mdbx_env_stat_ex()` to returning statistics of the whole environment instead of MainDB only (https://libmdbx.dqdkfa.ru/dead-github/issues/190).
|
||||
- Fixed building by GCC 4.8.5 (added workaround for a preprocessor's bug).
|
||||
- Fixed building C++ part for iOS <= 13.0 (unavailability of `std::filesystem::path`).
|
||||
- Fixed building for Windows target versions prior to Windows Vista (`WIN32_WINNT < 0x0600`).
|
||||
- Fixed building by MinGW for Windows (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/155).
|
||||
- Fixed building by MinGW for Windows (https://libmdbx.dqdkfa.ru/dead-github/issues/155).
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@@ -899,7 +1121,7 @@ Removed options and features:
|
||||
New features:
|
||||
|
||||
- Package for FreeBSD is available now by Mahlon E. Smith.
|
||||
- New API functions to get/set various options (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/128):
|
||||
- New API functions to get/set various options (https://libmdbx.dqdkfa.ru/dead-github/issues/128):
|
||||
- the maximum number of named databases for the environment;
|
||||
- the maximum number of threads/reader slots;
|
||||
- threshold (since the last unsteady commit) to force flush the data buffers to disk;
|
||||
@@ -912,7 +1134,7 @@ New features:
|
||||
- maximal part of the dirty pages may be spilled when necessary;
|
||||
- minimal part of the dirty pages should be spilled when necessary;
|
||||
- how much of the parent transaction dirty pages will be spilled while start each child transaction;
|
||||
- Unlimited/Dynamic size of retired and dirty page lists (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/123).
|
||||
- Unlimited/Dynamic size of retired and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/123).
|
||||
- Added `-p` option (purge subDB before loading) to `mdbx_load` tool.
|
||||
- Reworked spilling of large transaction and committing of nested transactions:
|
||||
- page spilling code reworked to avoid the flaws and bugs inherited from LMDB;
|
||||
@@ -922,22 +1144,22 @@ New features:
|
||||
- Added `MDBX_ENABLE_REFUND` and `MDBX_PNL_ASCENDING` internal/advanced build options.
|
||||
- Added `mdbx_default_pagesize()` function.
|
||||
- Better support architectures with a weak/relaxed memory consistency model (ARM, AARCH64, PPC, MIPS, RISC-V, etc) by means [C11 atomics](https://en.cppreference.com/w/c/atomic).
|
||||
- Speed up page number lists and dirty page lists (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/132).
|
||||
- Speed up page number lists and dirty page lists (https://libmdbx.dqdkfa.ru/dead-github/issues/132).
|
||||
- Added `LIBMDBX_NO_EXPORTS_LEGACY_API` build option.
|
||||
|
||||
Fixes:
|
||||
|
||||
- Fixed missing cleanup (null assigned) in the C++ commit/abort (https://web.archive.org/web/https://github.com/erthink/libmdbx/pull/143).
|
||||
- Fixed missing cleanup (null assigned) in the C++ commit/abort (https://libmdbx.dqdkfa.ru/dead-github/pull/143).
|
||||
- Fixed `mdbx_realloc()` for case of nullptr and `MDBX_WITHOUT_MSVC_CRT=ON` for Windows.
|
||||
- Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/146).
|
||||
- Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/153).
|
||||
- Fixed the possibility to use invalid and renewed (closed & re-opened, dropped & re-created) DBI-handles (https://libmdbx.dqdkfa.ru/dead-github/issues/146).
|
||||
- Fixed 4-byte aligned access to 64-bit integers, including access to the `bootid` meta-page's field (https://libmdbx.dqdkfa.ru/dead-github/issues/153).
|
||||
- Fixed minor/potential memory leak during page flushing and unspilling.
|
||||
- Fixed handling states of cursors's and subDBs's for nested transactions.
|
||||
- Fixed page leak in extra rare case the list of retired pages changed during update GC on transaction commit.
|
||||
- Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/153).
|
||||
- Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/123).
|
||||
- Fixed assertions to avoid false-positive UB detection by CLANG/LLVM (https://libmdbx.dqdkfa.ru/dead-github/issues/153).
|
||||
- Fixed `MDBX_TXN_FULL` and regressive `MDBX_KEYEXIST` during large transaction commit with `MDBX_LIFORECLAIM` (https://libmdbx.dqdkfa.ru/dead-github/issues/123).
|
||||
- Fixed auto-recovery (`weak->steady` with the same boot-id) when Database size at last weak checkpoint is large than at last steady checkpoint.
|
||||
- Fixed operation on systems with unusual small/large page size, including PowerPC (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/157).
|
||||
- Fixed operation on systems with unusual small/large page size, including PowerPC (https://libmdbx.dqdkfa.ru/dead-github/issues/157).
|
||||
|
||||
|
||||
## v0.9.2 at 2020-11-27
|
||||
@@ -975,11 +1197,11 @@ Fixes:
|
||||
- Fixed copy&paste typos.
|
||||
- Fixed minor false-positive GCC warning.
|
||||
- Added workaround for broken `DEFINE_ENUM_FLAG_OPERATORS` from Windows SDK.
|
||||
- Fixed cursor state after multimap/dupsort repeated deletes (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/121).
|
||||
- Fixed cursor state after multimap/dupsort repeated deletes (https://libmdbx.dqdkfa.ru/dead-github/issues/121).
|
||||
- Added `SIGPIPE` suppression for internal thread during `mdbx_env_copy()`.
|
||||
- Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/131).
|
||||
- Fixed spilled pages checking (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/126).
|
||||
- Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/136).
|
||||
- Fixed extra-rare `MDBX_KEY_EXIST` error during `mdbx_commit()` (https://libmdbx.dqdkfa.ru/dead-github/issues/131).
|
||||
- Fixed spilled pages checking (https://libmdbx.dqdkfa.ru/dead-github/issues/126).
|
||||
- Fixed `mdbx_load` for 'plain text' and without `-s name` cases (https://libmdbx.dqdkfa.ru/dead-github/issues/136).
|
||||
- Fixed save/restore/commit of cursors for nested transactions.
|
||||
- Fixed cursors state in rare/special cases (move next beyond end-of-data, after deletion and so on).
|
||||
- Added workaround for MSVC 19.28 (Visual Studio 16.8) (but may still hang during compilation).
|
||||
@@ -1032,7 +1254,7 @@ Fixes:
|
||||
- Fix a lot of typos & spelling (Thanks to Josh Soref for PR).
|
||||
- Fix `getopt()` messages for Windows (Thanks to Andrey Sporaw for reporting).
|
||||
- Fix MSVC compiler version requirements (Thanks to Andrey Sporaw for reporting).
|
||||
- Workarounds for QEMU's bugs to run tests for cross-builded library under QEMU.
|
||||
- Workarounds for QEMU's bugs to run tests for cross-built[A library under QEMU.
|
||||
- Now C++ compiler optional for building by CMake.
|
||||
|
||||
|
||||
@@ -1101,7 +1323,7 @@ Deprecated functions and flags:
|
||||
- Avoid using `pwritev()` for single-writes (up to 10% speedup for some kernels & scenarios).
|
||||
- Avoiding `MDBX_UTTERLY_NOSYNC` as result of flags merge.
|
||||
- Add `mdbx_dbi_dupsort_depthmask()` function.
|
||||
- Add `MDBX_CP_FORCE_RESIZEABLE` option.
|
||||
- Add `MDBX_CP_FORCE_RESIZABLE` option.
|
||||
- Add deprecated `MDBX_MAP_RESIZED` for compatibility.
|
||||
- Add `MDBX_BUILD_TOOLS` option (default `ON`).
|
||||
- Refine `mdbx_dbi_open_ex()` to safe concurrently opening the same handle from different threads.
|
||||
|
||||
41
GNUmakefile
41
GNUmakefile
@@ -6,7 +6,7 @@
|
||||
#
|
||||
################################################################################
|
||||
#
|
||||
# Basic internal definitios. For a customizable variables and options see below.
|
||||
# Basic internal definitions. For a customizable variables and options see below.
|
||||
#
|
||||
$(info // The GNU Make $(MAKE_VERSION))
|
||||
SHELL := $(shell env bash -c 'echo $$BASH')
|
||||
@@ -715,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 riscv64-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 riscv64-linux-gnu-gcc"
|
||||
@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 $$?; \
|
||||
@@ -743,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 && \
|
||||
@@ -788,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
|
||||
@@ -802,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
|
||||
@@ -813,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)))
|
||||
|
||||
49
README.md
49
README.md
@@ -81,19 +81,48 @@ Historically, _libmdbx_ is a deeply revised and extended descendant of the amazi
|
||||
[Lightning Memory-Mapped Database](https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database).
|
||||
_libmdbx_ inherits all benefits from _LMDB_, but resolves some issues and adds [a set of improvements](#improvements-beyond-lmdb).
|
||||
|
||||
### MithrilDB and Future
|
||||
|
||||
<!-- section-begin mithril -->
|
||||
|
||||
The next version is under active non-public development from scratch and will be
|
||||
The next version is under non-public development from scratch and will be
|
||||
released as **MithrilDB** and `libmithrildb` for libraries & packages.
|
||||
Admittedly mythical [Mithril](https://en.wikipedia.org/wiki/Mithril) is
|
||||
resembling silver but being stronger and lighter than steel. Therefore
|
||||
_MithrilDB_ is a rightly relevant name.
|
||||
|
||||
> _MithrilDB_ will be radically different from _libmdbx_ by the new
|
||||
> database format and API based on C++17, as well as the [Apache 2.0
|
||||
> License](https://www.apache.org/licenses/LICENSE-2.0). The goal of this
|
||||
> revolution is to provide a clearer and robust API, add more features and
|
||||
> new valuable properties of the database.
|
||||
_MithrilDB_ is radically different from _libmdbx_ by the new database
|
||||
format and API based on C++20. The goal of this revolution is to provide
|
||||
a clearer and robust API, add more features and new valuable properties
|
||||
of the database. All fundamental architectural problems of libmdbx/LMDB
|
||||
have been solved there, but now the active development has been
|
||||
suspended for top-three reasons:
|
||||
|
||||
1. For now _libmdbx_ «mostly» enough for all [our products](https://www.ptsecurity.com/ww-en/products/),
|
||||
and I’m busy in development of replication for scalability.
|
||||
2. Waiting for fresh [Elbrus CPU](https://wiki.elbrus.ru/) of [e2k architecture](https://en.wikipedia.org/wiki/Elbrus_2000),
|
||||
especially with hardware acceleration of [Streebog](https://en.wikipedia.org/wiki/Streebog) and
|
||||
[Kuznyechik](https://en.wikipedia.org/wiki/Kuznyechik), which are required for Merkle tree, etc.
|
||||
3. The expectation of needs and opportunities due to the wide use of NVDIMM (aka persistent memory),
|
||||
modern NVMe and [Ангара](https://ru.wikipedia.org/wiki/Ангара_(интерконнект)).
|
||||
|
||||
However, _MithrilDB_ will not be available for countries unfriendly to
|
||||
Russia (i.e. acceded the sanctions, devil adepts and/or NATO). But it is
|
||||
not yet known whether such restriction will be implemented only through
|
||||
a license and support, either the source code will not be open at all.
|
||||
Basically we are not inclined to allow our work to contribute to the
|
||||
profit that goes to weapons that kill our relatives and friends.
|
||||
NO OPTIONS.
|
||||
|
||||
Nonetheless, I try not to make any promises regarding _MithrilDB_ until release.
|
||||
|
||||
Contrary to _MithrilDB_, _libmdbx_ will forever free and open source.
|
||||
Moreover with high-quality support whenever possible. Tu deviens
|
||||
responsable pour toujours de ce que tu as apprivois. So we will continue
|
||||
to comply with the original open license and the principles of
|
||||
constructive cooperation, in spite of outright Github sabotage and
|
||||
sanctions. I will also try to keep (not drop) Windows support, despite
|
||||
it is an unused obsolete technology for us.
|
||||
|
||||
<!-- section-end -->
|
||||
|
||||
@@ -248,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).
|
||||
|
||||
@@ -435,7 +464,7 @@ unexpected or broken down.
|
||||
|
||||
### Testing
|
||||
The amalgamated source code does not contain any tests for or several reasons.
|
||||
Please read [the explanation](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/214#issuecomment-870717981) and don't ask to alter this.
|
||||
Please read [the explanation](https://libmdbx.dqdkfa.ru/dead-github/issues/214#issuecomment-870717981) and don't ask to alter this.
|
||||
So for testing _libmdbx_ itself you need a full source code, i.e. the clone of a git repository, there is no option.
|
||||
|
||||
The full source code of _libmdbx_ has a [`test` subdirectory](https://gitflic.ru/project/erthink/libmdbx/tree/master/test) with minimalistic test "framework".
|
||||
@@ -618,7 +647,7 @@ Bindings
|
||||
| Rust | [libmdbx-rs](https://github.com/vorot93/libmdbx-rs) | [Artem Vorotnikov](https://github.com/vorot93) |
|
||||
| Rust | [mdbx](https://crates.io/crates/mdbx) | [gcxfd](https://github.com/gcxfd) |
|
||||
| Java | [mdbxjni](https://github.com/castortech/mdbxjni) | [Castor Technologies](https://castortech.com/) |
|
||||
| Python (draft) | [python-bindings](https://web.archive.org/web/https://github.com/erthink/libmdbx/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi)
|
||||
| Python (draft) | [python-bindings](https://libmdbx.dqdkfa.ru/dead-github/commits/python-bindings) branch | [Noel Kuntze](https://github.com/Thermi)
|
||||
| .NET (obsolete) | [mdbx.NET](https://github.com/wangjia184/mdbx.NET) | [Jerry Wang](https://github.com/wangjia184) |
|
||||
|
||||
<!-- section-end -->
|
||||
@@ -630,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.
|
||||
|
||||
22
TODO.md
22
TODO.md
@@ -11,19 +11,19 @@ For the same reason ~~Github~~ is blacklisted forever.
|
||||
|
||||
So currently most of the links are broken due to noted malicious ~~Github~~ sabotage.
|
||||
|
||||
- [Move most of `mdbx_chk` functional to the library API](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/204).
|
||||
- [Replace SRW-lock on Windows to allow shrink DB with `MDBX_NOTLS` option](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/210).
|
||||
- [More flexible support of asynchronous runtime/framework(s)](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/200).
|
||||
- [Migration guide from LMDB to MDBX](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/199).
|
||||
- [Support for RAW devices](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/124).
|
||||
- [Support MessagePack for Keys & Values](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/115).
|
||||
- [Engage new terminology](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/137).
|
||||
- [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).
|
||||
- [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://web.archive.org/web/https://github.com/erthink/libmdbx/issues/223).
|
||||
- [Engage an "overlapped I/O" on Windows](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/224).
|
||||
- [Large/Overflow pages accounting for dirty-room](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/192).
|
||||
- [Get rid of dirty-pages list in MDBX_WRITEMAP mode](https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/193).
|
||||
- [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.
|
||||
|
||||
@@ -67,7 +67,7 @@ the end is hit.
|
||||
To retrieve all keys starting from a specified key value, use \ref MDBX_SET. For
|
||||
more cursor operations, see the \ref c_api reference.
|
||||
|
||||
When using \ref mdbx_cursor_put()\ref , either the function will position the cursor
|
||||
When using \ref mdbx_cursor_put(), either the function will position the cursor
|
||||
for you based on the key, or you can use operation \ref MDBX_CURRENT to use the
|
||||
current position of the cursor. \note Note that key must then match the current
|
||||
position's key.
|
||||
|
||||
@@ -38,4 +38,4 @@ including creating [merge-request](https://gitflic.ru/project/erthink/libmdbx/me
|
||||
|
||||
---
|
||||
|
||||
\section MithrilDB MithrilDB
|
||||
\section MithrilDB MithrilDB and Future
|
||||
|
||||
@@ -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.
|
||||
|
||||
184
mdbx.h
184
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
|
||||
@@ -695,11 +695,11 @@ extern LIBMDBX_VERINFO_API const struct MDBX_build_info {
|
||||
* automatically (de)initialization, releasing reader lock table slots
|
||||
* and so on.
|
||||
*
|
||||
* If MDBX builded as a DLL this is done out-of-the-box by DllEntry() function,
|
||||
* If MDBX built as a DLL this is done out-of-the-box by DllEntry() function,
|
||||
* which called automatically by Windows core with passing corresponding reason
|
||||
* argument.
|
||||
*
|
||||
* Otherwise, if MDBX was builded not as a DLL, some black magic
|
||||
* Otherwise, if MDBX was built not as a DLL, some black magic
|
||||
* may be required depending of Windows version:
|
||||
*
|
||||
* - Modern Windows versions, including Windows Vista and later, provides
|
||||
@@ -881,7 +881,7 @@ enum MDBX_constants {
|
||||
/* DEBUG & LOGGING ************************************************************/
|
||||
|
||||
/** \addtogroup c_debug
|
||||
* \note Most of debug feature enabled only when libmdbx builded with
|
||||
* \note Most of debug feature enabled only when libmdbx built with
|
||||
* \ref MDBX_DEBUG build option. @{ */
|
||||
|
||||
/** Log level
|
||||
@@ -946,7 +946,7 @@ typedef enum MDBX_log_level_t MDBX_log_level_t;
|
||||
*
|
||||
* \details `MDBX_DBG_DUMP` and `MDBX_DBG_LEGACY_MULTIOPEN` always have an
|
||||
* effect, but `MDBX_DBG_ASSERT`, `MDBX_DBG_AUDIT` and `MDBX_DBG_JITTER` only if
|
||||
* libmdbx builded with \ref MDBX_DEBUG. */
|
||||
* libmdbx built with \ref MDBX_DEBUG. */
|
||||
enum MDBX_debug_flags_t {
|
||||
MDBX_DBG_NONE = 0,
|
||||
|
||||
@@ -1682,7 +1682,7 @@ enum MDBX_copy_flags_t {
|
||||
* pages sequentially */
|
||||
MDBX_CP_COMPACT = 1u,
|
||||
|
||||
/** Force to make resizeable copy, i.e. dynamic size instead of fixed */
|
||||
/** Force to make resizable copy, i.e. dynamic size instead of fixed */
|
||||
MDBX_CP_FORCE_DYNAMIC_SIZE = 2u
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
@@ -1926,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,
|
||||
|
||||
@@ -2051,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.
|
||||
*
|
||||
@@ -2220,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().
|
||||
@@ -2239,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().
|
||||
@@ -2260,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()
|
||||
*
|
||||
@@ -2327,8 +2373,11 @@ 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)
|
||||
LIBMDBX_API int mdbx_env_openW(MDBX_env *env, const wchar_t *pathnameW,
|
||||
#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 */
|
||||
|
||||
@@ -2358,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.
|
||||
*
|
||||
@@ -2374,8 +2425,12 @@ typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t;
|
||||
* so no deletion was performed. */
|
||||
LIBMDBX_API int mdbx_env_delete(const char *pathname,
|
||||
MDBX_env_delete_mode_t mode);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathnameW,
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -2388,6 +2443,8 @@ LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathnameW,
|
||||
* 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.
|
||||
@@ -2407,12 +2464,16 @@ LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathnameW,
|
||||
* account skipping free pages.
|
||||
*
|
||||
* - \ref MDBX_CP_FORCE_DYNAMIC_SIZE
|
||||
* Force to make resizeable copy, i.e. dynamic size instead of fixed.
|
||||
* Force to make resizable copy, i.e. dynamic size instead of fixed.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success. */
|
||||
LIBMDBX_API int mdbx_env_copy(MDBX_env *env, const char *dest,
|
||||
MDBX_copy_flags_t flags);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#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 */
|
||||
@@ -2555,16 +2616,18 @@ 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
|
||||
@@ -2863,7 +2926,7 @@ enum MDBX_warmup_flags_t {
|
||||
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 simpliest
|
||||
* 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
|
||||
@@ -2899,7 +2962,7 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_warmup_flags_t)
|
||||
* \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 spefified.
|
||||
* option was specified.
|
||||
*
|
||||
* \returns A non-zero error value on failure and 0 on success.
|
||||
* Some possible errors are:
|
||||
@@ -2951,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
|
||||
@@ -2959,9 +3024,12 @@ LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags);
|
||||
* \returns A non-zero error value on failure and 0 on success,
|
||||
* some possible errors are:
|
||||
* \retval MDBX_EINVAL An invalid parameter was specified. */
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest);
|
||||
#else
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -3027,7 +3095,7 @@ LIBMDBX_API int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *fd);
|
||||
* was called after \ref mdbx_env_open() but OUTSIDE a write transaction,
|
||||
* then MDBX will execute internal pseudo-transaction to apply new parameters
|
||||
* (but only if anything has been changed), and changes be visible to any
|
||||
* others processes immediately after succesful completion of function.
|
||||
* others processes immediately after successful completion of function.
|
||||
*
|
||||
* Essentially a concept of "automatic size management" is simple and useful:
|
||||
* - There are the lower and upper bounds of the database file size;
|
||||
@@ -3766,13 +3834,10 @@ struct MDBX_commit_latency {
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC ради данных пользователя. */
|
||||
uint32_t work_rtime_monotonic;
|
||||
/** \brief Монотонное время по "настенным часам" затраченное
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное
|
||||
* на подготовку страниц извлекаемых из GC для данных пользователя,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t work_xtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на чтение и поиск
|
||||
* внтури GC ради данных пользователя. */
|
||||
uint32_t work_rtime_cpu;
|
||||
uint32_t work_xtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* ради данных пользователя. */
|
||||
uint32_t work_rsteps;
|
||||
@@ -3789,13 +3854,10 @@ struct MDBX_commit_latency {
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rtime_monotonic;
|
||||
/** \brief Монотонное время по "настенным часам" затраченное на подготовку
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на подготовку
|
||||
* страниц извлекаемых из GC для целей поддержки и обновления самой GC,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t self_xtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на чтение и поиск
|
||||
* внтури GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rtime_cpu;
|
||||
uint32_t self_xtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rsteps;
|
||||
@@ -4128,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
|
||||
@@ -4147,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
|
||||
@@ -5222,7 +5289,7 @@ mdbx_get_datacmp(MDBX_db_flags_t flags);
|
||||
* \param [in] thread The reader thread ID.
|
||||
* \param [in] bytes_used The number of last used page
|
||||
* in the MVCC-snapshot which being read,
|
||||
* i.e. database file can't shrinked beyond this.
|
||||
* i.e. database file can't be shrunk beyond this.
|
||||
* \param [in] bytes_retained The total size of the database pages that were
|
||||
* retired by committed write transactions after
|
||||
* the reader's MVCC-snapshot,
|
||||
@@ -5444,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,
|
||||
@@ -5466,13 +5535,20 @@ 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)
|
||||
|
||||
#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 *pathnameW,
|
||||
const wchar_t *pathname,
|
||||
unsigned target_meta,
|
||||
bool writeable);
|
||||
#endif /* Windows */
|
||||
|
||||
242
mdbx.h++
242
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) || \
|
||||
@@ -223,17 +228,18 @@
|
||||
#endif /* MDBX_CXX20_UNLIKELY */
|
||||
|
||||
#ifndef MDBX_HAVE_CXX20_CONCEPTS
|
||||
#if defined(DOXYGEN) || \
|
||||
(defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L)
|
||||
#if defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L
|
||||
#include <concepts>
|
||||
#define MDBX_HAVE_CXX20_CONCEPTS 1
|
||||
#elif defined(DOXYGEN)
|
||||
#define MDBX_HAVE_CXX20_CONCEPTS 1
|
||||
#else
|
||||
#define MDBX_HAVE_CXX20_CONCEPTS 0
|
||||
#endif /* <concepts> */
|
||||
#endif /* MDBX_HAVE_CXX20_CONCEPTS */
|
||||
|
||||
#ifndef MDBX_CXX20_CONCEPT
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN)
|
||||
#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) CONCEPT NAME
|
||||
#else
|
||||
#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) typename NAME
|
||||
@@ -241,7 +247,7 @@
|
||||
#endif /* MDBX_CXX20_CONCEPT */
|
||||
|
||||
#ifndef MDBX_ASSERT_CXX20_CONCEPT_SATISFIED
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN)
|
||||
#define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, TYPE) \
|
||||
static_assert(CONCEPT<TYPE>)
|
||||
#else
|
||||
@@ -287,7 +293,7 @@ namespace mdbx {
|
||||
// To enable all kinds of an compiler optimizations we use a byte-like type
|
||||
// that don't presumes aliases for pointers as does the `char` type and its
|
||||
// derivatives/typedefs.
|
||||
// Please see https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/263
|
||||
// Please see https://libmdbx.dqdkfa.ru/dead-github/issues/263
|
||||
// for reasoning of the use of `char8_t` type and switching to `__restrict__`.
|
||||
using byte = char8_t;
|
||||
#else
|
||||
@@ -385,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
|
||||
/// @{
|
||||
|
||||
@@ -551,8 +562,11 @@ static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload,
|
||||
/// \defgroup cxx_data slices and buffers
|
||||
/// @{
|
||||
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS
|
||||
#if MDBX_HAVE_CXX20_CONCEPTS || defined(DOXYGEN)
|
||||
|
||||
/** \concept MutableByteProducer
|
||||
* \interface MutableByteProducer
|
||||
* \brief MutableByteProducer C++20 concept */
|
||||
template <typename T>
|
||||
concept MutableByteProducer = requires(T a, char array[42]) {
|
||||
{ a.is_empty() } -> std::same_as<bool>;
|
||||
@@ -560,6 +574,9 @@ concept MutableByteProducer = requires(T a, char array[42]) {
|
||||
{ a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>;
|
||||
};
|
||||
|
||||
/** \concept ImmutableByteProducer
|
||||
* \interface ImmutableByteProducer
|
||||
* \brief ImmutableByteProducer C++20 concept */
|
||||
template <typename T>
|
||||
concept ImmutableByteProducer = requires(const T &a, char array[42]) {
|
||||
{ a.is_empty() } -> std::same_as<bool>;
|
||||
@@ -567,6 +584,9 @@ concept ImmutableByteProducer = requires(const T &a, char array[42]) {
|
||||
{ a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>;
|
||||
};
|
||||
|
||||
/** \concept SliceTranscoder
|
||||
* \interface SliceTranscoder
|
||||
* \brief SliceTranscoder C++20 concept */
|
||||
template <typename T>
|
||||
concept SliceTranscoder = ImmutableByteProducer<T> &&
|
||||
requires(const slice &source, const T &a) {
|
||||
@@ -2639,7 +2659,7 @@ public:
|
||||
return buffer(src, make_reference);
|
||||
}
|
||||
|
||||
static buffer key_from(const silo &&src) noexcept {
|
||||
static buffer key_from(silo &&src) noexcept {
|
||||
return buffer(::std::move(src));
|
||||
}
|
||||
|
||||
@@ -3106,10 +3126,12 @@ public:
|
||||
operate_parameters(const operate_parameters &) noexcept = default;
|
||||
MDBX_CXX14_CONSTEXPR operate_parameters &
|
||||
operator=(const operate_parameters &) noexcept = default;
|
||||
MDBX_env_flags_t
|
||||
make_flags(bool accede = true, ///< \copydoc MDBX_ACCEDE
|
||||
bool use_subdirectory =
|
||||
false ///< use subdirectory to place the DB files
|
||||
MDBX_env_flags_t make_flags(
|
||||
bool accede = true, ///< Allows accepting incompatible operating options
|
||||
///< in case the database is already being used by
|
||||
///< another process(es) \see MDBX_ACCEDE
|
||||
bool use_subdirectory =
|
||||
false ///< use subdirectory to place the DB files
|
||||
) const;
|
||||
static env::mode mode_from_flags(MDBX_env_flags_t) noexcept;
|
||||
static env::durability durability_from_flags(MDBX_env_flags_t) noexcept;
|
||||
@@ -3334,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.
|
||||
@@ -3348,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);
|
||||
@@ -3450,7 +3532,7 @@ public:
|
||||
/// transactions since the current read
|
||||
/// transaction started.
|
||||
size_t bytes_used; ///< The number of last used page in the MVCC-snapshot
|
||||
///< which being read, i.e. database file can't shrinked
|
||||
///< which being read, i.e. database file can't be shrunk
|
||||
///< beyond this.
|
||||
size_t bytes_retained; ///< The total size of the database pages that
|
||||
///< were retired by committed write transactions
|
||||
@@ -3591,7 +3673,7 @@ public:
|
||||
void close(bool dont_sync = false);
|
||||
|
||||
env_managed(env_managed &&) = default;
|
||||
env_managed &operator=(env_managed &&other) {
|
||||
env_managed &operator=(env_managed &&other) noexcept {
|
||||
if (MDBX_UNLIKELY(handle_))
|
||||
MDBX_CXX20_UNLIKELY {
|
||||
assert(handle_ != other.handle_);
|
||||
@@ -3890,7 +3972,7 @@ class LIBMDBX_API_TYPE txn_managed : public txn {
|
||||
public:
|
||||
MDBX_CXX11_CONSTEXPR txn_managed() noexcept = default;
|
||||
txn_managed(txn_managed &&) = default;
|
||||
txn_managed &operator=(txn_managed &&other) {
|
||||
txn_managed &operator=(txn_managed &&other) noexcept {
|
||||
if (MDBX_UNLIKELY(handle_))
|
||||
MDBX_CXX20_UNLIKELY {
|
||||
assert(handle_ != other.handle_);
|
||||
@@ -4112,7 +4194,7 @@ public:
|
||||
void close();
|
||||
|
||||
cursor_managed(cursor_managed &&) = default;
|
||||
cursor_managed &operator=(cursor_managed &&other) {
|
||||
cursor_managed &operator=(cursor_managed &&other) noexcept {
|
||||
if (MDBX_UNLIKELY(handle_))
|
||||
MDBX_CXX20_UNLIKELY {
|
||||
assert(handle_ != other.handle_);
|
||||
@@ -5056,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.
|
||||
*
|
||||
|
||||
46
src/base.h
46
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.
|
||||
*
|
||||
@@ -293,8 +293,8 @@ __extern_C key_t ftok(const char *, int);
|
||||
/* Byteorder */
|
||||
|
||||
#if defined(i386) || defined(__386) || defined(__i386) || defined(__i386__) || \
|
||||
defined(i486) || defined(__i486) || defined(__i486__) || \
|
||||
defined(i586) | defined(__i586) || defined(__i586__) || defined(i686) || \
|
||||
defined(i486) || defined(__i486) || defined(__i486__) || defined(i586) || \
|
||||
defined(__i586) || defined(__i586__) || defined(i686) || \
|
||||
defined(__i686) || defined(__i686__) || defined(_M_IX86) || \
|
||||
defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \
|
||||
defined(__INTEL__) || defined(__x86_64) || defined(__x86_64__) || \
|
||||
@@ -572,17 +572,13 @@ __extern_C key_t ftok(const char *, int);
|
||||
|
||||
#ifndef __hot
|
||||
#if defined(__OPTIMIZE__)
|
||||
#if defined(__e2k__)
|
||||
#define __hot __attribute__((__hot__)) __optimize(3)
|
||||
#elif defined(__clang__) && !__has_attribute(__hot_) && \
|
||||
#if defined(__clang__) && !__has_attribute(__hot__) && \
|
||||
__has_attribute(__section__) && \
|
||||
(defined(__linux__) || defined(__gnu_linux__))
|
||||
/* just put frequently used functions in separate section */
|
||||
#define __hot __attribute__((__section__("text.hot"))) __optimize("O3")
|
||||
#elif defined(__LCC__)
|
||||
#define __hot __attribute__((__hot__, __optimize__("Ofast,O4")))
|
||||
#elif defined(__GNUC__) || __has_attribute(__hot__)
|
||||
#define __hot __attribute__((__hot__)) __optimize("O3")
|
||||
#define __hot __attribute__((__hot__))
|
||||
#else
|
||||
#define __hot __optimize("O3")
|
||||
#endif
|
||||
@@ -593,17 +589,13 @@ __extern_C key_t ftok(const char *, int);
|
||||
|
||||
#ifndef __cold
|
||||
#if defined(__OPTIMIZE__)
|
||||
#if defined(__e2k__)
|
||||
#define __cold __attribute__((__cold__)) __optimize(1)
|
||||
#elif defined(__clang__) && !__has_attribute(cold) && \
|
||||
#if defined(__clang__) && !__has_attribute(__cold__) && \
|
||||
__has_attribute(__section__) && \
|
||||
(defined(__linux__) || defined(__gnu_linux__))
|
||||
/* just put infrequently used functions in separate section */
|
||||
#define __cold __attribute__((__section__("text.unlikely"))) __optimize("Os")
|
||||
#elif defined(__LCC__)
|
||||
#define __hot __attribute__((__cold__, __optimize__("Osize")))
|
||||
#elif defined(__GNUC__) || __has_attribute(cold)
|
||||
#define __cold __attribute__((__cold__)) __optimize("Os")
|
||||
#elif defined(__GNUC__) || __has_attribute(__cold__)
|
||||
#define __cold __attribute__((__cold__))
|
||||
#else
|
||||
#define __cold __optimize("Os")
|
||||
#endif
|
||||
@@ -669,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,12 +1,12 @@
|
||||
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| |TXN_UPDATE_GC |INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 | |
|
||||
6 |0000 0040| |TXN_FROZEN_RE |REVERSEDUP|CURRENT |DBI_DUPDATA | |P_SUBP | |
|
||||
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 | | | | | | | <= |
|
||||
9 |0000 0200| _MAY_UNMAP| | | | | | | <= |
|
||||
@@ -15,7 +15,7 @@ N | MASK | ENV | TXN | DB | PUT | DBI | NOD
|
||||
12|0000 1000| | | | | | | | |
|
||||
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 | | | | |
|
||||
|
||||
6024
src/core.c
6024
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
|
||||
|
||||
413
src/internals.h
413
src/internals.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.
|
||||
*
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
/** Disables using GNU/Linux libc extensions.
|
||||
* \ingroup build_option
|
||||
* \note This option couldn't be moved to the options.h since dependant
|
||||
* \note This option couldn't be moved to the options.h since dependent
|
||||
* control macros/defined should be prepared before include the options.h */
|
||||
#ifndef MDBX_DISABLE_GNU_SOURCE
|
||||
#define MDBX_DISABLE_GNU_SOURCE 0
|
||||
@@ -86,14 +86,18 @@
|
||||
#pragma warning(disable : 4464) /* relative include path contains '..' */
|
||||
#endif
|
||||
#if _MSC_VER > 1913
|
||||
#pragma warning(disable : 5045) /* Compiler will insert Spectre mitigation... \
|
||||
*/
|
||||
#pragma warning(disable : 5045) /* will insert Spectre mitigation... */
|
||||
#endif
|
||||
#if _MSC_VER > 1914
|
||||
#pragma warning( \
|
||||
disable : 5105) /* winbase.h(9531): warning C5105: macro expansion \
|
||||
producing 'defined' has undefined behavior */
|
||||
#endif
|
||||
#if _MSC_VER > 1930
|
||||
#pragma warning(disable : 6235) /* <expression> is always a constant */
|
||||
#pragma warning(disable : 6237) /* <expression> is never evaluated and might \
|
||||
have side effects */
|
||||
#endif
|
||||
#pragma warning(disable : 4710) /* 'xyz': function not inlined */
|
||||
#pragma warning(disable : 4711) /* function 'xyz' selected for automatic \
|
||||
inline expansion */
|
||||
@@ -227,6 +231,142 @@ extern LIBMDBX_API const char *const mdbx_sourcery_anchor;
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Debug and Logging stuff */
|
||||
|
||||
#define MDBX_RUNTIME_FLAGS_INIT \
|
||||
((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
|
||||
|
||||
extern uint8_t runtime_flags;
|
||||
extern uint8_t loglevel;
|
||||
extern MDBX_debug_func *debug_logger;
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline void jitter4testing(bool tiny) {
|
||||
#if MDBX_DEBUG
|
||||
if (MDBX_DBG_JITTER & runtime_flags)
|
||||
osal_jitter(tiny);
|
||||
#else
|
||||
(void)tiny;
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
|
||||
debug_log(int level, const char *function, int line, const char *fmt, ...)
|
||||
MDBX_PRINTF_ARGS(4, 5);
|
||||
MDBX_INTERNAL_FUNC void debug_log_va(int level, const char *function, int line,
|
||||
const char *fmt, va_list args);
|
||||
|
||||
#if MDBX_DEBUG
|
||||
#define LOG_ENABLED(msg) unlikely(msg <= loglevel)
|
||||
#define AUDIT_ENABLED() unlikely((runtime_flags & MDBX_DBG_AUDIT))
|
||||
#else /* MDBX_DEBUG */
|
||||
#define LOG_ENABLED(msg) (msg < MDBX_LOG_VERBOSE && msg <= loglevel)
|
||||
#define AUDIT_ENABLED() (0)
|
||||
#endif /* MDBX_DEBUG */
|
||||
|
||||
#if MDBX_FORCE_ASSERTIONS
|
||||
#define ASSERT_ENABLED() (1)
|
||||
#elif MDBX_DEBUG
|
||||
#define ASSERT_ENABLED() likely((runtime_flags & MDBX_DBG_ASSERT))
|
||||
#else
|
||||
#define ASSERT_ENABLED() (0)
|
||||
#endif /* assertions */
|
||||
|
||||
#define DEBUG_EXTRA(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_EXTRA)) \
|
||||
debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_EXTRA_PRINT(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_EXTRA)) \
|
||||
debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define TRACE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_TRACE)) \
|
||||
debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_DEBUG)) \
|
||||
debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define VERBOSE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_VERBOSE)) \
|
||||
debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define NOTICE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_NOTICE)) \
|
||||
debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define WARNING(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_WARN)) \
|
||||
debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#undef ERROR /* wingdi.h \
|
||||
Yeah, morons from M$ put such definition to the public header. */
|
||||
|
||||
#define ERROR(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_ERROR)) \
|
||||
debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define FATAL(fmt, ...) \
|
||||
debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
|
||||
|
||||
#if MDBX_DEBUG
|
||||
#define ASSERT_FAIL(env, msg, func, line) mdbx_assert_fail(env, msg, func, line)
|
||||
#else /* MDBX_DEBUG */
|
||||
MDBX_NORETURN __cold void assert_fail(const char *msg, const char *func,
|
||||
unsigned line);
|
||||
#define ASSERT_FAIL(env, msg, func, line) \
|
||||
do { \
|
||||
(void)(env); \
|
||||
assert_fail(msg, func, line); \
|
||||
} while (0)
|
||||
#endif /* MDBX_DEBUG */
|
||||
|
||||
#define ENSURE_MSG(env, expr, msg) \
|
||||
do { \
|
||||
if (unlikely(!(expr))) \
|
||||
ASSERT_FAIL(env, msg, __func__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE(env, expr) ENSURE_MSG(env, expr, #expr)
|
||||
|
||||
/* assert(3) variant in environment context */
|
||||
#define eASSERT(env, expr) \
|
||||
do { \
|
||||
if (ASSERT_ENABLED()) \
|
||||
ENSURE(env, expr); \
|
||||
} while (0)
|
||||
|
||||
/* assert(3) variant in cursor context */
|
||||
#define cASSERT(mc, expr) eASSERT((mc)->mc_txn->mt_env, expr)
|
||||
|
||||
/* assert(3) variant in transaction context */
|
||||
#define tASSERT(txn, expr) eASSERT((txn)->mt_env, expr)
|
||||
|
||||
#ifndef xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#undef assert
|
||||
#define assert(expr) eASSERT(NULL, expr)
|
||||
#endif
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Atomics */
|
||||
|
||||
@@ -525,16 +665,12 @@ typedef struct MDBX_meta {
|
||||
* Each non-metapage up to MDBX_meta.mm_last_pg is reachable exactly once
|
||||
* in the snapshot: Either used by a database or listed in a GC record. */
|
||||
typedef struct MDBX_page {
|
||||
union {
|
||||
#define IS_FROZEN(txn, p) ((p)->mp_txnid < (txn)->mt_txnid)
|
||||
#define IS_SPILLED(txn, p) ((p)->mp_txnid == (txn)->mt_txnid)
|
||||
#define IS_SHADOWED(txn, p) ((p)->mp_txnid > (txn)->mt_txnid)
|
||||
#define IS_VALID(txn, p) ((p)->mp_txnid <= (txn)->mt_front)
|
||||
#define IS_MODIFIABLE(txn, p) ((p)->mp_txnid == (txn)->mt_front)
|
||||
uint64_t
|
||||
mp_txnid; /* txnid which created this page, maybe zero in legacy DB */
|
||||
struct MDBX_page *mp_next; /* for in-memory list of freed pages */
|
||||
};
|
||||
uint64_t mp_txnid; /* txnid which created page, maybe zero in legacy DB */
|
||||
uint16_t mp_leaf2_ksize; /* key size if this is a LEAF2 page */
|
||||
#define P_BRANCH 0x01u /* branch page */
|
||||
#define P_LEAF 0x02u /* leaf page */
|
||||
@@ -576,18 +712,24 @@ typedef struct MDBX_page {
|
||||
/* Size of the page header, excluding dynamic data at the end */
|
||||
#define PAGEHDRSZ offsetof(MDBX_page, mp_ptrs)
|
||||
|
||||
/* Pointer displacement without casting to char* to avoid pointer-aliasing */
|
||||
#define ptr_disp(ptr, disp) ((void *)(((intptr_t)(ptr)) + ((intptr_t)(disp))))
|
||||
|
||||
/* Pointer distance as signed number of bytes */
|
||||
#define ptr_dist(more, less) (((intptr_t)(more)) - ((intptr_t)(less)))
|
||||
|
||||
#define mp_next(mp) \
|
||||
(*(MDBX_page **)ptr_disp((mp)->mp_ptrs, sizeof(void *) - sizeof(uint32_t)))
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct profgc_stat {
|
||||
/* Монотонное время по "настенным часам"
|
||||
* затраченное на чтение и поиск внутри GC */
|
||||
uint64_t rtime_monotonic;
|
||||
/* Монотонное время по "настенным часам" затраченное
|
||||
* на подготовку страниц извлекаемых из GC, включая подкачку с диска. */
|
||||
uint64_t xtime_monotonic;
|
||||
/* Процессорное время в режим пользователя
|
||||
* затраченное на чтение и поиск внутри GC */
|
||||
uint64_t rtime_cpu;
|
||||
* на подготовку страниц извлекаемых из GC, включая подкачку с диска. */
|
||||
uint64_t xtime_cpu;
|
||||
/* Количество итераций чтения-поиска внутри GC при выделении страниц */
|
||||
uint32_t rsteps;
|
||||
/* Количество запросов на выделение последовательностей страниц,
|
||||
@@ -617,6 +759,14 @@ typedef struct pgop_stat {
|
||||
MDBX_atomic_uint64_t
|
||||
fsync; /* Number of explicit fsync/flush-to-disk operations */
|
||||
|
||||
MDBX_atomic_uint64_t prefault; /* Number of prefault write operations */
|
||||
MDBX_atomic_uint64_t mincore; /* Number of mincore() calls */
|
||||
|
||||
MDBX_atomic_uint32_t
|
||||
incoherence; /* number of https://libmdbx.dqdkfa.ru/dead-github/issues/269
|
||||
caught */
|
||||
MDBX_atomic_uint32_t reserved;
|
||||
|
||||
/* Статистика для профилирования GC.
|
||||
* Логически эти данные может быть стоит вынести в другую структуру,
|
||||
* но разница будет сугубо косметическая. */
|
||||
@@ -756,6 +906,10 @@ typedef struct MDBX_lockinfo {
|
||||
|
||||
/* Low 32-bit of txnid with which meta-pages was synced,
|
||||
* i.e. for sync-polling in the MDBX_NOMETASYNC mode. */
|
||||
#define MDBX_NOMETASYNC_LAZY_UNK (UINT32_MAX / 3)
|
||||
#define MDBX_NOMETASYNC_LAZY_FD (MDBX_NOMETASYNC_LAZY_UNK + UINT32_MAX / 8)
|
||||
#define MDBX_NOMETASYNC_LAZY_WRITEMAP \
|
||||
(MDBX_NOMETASYNC_LAZY_UNK - UINT32_MAX / 8)
|
||||
MDBX_atomic_uint32_t mti_meta_sync_txnid;
|
||||
|
||||
/* Period for timed auto-sync feature, i.e. at the every steady checkpoint
|
||||
@@ -770,7 +924,7 @@ typedef struct MDBX_lockinfo {
|
||||
|
||||
/* Paired counter of processes that have mlock()ed part of mmapped DB.
|
||||
* The (mti_mlcnt[0] - mti_mlcnt[1]) > 0 means at least one process
|
||||
* lock at leat one page, so therefore madvise() could return EINVAL. */
|
||||
* lock at least one page, so therefore madvise() could return EINVAL. */
|
||||
MDBX_atomic_uint32_t mti_mlcnt[2];
|
||||
|
||||
MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
|
||||
@@ -805,6 +959,12 @@ typedef struct MDBX_lockinfo {
|
||||
/* Shared anchor for tracking readahead edge and enabled/disabled status. */
|
||||
pgno_t mti_readahead_anchor;
|
||||
|
||||
/* Shared cache for mincore() results */
|
||||
struct {
|
||||
pgno_t begin[4];
|
||||
uint64_t mask[4];
|
||||
} mti_mincore_cache;
|
||||
|
||||
MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
|
||||
|
||||
/* Readeaders registration lock. */
|
||||
@@ -877,7 +1037,8 @@ typedef struct MDBX_lockinfo {
|
||||
#endif /* MDBX_WORDBITS */
|
||||
|
||||
#define MDBX_READERS_LIMIT 32767
|
||||
#define MDBX_RADIXSORT_THRESHOLD 333
|
||||
#define MDBX_RADIXSORT_THRESHOLD 142
|
||||
#define MDBX_GOLD_RATIO_DBL 1.6180339887498948482
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
@@ -902,14 +1063,7 @@ typedef txnid_t *MDBX_TXL;
|
||||
/* An Dirty-Page list item is an pgno/pointer pair. */
|
||||
typedef struct MDBX_dp {
|
||||
MDBX_page *ptr;
|
||||
pgno_t pgno;
|
||||
union {
|
||||
uint32_t extra;
|
||||
__anonymous_struct_extension__ struct {
|
||||
unsigned multi : 1;
|
||||
unsigned lru : 31;
|
||||
};
|
||||
};
|
||||
pgno_t pgno, npages;
|
||||
} MDBX_dp;
|
||||
|
||||
/* An DPL (dirty-page list) is a sorted array of MDBX_DPs. */
|
||||
@@ -925,7 +1079,8 @@ typedef struct MDBX_dpl {
|
||||
} MDBX_dpl;
|
||||
|
||||
/* PNL sizes */
|
||||
#define MDBX_PNL_GRANULATE 1024
|
||||
#define MDBX_PNL_GRANULATE_LOG2 10
|
||||
#define MDBX_PNL_GRANULATE (1 << MDBX_PNL_GRANULATE_LOG2)
|
||||
#define MDBX_PNL_INITIAL \
|
||||
(MDBX_PNL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(pgno_t))
|
||||
|
||||
@@ -933,7 +1088,7 @@ typedef struct MDBX_dpl {
|
||||
#define MDBX_TXL_INITIAL \
|
||||
(MDBX_TXL_GRANULATE - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
|
||||
#define MDBX_TXL_MAX \
|
||||
((1u << 17) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
|
||||
((1u << 26) - 2 - MDBX_ASSUME_MALLOC_OVERHEAD / sizeof(txnid_t))
|
||||
|
||||
#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
|
||||
#define MDBX_PNL_GETSIZE(pl) ((size_t)((pl)[0]))
|
||||
@@ -949,9 +1104,11 @@ typedef struct MDBX_dpl {
|
||||
#define MDBX_PNL_END(pl) (&(pl)[MDBX_PNL_GETSIZE(pl) + 1])
|
||||
|
||||
#if MDBX_PNL_ASCENDING
|
||||
#define MDBX_PNL_EDGE(pl) ((pl) + 1)
|
||||
#define MDBX_PNL_LEAST(pl) MDBX_PNL_FIRST(pl)
|
||||
#define MDBX_PNL_MOST(pl) MDBX_PNL_LAST(pl)
|
||||
#else
|
||||
#define MDBX_PNL_EDGE(pl) ((pl) + MDBX_PNL_GETSIZE(pl))
|
||||
#define MDBX_PNL_LEAST(pl) MDBX_PNL_LAST(pl)
|
||||
#define MDBX_PNL_MOST(pl) MDBX_PNL_FIRST(pl)
|
||||
#endif
|
||||
@@ -1000,13 +1157,11 @@ struct MDBX_txn {
|
||||
/* Additional flag for sync_locked() */
|
||||
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
|
||||
|
||||
#define MDBX_TXN_UPDATE_GC 0x20 /* GC is being updated */
|
||||
#define MDBX_TXN_FROZEN_RE 0x40 /* list of reclaimed-pgno must not altered */
|
||||
#define MDBX_TXN_DRAINED_GC 0x20 /* GC was depleted up to oldest reader */
|
||||
|
||||
#define TXN_FLAGS \
|
||||
(MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \
|
||||
MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID | MDBX_TXN_UPDATE_GC | \
|
||||
MDBX_TXN_FROZEN_RE)
|
||||
MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID | MDBX_TXN_DRAINED_GC)
|
||||
|
||||
#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) || \
|
||||
((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) & \
|
||||
@@ -1065,7 +1220,7 @@ struct MDBX_txn {
|
||||
struct {
|
||||
meta_troika_t troika;
|
||||
/* In write txns, array of cursors for each DB */
|
||||
pgno_t *relist; /* Reclaimed GC pages */
|
||||
MDBX_PNL relist; /* Reclaimed GC pages */
|
||||
txnid_t last_reclaimed; /* ID of last used record */
|
||||
#if MDBX_ENABLE_REFUND
|
||||
pgno_t loose_refund_wl /* FIXME: describe */;
|
||||
@@ -1088,11 +1243,17 @@ struct MDBX_txn {
|
||||
MDBX_page *loose_pages;
|
||||
/* Number of loose pages (tw.loose_pages) */
|
||||
size_t loose_count;
|
||||
size_t spill_least_removed;
|
||||
/* The sorted list of dirty pages we temporarily wrote to disk
|
||||
* because the dirty list was full. page numbers in here are
|
||||
* shifted left by 1, deleted slots have the LSB set. */
|
||||
MDBX_PNL spill_pages;
|
||||
union {
|
||||
struct {
|
||||
size_t least_removed;
|
||||
/* The sorted list of dirty pages we temporarily wrote to disk
|
||||
* because the dirty list was full. page numbers in here are
|
||||
* shifted left by 1, deleted slots have the LSB set. */
|
||||
MDBX_PNL list;
|
||||
} spilled;
|
||||
size_t writemap_dirty_npages;
|
||||
size_t writemap_spilled_npages;
|
||||
};
|
||||
} tw;
|
||||
};
|
||||
};
|
||||
@@ -1142,6 +1303,9 @@ struct MDBX_cursor {
|
||||
#define C_SUB 0x04 /* Cursor is a sub-cursor */
|
||||
#define C_DEL 0x08 /* last op was a cursor_del */
|
||||
#define C_UNTRACK 0x10 /* Un-track cursor when closing */
|
||||
#define C_GCU \
|
||||
0x20 /* Происходит подготовка к обновлению GC, поэтому \
|
||||
* можно брать страницы из GC даже для FREE_DBI */
|
||||
uint8_t mc_flags;
|
||||
|
||||
/* Cursor checking flags. */
|
||||
@@ -1200,12 +1364,12 @@ struct MDBX_env {
|
||||
#define ENV_INTERNAL_FLAGS (MDBX_FATAL_ERROR | MDBX_ENV_ACTIVE | MDBX_ENV_TXKEY)
|
||||
uint32_t me_flags;
|
||||
osal_mmap_t me_dxb_mmap; /* The main data file */
|
||||
#define me_map me_dxb_mmap.dxb
|
||||
#define me_map me_dxb_mmap.base
|
||||
#define me_lazy_fd me_dxb_mmap.fd
|
||||
#define me_fd4data me_ioring.fd
|
||||
mdbx_filehandle_t me_dsync_fd, me_fd4meta;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE me_overlapped_fd, me_data_lock_event;
|
||||
#define me_overlapped_fd me_ioring.overlapped_fd
|
||||
HANDLE me_data_lock_event;
|
||||
#endif /* Windows */
|
||||
osal_mmap_t me_lck_mmap; /* The lock file */
|
||||
#define me_lfd me_lck_mmap.fd
|
||||
@@ -1233,10 +1397,12 @@ struct MDBX_env {
|
||||
uint16_t *me_dbflags; /* array of flags from MDBX_db.md_flags */
|
||||
MDBX_atomic_uint32_t *me_dbiseqs; /* array of dbi sequence numbers */
|
||||
unsigned
|
||||
me_maxgc_ov1page; /* Number of pgno_t fit in a single overflow page */
|
||||
uint32_t me_live_reader; /* have liveness lock in reader table */
|
||||
void *me_userctx; /* User-settable context */
|
||||
me_maxgc_ov1page; /* Number of pgno_t fit in a single overflow page */
|
||||
unsigned me_maxgc_per_branch;
|
||||
uint32_t me_live_reader; /* have liveness lock in reader table */
|
||||
void *me_userctx; /* User-settable context */
|
||||
MDBX_hsr_func *me_hsr_callback; /* Callback for kicking laggard readers */
|
||||
size_t me_madv_threshold;
|
||||
|
||||
struct {
|
||||
unsigned dp_reserve_limit;
|
||||
@@ -1248,11 +1414,17 @@ struct MDBX_env {
|
||||
uint8_t spill_min_denominator;
|
||||
uint8_t spill_parent4child_denominator;
|
||||
unsigned merge_threshold_16dot16_percent;
|
||||
#if !(defined(_WIN32) || defined(_WIN64))
|
||||
unsigned writethrough_threshold;
|
||||
#endif /* Windows */
|
||||
bool prefault_write;
|
||||
union {
|
||||
unsigned all;
|
||||
/* tracks options with non-auto values but tuned by user */
|
||||
struct {
|
||||
unsigned dp_limit : 1;
|
||||
unsigned rp_augment_limit : 1;
|
||||
unsigned prefault_write : 1;
|
||||
} non_auto;
|
||||
} flags;
|
||||
} me_options;
|
||||
@@ -1274,6 +1446,7 @@ struct MDBX_env {
|
||||
int semid;
|
||||
} me_sysv_ipc;
|
||||
#endif /* MDBX_LOCKING == MDBX_LOCKING_SYSV */
|
||||
bool me_incore;
|
||||
|
||||
MDBX_env *me_lcklist_next;
|
||||
|
||||
@@ -1282,6 +1455,7 @@ struct MDBX_env {
|
||||
MDBX_txn *me_txn; /* current write transaction */
|
||||
osal_fastmutex_t me_dbi_lock;
|
||||
MDBX_dbi me_numdbs; /* number of DBs opened */
|
||||
bool me_prefault_write;
|
||||
|
||||
MDBX_page *me_dp_reserve; /* list of malloc'ed blocks for re-use */
|
||||
unsigned me_dp_reserve_len;
|
||||
@@ -1293,6 +1467,8 @@ struct MDBX_env {
|
||||
osal_srwlock_t me_remap_guard;
|
||||
/* Workaround for LockFileEx and WriteFile multithread bug */
|
||||
CRITICAL_SECTION me_windowsbug_lock;
|
||||
char *me_pathname_char; /* cache of multi-byte representation of pathname
|
||||
to the DB files */
|
||||
#else
|
||||
osal_fastmutex_t me_remap_guard;
|
||||
#endif
|
||||
@@ -1323,139 +1499,6 @@ struct MDBX_env {
|
||||
};
|
||||
|
||||
#ifndef __cplusplus
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Debug and Logging stuff */
|
||||
|
||||
#define MDBX_RUNTIME_FLAGS_INIT \
|
||||
((MDBX_DEBUG) > 0) * MDBX_DBG_ASSERT + ((MDBX_DEBUG) > 1) * MDBX_DBG_AUDIT
|
||||
|
||||
extern uint8_t runtime_flags;
|
||||
extern uint8_t loglevel;
|
||||
extern MDBX_debug_func *debug_logger;
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline void jitter4testing(bool tiny) {
|
||||
#if MDBX_DEBUG
|
||||
if (MDBX_DBG_JITTER & runtime_flags)
|
||||
osal_jitter(tiny);
|
||||
#else
|
||||
(void)tiny;
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC void MDBX_PRINTF_ARGS(4, 5)
|
||||
debug_log(int level, const char *function, int line, const char *fmt, ...)
|
||||
MDBX_PRINTF_ARGS(4, 5);
|
||||
MDBX_INTERNAL_FUNC void debug_log_va(int level, const char *function, int line,
|
||||
const char *fmt, va_list args);
|
||||
|
||||
#if MDBX_DEBUG
|
||||
#define LOG_ENABLED(msg) unlikely(msg <= loglevel)
|
||||
#define AUDIT_ENABLED() unlikely((runtime_flags & MDBX_DBG_AUDIT))
|
||||
#else /* MDBX_DEBUG */
|
||||
#define LOG_ENABLED(msg) (msg < MDBX_LOG_VERBOSE && msg <= loglevel)
|
||||
#define AUDIT_ENABLED() (0)
|
||||
#endif /* MDBX_DEBUG */
|
||||
|
||||
#if MDBX_FORCE_ASSERTIONS
|
||||
#define ASSERT_ENABLED() (1)
|
||||
#elif MDBX_DEBUG
|
||||
#define ASSERT_ENABLED() likely((runtime_flags & MDBX_DBG_ASSERT))
|
||||
#else
|
||||
#define ASSERT_ENABLED() (0)
|
||||
#endif /* assertions */
|
||||
|
||||
#define DEBUG_EXTRA(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_EXTRA)) \
|
||||
debug_log(MDBX_LOG_EXTRA, __func__, __LINE__, fmt, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_EXTRA_PRINT(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_EXTRA)) \
|
||||
debug_log(MDBX_LOG_EXTRA, NULL, 0, fmt, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define TRACE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_TRACE)) \
|
||||
debug_log(MDBX_LOG_TRACE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_DEBUG)) \
|
||||
debug_log(MDBX_LOG_DEBUG, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define VERBOSE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_VERBOSE)) \
|
||||
debug_log(MDBX_LOG_VERBOSE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define NOTICE(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_NOTICE)) \
|
||||
debug_log(MDBX_LOG_NOTICE, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define WARNING(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_WARN)) \
|
||||
debug_log(MDBX_LOG_WARN, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#undef ERROR /* wingdi.h \
|
||||
Yeah, morons from M$ put such definition to the public header. */
|
||||
|
||||
#define ERROR(fmt, ...) \
|
||||
do { \
|
||||
if (LOG_ENABLED(MDBX_LOG_ERROR)) \
|
||||
debug_log(MDBX_LOG_ERROR, __func__, __LINE__, fmt "\n", __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define FATAL(fmt, ...) \
|
||||
debug_log(MDBX_LOG_FATAL, __func__, __LINE__, fmt "\n", __VA_ARGS__);
|
||||
|
||||
#if MDBX_DEBUG
|
||||
#define ASSERT_FAIL(env, msg, func, line) mdbx_assert_fail(env, msg, func, line)
|
||||
#else /* MDBX_DEBUG */
|
||||
MDBX_NORETURN __cold void assert_fail(const char *msg, const char *func,
|
||||
unsigned line);
|
||||
#define ASSERT_FAIL(env, msg, func, line) \
|
||||
do { \
|
||||
(void)(env); \
|
||||
assert_fail(msg, func, line); \
|
||||
} while (0)
|
||||
#endif /* MDBX_DEBUG */
|
||||
|
||||
#define ENSURE_MSG(env, expr, msg) \
|
||||
do { \
|
||||
if (unlikely(!(expr))) \
|
||||
ASSERT_FAIL(env, msg, __func__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE(env, expr) ENSURE_MSG(env, expr, #expr)
|
||||
|
||||
/* assert(3) variant in environment context */
|
||||
#define eASSERT(env, expr) \
|
||||
do { \
|
||||
if (ASSERT_ENABLED()) \
|
||||
ENSURE(env, expr); \
|
||||
} while (0)
|
||||
|
||||
/* assert(3) variant in cursor context */
|
||||
#define cASSERT(mc, expr) eASSERT((mc)->mc_txn->mt_env, expr)
|
||||
|
||||
/* assert(3) variant in transaction context */
|
||||
#define tASSERT(txn, expr) eASSERT((txn)->mt_env, expr)
|
||||
|
||||
#ifndef xMDBX_TOOLS /* Avoid using internal eASSERT() */
|
||||
#undef assert
|
||||
#define assert(expr) eASSERT(NULL, expr)
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Cache coherence and mmap invalidation */
|
||||
|
||||
@@ -1466,7 +1509,8 @@ MDBX_NORETURN __cold void assert_fail(const char *msg, const char *func,
|
||||
#endif /* MDBX_CPU_WRITEBACK_INCOHERENT */
|
||||
|
||||
MDBX_MAYBE_UNUSED static __inline void
|
||||
osal_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
|
||||
osal_flush_incoherent_mmap(const void *addr, size_t nbytes,
|
||||
const intptr_t pagesize) {
|
||||
#if MDBX_MMAP_INCOHERENT_FILE_WRITE
|
||||
char *const begin = (char *)(-pagesize & (intptr_t)addr);
|
||||
char *const end =
|
||||
@@ -1482,7 +1526,7 @@ osal_flush_incoherent_mmap(void *addr, size_t nbytes, const intptr_t pagesize) {
|
||||
#ifdef DCACHE
|
||||
/* MIPS has cache coherency issues.
|
||||
* Note: for any nbytes >= on-chip cache size, entire is flushed. */
|
||||
cacheflush(addr, nbytes, DCACHE);
|
||||
cacheflush((void *)addr, nbytes, DCACHE);
|
||||
#else
|
||||
#error "Oops, cacheflush() not available"
|
||||
#endif /* DCACHE */
|
||||
@@ -1641,16 +1685,7 @@ typedef struct MDBX_node {
|
||||
* | 1, a > b
|
||||
* \
|
||||
*/
|
||||
#ifndef __e2k__
|
||||
/* LY: fast enough on most systems */
|
||||
#define CMP2INT(a, b) (((b) > (a)) ? -1 : (a) > (b))
|
||||
#else
|
||||
/* LY: more parallelable on VLIW Elbrus */
|
||||
#define CMP2INT(a, b) (((a) > (b)) - ((b) > (a)))
|
||||
#endif
|
||||
|
||||
/* Do not spill pages to disk if txn is getting full, may fail instead */
|
||||
#define MDBX_NOSPILL 0x8000
|
||||
#define CMP2INT(a, b) (((a) != (b)) ? (((a) < (b)) ? -1 : 1) : 0)
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
|
||||
int64pgno(int64_t i64) {
|
||||
@@ -1662,14 +1697,14 @@ int64pgno(int64_t i64) {
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
|
||||
pgno_add(size_t base, size_t augend) {
|
||||
assert(base <= MAX_PAGENO + 1 && augend < MAX_PAGENO);
|
||||
return int64pgno(base + augend);
|
||||
return int64pgno((int64_t)base + (int64_t)augend);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __inline pgno_t
|
||||
pgno_sub(size_t base, size_t subtrahend) {
|
||||
assert(base >= MIN_PAGENO && base <= MAX_PAGENO + 1 &&
|
||||
subtrahend < MAX_PAGENO);
|
||||
return int64pgno(base - subtrahend);
|
||||
return int64pgno((int64_t)base - (int64_t)subtrahend);
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED MDBX_NOTHROW_CONST_FUNCTION static __always_inline bool
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -152,8 +152,10 @@ static __inline int flock(HANDLE fd, unsigned flags, size_t offset,
|
||||
|
||||
static __inline int flock_data(const MDBX_env *env, unsigned flags,
|
||||
size_t offset, size_t bytes) {
|
||||
return flock_with_event(env->me_fd4data, env->me_data_lock_event, flags,
|
||||
offset, 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) {
|
||||
@@ -173,7 +175,7 @@ static int funlock(mdbx_filehandle_t fd, size_t offset, size_t bytes) {
|
||||
#else
|
||||
#define DXB_MAXLEN UINT32_C(0x7ff00000)
|
||||
#endif
|
||||
#define DXB_BODY (env->me_psize * NUM_METAS), DXB_MAXLEN
|
||||
#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) {
|
||||
@@ -192,25 +194,35 @@ int mdbx_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
}
|
||||
}
|
||||
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
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 = flock_with_event(env->me_fd4data, env->me_data_lock_event,
|
||||
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);
|
||||
rc = flock_with_event(env->me_fd4data, env->me_data_lock_event,
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
if (rc == ERROR_LOCK_VIOLATION) {
|
||||
SleepEx(0, true);
|
||||
rc = flock_with_event(env->me_fd4data, env->me_data_lock_event,
|
||||
rc = flock_with_event(fd4data, env->me_data_lock_event,
|
||||
LCK_EXCLUSIVE | LCK_DONTWAIT, DXB_BODY);
|
||||
}
|
||||
}
|
||||
if (rc == MDBX_SUCCESS)
|
||||
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;
|
||||
@@ -218,7 +230,9 @@ int mdbx_txn_lock(MDBX_env *env, bool dontwait) {
|
||||
|
||||
void mdbx_txn_unlock(MDBX_env *env) {
|
||||
if ((env->me_flags & MDBX_EXCLUSIVE) == 0) {
|
||||
int err = funlock(env->me_fd4data, DXB_BODY);
|
||||
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);
|
||||
}
|
||||
@@ -275,17 +289,18 @@ static int suspend_and_append(mdbx_handle_array_t **array,
|
||||
const DWORD ThreadId) {
|
||||
const unsigned limit = (*array)->limit;
|
||||
if ((*array)->count == limit) {
|
||||
void *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 * 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;
|
||||
}
|
||||
|
||||
@@ -451,18 +466,20 @@ static void lck_unlock(MDBX_env *env) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
if (env->me_fd4data != 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) */
|
||||
do
|
||||
err = funlock(env->me_fd4data, DXB_BODY);
|
||||
err = funlock(fd4data, DXB_BODY);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
do
|
||||
err = funlock(env->me_fd4data, DXB_WHOLE);
|
||||
err = funlock(fd4data, DXB_WHOLE);
|
||||
while (err == MDBX_SUCCESS);
|
||||
assert(err == ERROR_NOT_LOCKED ||
|
||||
(mdbx_RunningUnderWine() && err == ERROR_LOCK_VIOLATION));
|
||||
@@ -522,7 +539,9 @@ static int internal_seize_lck(HANDLE lfd) {
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
assert(env->me_fd4data != INVALID_HANDLE_VALUE);
|
||||
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 */
|
||||
@@ -554,7 +573,7 @@ MDBX_INTERNAL_FUNC int osal_lck_seize(MDBX_env *env) {
|
||||
return err;
|
||||
}
|
||||
jitter4testing(false);
|
||||
err = funlock(env->me_fd4data, DXB_WHOLE);
|
||||
err = funlock(fd4data, DXB_WHOLE);
|
||||
if (err != MDBX_SUCCESS)
|
||||
mdbx_panic("%s(%s) failed: err %u", __func__,
|
||||
"unlock-against-without-lck", err);
|
||||
@@ -564,8 +583,10 @@ MDBX_INTERNAL_FUNC int osal_lck_seize(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_fd4data != INVALID_HANDLE_VALUE);
|
||||
assert(fd4data != INVALID_HANDLE_VALUE);
|
||||
assert(env->me_lfd != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (env->me_flags & MDBX_EXCLUSIVE)
|
||||
@@ -740,7 +761,7 @@ static void WINAPI stub_srwlock_AcquireShared(osal_srwlock_t *srwl) {
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -754,7 +775,7 @@ static void WINAPI stub_srwlock_AcquireShared(osal_srwlock_t *srwl) {
|
||||
|
||||
// Remove from the readers list, spin, try again
|
||||
_InterlockedDecrement(&srwl->readerCount);
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,7 +791,7 @@ static void WINAPI stub_srwlock_AcquireExclusive(osal_srwlock_t *srwl) {
|
||||
// If there's a writer already, spin without unnecessarily
|
||||
// interlocking the CPUs
|
||||
if (srwl->writerCount != 0) {
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -785,7 +806,7 @@ static void WINAPI stub_srwlock_AcquireExclusive(osal_srwlock_t *srwl) {
|
||||
// that we're the writer.
|
||||
while (srwl->readerCount != 0) {
|
||||
assert(srwl->writerCount >= 0 && srwl->readerCount >= 0);
|
||||
YieldProcessor();
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,38 +848,40 @@ MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange;
|
||||
#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);
|
||||
GET_PROC_ADDR(hKernel32dll, SetFileIoOverlappedRange);
|
||||
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 HINSTANCE hAdvapi32dll = GetModuleHandleA("advapi32.dll");
|
||||
GET_PROC_ADDR(hAdvapi32dll, RegGetValueA);
|
||||
#undef GET_PROC_ADDR
|
||||
|
||||
const osal_srwlock_t_function init = (osal_srwlock_t_function)GetProcAddress(
|
||||
hKernel32dll, "InitializeSRWLock");
|
||||
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(
|
||||
@@ -876,6 +899,12 @@ static void mdbx_winnt_import(void) {
|
||||
osal_srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive;
|
||||
osal_srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive;
|
||||
}
|
||||
|
||||
const HINSTANCE hAdvapi32dll = GetModuleHandleA("advapi32.dll");
|
||||
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 "2022-11-11" "MDBX 0.12.2"
|
||||
.TH MDBX_CHK 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_chk \- MDBX checking 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_COPY 1 "2022-11-11" "MDBX 0.12.2"
|
||||
.TH MDBX_COPY 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_copy \- MDBX environment copy tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -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 "2022-11-11" "MDBX 0.12.2"
|
||||
.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 "2022-11-11" "MDBX 0.12.2"
|
||||
.TH MDBX_DUMP 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_dump \- MDBX environment export 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_LOAD 1 "2022-11-11" "MDBX 0.12.2"
|
||||
.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 "2022-11-11" "MDBX 0.12.2"
|
||||
.TH MDBX_STAT 1 "2023-03-03" "MDBX 0.12.4"
|
||||
.SH NAME
|
||||
mdbx_stat \- MDBX environment status tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -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"
|
||||
|
||||
435
src/mdbx_chk.c
435
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.
|
||||
*
|
||||
@@ -23,6 +23,8 @@
|
||||
#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;
|
||||
@@ -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,6 +127,97 @@ static void MDBX_PRINTF_ARGS(1, 2) print(const char *msg, ...) {
|
||||
}
|
||||
}
|
||||
|
||||
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[] = {
|
||||
@@ -190,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) {
|
||||
osal_free((void *)walk.dbi[i].name);
|
||||
walk.dbi[i].name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -212,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 = osal_strdup(dbi_name);
|
||||
dbi->name = *dbi_name;
|
||||
return last = dbi;
|
||||
}
|
||||
|
||||
@@ -304,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;
|
||||
@@ -318,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;
|
||||
@@ -383,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);
|
||||
}
|
||||
@@ -408,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;
|
||||
@@ -480,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -491,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) {
|
||||
@@ -541,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];
|
||||
@@ -560,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);
|
||||
}
|
||||
@@ -570,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);
|
||||
}
|
||||
@@ -581,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 &&
|
||||
@@ -608,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 = osal_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);
|
||||
osal_free(name);
|
||||
if (rc != MDBX_INCOMPATIBLE)
|
||||
return rc;
|
||||
|
||||
return handle_userdb(record_number, key, data);
|
||||
}
|
||||
|
||||
@@ -691,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;
|
||||
@@ -701,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);
|
||||
@@ -720,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) {
|
||||
@@ -754,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) {
|
||||
@@ -830,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,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)
|
||||
@@ -917,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",
|
||||
@@ -1102,9 +1182,9 @@ 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)
|
||||
@@ -1171,7 +1251,7 @@ int main(int argc, char *argv[]) {
|
||||
envflags &= ~MDBX_RDONLY;
|
||||
#if MDBX_MMAP_INCOHERENT_FILE_WRITE
|
||||
/* Temporary `workaround` for OpenBSD kernel's flaw.
|
||||
* See https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/67 */
|
||||
* See https://libmdbx.dqdkfa.ru/dead-github/issues/67 */
|
||||
envflags |= MDBX_WRITEMAP;
|
||||
#endif /* MDBX_MMAP_INCOHERENT_FILE_WRITE */
|
||||
break;
|
||||
@@ -1182,9 +1262,10 @@ 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;
|
||||
@@ -1222,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;
|
||||
}
|
||||
}
|
||||
@@ -1415,7 +1497,7 @@ int main(int argc, char *argv[]) {
|
||||
alloc_pages = backed_pages;
|
||||
}
|
||||
} else {
|
||||
/* LY: DB may be shrinked by writer down to the allocated pages. */
|
||||
/* LY: DB may be shrunk by writer down to the allocated pages. */
|
||||
if (alloc_pages > backed_pages) {
|
||||
print(" ! alloc-pages %" PRIu64 " > backed-pages %" PRIu64 "\n",
|
||||
alloc_pages, backed_pages);
|
||||
@@ -1563,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;
|
||||
}
|
||||
@@ -1574,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)
|
||||
@@ -1608,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)
|
||||
@@ -1624,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);
|
||||
@@ -1639,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;
|
||||
@@ -1685,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) {
|
||||
@@ -1694,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",
|
||||
@@ -1728,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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
@@ -87,6 +93,19 @@
|
||||
#error MDBX_ENABLE_PGOP_STAT must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_PGOP_STAT */
|
||||
|
||||
/** 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
|
||||
@@ -147,7 +166,7 @@
|
||||
|
||||
/** Controls sort order of internal page number lists.
|
||||
* This mostly experimental/advanced option with not for regular MDBX users.
|
||||
* \warning The database format depend on this option and libmdbx builded with
|
||||
* \warning The database format depend on this option and libmdbx built with
|
||||
* different option value are incompatible. */
|
||||
#ifndef MDBX_PNL_ASCENDING
|
||||
#define MDBX_PNL_ASCENDING 0
|
||||
@@ -201,7 +220,11 @@
|
||||
#endif /* MDBX_HAVE_C11ATOMICS */
|
||||
|
||||
/** If defined then enables use the GCC's `__builtin_cpu_supports()`
|
||||
* for runtime dispatching depending on the CPU's capabilities. */
|
||||
* 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
|
||||
@@ -287,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 */
|
||||
@@ -300,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). */
|
||||
@@ -309,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). */
|
||||
@@ -320,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 */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -331,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
|
||||
@@ -339,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
|
||||
@@ -351,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
|
||||
@@ -360,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 */
|
||||
@@ -385,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
|
||||
|
||||
507
src/osal.c
507
src/osal.c
File diff suppressed because it is too large
Load Diff
121
src/osal.h
121
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.
|
||||
*
|
||||
@@ -211,7 +211,8 @@ typedef pthread_mutex_t osal_fastmutex_t;
|
||||
/* OS abstraction layer stuff */
|
||||
|
||||
MDBX_INTERNAL_VAR unsigned sys_pagesize;
|
||||
MDBX_MAYBE_UNUSED MDBX_INTERNAL_VAR unsigned sys_allocation_granularity;
|
||||
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
|
||||
@@ -224,14 +225,15 @@ osal_syspagesize(void) {
|
||||
|
||||
#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_param {
|
||||
typedef struct osal_mmap {
|
||||
union {
|
||||
void *address;
|
||||
uint8_t *dxb;
|
||||
void *base;
|
||||
struct MDBX_lockinfo *lck;
|
||||
};
|
||||
mdbx_filehandle_t fd;
|
||||
@@ -313,13 +315,12 @@ typedef struct osal_ioring {
|
||||
unsigned slots_left;
|
||||
unsigned allocated;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define IOR_DIRECT 1
|
||||
#define IOR_OVERLAPPED 2
|
||||
#define IOR_STATE_LOCKED 1
|
||||
HANDLE overlapped_fd;
|
||||
unsigned pagesize;
|
||||
unsigned last_sgvcnt;
|
||||
size_t last_bytes;
|
||||
uint8_t flags, state, pagesize_ln2;
|
||||
uint8_t direct, state, pagesize_ln2;
|
||||
unsigned event_stack;
|
||||
HANDLE *event_pool;
|
||||
volatile LONG async_waiting;
|
||||
@@ -336,7 +337,6 @@ typedef struct osal_ioring {
|
||||
#define ior_last_sgvcnt(ior, item) (1)
|
||||
#define ior_last_bytes(ior, item) (item)->single.iov_len
|
||||
#endif /* !Windows */
|
||||
mdbx_filehandle_t fd;
|
||||
ior_item_t *last;
|
||||
ior_item_t *pool;
|
||||
char *boundary;
|
||||
@@ -345,11 +345,13 @@ typedef struct osal_ioring {
|
||||
#ifndef __cplusplus
|
||||
|
||||
/* Actually this is not ioring for now, but on the way. */
|
||||
MDBX_INTERNAL_FUNC int osal_ioring_create(osal_ioring_t *,
|
||||
MDBX_INTERNAL_FUNC int osal_ioring_create(osal_ioring_t *
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
uint8_t flags,
|
||||
,
|
||||
bool enable_direct,
|
||||
mdbx_filehandle_t overlapped_fd
|
||||
#endif /* Windows */
|
||||
mdbx_filehandle_t fd);
|
||||
);
|
||||
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 *);
|
||||
@@ -360,7 +362,7 @@ typedef struct osal_ioring_write_result {
|
||||
unsigned wops;
|
||||
} osal_ioring_write_result_t;
|
||||
MDBX_INTERNAL_FUNC osal_ioring_write_result_t
|
||||
osal_ioring_write(osal_ioring_t *ior);
|
||||
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(
|
||||
@@ -378,11 +380,13 @@ osal_ioring_used(const osal_ioring_t *ior) {
|
||||
}
|
||||
|
||||
MDBX_MAYBE_UNUSED static inline int
|
||||
osal_ioring_reserve(osal_ioring_t *ior, size_t items, size_t bytes) {
|
||||
osal_ioring_prepare(osal_ioring_t *ior, size_t items, size_t bytes) {
|
||||
items = (items > 32) ? items : 32;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const size_t npages = bytes >> ior->pagesize_ln2;
|
||||
items = (items > npages) ? items : npages;
|
||||
if (ior->direct) {
|
||||
const size_t npages = bytes >> ior->pagesize_ln2;
|
||||
items = (items > npages) ? items : npages;
|
||||
}
|
||||
#else
|
||||
(void)bytes;
|
||||
#endif
|
||||
@@ -522,9 +526,10 @@ MDBX_INTERNAL_FUNC int osal_thread_join(osal_thread_t thread);
|
||||
|
||||
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 osal_fsync(mdbx_filehandle_t fd,
|
||||
@@ -546,6 +551,19 @@ enum osal_openfile_purpose {
|
||||
MDBX_OPEN_DELETE
|
||||
};
|
||||
|
||||
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,
|
||||
@@ -559,9 +577,8 @@ 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 osal_mmap(const int flags, osal_mmap_t *map,
|
||||
const size_t must, const size_t limit,
|
||||
const unsigned options);
|
||||
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
|
||||
@@ -583,6 +600,7 @@ MDBX_INTERNAL_FUNC int osal_msync(const osal_mmap_t *map, size_t offset,
|
||||
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 osal_getpid(void) {
|
||||
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));
|
||||
@@ -685,7 +703,7 @@ MDBX_INTERNAL_FUNC int osal_lck_destroy(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 reson for such downgrade:
|
||||
/// operational level specified by argument. The reason for such downgrade:
|
||||
/// - unblocking of other processes that are waiting for access, i.e.
|
||||
/// if (env->me_flags & MDBX_EXCLUSIVE) != 0, then other processes
|
||||
/// should be made aware that access is unavailable rather than
|
||||
@@ -739,22 +757,7 @@ MDBX_INTERNAL_FUNC int osal_rpid_check(MDBX_env *env, uint32_t pid);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
MDBX_INTERNAL_FUNC size_t osal_mb2w(wchar_t *dst, size_t dst_n, const char *src,
|
||||
size_t src_n);
|
||||
|
||||
#define OSAL_MB2WIDE(FROM, TO) \
|
||||
do { \
|
||||
const char *const from_tmp = (FROM); \
|
||||
const size_t from_mblen = strlen(from_tmp); \
|
||||
const size_t to_wlen = osal_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 != \
|
||||
osal_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 *osal_srwlock_t_function)(osal_srwlock_t *);
|
||||
MDBX_INTERNAL_VAR osal_srwlock_t_function osal_srwlock_Init,
|
||||
@@ -886,6 +889,46 @@ MDBX_INTERNAL_VAR MDBX_SetFileIoOverlappedRange mdbx_SetFileIoOverlappedRange;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
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. */
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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 */
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -142,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);
|
||||
@@ -153,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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -129,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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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;
|
||||
@@ -435,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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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,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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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,8 +30,24 @@
|
||||
...
|
||||
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 iov_write() as workaround for https://web.archive.org/web/https://github.com/erthink/libmdbx/issues/269
|
||||
# memcmp() inside iov_write() as workaround for https://libmdbx.dqdkfa.ru/dead-github/issues/269
|
||||
{
|
||||
iov-pagecheck-1
|
||||
Memcheck:Cond
|
||||
|
||||
Reference in New Issue
Block a user