Стабилизирующий выпуск с исправлением обнаруженных ошибок, устранением
недочетов и технических долгов. Ветка 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>
Никаких значимых изменений, только обход "странностей" в MSVC.
Как оказалось MSVC распространяет действие директивы
`pragma(warning(supppress:#))` строго на следующую строку, даже если эта
строка является продолжением комментария начатого в самой директиве
и/или не содержит синтаксических конструкций языка.
Поэтому большинство из добавленных ранее директив для подавления ложных
предупреждений, перестало работать после переформатирования исходного
кода.
В том числе для устранения проблемы
`error: inlining failed in call to ‘always_inline FOO(...)’: target specific option mismatch`
при сборке посредством GCC >10.x для SH4.
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.
В том числе, для устранения срабатывания assert-проверки
`size_bytes == env->me_dxb_mmap.current` в специфических многопоточных
сценариях использования.
Проверка срабатывала только в отладочных сборках, при специфическом
наложении во времени читающей и пишущей транзакции в разных потоках,
одновременно с изменением размера БД.
Кроме срабатывание проверки, каких-либо других последствий не возникало.
Цель в предотвращении ошибки ERROR_NOT_ENOUGH_MEMORY в Windows, которая
совсем не информативна для пользователя и возникает в этом случае (когда
файл открыт read-only и короче запрошенного размера).
Выпуск с существенными доработками и новой функциональностью в память о закрытом 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>