disk-load: keep a reading of an item no longer declared, retired with when and why, and clear it when declared again; sdk 31e90aa (issue 1955, ADR 0233)

This commit is contained in:
2026-10-29 23:57:18 +01:00
parent 62b53c2eda
commit 60231234a5
4 changed files with 68 additions and 4 deletions
+48 -1
View File
@@ -86,12 +86,55 @@ func (k *Keeper) Round(ctx context.Context, walks bool) (written, kept int, err
}
}
}
retired, err := k.retireGone(items)
written += retired
if err != nil {
failed = append(failed, err.Error())
}
if len(failed) > 0 {
return written, kept, errors.New("readings not kept: " + strings.Join(failed, "; "))
}
return written, kept, nil
}
// retireGone marks retired every reading of this node whose item the node no longer declares — its module was unassigned
// there, or is no longer pulled in — with when and why, and keeps it: the record of what the module left behind, until a
// person deletes it (ADR 0233). It is cleared when the item is declared again (measureOne).
func (k *Keeper) retireGone(declared map[string][]catalogue.PlacedDataItem) (int, error) {
keys, err := k.Store.Keys()
if err != nil {
return 0, err
}
declaredNow := map[string]bool{}
for module, its := range declared {
for _, it := range its {
declaredNow[health.ReadingKey(k.Node, module, it.ID)] = true
}
}
now := k.Measurer.Now().UTC()
n := 0
for _, key := range keys {
if !strings.HasPrefix(key, k.Node+".") || declaredNow[key] {
continue
}
raw, err := k.Store.Get(key)
if err != nil || len(raw) == 0 {
continue
}
r, err := health.DecodeReading(raw)
if err != nil || r.Node != k.Node || !r.RetiredAt.IsZero() {
continue
}
r.RetiredAt = now
r.RetiredWhy = fmt.Sprintf("no longer declared on %s: its module was unassigned there, or is no longer pulled in", k.Node)
if err := k.Store.Put(key, r); err != nil {
return n, err
}
n++
}
return n, nil
}
func (k *Keeper) measureOne(ctx context.Context, it catalogue.PlacedDataItem, walks bool) (bool, error) {
key := health.ReadingKey(k.Node, it.Module, it.ID)
var prev *health.Reading
@@ -105,11 +148,15 @@ func (k *Keeper) measureOne(ctx context.Context, it catalogue.PlacedDataItem, wa
}
}
now := k.Measurer.Now()
if prev != nil && it.Measure == catalogue.MeasureWalk && !walks && prev.MeasuredAt != nil && now.Sub(*prev.MeasuredAt) < WalkEvery {
if prev != nil && prev.RetiredAt.IsZero() && it.Measure == catalogue.MeasureWalk && !walks && prev.MeasuredAt != nil && now.Sub(*prev.MeasuredAt) < WalkEvery {
return false, nil
}
m := k.Measurer.Measure(ctx, it)
next, changed := health.NextReading(prev, k.Node, it, m, now)
if prev != nil && !prev.RetiredAt.IsZero() {
// Declared again: it is no longer retired.
next.RetiredAt, next.RetiredWhy, changed = time.Time{}, "", true
}
if !changed {
return false, nil
}
@@ -9,6 +9,7 @@ import (
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/health"
)
type memStore struct{ m map[string]json.RawMessage }
@@ -65,6 +66,22 @@ func TestARoundMeasuresTheDeclaredItemsAndWritesWhatChanged(t *testing.T) {
if _, _, err := k.MeasureNow(context.Background(), "pg", "data"); err != nil || walks != 2 {
t.Fatalf("measure now: %v, %d walks", err, walks)
}
// An item no longer declared is kept, retired with when and why; declared again, it is not retired any more.
delete(placed, "pg")
if _, _, err := k.Round(context.Background(), false); err != nil {
t.Fatal(err)
}
gone, _ := health.DecodeReading(store.m["ace.pg.data"])
if gone.RetiredAt.IsZero() || !strings.Contains(gone.RetiredWhy, "no longer declared on ace") || gone.FirstSeen.IsZero() {
t.Fatalf("a reading of an item no longer declared: %+v", gone)
}
placed["pg"] = []catalogue.PlacedDataItem{{Module: "pg", ID: "data", Class: "valuable", Path: "/srv/pg", Measure: catalogue.MeasureWalk}}
if _, _, err := k.Round(context.Background(), false); err != nil {
t.Fatal(err)
}
if back, _ := health.DecodeReading(store.m["ace.pg.data"]); !back.RetiredAt.IsZero() {
t.Fatalf("a reading declared again is still retired: %+v", back)
}
if _, _, err := k.MeasureNow(context.Background(), "pg", "tmp"); err == nil {
t.Fatal("a cache was measured")
}
+1 -1
View File
@@ -2,4 +2,4 @@ module diskload
go 1.26.0
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029223134-08fc70783a7c
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029225606-31e90aaa0f0d
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029223134-08fc70783a7c h1:inVTVNIZI4/v7/aVhL+EkKzHCDlN73hJrWKz3jI59mY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029223134-08fc70783a7c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029225606-31e90aaa0f0d h1:HHSXxRS+GEYNgtdg9MFB8W2Y6ycPJF7YLF46y3oj7Ow=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029225606-31e90aaa0f0d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA=
github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/nats-io/nats.go v1.54.0 h1:vsXoOxjHp/GmPUN+EcI7uOf/uB+iAP+kEsAFNQN0yzA=