# Цена слияния на широкой доставке **Приоритет:** средний Вынуто ревью кода задачи `pravilo-sliyaniya-tochek` (профиль `deep`, враждебный проход и независимая реализация — независимо друг от друга). ## Оракул: измерено Тело 63 МБ (в запросе ~200 КБ gzip — предел приёма 64 МиБ), 119 точек на ОДНОЙ координате: ``` транзакция держалась 5.149 с, аллоцировано 6108 МБ, пик кучи 189 МБ ``` При `busy_timeout` 5000 мс и `_txlock=immediate` параллельная доставка получает `SQLITE_BUSY`, `inTx` повторяет её до пяти раз (каждый повтор — полный пересчёт слияния), и на исчерпании попыток доставка уходит в `parse_status=failed`. Тело при этом в архиве остаётся, но пересборки, которая его подберёт, ещё нет. Отдельный вклад, измеренный бенчмарком на часовом объекте нижнего слоя (3 600 точек): ``` HashAll на объект 9.46 мс 6.7 МБ аллокаций Form одной точки 2.2 мкс ``` `hashPoints` пересчитывает каноническую форму ВСЕХ точек часа на каждое слияние, включая неизменившиеся. Утверждение `docs/architecture.md` о дешевизне глубокого прохода («4400 сравнений хеша, почти все сойдутся») стоимости самих сравнений не учитывает: чтобы сравнить хеш, его надо посчитать. Часть цены задачей `pravilo-sliyaniya-tochek` уже снята: `isEmpty` больше не материализует значение (было 410 мс на точку 16.5 МБ), а разбор точки переиспользуется через `canon.Fields`. Осталось структурное. ## Что делать 1. Держать хеш каждой точки в `payload` рядом с координатами (`storedPoint` уже есть) и пересчитывать форму только для новых и выигравших столкновение — стоимость станет пропорциональна дельте, а не объёму часа. 2. Считать `canon.Form` точки один раз на столкновение и переиспользовать в `Equal`, `Relate` и порядке вместо трёх независимых разборов. 3. Проверять `ctx.Err()` в цикле по точкам: сейчас дедлайн свёртки неисполним, прервать слияние нечем. 4. Оценить потолок числа кандидатов на одной координате: выбор победителя квадратичен по ним, и 119 точек на одну метку — вход, который приём принимает. ## Связано - Разнесение ответа приёма и свёртки **сделано** (архив change `2026-08-02-otvet-i-svyortka`): воркер убрал влияние на время ответа, но не на блокировку записи — длинная транзакция слияния держит её по-прежнему. Заодно оттуда взято главное смягчение: занятость базы больше не выводит доставку из очереди, она остаётся `pending` и пересворачивается. Оракул окна — `task verify:busy`. - Пересборка (`healthlog reindex`) подбирает доставки, ушедшие в `failed` по другим причинам.