Improvements: что добавлено в libmdbx по сравнению с LMDB
Публичная редакция для амальгамированного пакета. Каталог доработок libmdbx над LMDB: возможности, расширения API, механизмы движка, исправления и оптимизации. Смежные:
architecture.ru.md,deep-dive.ru.md. Это попытка разложить по полочкам, чем именно libmdbx отличается от той базы, из которой выросла. История начиналась с форка, но довольно быстро перестала быть «LMDB с правками»: сегодня это самостоятельная кодовая база со своим характером. Ниже — её послужной список: что добавлено, что переделано, что вылечено и что ускорено, вплоть до того, как именно движок ищет свободные страницы (спойлер: там векторные инструкции).Точность здесь важнее краткости, но и краткость важна: у пунктов указаны версии, начиная с которых изменение стало заметным, — как ориентиры, а не как строгая историческая граница.
1. Сводная карта
| Категория | Краткая суть | Ключевые пункты |
|---|---|---|
| A. Надёжность | Устранены дефекты, до сих пор живущие в LMDB | §2 |
| B. Модель данных и формат | Длиннее ключи, нулевая длина, формат независим от разрядности | §3 |
| C. Транзакции и конкурентность | Парковка/вытеснение, клонирование, fork, HSR | §4 |
| D. GC и размер БД | Big Foot, LIFO/FIFO, авто-компактификация, дефрагментация | §5 |
| E. Долговечность | SAFE_NOSYNC, steady-точки, троика мета, восстановление | §6 |
| F. Движок B+tree | Умные split, merge-тактика, мультизначения, оценки | §7 |
| G. C API | Расширенные операции, информация, опции, кэш | §8 |
| H. C++ API | Полный типобезопасный слой | §9 |
| I. Утилиты и диагностика | chk/defrag/copy/dump, статистика, UUID | §10 |
| J. Оптимизации | SIMD, branchless, prefault, спилл, сортировки | §11 |
| K. Переносимость | Платформы, блокировки, TLS, endianness | §12 |
| L. Сборка/дистрибуция | Amalgamation, CMake/Make, LTO, лицензия, Conan | §13 |
| M. Экосистема | Сотни проектов, биндинги, награды, MithrilDB | §14 |
Хронологическая таблица по версиям — §15.
2. Надёжность: устранённые дефекты, унаследованные от LMDB
Значительная часть изменений — это исправление дефектов, которые в LMDB живут годами и десятилетиями и воспроизводятся только в определённых сочетаниях условий, что делает их особенно коварными. Ниже перечислены те из них, которые удалось идентифицировать и закрыть.
Известные и публично зафиксированные:
- Утечки страниц БД и ошибочная статистика таблиц. Последствия двоякие: теряется пространство файла (страницы выпадают из оборота), а метрики роста становятся недостоверными — приложение видит «раздувание» базы, которого на самом деле нет.
- Segfault'ы в нескольких условиях: повреждённые базы, крайние случаи позиционирования
курсоров, использование хендла таблицы
0в читающей транзакции, обход деревьев после частичной порчи. Устранение сводится к строгим проверкам на границах данных. - Неоптимальная стратегия слияния страниц при удалении. LMDB при опустошении листа всегда сливала его с наименее заполненным соседом; исправлено на тактику «предпочесть уже изменённую (грязную) страницу» — подробнее в §5.5/§7. Выигрыш — до 50% на массовых удалениях.
- Обновление существующей записи с изменением размера данных (в том числе в multimap). В определённых случаях LMDB может молча терять данные при больших значениях; в libmdbx этот путь переработан так, чтобы либо корректно переразместить значение, либо вернуть ошибку.
- Повреждение БД в режиме
DUPFIXEDпри длинных или нечётных мультизначениях (LEAF2-страницы). Причина — резервирование места без учёта возможного переполнения страницы. Ошибка присутствовала в LMDB более 11 лет и была унаследована; в libmdbx исправлена (0.12.10). - «Реинкарнация» удалённой под-БД и неявное удаление таблиц через операции над
@MAIN. Раньше удалённая таблица могла «оживать» в новой транзакции; теперь жизненный цикл таблицы отслеживается явно. - Гонки при открытии DBI-хендлов и при старте транзакции параллельно с созданием дескриптора таблицы. Устраняются синхронизацией импорта хендлов в транзакцию.
- Циклирование обновления GC при коммите (расходимость, когда повторная обработка не сходится к стабильному состоянию). Устранено корректирующей обратной связью в цикле обновления.
- Ложное
MDBX_CORRUPTEDпри невыровненном доступе к 64-битным полям — в том числе на ARM и после#pragma pack; закрыто аккуратными работами с выравниванием. - Ошибки копирования БД на NFS/CIFS/SMB (конфликт
fcntl/flock,EAGAIN/EWOULDBLOCK): функция копирования теперь корректно работает с сетевыми ФС. - Потеря содержимого таблицы при abort вложенной транзакции, в которой таблица была удалена (0.14.x): состояние таблицы теперь восстанавливается вместе с остальными данными.
- Некорректное закрытие DBI-дескриптора изменённой таблицы: могло создавать таблицу с пустым именем, терять страницы или портить ссылку на корень дерева; теперь возвращается ошибка.
- «Воскрешение» закрытых курсоров вложенных транзакций: приводило к утечкам памяти и использованию-после-освобождения; жизненный цикл курсоров отслеживается жёстче.
Системные гарантии надёжности:
- Целостность при асинхронной неупорядоченной записи (
SAFE_NOSYNC). В отличие отMDB_NOSYNC, база не разрушается при системном сбое: выполняется откат к последнему steady-коммиту. Для поведения, в точности совпадающего с LMDB, предусмотрен отдельный режимMDBX_UTTERLY_NOSYNC— выбор делается явно. - Контроль по
boot_idпри принятии решения об откате слабых мета-страниц — в том числе при работе внутри LXC-контейнера. - Защита от некогерентности unified page/buffer cache (Linux, issue #269): полный workaround, внесённый в сериях 0.11.5–0.11.6.
- Проверка согласованности файловых систем. Для неподходящих ФС библиотека либо отказывает с явной ошибкой, либо предупреждает; эксклюзивный режим на сетевых шарингах разрешён, кооперативный read-only — тоже.
- Чистка «зависших» читателей при открытии и перед ростом БД, а также авто-очистка «зависших» писателей (признак устаревшей регистрации).
MDBX_EMULTIVALпри неоднозначном обновлении/удалении. Вместо тихого (и потому опасного) поведения возвращается явная ошибка «несколько значений».- Защита от двойного открытия одной БД в пределах процесса: отслеживание и восстановление
POSIX-блокировок после
fork; для совместимости со старым поведением предусмотрен legacy-режим. - Возврат
ENOLCKна WSL1, где работа невозможна в принципе: явный отказ предпочтительнее молчаливого повреждения данных.
3. Модель данных и формат
- Ключи более чем в два раза длиннее, чем в LMDB: до ~½ страницы (2022 байта при странице
4 КБ, 32742 при 64 КБ) против 511 байт. Лимиты вынесены в API (
mdbx_limits_*,mdbx_env_get_maxkeysize()и др.). Практический эффект — для многих схем отпадает необходимость хешировать длинные ключи или вводить отдельные таблицы-справочники. - Нулевая длина ключей и значений. У LMDB ключ обязан быть ненулевой длины. Возможность хранить «пустые» сущности упрощает представление бинарных протоколов и разреженных структур.
- Формат БД одинаков для 32- и 64-битных сборок — зависит только от endianness платформы. Файл, созданный на 64-битной машине, открывается на 32-битной и наоборот; это существенно для переноса баз между средами.
- Мультизначения. Поддерживаются три формы хранения: плотные dupfix-страницы фиксированной
длины, вложенные деревья и суб-страницы; выбор делается автоматически по числу и размеру
значений. Лимиты и глубина вложенности доступны через API (
dupsort_depthmask,count_ex). - Последовательности (sequences) и три персистентных 64-битных маркера (vector-clock) — штатный инструмент для генерации монотонных номеров и меток вида «кто и когда менял данные».
- UUID базы в поле
mi_dxbid: позволяет отличать разные копии одной базы, а не только проверять совпадение сигнатуры формата. - Внутренние размеры узлов уточнены: в ряде случаев меньше overflow-страниц и выше лимиты ключей для одного и того же размера страницы.
- Непечатные и пустые имена таблиц обрабатываются корректно (вплоть до бинарных имён).
- Номер последней модифицирующей транзакции для каждой таблицы (per-subDB last-update txnid) — основа для дельта-синхронизации и репликационных схем поверх базы.
Почему это важно. Модель данных — это контракт: его нельзя «подклеить» поверх готовой базы. Удлинение ключей, поддержка нулевой длины и единый 32/64-битный формат меняют не отдельные функции, а сам допустимый набор данных и совместимость файлов. Поэтому эти пункты вынесены отдельно от мелочей API: это фундамент, на котором строятся остальные доработки.
4. Транзакции и конкурентность
- Парковка читающих транзакций (
mdbx_txn_park/unpark) с флагамиPARKED/AUTOUNPARK/OUSTEDи авто-перезапуском вытесненных (restart_if_ousted). Припаркованная транзакция освобождает слот читателя: её снапшот перестаёт удерживать переиспользование страниц, а при возобновлении транзакция продолжает работу с того же места. - Вытеснение (ousting) припаркованных читателей. Если писателю не хватает пространства, он
атомарно переводит слот из состояния
PARKEDвOUSTED; читатель при следующем обращении либо перезапускается на свежем снапшоте, либо получает явный код результата. - Handle-Slow-Readers (HSR) — колбэк для разрешения переполнения, вызванного долгими
читателями (развитие старого
mdbx_env_set_oomfunc). Вместе с парковкой образует законченный инструментарий работы с «застрявшими» снапшотами. - Клонирование читающих транзакций (
mdbx_txn_clone): несколько позиций на одном снапшоте. mdbx_env_resurrect_after_fork()— безопасное переоткрытие окружения в дочернем процессе послеfork(), без полного закрытия и повторного открытия.- Вложенные транзакции радикально переработаны: быстрый путь для «чистой» вложенной транзакции, ленивое затенение курсоров, корректная судьба созданных и удалённых таблиц, поддержка в C++ API.
- Вложенные read-only транзакции и «фейковые» read-only — для единообразия API.
- Расширенный набор операций над транзакцией:
mdbx_txn_refresh(),mdbx_txn_checkpoint()(коммит без снятия блокировки),mdbx_txn_commit_embark_read()(коммит, сразу переходящий в читающую транзакцию),mdbx_txn_amend()(запись на основе читательского снапшота),mdbx_txn_rollback()(abort + restart без потери блокировки). mdbx_txn_break()— явная пометка транзакции как повреждённой.- NOSTICKYTHREADS вместо LMDB'шного
MDBX_NOTLS. Транзакцию можно передавать между потоками; нарушение дисциплины детектируется и возвращается явными кодами (MDBX_THREAD_MISMATCH,MDBX_TXN_OVERLAPPING,MDBX_BAD_RSLOT,MDBX_BUSY). Это важно для корутин и пулов потоков, где «прилипание» транзакции к одному потоку неприемлемо. - Явная регистрация/дерегистрация потоков-читателей (
mdbx_thread_register/unregister). - Управление основной блокировкой lock/unlock/upgrade/downgrade для сложных сценариев координации писателей.
- Дисциплина курсоров: все курсоры можно переиспользовать и требуется закрывать явно —
это устраняет целый класс use-after-free и двойных освобождений. Соответствующие операции:
mdbx_cursor_create/bind/unbind,mdbx_txn_release_all_cursors[_ex]. - Позиционирование курсоров операциями
<,<=,==,>=,>(в том числе для пар ключ-значение);MDBX_SET_LOWERBOUND,MDBX_SET_UPPERBOUND,mdbx_cursor_compare(аналог оператора<=>),mdbx_cursor_scan[_from],on_first_dup/on_last_dup. - Курсоры на одну таблицу в разных read-транзакциях допустимы (multi-cursor API).
mdbx_preopen_snapinfo()— получение информации о базе без её открытия.
Общий замысел. LMDB трактует транзакцию как короткий отрезок работы в одном потоке;
libmdbx — как объект с собственным жизненным циклом. Отсюда набор операций: транзакцию можно
приостановить (парковка), размножить (clone), перенести в другой поток (NOSTICKYTHREADS),
пережить fork() и превратить read-в-write на лету. Каждый режим покрывает конкретный паттерн
реальных приложений.
5. Переиспользование страниц (GC), рост и размер БД
- Big Foot (0.12.1) — разбиение больших списков retired-страниц на цепочки записей GC. Устраняет требование искать и выделять длинные последовательности свободных страниц для хранения самих списков; критично для транзакций, утилизирующих миллионы страниц (например, в нагрузках Ethereum-экосистемы).
- Early GC Cleanup (0.14.x) — утилизированные записи GC удаляются как можно раньше, а не только на коммите; открывает путь к дефрагментации и нелинейной переработке GC.
- LIFO-политика переиспользования (
MDBX_LIFORECLAIM) при FIFO по умолчанию. LIFO берёт самые свежие освобождения: страница циркулирует по минимально короткому кругу и не успевает выпасть из дискового write-back кэша. На системах с таким кэшем заметно растёт скорость записи. - Автоматическая подстройка размера БД на лету — рост и сокращение — через параметры
геометрии
lower/now/upper/growth_step/shrink_threshold. - Непрерывная компактификация с нулевыми накладными расходами: возврат свободного хвоста в
неразмеченное пространство (refund) на каждом коммите + усечение файла при накоплении
(implicit shrink,
stockpile_gap,madvise(MADV_DONTNEED/REMOVE)). Работа идёт попутно с обычными коммитами, без отдельного прохода. - Явная дефрагментация (
mdbx_env_defrag, утилитаmdbx_defrag) с контролем целей, времени и допустимой «отдачи» (backlash). - Динамические лимиты:
rp_augment_limit(авто-подстройка от размера БД),gc_time_limit(лимит времени поиска последовательностей), лимиты грязных страниц (txn_dp_limit— авто от объёма ОЗУ) и спилл-деноминаторы. - Авто-слияние записей GC и оптимизированный
pnl_merge; профилирование работы GC (MDBX_ENABLE_PROFGC). - Диагностика GC:
mdbx_gc_info()(состояние, гистограммы, итерация записей) и счётчикgcrtime— время, потраченное на поиск и переработку. - Refund/loose-страницы: возврат освобождённых страниц внутри текущей транзакции без
обращения к GC (опции
MDBX_ENABLE_REFUND,MDBX_opt_loose_limit,dp_reserve_limit). - RKL — отслеживание идентификаторов записей GC (интервалы + списки) с «резервированием со взвешенным запасом»: одно-проходное обновление GC с оценкой сложности от O(1) до O(log N).
- Разреженные и lock-free наборы DBI-хендлов (
MDBX_ENABLE_DBI_SPARSE,MDBX_ENABLE_DBI_LOCKFREE) — снижение накладных расходов при большом числе таблиц. - Счётчики пространства в
mdbx_txn_info: dirty/leftover/retired/limit для читающих и пишущих транзакций — рабочий инструмент диагностики влияния «долгих читателей».
Как это складывается в систему. GC в libmdbx — не сборщик мусора в классическом смысле,
а постоянный учёт свободных страниц внутри самого файла. Поэтому важны не отдельные механизмы,
а их связка: политика FIFO/LIFO выбирает порядок записей GC по txnid (какие освобождения вернуть
в первую очередь); refund возвращает хвост без
записи в GC; Big Foot упаковывает гигантские списки освобождений; лимиты (rp_augment_limit,
gc_time_limit) не дают поиску свободного места съесть весь коммит. В сумме это делает
переработку свободного списка при огромных транзакциях предсказуемым и настраиваемым процессом.
6. Долговечность и синхронизация
- Три мета-страницы + метод фиксации «Troika» (0.12.1). Два устойчивых снапшота плюс хвостовой слот для перезаписи; двухфазное обновление с минимумом барьеров памяти, сравнений и условных переходов. У LMDB мета-страниц две, и их обновление — источник тонких гонок.
- Явные режимы синхронизации:
MDBX_SYNC_DURABLE,MDBX_NOMETASYNC,MDBX_SAFE_NOSYNC(переименованиеMDBX_NOSYNC),MDBX_UTTERLY_NOSYNC;MDBX_MAPASYNCобъявлен устаревшим. Названия режимов отражают степень риска — это снижает вероятность случайного выбора «недолговечного» режима. - Steady и weak мета-страницы. Понятие устойчивой точки формализовано; при нехватке пространства библиотека автоматически формирует новый steady-point.
- Автоматическая синхронизация по порогам и/или таймауту с дешёвым polling:
mdbx_env_set_syncbytes/syncperiod,MDBX_opt_sync_bytes/period,presync_threshold, асинхронныеmdbx_env_sync[_ex|_poll]с предварительной проверкой и повторной попыткой. - Динамический выбор способа записи (
MDBX_opt_writethrough_threshold): сквозная запись (O_DSYNC) против записи с последующимfdatasync()— в зависимости от числа страниц и задержки канала хранения. - Prefault-запись (
MDBX_opt_prefault_write_enable) — упреждающая запись страниц, выделенных дляWRITEMAP, чтобы устранить page-fault'ы и чтения с диска при первом обращении. - Восстановление без WAL: выбор последней цельной мета-страницы, режим
open_for_recoveryи переключение на заданную мета-страницу; начиная с 0.12.7 recovery-проверки не изменяют базу. - Диагностические коды
MDBX_WANNA_RECOVERY/MDBX_MVCC_RETARDED. - Контроль некогерентности unified page cache (см. §2).
- На macOS/iOS используется
fcntl(F_FULLFSYNC)по умолчанию — единственный способ гарантировать долговечность при сбое питания; опцияMDBX_APPLE_SPEED_INSTEADOF_DURABILITYпозволяет пожертвовать долговечностью ради скорости.
Наблюдение. Долговечность — область, где подход отличается сильнее всего. Режимы синхронизации названы так, чтобы из названия была понятна цена вопроса (SAFE/UTTERLY), steady-точка формализована, а восстановление после сбоя сведено к воспроизводимой процедуре: выбрать последнюю цельную мета-страницу, при необходимости аккуратно переключить тройку под эксклюзивной блокировкой.
7. Движок B+tree и страницы
- Split с «auto-appending» (0.10.0) — при вставке упорядоченных последовательностей ключей страницы заполняются плотнее; split «по середине» — дерево остаётся сбалансированным в среднем, а не «перекошенным» в сторону вставок.
- Тактика слияния при удалении. При опустошении листа слияние выполняется преимущественно
с уже изменённой (грязной) страницей; если статусы одинаковы — с наименее заполненной.
Снижает WAF, до 50% выигрыша на массовых удалениях. Управляется
prefer_waf_insteadof_balanceиmerge_threshold(с 0.14.x по умолчанию 33%). - Прозрачный спилл (0.10.0) — грязные страницы переводятся в состояние «готовы к выгрузке»
без последующих изменений; LRU-политика с приоритетом для overflow-страниц; спилл учитывает
размер large/overflow-страниц;
MDBX_TXN_NIPPEDпозволяет приостановить спилл при обработке GC. - Массовые операции. Удаление «гроздьями» (
mdbx_cursor_bunch_delete,delete_range) вырезает целые страницы и ветви вместо поштучного удаления; пакетное чтение (mdbx_cursor_get_batch); пакетная работа с мультизначениями (MDBX_GET/PUT_MULTIPLE,SEEK_AND_GET_MULTIPLE, put/seek samelength, batch put). - Оценка объёма диапазонных запросов (
mdbx_estimate_range/distance/move,MDBX_EPSILON): оценка по общим страницам стеков курсоров, без сканирования данных. - Проверка страниц «на лету»: улучшенная онлайн-валидация; опция
MDBX_VALIDATIONдля работы с повреждёнными или недоверенными базами; обнаружение повреждений по полюparent-page-txnid. - Параметры плотности:
MDBX_opt_subpage_*(лимит суб-страниц и резерв) иsplit_reserve. - Трекинг курсоров в пишущих транзакциях (repoint/shadow) и
mdbx_is_dirty()для того, чтобы не копировать данные с грязных страниц. - Минимизация чтения листовых страниц при удалении таблиц и вложенных деревьев.
Наблюдение. B+tree — простая структура, но вся разница в деталях перестроек. Auto-appending split позволяет писать упорядоченные последовательности почти без потери места; слияние с грязным соседом экономит записываемые страницы (WAF); bunch-delete вырезает поддеревья вместо поштучного стирания; оценка диапазонов избавляет от сканирования. По отдельности каждый пункт — мелочь, вместе они дают заметную разницу в бенчмарках и в реальных нагрузках.
8. C API: расширения
- Единый API опций
mdbx_env_set_option/get_optionс наборомMDBX_opt_*:max_db,max_readers,sync_bytes,sync_period,rp_augment_limit,loose_limit,dp_reserve_limit,txn_dp_limit,txn_dp_initial,spill_max_denominator,spill_min_denominator,spill_parent4child_denominator,merge_threshold,prefer_waf_insteadof_balance,writethrough_threshold,prefault_write_enable,gc_time_limit,split_reserve,subpage_limit,subpage_room_threshold,subpage_reserve_prereq,subpage_reserve_limit,presync_threshold. - Расширенные CRUD: put с получением предыдущего значения; обновление/удаление конкретного
мультизначения;
MDBX_UPSERT,MDBX_ALLDUPS,MDBX_APPEND/DUP,MDBX_NOOVERWRITE; upsert всех дубликатов;reserve;empty-dataвMDBX_MULTIPLE. - «get-cached»:
mdbx_cache_get[_SingleThreaded]— ленивый поиск по версионным меткам страниц со статусами HIT/CONFIRMED/REFRESHED/DIRTY/BEHIND/UNABLE/RACE; разделяемый lock-free. Повторное чтение «горячего» ключа превращается из полного спуска по дереву в пару сравнений. - Геометрия и лимиты:
mdbx_env_set_geometry,mdbx_limits_*(keysize/valsize/pairsize...4page_max, минимальные границы),mdbx_default_pagesize,mdbx_get_sysraminfo. - Информация:
mdbx_env_info_ex(геометрия, меты, meta[3], UUID, статистика операций со страницами),mdbx_txn_info(включаяscan_rlt),mdbx_dbi_flags_ex(состояние DIRTY/STALE/FRESH/CREAT),mdbx_enumerate_tables,mdbx_cursor_count_ex. - Транзакции: весь набор из §4;
mdbx_txn_commit_exс метриками задержек;mdbx_txn_copy2pathname/fd(копия из транзакции). - Таблицы:
mdbx_dbi_rename[_2],mdbx_dbi_sequence, маркерыmdbx_canary_*, APImdbx_drop, отложенная инвалидация хендлов удалённых таблиц (0.14.3+),MDBX_DB_ACCEDE. - Окружение:
mdbx_env_delete(мультипроцессное удаление),mdbx_env_warmup,mdbx_env_chk(проверка изнутри библиотеки),mdbx_env_defrag,mdbx_env_sync_poll, режимы exclusive/read-only/без-LCK,mdbx_env_get_path[_W],mdbx_set_panic, пользовательский контекст для транзакций и курсоров. - Преобразования ключей: value-to-key для чисел (int32/int64, float/double, JSON-integer),
mdbx_key_from_*— рекомендуется вместо кастомных компараторов, чтобы базу можно было проверять штатнымmdbx_chk. - Логирование: callback без
vprintf(удобно для привязок к другим языкам),mdbx_assert_failв публичном API, настройка уровня через переменные окружения, уровниMDBX_LOG_DEBUG/TRACEдля ошибок API. - Диагностика времени выполнения:
mdbx_get_sysraminfo, page-op статистика черезmdbx_env_info_ex,MDBX_ENABLE_PGET_STAT(счётчик обращений к страницам).
Наблюдение. Практически каждый внутренний механизм имеет либо настройку (MDBX_opt_*),
либо измеритель (txn_info, page-op счётчики, gc_info), либо и то и другое. Это сознательная
цена (интерфейс больше), но именно она позволяет диагностировать долгие читатели, WAF и churn
GC, не вскрывая исходники.
9. C++ API
- Полный типобезопасный RAII-слой:
env/env_managed,txn/txn_managed,cursor/cursor_managed,map_handle,slice/buffer<>(полиморфные аллокаторы C++17, политики владения,inplace_storage_size_rounding). - Иерархия исключений, сопоставленная кодам C API;
make_broken(); конвенции[[nodiscard]]; C++20 concepts при наличии. - Типизированные map-операции,
mdbx::pair, трансляция ключей/значений (включая value2key). - Кодировщики: hex/base58/base64 (высокопроизводительный base58 по черновику RFC),
is_printable, проверки UTF-8, безопасные middle/резервирование. mdbx::comparator,default_comparator,estimate_result,extra_runtime_option, геометрия с fluent-сеттерами, метрики задержек коммита.- Вложенные пишущие транзакции, buffer append/reserve,
get_/set_context, move/copy assignment для управляемых классов,withdraw_handle. - Явная инстанциация шаблонов внутри библиотеки — быстрее сборка потребителей.
10. Утилиты и диагностика
mdbx_chk: глубокая проверка (мета/троика, деревья, порядок ключей, GC, scopes, гистограммы заполнения страниц и мультизначений), проверка по указанной мета-странице, переключение мета-страниц, опции-u/-U(warmup), уровень подробности, «выживание» при повреждённых деревьях (обходит испорченные ветки вместо падения).mdbx_copy: горячее резервное копирование (в том числе в pipe), copy-with-compaction (обнуление неиспользуемых промежутков), опции-d/-p/-f, overwrite.mdbx_defrag: явная дефрагментация с целями и лимитами.mdbx_dump/mdbx_load: полная поддержка атрибутов, компактный режим-c(однократные ключи), purge-p, batch-insert-b, лимиты-L, плотность-d, геометрия-G.mdbx_drop,mdbx_stat(включая-p— page-op статистику и все счётчики),mdbx_test(стохастические сценарии,--geometry-jitter,--numa,--pagesize,--loglevel),stochastic.sh,battery-tmux.sh.- Версия/сборка:
VERSION.json,SOURCE_DATE_EPOCH,MDBX_BUILD_TIMESTAMP,MDBX_BUILD_METADATA, выводoptions:для совместимости хоста/контейнеров.
11. Оптимизации производительности
11.1. Микрооптимизации движка
- SIMD-поиск последовательностей свободных страниц: ядра
scan4seq_*для SSE2/NEON/AVX2/AVX512 — ускорение ×4/×8/×16 (0.12.1); выбор ядра на этапе выполнения (scan4seq_resolver), поэтому одна сборка работает и на старом x86, и на современном AVX-512 сервере; NEON починен для ARM64-Windows. - Branchless бинарный поиск (bsearch/lower_bound на CMOV) с обходом бага CLANG для x86; позднее — встраивание кода встроенных/дефолтных компараторов (0.14.2): поиск по числовым ключам сводится к последовательности безусловных инструкций.
- Сортировки: адаптивная бинпоиск-сортировка, radix-sort (LSB-first, 2×16-бит цифры),
сортировочные сети для n=3..8, branch-free compare-swap; быстрые сортировки списков страниц
(PNL/DPL); порог переключения radix (
MDBX_RADIXSORT_THRESHOLD). - Лениво-сортируемый список грязных страниц (DPL) с сортировкой по требованию;
оптимизированный
dpl_append. - C11-атомики для слабых моделей памяти (ARM/AArch64/PPC/MIPS/RISC-V): acquire/release, CAS, протокол safe64 для чтения 64-битных значений; проверка атомарности на этапе сборки.
- Рациональная разметка ветвлений и функций:
pure/const,__cold/__hot,__always_inline,likely/unlikely(в исходниках — тысячи расставленных подсказок). __builtin_cpu_supportsдля диспетчеризации SIMD (MDBX_HAVE_BUILTIN_CPU_SUPPORTS).- Минимизация системных вызовов: отказ от
pwritevдля одиночных записей, объединение регионов записи, избегание лишнихmsync, отказ отcopy_file_rangeна дефектных ядрах,fallocateпротив SIGBUS,fcntl64для блокировок. - Prefault-запись и mincore-отслеживание резидентности страниц для предотвращения
page-fault'ов в
WRITEMAP. - Отсутствие операций с плавающей точкой и зависимости от
libm(0.14.x); 16.16 fixed-point представление для времени и порогов. - Атрибуты TLS (
tls_model("local-dynamic")) и аккуратная работа с деструкторами TLS. -fno-semantic-interposition— снижение накладных расходов на вызовы собственных функций.
Наблюдение. Разница в производительности складывается из сотен мелких правок: часть операций быстрого пути переведена на CMOV, сортировка списков страниц ускорена ради того, чтобы спилл не простаивал, а SIMD-ядра поиска последовательностей дают ×4–×16 на конкретной операции. По отдельности каждая правка незначительна, совокупность обеспечивает заявленный выигрыш в CRUD-бенчмарках.
11.2. Алгоритмические улучшения
- Прозрачный спилл + LRU (см. §7), refund/loose, авто-слияние записей GC, одно-проходное обновление GC через RKL (см. §5).
- Ускорение обновления GC для огромных транзакций (сценарии Ethereum/Erigon) — 0.11.3.
- Auto-appending split и «split по середине»; слияние с грязным соседом (см. §7).
- Динамические эвристики: авто-подстройка
dp_limitот объёма ОЗУ,rp_augment_limitот размера БД, автоподбор размера страницы и геометрии по умолчанию.
11.3. Синхронизация/параллелизм
- Wait-free читатели без атомик на пути чтения; lock-free сканирование таблицы читателей; кэширование старейшего читателя.
- OFD-блокировки (с fallback на POSIX
fcntl64), таймаутные ожидания, SysV/semaphore варианты, режим без LCK-файла. - Файловые блокировки на Windows — осознанный выбор вместо именованных мьютексов LMDB. Причины и следствия:
LockFileEx()позволяет размещать базу на сетевых дисках (именованные мьютексы — локальная сущность и для сетевых шарингов бесполезны);- файловые блокировки дают защиту от некомпетентных действий пользователя (совместно с эксклюзивным режимом открытия) — защита от класса ошибок, приводящих к повреждению БД;
- цена — производительность: в ядре Windows файловые блокировки реализованы плохо, поэтому в наивных бенчмарках с множеством мелких транзакций libmdbx может отставать от LMDB (об этом прямо сказано в FAQ проекта и ChangeLog 0.12.3);
- это сознательный компромисс «надёжность и переносимость против скорости».
- Overlapped/async запись на Windows (
WriteGather, небуферизованный I/O) — сокращение накладных расходов на взаимодействие с ОС.
12. Переносимость и платформы
- Платформы: Linux, Windows, macOS/iOS, Android, Harmony OS, Haiku, FreeBSD, NetBSD, OpenBSD, DragonFly, Solaris/OpenIndiana/OpenSolaris, Plan 9/9P (эксклюзивный режим), WSL2 (и корректный отказ на WSL1); инструментальные цепочки — GNU Make + CMake + MinGW + MSVC + CLANG + GCC + Elbrus/LCC.
- Слабые модели памяти (см. §11.1); big-endian и нестандартные размеры страницы; большие БД (>4 ГБ) из 32-битного кода.
- Обработка специфики ОС: workaround'ы для Wine, DrvFs, NFS/CIFS/SMB, CDROM,
F_FULLFSYNC,GetExitCodeThread,boot_idна Windows и в LXC. - Защита от повторного использования pid/tid; проверки живости читателей; безопасный
fork.
Наблюдение. Переносимость здесь означает не «скомпилировалось на N платформ», а «корректно работает при разных моделях памяти, endianness и экзотических ОС». Слабые модели памяти требуют аккуратных атомик; big-endian — симметричного формата страниц; 32-битные платформы — работы с большими файлами через mmap-окна.
13. Сборка, дистрибуция, лицензия
- Amalgamated single-file дистрибутив (по образцу SQLite) с отрезаемыми dev-маркерами;
make dist, пакеты, Conan-рецепт. - CMake (в том числе как подпроект), GNU Make, широкий набор build-опций
(
MDBX_WITHOUT_MSVC_CRT,MDBX_CHECKING,MDBX_VALIDATION,MDBX_ENABLE_*,MDBX_AVOID_MSYNC,MDBX_BUILD_TOOLS,MDBX_USE_OFDLOCKS). - Поддержка LTO (Link-Time Optimization) — отдельная подсистема сборки:
- в CMake доступность LTO определяется автоматически для GCC, CLANG и MSVC
(
GCC_LTO_AVAILABLE/CLANG_LTO_AVAILABLE/MSVC_LTO_AVAILABLE) с проверкой версий (GCC ≥ 7, CLANG ≥ 5, MSVC ≥ 19); - включается стандартной опцией
INTERPROCEDURAL_OPTIMIZATION; - для корректной сборки подбираются
ar/nm/ranlibс LTO-plugin (илиlld/ldдля CLANG) — нетривиальная часть скриптов; - в GNU Make предусмотрены отдельные цели
.static-ltoдля сборки утилит с-flto; - история правок отражает особенности интеграции: поиск GCC-инструментов для LTO,
детектирование CLANG-LTO для Android, подавление ложных предупреждений
-Wno-lto-type-mismatchдля старых GCC при LTO-сборках. - Воспроизводимые сборки (
SOURCE_DATE_EPOCH/MDBX_BUILD_TIMESTAMP), поддержка ASAN/UBSAN/MSAN (Valgrind/ASAN),ctest, проверки атомарности. - Лицензия Apache-2.0 (с 0.13), пояснения в COPYRIGHT.
- Отдельные config-файлы для GNU Make и CMake; ограничение утечек внутренних символов.
14. Экосистема
Данные с официального сайта (libmdbx.dqdkfa.ru, на 1 сентября 2026 г.): - Всего найдено 1109 открытых проектов с 50881 звёздами, использующих libmdbx как хранилище (без учёта форков, копий и клонов); информация собирается из GitHub, SourceCraft, SourceGraph, Codeberg, GitVerse, GitFlic, mos.hub, market.dev и Yandex Cloud Search. - Крупнейшие кластеры (top-42): Ethereum-инфраструктура — Reth, Erigon, optimism, taiko-mono, ethrex, sequencer (Starknet), citrea (Bitcoin ZK rollup), rbuilder (MEV), rindexer (EVM-индексаторы); L2/блокчейн — tempo, base, Nimiq core-rs-albatross, irys; приложения — mangayomi, Isar (NoSQL для Flutter), miranda-ng (мессенджер), qiqqa (научные исследования), Monica Pass (менеджер паролей), nzbget (Usenet), Cobalt (WhatsApp API), endee (векторная БД). - Официально отслеживаемые биндинги: Rust, Go, Node.js, Zig, Python, .NET (C#), C++, Dart, Nim, Java, Haskell, Ruby, Scala. - Проект — победитель конкурса Yandex Open Source среди открытых проектов; код остаётся открытым с бесплатной поддержкой. - Стратегическое направление — MithrilDB (анонсировано в конце 2025 г.): общий API для поддержки нескольких форматов баз. В планах — поиск с кэшированием по txnid, потоковые BLOB, опциональный mmap, шифрование и сжатие на уровне движка, SWIG, репликация и кроссязыковое взаимодействие C/C++↔Rust. Старые форматы и базы будут поддерживаться, пока это нужно пользователям.
15. Хронология по версиям (ключевые вехи)
| Версия (год) | Ключевые доработки |
|---|---|
| 2015–2017 (ReOpenLDAP/ранний) | Форк; базовая надёжность, более длинные ключи, нулевые ключи |
| ~0.9.x (2019–2021) | API опций; динамические списки; переработанный спилл; refund; C11-атомики; C++ API (0.9.1); env_delete, commit_ex, SET_LOWERBOUND |
| 0.10.x (2021) | set/get_option; прозрачный спилл + LRU; auto-appending split; get_sysraminfo; DISABLE_PAGECHECKS; статистика page-op |
| 0.11.x (2021–2022) | cursor_get_batch, SET_UPPERBOUND; ускорение GC для огромных транзакций; fix incoherent page cache (#269); переезд после удаления GitHub; wchar API; C++ finalized |
| 0.12.x (2022–2023) | Big Foot; Troika; SIMD-поиск (AVX2/AVX512/SSE2/NEON); branchless bsearch; prefault-write; writethrough; merge-тактика; warmup; Windows overlapped-I/O; LCK v2; VALIDATION |
| 0.13.x (2023–2025) | Apache-2.0; парковка/вытеснение; HSR; DBI sparse/lockfree; gc_time_limit; env_chk в библиотеке; rename; cursor scan/compare; resurrect_after_fork; NOSTICKYTHREADS; subpage-опции; prefer_waf_insteadof_balance; UUID; большая серия API-расширений |
| 0.14.x (2025–2026) | Early GC cleanup; явная дефрагментация + mdbx_defrag; bunch_delete/delete_range; cache_get; txn_clone/refresh/checkpoint/amend/rollback/embark_read; вложенные read-only; gc_info; split_reserve; distance/scroll/distribute; Harmony OS/Haiku; без float/libm; MDBX_CHECKING; branchless + встроенные компараторы; presync_threshold; deferred-инвалидация DBI; стабилизация 0.14.x (0.14.3) |
16. Статус и дальнейшие шаги
Каталог обновлён по данным официального сайта (экосистема, блокировки Windows, LTO). Дальнейшие шаги:
- Сверить пункты с кодом для категорий, где это критично (формат, опции, мета).
- Добавить ссылки на разделы
deep-dive.ru.md, где механизмы описаны подробно. - При необходимости — отдельный документ «что именно отличается в поведении по умолчанию».