dd7cdc09e7
gates / gates (push) Successful in 1m6s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
61 lines
2.0 KiB
Go
61 lines
2.0 KiB
Go
package backup
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-agent/internal/hub"
|
|
)
|
|
|
|
// ForeignKeyLedger (R-366 slice 2, `09` §3 decision 168) holds, per backup tier, the whole-guest archives the
|
|
// restore-test pick skipped because another key wrote them (R-727 — an earlier install of this box). Since R-727 the
|
|
// skip was one INFO log line per archive and nothing else, so after a reinstall the operator was never told that the
|
|
// box's older whole-guest copies are unreadable to it. The host report carries this ledger; the hub raises ONE
|
|
// operator event when it changes.
|
|
//
|
|
// It reports nil until a tier has been evaluated since the agent started, so a restart does not read as "the set
|
|
// changed to empty" (the hub keeps its last state for an absent field).
|
|
type ForeignKeyLedger struct {
|
|
mu sync.Mutex
|
|
byTarget map[string]hub.ForeignKeyArchives
|
|
}
|
|
|
|
// NewForeignKeyLedger builds an empty ledger.
|
|
func NewForeignKeyLedger() *ForeignKeyLedger {
|
|
return &ForeignKeyLedger{}
|
|
}
|
|
|
|
func (l *ForeignKeyLedger) set(target string, n int, oldest, newest int64) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
if l.byTarget == nil {
|
|
l.byTarget = map[string]hub.ForeignKeyArchives{}
|
|
}
|
|
e := hub.ForeignKeyArchives{Target: target, Count: n}
|
|
if n > 0 {
|
|
e.Oldest = time.Unix(oldest, 0).UTC().Format(time.RFC3339)
|
|
e.Newest = time.Unix(newest, 0).UTC().Format(time.RFC3339)
|
|
}
|
|
l.byTarget[target] = e
|
|
}
|
|
|
|
// ForeignKeyArchives implements hub.ForeignKeyArchiveReporter: nil before any evaluation; otherwise the tiers that
|
|
// hold such archives (`Tiers` empty, never nil, when none do), sorted by tier.
|
|
func (l *ForeignKeyLedger) ForeignKeyArchives(context.Context) *hub.ForeignKeyArchivesStanza {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
if l.byTarget == nil {
|
|
return nil
|
|
}
|
|
out := []hub.ForeignKeyArchives{}
|
|
for _, e := range l.byTarget {
|
|
if e.Count > 0 {
|
|
out = append(out, e)
|
|
}
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Target < out[j].Target })
|
|
return &hub.ForeignKeyArchivesStanza{Tiers: out}
|
|
}
|