fpta: выпуск v0.3.18

Стабильный релиз с исправлением ошибок, мажорным обновлением libmdbx (опорного движка хранения) и изменением API функций связанных со справочником схемы.

Исправления и доработки в libfpta:
==================================

 - Устранена проблема зацикливания читающих транзакций в процессах переполняющих БД:

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

 - Изменение API для возможности использования `std::string_view` и `struct iovec`
   при получении и передачи имен элементов схемы:

    - Добавлены функции API принимающие имена объектов в `struct iovec`,
      что позволяет использовать `std::string_view`.
    - Изменен тип результата возвращаемого функциями API,
      связанными со справочником схемы и получения схемы БД в формате JSON.

 - Несущественные доработки юнит-тестов:

    - Исправление опечаток.
    - Установка affinity потоков для более быстрого воспроизведения целевых
      ситуаций и уменьшения внутренних итераций тестов,
      что существенно сокращает затрачиваемое время.
    - Устранены сбои при срабатывании таймаутов на максимальное время
      выполнения тестов, отдельных тестов.

  - Устранены несущественные предупреждения новых версий компиляторов и Coverity.

  - Мажорное обновление libmdbx с `0.11.13.0` на `0.12.6.6`.

Исправления и доработки в libmdbx:
==================================

Новое:
------

 - Реализована 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_warmup()` для "прогрева" БД с возможностью
   закрепления страниц в памяти.
   В утилиты `mdbx_chk`, `mdbx_copy` и `mdbx_dump` добавлены опции `-u` и `-U`
   для активации соответствующего функционала.

 - Отключение учета «грязных» страниц в не требующих этого режимах
   (`MDBX_WRITEMAP` при `MDBX_AVOID_MSYNC=0`). Доработка позволяет снизить
   накладные расходы и была запланирована давно, но откладывалась так как
   требовала других изменений.

 - Вытеснение из памяти (спиллинг) «грязных» страниц с учетом размера
   large/overflow-страниц. Доработка позволяет корректно соблюдать политику
   задаваемую опциями `MDBX_opt_txn_dp_limit`,
   `MDBX_opt_spill_max_denominator`, `MDBX_opt_spill_min_denominator` и
   была запланирована давно, но откладывалась так как требовала других
   изменений.

 - В API добавлены функции `mdbx_limits_valsize4page_max()` и
   `mdbx_env_get_valsize4page_max()` возвращающие максимальный размер в
   байтах значения, которое может быть размещена в одной
   large/overflow-странице, а не последовательности из двух или более таких
   страниц. Для таблиц с поддержкой дубликатов вынос значений на
   large/overflow-страницы не поддерживается, поэтому результат совпадает с
   `mdbx_limits_valsize_max()`.

 - В API добавлены функции `mdbx_limits_pairsize4page_max()`и
   `mdbx_env_get_pairsize4page_max()` возвращающие в байтах максимальный
   суммарный размер пары ключ-значение для их размещения на одной листовой
   страницы, без выноса значения на отдельную large/overflow-страницу. Для
   таблиц с поддержкой дубликатов вынос значений на large/overflow-страницы
   не поддерживается, поэтому результат определяет максимальный/допустимый
   суммарный размер пары ключ-значение.

 - Реализовано использование асинхронной (overlapped) записи в Windows,
   включая использования небуфферизированного ввода-вывода и `WriteGather()`.
   Это позволяет сократить накладные расходы и частично обойти проблемы
   Windows с низкой производительностью ввода-вывода, включая большие
   задержки `FlushFileBuffers()`. Новый код также обеспечивает консолидацию
   записываемых регионов на всех платформах, а на Windows использование
   событий (events) сведено к минимум, одновременно с автоматических
   использованием `WriteGather()`. Поэтому ожидается существенное снижение
   накладных расходов взаимодействия с ОС, а в Windows это ускорение, в
   некоторых сценариях, может быть кратным в сравнении с LMDB.

- Добавлена опция сборки `MDBX_AVOID_MSYNC`, которая определяет
   поведение libmdbx в режиме `MDBX_WRITE_MAP` (когда данные изменяются
   непосредственно в отображенных в ОЗУ страницах БД):

    * Если `MDBX_AVOID_MSYNC=0` (по умолчанию на всех системах кроме Windows),
      то (как прежде) сохранение данных выполняется посредством `msync()`,
      либо `FlushViewOfFile()` на Windows. На платформах с полноценной
      подсистемой виртуальной памяти и адекватным файловым вводом-выводом
      это обеспечивает минимум накладных расходов (один системный вызов)
      и максимальную производительность. Однако, на Windows приводит
      к значительной деградации, в том числе из-за того что после
      `FlushViewOfFile()` требуется также вызов `FlushFileBuffers()`
      с массой проблем и суеты внутри ядра ОС.

    * Если `MDBX_AVOID_MSYNC=1` (по умолчанию только на Windows), то
      сохранение данных выполняется явной записью в файл каждой измененной
      страницы БД. Это требует дополнительных накладных расходов, как
      на отслеживание измененных страниц (ведение списков "грязных"
      страниц), так и на системные вызовы для их записи.
      Кроме этого, с точки зрения подсистемы виртуальной памяти ядра ОС,
      страницы БД измененные в ОЗУ и явно записанные в файл, могут либо
      оставаться "грязными" и быть повторно записаны ядром ОС позже,
      либо требовать дополнительных накладных расходов для отслеживания
      PTE (Page Table Entries), их модификации и дополнительного копирования
      данных. Тем не менее, по имеющейся информации, на Windows такой путь
      записи данных в целом обеспечивает более высокую производительность.

 - Улучшение эвристики включения авто-слияния записей GC.

 - Изменение формата LCK и семантики некоторых внутренних полей. Версии
   libmdbx использующие разный формат не смогут работать с одной БД
   одновременно, а только поочередно (LCK-файл переписывается при открытии
   первым открывающим БД процессом).

 - В `C++` API добавлены методы фиксации транзакции с получением информации
   о задержках.

 - The `Big Foot` feature which significantly reduces GC overhead for processing large lists of retired pages from huge transactions.
   Now _libmdbx_ avoid creating large chunks of PNLs (page number lists) which required a long sequences of free pages, aka large/overflow pages.
   Thus avoiding searching, allocating and storing such sequences inside GC.
 - Improved hot/online validation and checking of database pages both for more robustness and performance.
 - New solid and fast method to latch meta-pages called `Troika`.
   The minimum of memory barriers, reads, comparisons and conditional transitions are used.
 - New `MDBX_VALIDATION` environment options to extra validation of DB structure and pages content for carefully/safe handling damaged or untrusted DB.
 - Accelerated ×16/×8/×4 by AVX512/AVX2/SSE2/Neon implementations of search page sequences.
 - Added the `gcrtime_seconds16dot16` counter to the "Page Operation Statistics" that accumulates time spent for GC searching and reclaiming.
 - Copy-with-compactification now clears/zeroes unused gaps inside database pages.
 - The `C` and `C++` APIs has been extended and/or refined to simplify using `wchar_t` pathnames.
   On Windows the `mdbx_env_openW()`, ``mdbx_env_get_pathW()`()`, `mdbx_env_copyW()`, `mdbx_env_open_for_recoveryW()` are available for now,
   but the `mdbx_env_get_path()` has been replaced in favor of `mdbx_env_get_pathW()`.
 - Added explicit error message for Buildroot's Microblaze toolchain maintainers.
 - Added `MDBX_MANAGE_BUILD_FLAGS` build options for CMake.
 - Speed-up internal `bsearch`/`lower_bound` implementation using branchless tactic, including workaround for CLANG x86 optimiser bug.
 - A lot internal refinement and micro-optimisations.
 - Internally counted volume of dirty pages (unused for now but for coming features).

Исправления:
------------

 - Поправлен экспорт из DSO/DLL устаревших функций,
   которые заменены на inline в текущем API.

 - Устранено использование неверного компаратора при создании или пересоздании
   `MainDB` с флагами/опциями предполагающим использование специфического
   компаратора (не по-умолчанию).

 - Добавлено ограничение размера отображения при коротком 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()`.
   Что в отладочных сборках могло приводить к ложным срабатываниям
   при восстановлении БД, в том числе при автоматическом откате слабых
   мета-страниц.

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

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

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

 - Добавление подсчета грязных страниц в `MDBX_WRITEMAP` для предоставления посредством `mdbx_txn_info()`
   актуальной информации об объеме изменений в процессе транзакций чтения-записи.

 - Never use modern `__cxa_thread_atexit()` on Apple's OSes.
 - Don't check owner for finished transactions.
 - Fixed typo in `MDBX_EINVAL` which breaks MingGW builds with CLANG.

   Более полная информация в [списке изменений libmdbx](https://gitflic.ru/project/erthink/libmdbx/blob?file=ChangeLog.md&branch=master).

51 files changed, 24173 insertions(+), 14452 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>

Этот тег не содержит заметок к релизу