При добавлении нового ключа в append-режиме, в случае когда в текущей
(последней) позиции с ключом связаны несколько значений и
(соответственно) вложенный dupsort-курсор инициализирован, вставка
происходила без сброса вложенного курсора.
В результате вложенный курсор логически оставался стоять на
multivalue-данных связанных с предыдущей позицией основного курсора,
т.е. переходил в неконсистентное состояние.
Ошибка проявлялась возвратом неверных значений из mdbx_cursor_count()
или срабатывание assert-проверки в отладочных сборках.
Из LXC-контейнера не доступен файл хостовой системы "/proc/sys/kernel/random/boot_id".
Вместо него, при каждом старте контейнера, создается и заполняется
случайными данными собственный boot_id смонтированный через bind из tmpfs.
https://github.com/lxc/lxc/issues/3027
Поэтому полноценный контроль по boot_id не возможен, так как при
рестарте LXC-контейнера (но не хоста) boot_id будет меняться, хотя
данные в unified page cache сохраняются.
Таким образом, при рестарте LXC-контейнера, libmdbx будет производить
откат БД до крайней точки устойчивой фиксации, что может приводить к
утрате данных пользователя в случаях когда они могли быть сохранены.
Однако, улучшить ситуацию пока не представляется возможным, как минимум
до доступности boot_id хостовой системы изнутри LXC-контейнера.
Этот коммит частично улучшает ситуацию тем, что позволяет использовать
фейковый/замещенный boot_id размещенный в файловой системе с типом tmpfs
при работе внутри LXC-контейнера.
Возможность полезная, но пожалуй еще нуждается в доработке и/или
до-осмыслении. Основное неудобство в нестыковке с основным логированием.
С одной стороны, сообщение об ошибках следует выводить с
уровнем/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).