Compare commits

...

148 Commits

Author SHA1 Message Date
Леонид Юрьев (Leonid Yuriev)
53177e483c mdbx: выпуск 0.12.4 "Арта-333"
Стабилизирующий выпуск с исправлением обнаруженных ошибок, устранением
недочетов и технических долгов. Ветка 0.12 считается готовой к
продуктовому использованию, получает статус стабильной и далее будет
получать только исправление ошибок. Разработка будет продолжена в ветке
0.13, а ветка 0.11 становится архивной.

Благодарности:
--------------

 - 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.

Исправления (без корректировок новых функций):
----------------------------------------------

 - Устранен регресс после коммита 474391c83c,
   приводящий к возврату 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`.

63 files changed, 1161 insertions(+), 569 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2023-03-03 23:23:08 +03:00
Леонид Юрьев (Leonid Yuriev)
ad93633d10 mdbx-tools: вывод всех счетчиков page-operations в mdbx_stat. 2023-03-03 21:18:35 +03:00
Леонид Юрьев (Leonid Yuriev)
f17c55a872 mdbx: обновление ChangeLog. 2023-03-02 16:34:19 +03:00
Леонид Юрьев (Leonid Yuriev)
7db014c4fc mdbx++: добавление в C++ API поддержки расширенных опций времени выполнения enum MDBX_option_t.
https://gitflic.ru/project/erthink/libmdbx/issue/4
2023-03-01 23:22:50 +03:00
Леонид Юрьев (Leonid Yuriev)
22405885f6 mdbx: корректировка излишней assert-проверки внутри override_meta(). 2023-03-01 01:09:10 +03:00
Леонид Юрьев (Leonid Yuriev)
2ae7bfd9be mdbx-make: актуализация списков для целей cross-gcc и cross-qemu. 2023-02-28 22:52:28 +03:00
Леонид Юрьев (Leonid Yuriev)
8f87ab252e mdbx: дополнение ChangeLog. 2023-02-28 00:52:40 +03:00
Леонид Юрьев (Leonid Yuriev)
800bd55ab9 mdbx-test: добавление опции --extra в скрипт test/long_stochastic.sh 2023-02-28 00:50:48 +03:00
Леонид Юрьев (Leonid Yuriev)
5c52adf358 mdbx-test: расширение набора режимов перебираемых скриптом test/long_stochastic.sh 2023-02-28 00:50:48 +03:00
Leonid Yuriev
6d74b10db1 mdbx: поддержка ASAN (Address Sanitizer) при сборке посредством MSVC. 2023-02-28 00:50:30 +03:00
Леонид Юрьев (Leonid Yuriev)
359489e271 mdbx: исправление семантической опечатки в комментарии о режиме работы. 2023-02-27 16:59:10 +03:00
Леонид Юрьев (Leonid Yuriev)
5f690bbc4f mdbx-test: по-умолчанию работа в режиме MDBX_SYNC_DURABLE. 2023-02-27 16:59:10 +03:00
Леонид Юрьев (Leonid Yuriev)
1b6e32071c mdbx: повторное "устранение" предупреждений MSVC Static Analyzer (aka Prefast).
Никаких значимых изменений, только обход "странностей" в MSVC.

Как оказалось MSVC распространяет действие директивы
`pragma(warning(supppress:#))` строго на следующую строку, даже если эта
строка является продолжением комментария начатого в самой директиве
и/или не содержит синтаксических конструкций языка.

Поэтому большинство из добавленных ранее директив для подавления ложных
предупреждений, перестало работать после переформатирования исходного
кода.
2023-02-27 16:59:06 +03:00
Леонид Юрьев (Leonid Yuriev)
29d12f1fc3 mdbx-doc: добавлено примечание к опции MDBX_HAVE_BUILTIN_CPU_SUPPORTS. 2023-02-14 12:09:44 +03:00
Леонид Юрьев (Leonid Yuriev)
2ea9fbe51b mdbx: дополнение ChangeLog. 2023-02-13 20:57:43 +03:00
Леонид Юрьев (Leonid Yuriev)
57ca0d6e1b mdbx: корректировка макросов __cold/__hot.
В том числе для устранения проблемы
`error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch`
при сборке посредством GCC >10.x для SH4.
2023-02-13 20:57:43 +03:00
Леонид Юрьев (Leonid Yuriev)
b8092dd0db mdbx: устранение ложного предупреждения GCC при сборке для SH4. 2023-02-13 16:29:47 +03:00
Леонид Юрьев (Leonid Yuriev)
8fba5ac8d8 mdbx: устранение излишней assert-проверки внутри override_meta(). 2023-02-12 23:27:39 +03:00
Леонид Юрьев (Leonid Yuriev)
c9d11cbac1 mdbx: дополнение ChangeLog. 2023-02-11 07:35:56 +03:00
Леонид Юрьев (Leonid Yuriev)
25e958f081 mdbx: устранение всех предупреждений статического анализатора MSVC (все несущественные или ложные). 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
7f5ea6d3b8 mdbx: корректировка прототипа __asan_default_options(). 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
e51140fe48 mdbx-doc: корректировка doxygen-описания C++ API, в особенности C++20 concepts. 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
bd35fe8970 mdbx-doc: добавление doxygen-описания для API с широкими символами. 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
1684d17b0f mdbx-windows: поддержка char-версии mdbx_env_get_path(). 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
ebbe98afa5 mdbx-windows: ликвидация макроса OSAL_MB2WIDE(). 2023-02-11 00:26:06 +03:00
Леонид Юрьев (Leonid Yuriev)
351a30f186 mdbx-windows: не расходуем стек под буферы для wchar-преобразования путей. 2023-02-09 22:37:31 +03:00
Леонид Юрьев (Leonid Yuriev)
2a41b24876 mdbx++: уточнение const и noexcept для нескольких методов. 2023-02-09 15:14:39 +03:00
Леонид Юрьев (Leonid Yuriev)
fb827959a9 mdbx: исправление put(MDBX_UPSERT+MDBX_ALLDUPS) для случая замены всех значений в subDb.
Fixed cursor_put_nochecklen() internals for case when dupsort'ed named subDb
contains a single key with multiple values (aka duplicates), which are replaced
with a single value by put-operation with the `MDBX_UPSERT+MDBX_ALLDUPS` flags.

In this case, the database becomes completely empty, without any pages.
However exactly this condition was not considered and
thus wasn't handled correctly.

Fixes https://gitflic.ru/project/erthink/libmdbx/issue/8

Thanks Masatoshi Fukunaga <https://gitflic.ru/user/mah0x211> for reporting.
2023-02-01 01:04:24 +03:00
Леонид Юрьев (Leonid Yuriev)
209f784ee7 mdbx: исправление assert-проверок внутри dxb_resize().
Устранение регресса после a484a1f89b.

Проверка `prev_limit_pgno >= used_pgno` правомочна только в части сценариев,
но не в общем случае.
2023-01-23 23:54:11 +03:00
Леонид Юрьев (Leonid Yuriev)
68ebbe1fde mdbx: Обновление ChangeLog. 2023-01-18 18:34:52 +03:00
Леонид Юрьев (Leonid Yuriev)
486711945d mdbx-doc: исправление copy&paste опечатки в "Getting started". 2023-01-18 18:34:25 +03:00
Леонид Юрьев (Leonid Yuriev)
3ade7c7ba1 mdbx: обновление статуса MithrilDB. 2023-01-16 19:12:08 +03:00
Леонид Юрьев (Leonid Yuriev)
c01f025bfa mdbx: обновление года на 2023. 2023-01-16 16:32:02 +03:00
Леонид Юрьев (Leonid Yuriev)
a484a1f89b mdbx: рефакторинг dxb_resize() и связанного кода.
В том числе, для устранения срабатывания assert-проверки
`size_bytes == env->me_dxb_mmap.current` в специфических многопоточных
сценариях использования.

Проверка срабатывала только в отладочных сборках, при специфическом
наложении во времени читающей и пишущей транзакции в разных потоках,
одновременно с изменением размера БД.

Кроме срабатывание проверки, каких-либо других последствий не возникало.
2023-01-16 02:20:56 +03:00
Леонид Юрьев (Leonid Yuriev)
0979a93a78 mdbx: добавлено примечание об ошибке MinGW MSYS2. 2023-01-12 17:01:27 +03:00
Леонид Юрьев (Leonid Yuriev)
a98c73f4f6 mdbx-cmake: вызов mdbx_chk в режиме чтения-записи для проверки MDBX_EXCLUSIVE в этом режиме. 2023-01-12 17:01:27 +03:00
Leonid Yuriev
9e15bd9b29 mdbx-windows: устранение регресса ERROR_SHARING_VIOLATION в режиме MDBX_EXCLUSIVE.
Спасибо maxc0d3r@protonmail.com за сообщение о проблеме.
2023-01-12 17:01:27 +03:00
Leonid Yuriev
0159f97e94 mdbx: ограничиваем размер отображения при коротком read-only файле.
Цель в предотвращении ошибки ERROR_NOT_ENOUGH_MEMORY в Windows, которая
совсем не информативна для пользователя и возникает в этом случае (когда
файл открыт read-only и короче запрошенного размера).
2023-01-12 01:53:22 +03:00
Леонид Юрьев (Leonid Yuriev)
56050f201f mdbx: обновление ChangeLog. 2023-01-10 15:03:38 +03:00
Леонид Юрьев (Leonid Yuriev)
525c4a55a4 mdbx: fix English typos.
Thanks to Dimitris Apostolou <dimitris.apostolou@icloud.com>
2023-01-10 14:16:08 +03:00
Леонид Юрьев (Leonid Yuriev)
702c67fc38 mdbx-test: доработка append-теста.
- добавлен speculum-контроль;
- с вероятностью 1/8 генерируются не-последовательные/не-упорядоченные ключи для проверки возврата MDBX_EKEYMISMATH;
- игнорирование расхождение хеша последовательности для не-последовательных ключей.
2023-01-09 23:51:34 +03:00
Леонид Юрьев (Leonid Yuriev)
3da23da7b3 mdbx: косметический рефакторинг контроля MDBX_APPEND. 2023-01-09 21:39:42 +03:00
Леонид Юрьев (Leonid Yuriev)
16cda5c2e8 mdbx: исправление опечаток в ChangeLog. 2023-01-08 12:40:44 +03:00
Леонид Юрьев (Leonid Yuriev)
f1fdb88938 mdbx: выпуск v0.12.3 "Акула"
Выпуск с существенными доработками и новой функциональностью в память о закрытом open-source проекте "Акула".

Благодарности:
--------------

 - [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()` из параллельного потока выполнения вне
   работающей транзакции.

 - Исправление регресса после коммита db72763de0 от 2022-10-08
   в логике возврата грязных страниц в режиме `MDBX_WRITEMAP`, из-за чего
   освободившиеся страницы использовались не немедленно, а попадали в
   retired-список совершаемой транзакции и происходил необоснованный рост
   размера транзакции.

 - Устранение SIGSEGV или ошибочного вызова `free()` в ситуациях
   повторного открытия среды посредством `mdbx_env_open()`.

 - Устранение ошибки совершенной в коммите fe20de136c от 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 для уменьшения накладных расходов.
 - Рефакторинг и микрооптимизация.

20 files changed, 4504 insertions(+), 2924 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
2023-01-07 00:11:51 +03:00
Леонид Юрьев (Leonid Yuriev)
68a8a15621 mdbx: изменение адреса ioarena. 2023-01-07 00:10:23 +03:00
Леонид Юрьев (Leonid Yuriev)
b86b71a948 mdbx: обновление ChangeLog. 2023-01-07 00:10:23 +03:00
Леонид Юрьев (Leonid Yuriev)
61e77e7b70 mdbx: контроль отсутствия дубликатов LCK-файла с альтернативными именами. 2023-01-07 00:10:23 +03:00
Леонид Юрьев (Leonid Yuriev)
08fb7d5838 mdbx: корректировка отключения MDBX_NOSUBDIR при открытии mdbx.dat без директории. 2023-01-07 00:10:19 +03:00
Леонид Юрьев (Leonid Yuriev)
f2a49b687a mdbx: обновление ChangeLog. 2023-01-04 00:19:48 +03:00
Леонид Юрьев (Leonid Yuriev)
c6b73c8a24 mdbx: добавление me_madv_threshold и рефакторинг/упрощение.
Для уменьшения затрат на MDBX_SHRINK_ALLOWED.
2023-01-03 20:20:03 +03:00
Леонид Юрьев (Leonid Yuriev)
24f2e878c1 mdbx: устранение несущественных предупреждений Valgrind. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
2c8d3e1e12 mdbx: исправление предупреждения UBSAN. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
ab55016599 mdbx: устранение ложного срабатывания assert внутри dpl_reserve(). 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
f0c2927fc7 mdbx: перенос LRU-отметок в теневые страницы по отрицательному смещению.
Это позволяет избавиться от повторного поиска в "гзязном" списке
страниц, уже находящихся в стеке курсора, для обнлвления LRU-отметок.
2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
8519fde741 mdbx: микро-оптимизация cmp_reverse(). 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
bcddeaba9f mdbx: изменение CMP2INT().
Решил вернуться к старому варианту. Вроде-бы все актуальные компиляторы
ведут себя с ним прилично (не хуже), а некоторые лучше.
2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
5317e516d2 mdbx: микро-оптимизация cmp_int(). 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
be05037906 mdbx: перемещение debug/assert-макросов перед атомиками. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
f53dc70038 mdbx: добавление eq_fast() для сравнений на (не)равенство.
Цель в том, чтобы уменьшить кол-во условных и безусловных переходов при
сравнениях равно/неравно, в том числе избегать вызовов задаваемых
кастомных компаратаров и memcmp() для коротких ключей/значений.
2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
2322138a8e mdbx: корректировка сообщения об ошибке. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
37867a0b84 mdbx: не обходим проверку когерентности в режиме восстановления. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
f0c43fb24a mdbx: без необходимости не объединяем не-грязные страницы в дереве. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
adf433a1bc mdbx-make: доработка макро для bench-целей. 2023-01-03 19:28:11 +03:00
Леонид Юрьев (Leonid Yuriev)
48bd3fc4c8 mdbx: упрощение default_prefault_write(). 2022-12-31 23:35:53 +03:00
Леонид Юрьев (Leonid Yuriev)
7ffea70087 mdbx: доработка loose-пути в page_retire(). 2022-12-31 23:35:53 +03:00
Леонид Юрьев (Leonid Yuriev)
ef460a9229 mdbx: выделение cursor_get() для уменьшения кол-ва проверок. 2022-12-29 23:03:12 +03:00
Леонид Юрьев (Leonid Yuriev)
df63ff0e7e mdbx: выделение cursor_del() для уменьшения кол-ва проверок. 2022-12-29 23:03:12 +03:00
Леонид Юрьев (Leonid Yuriev)
66a5704949 mdbx: выделение cursor_put() для уменьшения кол-ва проверок. 2022-12-29 19:26:50 +03:00
Леонид Юрьев (Leonid Yuriev)
61d21b0a02 mdbx: не трогать LRU и dbi в cursor_touch() для вложенных курсоров. 2022-12-29 01:20:04 +03:00
Леонид Юрьев (Leonid Yuriev)
0941319940 mdbx: парочка незначительных likely. 2022-12-29 01:20:04 +03:00
Леонид Юрьев (Leonid Yuriev)
bb2e3967eb mdbx: уменьшение кол-ва вызовов realloc(). 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
e458af602e mdbx: устранение ненужных условий в отладке (несущественно). 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
d29acf4fdc mdbx: актуализация bits.md (внутренний справочник). 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
a06fe4f168 mdbx: переработка контроля "некогерентности" для уменьшения накладных расходов.
Существует проблема https://libmdbx.dqdkfa.ru/dead-github/issues/269,
которая проявляется только при специфической неупорядоченности внутри
ядра ОС, когда страницы, записанные в файл отображенный в память,
становятся видны в памяти посредством работы unified page cache:

 - если записанная последней мета-страница "обгоняет" ранее записанные,
   т.е. когда записанное в файл позже становится видимым в отображении
   раньше, чем записанное ранее.

Теперь, вместо постоянной полной сверки записываемых страниц,
выполняется легковесная проверка при старте транзакций, с переключением
в режим "как раньше" при обнаружении проблемы.

В результате, в некоторых сценариях возвращается 5-10%
производительности, а в отдельных синтетических тестах до 30%.
2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
0498114469 mdbx: обнуление информации о задержках для невалидных транзакций в mdbx_txn_commit_ex(). 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
85828f677a mdbx: пересоздание пустой MAIN_DBI при необходимости. 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
9cbbdfa025 mdbx: добавление const к аргументам функций получения и контроля страниц. 2022-12-27 11:50:28 +03:00
Леонид Юрьев (Leonid Yuriev)
686145ec2e mdbx: рефакторинг с удалением cursor_spill() и MDBX_NOSPILL. 2022-12-27 11:50:23 +03:00
Леонид Юрьев (Leonid Yuriev)
fe55f25665 mdbx: использование msync(MS_ASYNC) для спиллинга в режиме MDBX_WRITEMAP вне зависимости от MDBX_AVOID_MSYNC и MDBX_MMAP_USE_MS_ASYNC. 2022-12-22 00:48:41 +03:00
Леонид Юрьев (Leonid Yuriev)
e9a2042df1 mdbx: добавление MDBX_NOTHROW_PURE_FUNCTION к некоторым функциям. 2022-12-22 00:48:41 +03:00
Леонид Юрьев (Leonid Yuriev)
fd98a635d9 mdbx: не возвращаем ошибку при попытке закрытия MAIN_DBI. 2022-12-22 00:48:41 +03:00
Леонид Юрьев (Leonid Yuriev)
722c6ecf43 mdbx: use attribute(tls_model(local-dynamic)) as workaround for CLANG bug. 2022-12-22 00:48:40 +03:00
Леонид Юрьев (Leonid Yuriev)
44493c6448 mdbx-tools: поддержка не-печатных имен subDb в mdbx_chk. 2022-12-22 00:48:40 +03:00
Леонид Юрьев (Leonid Yuriev)
7011743262 mdbx: поддержка не-печатных имен для subDb. 2022-12-21 22:29:03 +03:00
Леонид Юрьев (Leonid Yuriev)
b247b081af mdbx: переработка LRU-отметок для спиллинга.
Два существенных изменения:

1. Инкремент и обновление LRU происходит при изменении страницы,
   но не при доступе к ней.

2. Устранен регресс, из-за которого страницы в стеке курсора хоть
   помечались, но могли быть ошибочно пролиты на диск,
   так как dpl_age() возвращал не 0.
2022-12-21 22:29:03 +03:00
Леонид Юрьев (Leonid Yuriev)
bf2f3bfbbf mdbx: устранение чтения освобожденной памяти и жалоб ASAN при спиллинге.
Вероятность проявляния проблемы крайне низкая, но стало воспроизводиться после доработки спллинга.
2022-12-21 22:29:03 +03:00
Леонид Юрьев (Leonid Yuriev)
ffdff3f831 mdbx: обновление ChangeLog. 2022-12-14 10:58:31 +03:00
Леонид Юрьев (Leonid Yuriev)
07f2ccb752 mdbx: добавление опции MDBX_MMAP_USE_MS_ASYNC.
Суть в избавлении от лишнего вызова msync(MS_ASYNC) в режимах
MDBX_WRITEMAP+MDBX_SAFE_NOSYNC и т.п.

Гипотетически могут быть системы/платформы, на которых изменения в
разделяемой памяти не видны другим процессам до вызова msync(MS_ASYNC)
и/или до этого вызова не будет инициироваться вытеснение/запись таких
страниц на диск.

Поэтому использование msync(MS_ASYNC) вынесено под опцию
MDBX_MMAP_USE_MS_ASYNC, которая по-умолчанию включена только на системах
с MDBX_MMAP_INCOHERENT_FILE_WRITE или MDBX_MMAP_INCOHERENT_CPU_CACHE.
2022-12-14 02:05:52 +03:00
Леонид Юрьев (Leonid Yuriev)
23fedf6bba mdbx: контроль значений макросов-опций сборки. 2022-12-13 19:44:36 +03:00
Леонид Юрьев (Leonid Yuriev)
167011c2d5 mdbx: обновление ChangeLog. 2022-12-12 21:29:10 +03:00
Леонид Юрьев (Leonid Yuriev)
245a782912 mdbx: не игнорируем ошибки при открытии дескриптора с O_DSYNC. 2022-12-12 18:54:03 +03:00
Леонид Юрьев (Leonid Yuriev)
957c99d86f mdbx: добавление MDBX_opt_prefault_write_enable вместо MDBX_ENABLE_PREFAULT. 2022-12-12 18:54:03 +03:00
Леонид Юрьев (Leonid Yuriev)
b959e217b1 mdbx: рефакторинг обработки установки опций в значения по-умолчанию. 2022-12-12 18:54:03 +03:00
Леонид Юрьев (Leonid Yuriev)
54b15d7e41 mdbx: определение in-core БД (в tmpfs/ramfs/mfs) с отключением prefault-write.
Это вынужденный читинг для "починки" сравнительных бенчмарков при
размещении БД в /dev/shm.

Проблема в том, что актуальные ядра Linux для файлов размещенных в tmpfs
возвращают mincore=false. В результате, в простейших бенчмарках видно
двукратное снижение производительности, просто из-за вызовов write()
выполняемых для prefault.

Из-за этого, в таких синтетических тестах, новая libmdbx становится
существенно медленнее предыдущих версий, в том числе LMDB.
2022-12-12 18:54:03 +03:00
Леонид Юрьев (Leonid Yuriev)
69f7d6cdd8 mdbx-tools: несущественный рефакторинг mdbx_chk. 2022-12-11 20:33:11 +03:00
Леонид Юрьев (Leonid Yuriev)
0884f28f85 mdbx-tools: ускорение работы mdbx_chk при обработке пользовательских записей в @MAIN. 2022-12-11 20:33:11 +03:00
Леонид Юрьев (Leonid Yuriev)
1c93cff825 mdbx: дополнительные условия для prefault-write. 2022-12-11 00:14:40 +03:00
Леонид Юрьев (Leonid Yuriev)
1ae6a398ed mdbx-windows: исправление утечки overlapped-дескриптора. 2022-12-10 14:44:15 +03:00
Леонид Юрьев (Leonid Yuriev)
cd0ed2f155 mdbx: обновление ChangeLog. 2022-12-10 01:20:27 +03:00
Леонид Юрьев (Leonid Yuriev)
4ee8fff305 mdbx: +1 к подготавливаемому резерву в вырожденных случаях перед обновлением GC. 2022-12-09 19:18:17 +03:00
Леонид Юрьев (Leonid Yuriev)
1bb41ee8fc mdbx: отключение "экономии последовательностей" посредством MDBX_ENABLE_SAVING_SEQUENCES=0. 2022-12-09 18:07:16 +03:00
Леонид Юрьев (Leonid Yuriev)
a572902fde mdbx: автоматическая установка rp_augment_limit в "золотое сечение" от размера БД. 2022-12-09 18:07:16 +03:00
Леонид Юрьев (Leonid Yuriev)
ebc4976acb mdbx: перенос обновления geo-размера в map_resize(). 2022-12-09 18:07:16 +03:00
Леонид Юрьев (Leonid Yuriev)
fd7aaf5f35 mdbx: добавление ошибки MDBX_BACKLOG_DEPLETED и соответствующей логики в page_alloc_slowpath(). 2022-12-09 18:07:16 +03:00
Леонид Юрьев (Leonid Yuriev)
4b27c4c7c9 mdbx: предварительное вычисление me_maxgc_per_branch. 2022-12-08 16:29:18 +03:00
Леонид Юрьев (Leonid Yuriev)
3a77af7d8a mdbx: оптимизация поддержки сортировки в dpl_append(). 2022-12-07 00:06:07 +03:00
Леонид Юрьев (Leonid Yuriev)
a9163f6307 mdbx: доработка внутренних LRU-отметок для аккуратного спиллинга огромных транзакций. 2022-12-07 00:06:07 +03:00
Леонид Юрьев (Leonid Yuriev)
48eeb93628 mdbx: исправление падения в env_close() при закрытии среды пере-открытой в режиме только-для-чтения.
Ошибка не была замечена ранее из-за много-ходового сценария воспроизведения:
 1. Создаём экземпляр MDBX_env посредством mdbx_env_create();
 2. Пытаемся открыть БД посредством mdbx_env_open() в режиме
    чтения-записи и эта попытка должны быть неудачной;
 3. Не освобождая экземпляр MDBX_env повторно открываем его в режиме
    только-чтение;
 4. Закрываем среду посредством mdbx_env_close().

Падение происходит на пункте 4, либо на пункте 3, если попытка
повторного открытия будет не успешной.

Причина в том, что внутренний экземпляр osal_ioring_t инициализировался
только для режимов чтения-записи, а разрушался всегда. При этом после
первого разрушения намеренно оставался в состоянии вызывающем падение
при использовании без инициализации.

[Simon Leier](https://t.me/leisim) сообщал об этой проблеме (теперь
понятно что это было), но из-за сложности сценария проблему не удалось
воспроизвести и идентифицировать.
2022-12-05 20:46:51 +03:00
Леонид Юрьев (Leonid Yuriev)
a772a9d3e1 mdbx: добавление проверки посредством mincore() с кэшированием присутствия страниц в памяти (опция сборки MDBX_ENABLE_MINCORE). 2022-12-05 10:41:05 +03:00
Леонид Юрьев (Leonid Yuriev)
be3ff92772 mdbx: предотвращение бесполезных page-faults в режиме MDBX_WRITEMAP (опция сборки MDBX_ENABLE_PREFAULT). 2022-12-05 10:03:00 +03:00
Леонид Юрьев (Leonid Yuriev)
dc27d5d30a mdbx: рефакторинг с формированием page_alloc_finalize() и сокрашением метрик MDBX_ENABLE_PROFGC. 2022-12-04 18:24:30 +03:00
Леонид Юрьев (Leonid Yuriev)
48a56d1d05 mdbx: запрещение разного MDBX_WRITEMAP между процессами в режимах с отложенной/ленивой записью.
Ранее упущенный не очевидный момент: При работе БД в режимах
не-синхронной/отложенной фиксации на диске, все процессы-писатели должны
иметь одинаковый режим MDBX_WRITEMAP.

В противном случае, сброс на диск следует выполнять дважды: сначала
msync(), затем fdatasync(). При этом msync() не обязан отрабатывать в
процессах без MDBX_WRITEMAP, так как файл в память отображен только для
чтения. Поэтому, в общем случае, различия по MDBX_WRITEMAP не позволяют
выполнить фиксацию данных на диск, после их изменения в другом процессе.

В режиме MDBX_UTTERLY_NOSYNC позволять совместную работу с MDBX_WRITEMAP
также не следует, поскольку никакой процесс (в том числе последний) не
может гарантированно сбросить данные на диск, а следовательно не должен
помечать какую-либо транзакцию как steady.

В результате, требуется либо запретить совместную работу процессам с
разным MDBX_WRITEMAP в режиме отложенной записи, либо отслеживать такое
смешивание и блокировать steady-пометки - что контрпродуктивно.
2022-12-04 18:10:54 +03:00
Леонид Юрьев (Leonid Yuriev)
db83bd34d2 mdbx-test: чтение актуальных флагов режима работы БД. 2022-12-04 18:10:50 +03:00
Леонид Юрьев (Leonid Yuriev)
23d236f70e mdbx: добавление MDBX_opt_writethrough_threshold и сопутствующие доработки. 2022-12-04 13:41:50 +03:00
Леонид Юрьев (Leonid Yuriev)
822952ef01 mdbx: внутреннее переименование MDBX_SYNC_KICK (косметика). 2022-12-04 13:41:50 +03:00
Леонид Юрьев (Leonid Yuriev)
9f2d30c1a9 mdbx: изменение размера отображения внутри env_sync() если это требуется для сброса данных на диск. 2022-12-04 13:41:32 +03:00
Леонид Юрьев (Leonid Yuriev)
163486fa3a mdbx: добавление FIXME для MDBX_NOMETASYNC. 2022-12-01 03:00:40 +03:00
Леонид Юрьев (Leonid Yuriev)
512e6dbd08 mdbx: отключение безусловного предпочтения записи через дескриптор с O_DSYNC.
Требуется переработка = динамический выбор между write(O_DSYNC) и write()+fdatasync(),
в зависимости от количества записываемых линейных фрагментов.
2022-12-01 02:59:28 +03:00
Леонид Юрьев (Leonid Yuriev)
2776480f18 mdbx: оптимизация pnl_merge() для случаев неперекрывающихся объединяемых списков. 2022-11-29 02:50:34 +03:00
Леонид Юрьев (Leonid Yuriev)
b7734369a2 mdbx: кавычки для предупреждения о дырявости RISC-V для совместимости. 2022-11-29 02:50:34 +03:00
Леонид Юрьев (Leonid Yuriev)
01a39e7dc2 mdbx: добавление и использование ptr_disp() и ptr_dist().
Для уменьшения кастинга типов указателей и потенциальной нагрузки оптимизатора/кодогенератора алиасингом.
2022-11-29 02:50:34 +03:00
Леонид Юрьев (Leonid Yuriev)
d6b9a71825 mdbx-test: добавление исключений Valgrind для измененного кода. 2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
9cee1ff799 mdbx: определение ior_WriteFile_flag для ясности кода. 2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
8c74de57ea mdbx: исправление txn_commit() для случаев конкурентных и/или неверных вызовов при MDBX_ENABLE_PROFGC=1. 2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
05804e2f30 mdbx: доработка/оптимизация page_retire_ex(). 2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
7685b4080e mdbx: исправление возврата и подсчета "грязных" страниц в режиме MDBX_WRITEMAP.
Исправление регрессии после коммита db72763de0.

После отключения затратой поддержки списка "грязных" страниц логика
page_retire_ex() оказалась не полной и требовала доработки. Из-за этого
страницы добавленные или клонированные-и-измененные в текущей
транзакции, которые становились не нужными, не возвращались к доступным
для немедленного использования, а помещались в retired-список
становящихся доступными в последующих транзакциях.

В результате, в некоторых сценариях, особенно с интенсивным расщеплением
страниц из-за вставки ключей, происходило необоснованно сильное
потребление/выделение страниц БД. В свою очередь, это приводило к
использованию излишнего кол-ва страниц, увеличению GC, росту RSS и
размеру БД.
2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
c521a21f05 mdbx: перемещение mp_next в заголовке страницы для отделения от mp_txnid. 2022-11-28 23:56:42 +03:00
Леонид Юрьев (Leonid Yuriev)
c5ddf12602 mdbx: увеличение лимита MDBX_TXL_MAX до 2^26. 2022-11-28 15:51:36 +03:00
Леонид Юрьев (Leonid Yuriev)
07674ada47 mdbx: доработка подготовки резерва перед обновлением GC при включенном BigFoot. 2022-11-28 15:51:36 +03:00
Леонид Юрьев (Leonid Yuriev)
3757eb72f7 mdbx: экономия последовательностей при выделении одиночных страниц. 2022-11-28 15:51:36 +03:00
Леонид Юрьев (Leonid Yuriev)
b324844296 mdbx: Обновление ChangeLog. 2022-11-28 15:45:29 +03:00
Леонид Юрьев (Leonid Yuriev)
30972102e5 mdbx: исправление сборки при MDBX_PNL_ASCENDING=1. 2022-11-25 19:03:05 +03:00
Леонид Юрьев (Leonid Yuriev)
61eafe80c1 mdbx: использование https://libmdbx.dqdkfa.ru/dead-github для удаленных issues. 2022-11-23 01:18:25 +03:00
Леонид Юрьев (Leonid Yuriev)
a1333fc827 mdbx: fix SIGSEGV/invalid-deref/invalid-free inside env_close() when mdbx_env_open() failed in re-open case.
Thanks to [@leisim](https://t.me/leisim) for [reporting](https://t.me/libmdbx/3946) this issue.
2022-11-23 00:57:02 +03:00
Леонид Юрьев (Leonid Yuriev)
da023657f5 mdbx: переработка внутренних флагов связанных с выделением страниц из GC. 2022-11-23 00:56:09 +03:00
Леонид Юрьев (Leonid Yuriev)
141cce0c0f mdbx: использование size_t для npages (косметика). 2022-11-23 00:56:09 +03:00
Леонид Юрьев (Leonid Yuriev)
12ed2bcfbd mdbx: использование единого курсора для поиска в GC. 2022-11-23 00:56:09 +03:00
Леонид Юрьев (Leonid Yuriev)
1f93dfe5fd mdbx: обновление ChangeLog. 2022-11-19 23:19:30 +03:00
Леонид Юрьев (Leonid Yuriev)
543e52730d mdbx: доработка поддержки авто-слияния записей GC внутри page_alloc_slowpath(). 2022-11-19 23:19:30 +03:00
Леонид Юрьев (Leonid Yuriev)
c46c03e7c8 mdbx: fix nasty typo/rebase/merge bug with calling msync() on Linux. 2022-11-19 23:19:30 +03:00
Леонид Юрьев (Leonid Yuriev)
4a257133cb mdbx: устранение несущественных предупреждений Coverity. 2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
f73cd7a491 mdbx: упрощение page_alloc_slowpath().
Упрощение за счет удаления проверки флага `MDBX_ALLOC_GC`,
который всегда взведен при вызове page_alloc_slowpath().
2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
3e05d1a427 mdbx: оптимизация page_copy() для LEAF2 и добавление параноидального контроля от переполнения. 2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
e518edcfed mdbx: унифицирование инициализации mp_txnid внутри page_dirty(). 2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
3563ed00e3 mdbx: использование не-спаренного курсора и gc_cursor_init() внутри update_gc(). 2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
0f92baaa5e mdbx: обновление debug_begin.h и debug_end.h 2022-11-19 19:36:30 +03:00
Jan Biedermann
eaf063ca9b mdbx: fix typo of || inside #if byte-order condition.
https://gitflic.ru/project/erthink/libmdbx/merge-request/4
2022-11-19 19:36:30 +03:00
Леонид Юрьев (Leonid Yuriev)
6c840cf58e mdbx: подсчет грязных страниц в режиме MDBX_WRITEMAP для статистики. 2022-11-19 19:36:30 +03:00
68 changed files with 5613 additions and 3441 deletions

View File

@@ -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.
##

View File

@@ -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.

View File

@@ -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.

View File

@@ -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)))

View File

@@ -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 Im 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
View File

@@ -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).

View File

@@ -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")

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -38,4 +38,4 @@ including creating [merge-request](https://gitflic.ru/project/erthink/libmdbx/me
---
\section MithrilDB MithrilDB
\section MithrilDB MithrilDB and Future

View File

@@ -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.

View File

@@ -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
View File

@@ -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++
View File

@@ -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) {

View File

@@ -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.
*

View File

@@ -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)

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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.
*

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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) {

View File

@@ -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.
*

View File

@@ -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

View File

@@ -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) {

View File

@@ -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",

View File

@@ -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) {

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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. */

View File

@@ -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()

View File

@@ -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 &params) {
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);

View File

@@ -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 */

View File

@@ -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.
*

View File

@@ -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;
}

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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 &params,
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);
}
}

View File

@@ -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.
*

View File

@@ -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 ':':

View File

@@ -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.
*

View File

@@ -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))

View File

@@ -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;

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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);
}

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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);

View File

@@ -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;

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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.
*

View File

@@ -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