Тезисно:
- Использование DUPFIXED (включая INTEGERDUP) могло приводить к
повреждению БД и/или потере данных. Этот коммит устраняет эту угрозу.
- Вероятность проявления существенно увеличивается с увеличением
размера/длины мульти-значений/дубликатов (не ключей).
- В MDBX проблема унаследована от LMDB, где существует более 11 лет,
начиная с коммита ccc4d23e74
и до настоящего времени.
Для вложенных страниц типа LEAF2 (которые содержат только значения
одинаковой длины, без таблицы смещений к ним), упомянутым выше коммитом,
было добавлено резервирование места (что в целом спорно, но в некоторых
сценариях позволяет уменьшить накладные расходы). Ошибка была в том, что
в коде не исключалась возможность превышения размера страницы БД, что
далее приводило к арифметическому переполнению, повреждению БД и/или
просписи памяти.
Устранение упущения приводящего к нелогичной ситуации `me_dxb_mmap.curren > me_dxb_mmap.limit` при "дребезге" размера БД.
В текущем понимании, последствий кроме срабатывания assert-проверки нет, а вероятность проявления близка к нулю.
Повреждение БД и/или потери данных не происходило, проблема лишь в
возврате ложной ошибки.
Благодарю пользователя/разработчика @Dvirsw (https://t.me/Dvirsw) за
сообщения о проблеме и предоставление минимального/оптимального сценария
воспроизведения.
--
Проблема была из-за излишнего условия при контроле внутренего поля
mp_upper в ходе проверки структуры страниц БД.
Поле mp_upper указывает на нижнуюю границу заполнения страницы от конца
к началу. Вследствие того, что значения ключей выравниваетня на четную
границу, это поле четно во всех случаях за исключением LEAF2-страницы
(листовая страница вложенного дерева для множественных значений
финсированной/одинаковой длины одного ключа), на которой размещено
нечетное количество значений нечетной длины.
Ошибка не проявлялась в большинстве случаев (в том числе в
стохастических тестах), так как штатно лишняя проверка производилась
только при чтении страницы и перебалансировке ключей, но не при каждом
добавлении значения. Тем не менее, сценарии тестов требуют
доработки/расширения для явного добавления нечетных dupfixed-сценариев.
Когда rp_augment_limit не задан пользователем посредством
`MDBX_opt_rp_augment_limit`, то как и ранее он подстраивается в
зависимости от текущего размера БД (актуального кол-ва страниц).
Теперь-же авто-устанавливаемое значение rp_augment_limit вычисляется
обратно-пропорционально `MDBX_opt_gc_time_limit`:
- Если gc_time_limit == 0, то rp_augment_limit устанавливается в 1/3 от
общего кол-ва страниц БД, но не меньше рационального минимума.
Это соответствует прежнему поведению и обеспечивает достаточно глубокую
переработку GC во всех не-экстремальных сценариях.
- При gc_time_limit >= 16_секунд
rp_augment_limit устанавливается в минимальное значение.
- Когда 0 < gc_time_limit < 16_секунд
rp_augment_limit устанавливается между минимумом и 1/3 от размера БД
пропорционально остатку gc_time_limit до 16 секунд.
Соответственно, при больших значениях gc_time_limit, выбирается меньшее
значение rp_augment_limit, и контроль глубины переработки GC
ограничивается в основном по-времени.