Возможность полезная, но пожалуй еще нуждается в доработке и/или
до-осмыслении. Основное неудобство в нестыковке с основным логированием.
С одной стороны, сообщение об ошибках следует выводить с
уровнем/severity MDBX_LOG_ERROR. Однако, это замусоривает и ломает
тесты.
Поэтому сейчас при возвращении ошибок из API сообщения логируются
MDBX_LOG_ERROR, но производится это только при включении уровня
логирования MDBX_LOG_DEBUG или более детальном.
Было `MAJOR.MINOR.RELEASE.REVISION`
Теперь `MAJOR.MINOR.PATCH[.TWEAK][-PRERELEASE][+BUILDMETADATA]`
https://semver.org/
- вместо квартета `MAJOR.MINOR.RELEASE.REVISION`
триплет c опцинальным четвертым членом `MAJOR.MINOR.PATCH[.TWEAK]`
- `TWEAK` не входит в тег git, а формируется автоматически и
соответствует кол-ву коммитов после тега git и опускается если 0.
- Поле `PRERELEASE` опционально и переносится в версию из тега git.
- Поле `BUILDMETADATA` опционально, не входит в тег git, а
добавляется во время сборки если задана опцией `MDBX_BUILD_METADATA`.
Изменение поведения по-умолчанию, но без утраты контроля.
Без изменения:
Определение опции MDBX_WITHOUT_MSVC_CRT в значение 0 или 1 позволяет явно выбирать между использование ntdll и CRT.
При этом включение C++ API (MDBX_BUILD_CXX=1) требует использования CRT.
Ранее:
По-умолчанию, когда не определены опции MDBX_WITHOUT_MSVC_CRT и MDBX_BUILD_CXX, делался выбор в пользу использования ntdll, вместо CRT.
Теперь:
Функции ntdll будет использоваться вместо CRT только если явно выключена поддержка C++ API (задано MDBX_BUILD_CXX=0).
Исторически в API была слабость/неоднозначность в жизненном цикле читающих транзакций:
- В простейших сценариях читающие транзакции запускались посредством
mdbx_txn_begin() и завершались посредством mdbx_txn_abort(), либо mdbx_txn_commit();
- Для экономии накладных расходов были предусмотрены функции
mdbx_txn_reset() и mdbx_txn_renew(), которые сбрасывали/прерывали
читающую транзакцию без её освобождения/разрушения и затем перезапускали её.
При этом транзакции сброшенные посредством mdbx_txn_reset() должны были
быть либо перезапущены, либо освобождены посредством mdbx_txn_abort();
- Заминка возникала при вызове mdbx_txn_commit() для читающих
транзакций сброшенных/прерванных посредством mdbx_txn_reset().
В таких ситуациях возвращалась ошибка MDBX_BAD_TXN, а транзакция
не освобождалась.
Такое поведение вносило лишнюю асимметрию в API и способствовало
появлению ошибок утечки ресурсов, но поддерживалось для совместимости.
Этот коммит изменяет историческое поведение с нарушением совместимости,
но делает API более регулярным и уменьшает вероятность ошибок утечки
ресурсов.
Теперь mdbx_txn_commit() освобождает/разрушает читающие транзакции
сброшенные/прерванные посредством mdbx_txn_reset() возвращая при этом
MDBX_RESULT_TRUE вместо MDBX_SUCCESS, по аналогии обработки фиксации
аварийных пишущих транзакций.
При обновлении GC, с помещением/возвратом страниц, возникает рекурсивная
зависимость, так как страницы, необходимые для CoW-модификации GC и
размещения списков возвращаемых страниц, берутся/выделяются из этих-же
списков и/или из GC. Эта рекуррентная зависимость разрешается путём
подготовки необходимого запаса страниц и двух-стадийным заполнением
списков, с повторением всего цикла при изменении ситуации/расклада, плюс
применение некоторых эвристик и поправок. Кроме корректной работы,
принципиально важным тут является минимизация количества
повторов/рестартов процесса, в том числе исключение возможности
бесконечного зацикливания.
Существующая реализация многократно/итеративно дорабатывалась. Поэтому
она неплохо обкатана и стабильна, но одновременно сложна и запутана.
Тем не менее, до последнего момента для текущей реализации были известны
условия/сценарии, в которых сходимость итеративного процесса обновления
GC нарушалась и при фиксации транзакции возвращалась ошибка
MDBX_PROBLEM. Эти условия/сценарии очень специфичны и далеки от реальных
практических случаев, поэтому этот недостаток не мешал использованию
библиотеки.
Этим коммитом добавляется и активируется еще один механизм нацеленный на
улучшение сходимости и минимизацию повторов/рестартов. Суть механизма в
формировании и учета поправки, которая на следующем цикле позволит
учесть все переходные процессы/затраты вне зависимости от их природы, и
этим обеспечить моментальную сходимость.
В текущем понимании, описанный выше недостаток полностью
устраняется/исправляется этим коммитом.
На 32-битных платформах элементы массивов 64-битных типов могут быть
выравнены на 4-байтовую границу. Из-за этого `mdbx_put(MDBX_MULTIPLE)`
могла возвращать ошибку `MDBX_BAD_VALSIZE`, считая что переданные
пользователем данные не выровнены.
Новая версия со сменой лицензии, существенным расширением API,
добавлением функционала и внутренними переработками. В том числе,
с незначительным нарушением обратной совместимости API библиотеки.
Список нововведений, доработок и изменений слишком велик для размещения
здесь, но вся информация есть в файле
[ChangeLog](https://libmdbx.dqdkfa.ru/md__change_log.html).
```
git diff' stat: 157 files changed, 41949 insertions(+), 33741 deletions(-)
Signed-off-by: Леонид Юрьев (Leonid Yuriev) <leo@yuriev.ru>
```
Падение происходило в случае когда:
- Некоторый процесс увеличивал размер БД с изменением геометрии (с
увеличением предельного размера БД и её отображения в ОЗУ), затем
задействовал страницу из добавленного сегмента в качестве корневой для
FreeDB/GC и/или MainDB и фиксировал транзакцию.
- Другой процесс, уже работавший с БД до изменения геометрии первым
процессом, запускал транзакцию чтения. Падение происходило при проверке
«когерентности» отображения страниц БД в ОЗУ, при проверке отметок
модификации внутри корневых страниц, так как в этом случае они были вне
границ текущего отображения БД в адресном пространстве этого процесса.
Похоже что в ходе какого-то рефакторинга потерялась соответствующая
проверка. Этот коммит добавляет её как временное решение, до переноса
проверки «когерентности» после изменения размера отображения (добавлено в
TODO).
Упомянутый флажок отсутствовал в пути разрушения транзакции при ошибке
её запуска. Из-за чего делалась попытка разрушить курсоры, что приводило
к падению отладочных сборок, так как в них соответствующий массив
намеренно заполнен некорректными указателями.
Временная подпорка для coherency_check(), которую в перспективе
следует заменить вместе с переделкой установки mod_txnid.
Суть проблемы:
- coherency_check() в качестве одного из критериев "когерентности"
проверяет условие meta.maindb.mod_txnid == maindb.root->txnid;
- при обновлении maindb.sequence высталяется DBI_DIRTY, что приведет
к обновлению meta.maindb.mod_txnid = current_txnid;
- однако, если в само дерево maindb обновление не вносились и оно
не пустое, то корневая страницы останеться с прежним txnid и из-за
этого ложно сработает coherency_check().
Временное (текущее) решение: Принудительно обновляем корневую
страницу в описанной выше ситуации. Это устраняет проблему, но и
не создает рисков регресса.
Итоговое решение, которое предстоит реализовать:
- изменить семантику установки/обновления mod_txnid, привязав его
строго к изменению b-tree, но не атрибутов;
- обновлять mod_txnid при фиксации вложенных транзакций;
- для dbi-хендлов пользовательских subDb (видимо) можно оставить
DBI_DIRTY в качестве признака необходимости обновления записи
subDb в MainDB, при этом взводить DBI_DIRTY вместе с обновлением
mod_txnid, в том числе при обновлении sequence.
- для MAIN_DBI при обновлении sequence не следует взводить DBI_DIRTY
и/или обновлять mod_txnid, а только взводить MDBX_TXN_DIRTY.
- альтернативно, можно перераспределить флажки-признаки dbi_state,
чтобы различать состояние dirty-tree и dirty-attributes.