Цена читающего маршрута: чекпойнт WAL по таймеру и условный запрос
- рядом с воркером свёртки живёт горутина, раз в минуту разбирающая журнал пассивным чекпойнтом; «журнал не разбирается» видно строкой владельцу, а не только по `df`. Признак — пара чисел, а не флаг занятости: тот молчит под удерживаемым читателем (`busy=0` при 6256 страницах и пяти перенесённых), а при занятой блокировке отдаёт `-1` вместо ответа, и `-1 >= -1` читалось бы как «разобрано целиком» - каталог отвечает `304` на `If-None-Match`, не открывая снимок витрины. Метка собрана из всего, от чего зависит ответ: версии витрины (`data_version` с закреплённого соединения плюс поколение — значение локально для соединения и не переживает переоткрытия), горизонта измерения и области действия ресурса. Версия снимается до и после сборки: снятая после пометила бы устаревший снимок свежим номером - предел и дедлайн ответа отложены в задачу Read API точек вместе с измеренной ценой первого запроса; попутно починен флаки-тест чужой задачи, искавший значение точки в сыром буфере записи лога
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
## 1. Версия витрины в хранилище
|
||||
|
||||
- [x] 1.1 Соединение-щуп: `sql.Conn`, взятый по первому запросу версии,
|
||||
поколение (ULID через `internal/ident`), пересоздание с новым поколением
|
||||
только при `sql.ErrConnDone` — обстоятельства поколение не меняют
|
||||
- [x] 1.2 `Store.StateVersion(ctx)` — `PRAGMA data_version` со щупа, метка вида
|
||||
`<поколение>-<счётчик>`; `Store.VersionedRead` — двойная проба вокруг
|
||||
чтения; щуп закрывается раньше пула в `Close` и не воскресает после него
|
||||
- [x] 1.3 Тесты: неизменившаяся база даёт ту же версию; запись из пула её
|
||||
двигает; переоткрытие базы даёт другую версию; щуп пересоздаётся с новым
|
||||
поколением; после `Close` версия отказывает и `-wal` рядом не остаётся;
|
||||
щуп не удерживает читающий снимок
|
||||
|
||||
## 2. Обслуживание WAL
|
||||
|
||||
- [x] 2.1 `journal_size_limit` в DSN рабочего подключения, с причиной в
|
||||
комментарии (пассивный чекпойнт файл не укорачивает)
|
||||
- [x] 2.2 `Store.CheckpointWAL(ctx)` — `PRAGMA wal_checkpoint(PASSIVE)`,
|
||||
наружу тройка чисел (busy, log, checkpointed) без интерпретации
|
||||
- [x] 2.3 Цикл чекпойнта в `cmd/healthlog`: тик в минуту, `WARN` при
|
||||
«страниц больше порога и перенесено меньше», отказ не убивает цикл
|
||||
- [x] 2.4 Запуск и дренирование в `serve`: горутина ждётся в общем бюджете
|
||||
остановки, отдельного чекпойнта на выходе нет
|
||||
- [x] 2.5 Тесты: чекпойнт переносит страницы в тишине; удерживаемый читатель
|
||||
даёт `checkpointed < log` без ошибки; порог молчит на малом журнале;
|
||||
цикл выходит по отмене
|
||||
|
||||
## 3. Условный запрос в транспорте
|
||||
|
||||
- [x] 3.1 Помощник `httpapi`: разбор `If-None-Match` (список, `W/`, `*`),
|
||||
слабое сравнение, `304` без тела — общий для будущих читающих маршрутов
|
||||
- [x] 3.2 Источник версии передаётся транспорту функцией (как `worker.Notify`),
|
||||
проверка токена чтения остаётся раньше условия
|
||||
- [x] 3.3 Тесты помощника на формах заголовка: пусто, список, `W/`, `*`,
|
||||
мусор
|
||||
|
||||
## 4. Каталог отдаёт версию
|
||||
|
||||
- [x] 4.1 `catalog.Service.Metrics` возвращает снимок вместе с версией:
|
||||
проба до, сборка, проба после; расхождение — версии нет
|
||||
- [x] 4.2 `handleMetrics`: `ETag` из версии, `304` по `If-None-Match` без
|
||||
открытия снимка, ответ без `ETag` при расхождении проб
|
||||
- [x] 4.3 Тесты: два ответа подряд — одна метка и одинаковые байты; после
|
||||
свёртки метка другая; `304` не открывает снимок; `401` раньше `304`
|
||||
|
||||
## 5. Приёмочные критерии (рубрика ревью дизайна)
|
||||
|
||||
- [x] 5.1 Равная метка ⟹ побайтово равный ответ (кроме горизонта — назван в
|
||||
дизайне); обратное направление ошибок не допускается ни в одном тесте
|
||||
- [x] 5.2 Ни один новый лог не несёт значений точек, имён метрик без обрезки
|
||||
и секретов; уровень выбран по адресату
|
||||
- [x] 5.3 `task gate` зелёный; `task verify:archive` сходится (обслуживание
|
||||
WAL и версия не меняют витрину)
|
||||
- [x] 5.4 Поведенческая проверка на своём стенде из исходников (отдельный
|
||||
каталог данных, рабочий контейнер не трогаем): `curl` дважды даёт
|
||||
`304`, после доставки — `200`
|
||||
|
||||
## 6. Документация
|
||||
|
||||
- [x] 6.1 `docs/architecture.md`: версия витрины, условный запрос, обслуживание
|
||||
WAL, отвергнутые чужие решения с причинами
|
||||
- [x] 6.2 `README.md`: строка про условный запрос в примерах чтения
|
||||
- [x] 6.3 `docs/backlog`: задача снята, остаток (предел ответа, измеренная цена
|
||||
первого запроса, готовая машинерия условного запроса) перенесён в
|
||||
`read-api-tochki.md`; наблюдаемость — в `stats-nablyudaemost.md`, цена
|
||||
ветки исчерпанного бюджета — в `ostanovka-i-migraciya-sledy.md`
|
||||
Reference in New Issue
Block a user