A restore point is taken before a module moves across a change of how it writes a kept data, so each declaration (the old sections and every entry in requires by template) names its form, 0 where none is said, and the catch-up tool a restore is followed by. KeptDeclarations reads them in the one walk KeptStates now uses; FormChanges is what differs between the running manifest and the one applied (design 47). Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
136 lines
4.9 KiB
Go
136 lines
4.9 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// A kept data's form (novox/hq design 47, *A module's kept data on the bus, backed up and restored with its delivery*):
|
|
// every kept data a manifest declares, in an old section (`state`, `logs`, `streams`, `objects`) or in `requires` by
|
|
// template (the five kinds: state, stream, objects, ledger, log), names a `form`, a number its holder raises whenever it
|
|
// changes how it writes that data, or stops declaring it; a declaration naming none reads as form 0. Beside it, the
|
|
// catch-up tool: the module's own tool that brings the data forward once a restore point of it is restored, recorded in
|
|
// the restore point when it is taken. The declaration alone cannot tell a changed layout of the same bucket, so the holder
|
|
// says it. Which form is right, and that the catch-up tool is the module's own, is the indexer's judge's.
|
|
|
|
// KeptLayout is what a kept data's declaration says of the layout its holder writes: its form and its catch-up tool.
|
|
type KeptLayout struct {
|
|
// Form is the form of the kept data's layout, 0 where none is said.
|
|
Form int `json:"form,omitempty"`
|
|
// CatchUp is the module's own tool a restore of this kept data is followed by, named by the manifest that raised its
|
|
// form; empty where none is.
|
|
CatchUp string `json:"catch-up,omitempty"`
|
|
}
|
|
|
|
// The kinds of kept data, by the template each is on (ADR 0595 §2): the five a restore point is taken of.
|
|
const (
|
|
KeptKindState = "state"
|
|
KeptKindStream = "stream"
|
|
KeptKindObjects = "objects"
|
|
KeptKindLedger = "ledger"
|
|
KeptKindLog = "log"
|
|
)
|
|
|
|
// KeptDeclared is one kept data a manifest declares: its local name, its kind and its layout.
|
|
type KeptDeclared struct {
|
|
Name string
|
|
Kind string
|
|
KeptLayout
|
|
}
|
|
|
|
// KeptDeclarations are every kept data a manifest declares, in the old sections and in `requires` by template, sorted by
|
|
// name and kind, once each: the one reader of what a module keeps (KeptStates is its states). An entry in `requires` is
|
|
// of its storage type's kind, a stream on the template log a log.
|
|
func KeptDeclarations(m Manifest) []KeptDeclared {
|
|
var out []KeptDeclared
|
|
for _, s := range m.State {
|
|
out = append(out, KeptDeclared{s.Name, KeptKindState, s.KeptLayout})
|
|
}
|
|
for _, l := range m.Logs {
|
|
out = append(out, KeptDeclared{l.Name, KeptKindLog, l.KeptLayout})
|
|
}
|
|
for _, s := range m.Streams {
|
|
out = append(out, KeptDeclared{s.Name, KeptKindStream, s.KeptLayout})
|
|
}
|
|
for _, o := range m.Objects {
|
|
out = append(out, KeptDeclared{o.Name, KeptKindObjects, o.KeptLayout})
|
|
}
|
|
for _, e := range m.BusState {
|
|
kind := KeptKindStream
|
|
switch {
|
|
case e.Storage == StorageKeyValue:
|
|
kind = KeptKindState
|
|
case e.Storage == StorageObjectStore:
|
|
kind = KeptKindObjects
|
|
case e.Storage == StorageLedger:
|
|
kind = KeptKindLedger
|
|
case e.Template == TemplateLog:
|
|
kind = KeptKindLog
|
|
}
|
|
out = append(out, KeptDeclared{e.Name, kind, e.KeptLayout})
|
|
}
|
|
sort.SliceStable(out, func(i, j int) bool {
|
|
if out[i].Name != out[j].Name {
|
|
return out[i].Name < out[j].Name
|
|
}
|
|
return out[i].Kind < out[j].Kind
|
|
})
|
|
once := out[:0]
|
|
for i, k := range out {
|
|
if i > 0 && k.Name == out[i-1].Name && k.Kind == out[i-1].Kind {
|
|
continue
|
|
}
|
|
once = append(once, k)
|
|
}
|
|
return once
|
|
}
|
|
|
|
// FormChange is one kept data whose form differs between the build a node runs and the one a want moves it to, by its
|
|
// name and kind: Running is its declaration in the running manifest and Applied in the one being applied, nil where that
|
|
// manifest declares none.
|
|
type FormChange struct {
|
|
Name string
|
|
Kind string
|
|
Running *KeptLayout
|
|
Applied *KeptLayout
|
|
}
|
|
|
|
// FormChanges are the kept data whose form differs between the running manifest and the one being applied, sorted by name
|
|
// and kind: declared by both at another form, or by one of them only (a form-0 declaration of either side included, so
|
|
// a revert to a manifest that declared it before is seen). Which of them is backed up before the move, and which restored
|
|
// at a revert, is the node agent's applying it (design 47); a kept data whose form is unchanged is never one.
|
|
func FormChanges(running, applied Manifest) []FormChange {
|
|
type key struct{ name, kind string }
|
|
before := map[key]KeptLayout{}
|
|
for _, k := range KeptDeclarations(running) {
|
|
before[key{k.Name, k.Kind}] = k.KeptLayout
|
|
}
|
|
after := map[key]KeptLayout{}
|
|
for _, k := range KeptDeclarations(applied) {
|
|
after[key{k.Name, k.Kind}] = k.KeptLayout
|
|
}
|
|
var out []FormChange
|
|
for k, r := range before {
|
|
a, has := after[k]
|
|
if has && a.Form == r.Form {
|
|
continue
|
|
}
|
|
c := FormChange{Name: k.name, Kind: k.kind, Running: &r}
|
|
if has {
|
|
c.Applied = &a
|
|
}
|
|
out = append(out, c)
|
|
}
|
|
for k, a := range after {
|
|
if _, has := before[k]; !has {
|
|
out = append(out, FormChange{Name: k.name, Kind: k.kind, Applied: &a})
|
|
}
|
|
}
|
|
sort.Slice(out, func(i, j int) bool {
|
|
if out[i].Name != out[j].Name {
|
|
return out[i].Name < out[j].Name
|
|
}
|
|
return out[i].Kind < out[j].Kind
|
|
})
|
|
return out
|
|
}
|