полнота точки — множество ключей, победитель — функция множества точек
- отношение победы было нетранзитивным: полнота (частичный порядок) плюс тай-брейк (тотальный) в попарной свёртке давали цикл, из-за которого одна и та же доставка меняла содержимое объекта при каждой пересборке - надмножество побеждает только при совпадении значений общих содержательных ключей: иначе точка без единого измерения вытесняла измерение - Less стал тотальным, isEmpty не материализует значение, имя метрики в координате столкновения обрезается, отпечаток витрины включает units и sealed - на живом архиве строгий no-op: 1737 объектов, содержимое совпало побайтово
This commit is contained in:
@@ -72,6 +72,7 @@ type Stats struct {
|
||||
Buckets int
|
||||
Unchanged int
|
||||
Overwrites int
|
||||
Incomparable int
|
||||
SealedHits int
|
||||
UnitsConflicts int
|
||||
SkippedNoTime int
|
||||
@@ -80,6 +81,7 @@ type Stats struct {
|
||||
Layer string
|
||||
LayerMismatch bool
|
||||
Collisions []store.Collision
|
||||
IncomparableAt []store.Collision
|
||||
}
|
||||
|
||||
// Fold разбирает тело доставки и раскладывает точки по часовым объектам.
|
||||
@@ -138,9 +140,11 @@ func (s *Service) Fold(ctx context.Context, deliveryID string) (Stats, error) {
|
||||
stats.Buckets = merge.Buckets
|
||||
stats.Unchanged = merge.Unchanged
|
||||
stats.Overwrites = merge.Overwrites
|
||||
stats.Incomparable = merge.Incomparable
|
||||
stats.SealedHits = merge.SealedHits
|
||||
stats.UnitsConflicts = merge.UnitsConflicts
|
||||
stats.Collisions = merge.Collisions
|
||||
stats.IncomparableAt = merge.IncomparableAt
|
||||
|
||||
if err := s.finish(ctx, deliveryID, store.ParseDone, int64(stats.Points), stats.Layer); err != nil {
|
||||
s.log.ErrorContext(ctx, "delivery fold failed", "error", err, "delivery_id", deliveryID)
|
||||
@@ -173,6 +177,7 @@ func (s *Service) logResult(ctx context.Context, deliveryID string, st Stats) {
|
||||
"buckets", st.Buckets,
|
||||
"unchanged", st.Unchanged,
|
||||
"overwrites", st.Overwrites,
|
||||
"incomparable", st.Incomparable,
|
||||
"units_conflicts", st.UnitsConflicts,
|
||||
"sealed_hits", st.SealedHits,
|
||||
"skipped", skipped,
|
||||
@@ -185,6 +190,9 @@ func (s *Service) logResult(ctx context.Context, deliveryID string, st Stats) {
|
||||
if len(st.Collisions) > 0 {
|
||||
attrs = append(attrs, "collisions", formatCollisions(st.Collisions))
|
||||
}
|
||||
if len(st.IncomparableAt) > 0 {
|
||||
attrs = append(attrs, "incomparable_at", formatCollisions(st.IncomparableAt))
|
||||
}
|
||||
|
||||
// Доставка, у которой отброшены ВСЕ точки, — это сломавшийся формат, а не
|
||||
// штатная работа. Без этого условия смена формата метки выглядела бы как
|
||||
@@ -192,6 +200,11 @@ func (s *Service) logResult(ctx context.Context, deliveryID string, st Stats) {
|
||||
allSkipped := st.Points == 0 && skipped > 0
|
||||
|
||||
switch {
|
||||
case st.Incomparable > 0:
|
||||
// Выше перезаписей намеренно: несравнимый набор полей — событие реже и
|
||||
// информативнее, на живом потоке не случавшееся ни разу. Признаки при
|
||||
// этом идут атрибутами всегда, так что выбор ветви ничего не прячет.
|
||||
s.log.WarnContext(ctx, "delivery folded, incomparable point fields", attrs...)
|
||||
case st.Overwrites > 0:
|
||||
// Единственное наблюдение, по которому проверяется правило слияния.
|
||||
// В INFO оно тонуло: поток идёт раз в пять минут.
|
||||
|
||||
Reference in New Issue
Block a user