Дозакрыты находки ревью по слиянию сущностей
- Правило покрытия получило второй разряд (условный, как у точек), запрет вырождения формы и счёт содержательных элементов ряда: скелет из скаляров и ряд из null больше не затирают маршрут. Победитель внутри доставки стал функцией множества версий — общим помощником с точками, — а провенанс поднимается и при совпавшем хеше, иначе отложенная доставка возвращала витрину к прежнему содержимому. - Одно поле не того типа больше не уносит сущность, а пропуски видны в учётной записи доставки (миграция 00008, NULL = «не измерялось»); каноническая форма считается один раз и вне транзакции; откат бинаря поверх новой схемы отказывает на старте; текст ошибки разбора не несёт значений из тела. - Ревью кода профилем deep (девять проходов) нашло две регрессии и обе закрыты: безусловный второй разряд запирал законный досчёт навсегда, а выбор победителя был квадратичен по числу присланных версий одного ключа.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Пределы на размер сущности и потоковый расчёт формы
|
||||
|
||||
**Приоритет:** средний
|
||||
|
||||
Остаток задачи «Дозакрыть находки ревью по слиянию сущностей» (архивный 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`, но узнать о нём можно только из лога.
|
||||
|
||||
## Что делать
|
||||
|
||||
1. Предел на размер **одной сущности** и на суммарный размер секции, отдельно
|
||||
от предела тела (64 МиБ). Сегодня одна тренировка законно может занять всё
|
||||
тело целиком. Вход, превышающий предел, обязан отклоняться **до**
|
||||
канонизации, а не после.
|
||||
2. Потоковый расчёт канонической формы и хеша: `canon.Form` разворачивает
|
||||
значение в дерево `any`, из-за чего пик кучи кратен размеру входа (замер даёт
|
||||
множитель около 19×). Хеш считается по потоку; форма нужна целиком только для
|
||||
сравнения, и только когда хеш разошёлся.
|
||||
3. Разбор **сохранённой** версии всё ещё идёт внутри транзакции: её содержимое
|
||||
читается оттуда же. Убрать это можно оптимистичным чтением до транзакции —
|
||||
но только с перепроверкой хеша и провенанса **внутри** транзакции, иначе две
|
||||
конкурентные свёртки одного `id` дадут потерянное обновление и исход снова
|
||||
станет функцией порядка коммитов, а не журнала.
|
||||
|
||||
## Условия, пришедшие из закрывающей задачи
|
||||
|
||||
1. Мягкое чтение заголовка сущности увеличило долю тел, доходящих до
|
||||
канонизации: сущность, которая раньше отсекалась на `json.Unmarshal`
|
||||
заголовка почти бесплатно, теперь разбирается и канонизируется целиком. То
|
||||
есть худший случай по памяти стал достижим на входах, которые до него не
|
||||
доходили, — предел из пункта 1 после этого **обязателен**, а не желателен.
|
||||
|
||||
2. Каноническая форма и множества ключей всех версий доставки теперь
|
||||
**удерживаются** до конца транзакции слияния (раньше считались лениво и на
|
||||
одной доставке из сорока четырёх). Расход стал пропорционален размеру
|
||||
ДОСТАВКИ, а не самой большой её сущности; предел обязан считать суммарный
|
||||
размер секции, а не только одной сущности.
|
||||
|
||||
3. **Потолок на число версий одного ключа в одной доставке.** Выбор победителя
|
||||
квадратичен по числу кандидатов; версии с совпавшей канонической формой
|
||||
схлопываются, но различных тело вмещает сколько угодно. Отмена цикл
|
||||
прерывает (дедлайн свёртки снова работает), но доставка при этом уходит в
|
||||
`failed` — то есть отравленное тело стоит полного дедлайна воркера. Тот же
|
||||
вопрос открыт для точек на одной координате: `cena-sliyaniya-na-shirokoj-dostavke.md`,
|
||||
пункт 4.
|
||||
|
||||
## Связано
|
||||
|
||||
- [Цена слияния на широкой доставке](cena-sliyaniya-na-shirokoj-dostavke.md) —
|
||||
та же плата со стороны **точек** (`hashPoints` пересчитывает форму всех точек
|
||||
часа). Задачи делать вместе: половина решения общая — `canon`.
|
||||
- Из того же ревью: «хеш без полного прохода по содержимому не посчитать» —
|
||||
отброшено как предел по конструкции, но условием ложится сюда.
|
||||
Reference in New Issue
Block a user