store: при равной полноте точек побеждает пришедшая доставка
- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
This commit is contained in:
@@ -236,6 +236,38 @@ func (s *Store) PendingDeliveries(ctx context.Context, after PendingDelivery, li
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ParsedAfter отвечает, есть ли в журнале доставка ПОЗЖЕ указанной позиции,
|
||||
// уже записавшая свой разбор в витрину.
|
||||
//
|
||||
// Нужен ровно одному наблюдению: свёртка вне порядка журнала. Правило слияния
|
||||
// точек разрешает равную полноту в пользу пришедшей доставки, то есть исход
|
||||
// есть функция порядка свёртки; доставка, свёрнутая после своей преемницы,
|
||||
// возвращает координату к версии, которую источник уже пересчитал, и живая
|
||||
// витрина расходится с пересборкой. Барьер воркера этого не ловит: отставшей
|
||||
// доставки в момент прохода просто не существует — строка учёта становится
|
||||
// видимой только после записи тела.
|
||||
//
|
||||
// `failed` в предикат НЕ входит: такая доставка в витрину ничего не записала,
|
||||
// перестановка относительно неё содержимого не разводит, а исход этот штатный
|
||||
// (невыводимый слой), и его учёт превратил бы WARN в шум.
|
||||
//
|
||||
// Это страж окна, а не постоянная часть свёртки: закрыв порядок на самом
|
||||
// приёме, метод и его вызов сносят вместе с окном.
|
||||
func (s *Store) ParsedAfter(ctx context.Context, at time.Time, id string) (bool, error) {
|
||||
// Кортежное сравнение, а не через OR: развёрнутая форма даёт SCAN по
|
||||
// индексу вместо SEARCH — тот же приём, что в PendingDeliveries.
|
||||
const q = `
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM delivery
|
||||
WHERE parse_status IN (?, ?) AND (received_at, id) > (?, ?))`
|
||||
|
||||
var found bool
|
||||
if err := s.db.GetContext(ctx, &found, q, ParseDone, ParsePartial, FormatTime(at), id); err != nil {
|
||||
return false, fmt.Errorf("select parsed after: %w", err)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// CountPendingDeliveries возвращает размер задолженности — сколько доставок
|
||||
// ждут свёртки. Нужен ровно одной строке лога при старте: сколько сервис должен
|
||||
// разобрать, прежде чем витрина станет полной.
|
||||
|
||||
Reference in New Issue
Block a user