- Правило покрытия получило второй разряд (условный, как у точек), запрет вырождения формы и счёт содержательных элементов ряда: скелет из скаляров и ряд из null больше не затирают маршрут. Победитель внутри доставки стал функцией множества версий — общим помощником с точками, — а провенанс поднимается и при совпавшем хеше, иначе отложенная доставка возвращала витрину к прежнему содержимому. - Одно поле не того типа больше не уносит сущность, а пропуски видны в учётной записи доставки (миграция 00008, NULL = «не измерялось»); каноническая форма считается один раз и вне транзакции; откат бинаря поверх новой схемы отказывает на старте; текст ошибки разбора не несёт значений из тела. - Ревью кода профилем deep (девять проходов) нашло две регрессии и обе закрыты: безусловный второй разряд запирал законный досчёт навсегда, а выбор победителя был квадратичен по числу присланных версий одного ключа.
5.8 KiB
Пределы на размер сущности и потоковый расчёт формы
Приоритет: средний
Остаток задачи «Дозакрыть находки ревью по слиянию сущностей» (архивный change
dozakryt-nahodki-sushchnostej). Та задача убрала канонизацию приехавшей
сущности из транзакции и перестала считать каноническую форму дважды. Осталось
структурное: предела на размер одной сущности нет вовсе, а форма и хеш
считаются материализацией значения целиком.
Оракул: измерено
Оракулы жили в tmp/adv/mem_test.go и tmp/adv/lock_test.go; числа снимались
на теле в пределах приёма (64 МиБ):
тело 40 МиБ → пик HeapAlloc 768.3 МиБ
тело 63 МиБ → повторная доставка держит блокировку 5.019 с при busy_timeout 5000
При _txlock=immediate конкурентный CreateDelivery получает SQLITE_BUSY,
inTx повторяет до пяти раз и на исчерпании отдаёт store.ErrBusy — приём
отвечает 500 по доставке, тело которой уже в архиве. Осиротевшее тело подберёт
reindex, но узнать о нём можно только из лога.
Что делать
- Предел на размер одной сущности и на суммарный размер секции, отдельно от предела тела (64 МиБ). Сегодня одна тренировка законно может занять всё тело целиком. Вход, превышающий предел, обязан отклоняться до канонизации, а не после.
- Потоковый расчёт канонической формы и хеша:
canon.Formразворачивает значение в деревоany, из-за чего пик кучи кратен размеру входа (замер даёт множитель около 19×). Хеш считается по потоку; форма нужна целиком только для сравнения, и только когда хеш разошёлся. - Разбор сохранённой версии всё ещё идёт внутри транзакции: её содержимое
читается оттуда же. Убрать это можно оптимистичным чтением до транзакции —
но только с перепроверкой хеша и провенанса внутри транзакции, иначе две
конкурентные свёртки одного
idдадут потерянное обновление и исход снова станет функцией порядка коммитов, а не журнала.
Условия, пришедшие из закрывающей задачи
-
Мягкое чтение заголовка сущности увеличило долю тел, доходящих до канонизации: сущность, которая раньше отсекалась на
json.Unmarshalзаголовка почти бесплатно, теперь разбирается и канонизируется целиком. То есть худший случай по памяти стал достижим на входах, которые до него не доходили, — предел из пункта 1 после этого обязателен, а не желателен. -
Каноническая форма и множества ключей всех версий доставки теперь удерживаются до конца транзакции слияния (раньше считались лениво и на одной доставке из сорока четырёх). Расход стал пропорционален размеру ДОСТАВКИ, а не самой большой её сущности; предел обязан считать суммарный размер секции, а не только одной сущности.
-
Потолок на число версий одного ключа в одной доставке. Выбор победителя квадратичен по числу кандидатов; версии с совпавшей канонической формой схлопываются, но различных тело вмещает сколько угодно. Отмена цикл прерывает (дедлайн свёртки снова работает), но доставка при этом уходит в
failed— то есть отравленное тело стоит полного дедлайна воркера. Тот же вопрос открыт для точек на одной координате:cena-sliyaniya-na-shirokoj-dostavke.md, пункт 4.
Связано
- Цена слияния на широкой доставке —
та же плата со стороны точек (
hashPointsпересчитывает форму всех точек часа). Задачи делать вместе: половина решения общая —canon. - Из того же ревью: «хеш без полного прохода по содержимому не посчитать» — отброшено как предел по конструкции, но условием ложится сюда.