Состоялся выпуск библиотеки libmdbx 0.12.3 (MDBX) с реализацией высокопроизводительной компактной встраиваемой базы данных класса ключ-значение. Код libmdbx распространяется под лицензией OpenLDAP Public License. Поддерживаются все актуальные операционные системы и архитектуры, а также российский Эльбрус 2000. Для libmdbx предлагается развитое C++ API, а также поддерживаемые энтузиастами привязки к языкам Rust, Haskell, Python, NodeJS, Ruby, Go, Nim, Deno, Scala.
Исторически libmdbx является глубокой переработкой СУБД LMDB и превосходит своего прародителя по надёжности, набору возможностей и производительности. В сравнении с LMDB, в libmdbx большое внимание уделяется качеству кода, стабильной работе API, тестированию и автоматическим проверкам. Поставляется утилита проверки целостности структуры БД с некоторыми возможностями восстановления. Технологически libmdbx предлагает ACID, строгую сериализацию изменений и неблокирующее чтение с линейным масштабированием по ядрам ЦПУ. Поддерживается автокомпактификация, автоматическое управление размером БД, оценка объёма выборок по диапазонам (range query estimation).
Основные новшества, доработки и исправления:
- Реализована prefault-запись при выделении страниц для read-write отображений. Это приводит к кратному снижению системных издержек и существенному увеличению производительности в соответствующих сценариях использования, когда: размер БД и объём данных существенно больше ОЗУ; используется режим MDBX_WRITEMAP; не-мелкие транзакции (по ходу транзакции выделяется многие сотни или тысячи страниц).
В режиме MDBX_WRITEMAP выделение/переиспользование страниц приводит к page-fault и чтению страницы с диска, даже если содержимое страницы не нужно (будет перезаписано). Это является следствием работы подсистемы виртуальной памяти, а штатный способ лечения через MADV_REMOVE работает не на всех ФС и обычно дороже получаемой экономии. В libmdbx теперь используется “упреждающая запись” таких страниц, которая на системах с unified page cache приводит к “вталкиванию” данных, устраняя необходимость чтения с диска при обращении к такой странице памяти. Новая функциональность работает в согласованности с автоматическим управлением read-ahead и кэшем статуса присутствия страниц в ОЗУ, посредством mincore().
- Добавлена опция MDBX_opt_prefault_write_enable для принудительного включения/выключения prefault-записи.
- Реализован динамический выбор между сквозной записью на диск и обычной записью с последующим вызовом fdatasync(), управляемый опцией 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-файлов с альтернативным именованием.
- Доработана поддержка авто-слияния записей GC внутри page_alloc_slowpath(). Задействован единый курсор для поиска в GC.
Переработаны внутренние флаги, связанные с выделением страниц из GC. Доработана подготовка резерва перед обновлением GC при включённом BigFoot. - Оптимизировано применение pnl_merge() для случаев неперекрывающихся объединяемых списков. Оптимизирована поддержка отсортированного списка страниц в dpl_append(). Ускорена работа mdbx_chk при обработке пользовательских записей в @MAIN.
- Выполнена переработка LRU-отметок для спиллинга.
- Переработан контроль “некогерентности” Unified page cache для уменьшения накладных расходов.