package catalogue import ( "fmt" "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"` } // refuse is the one reading of a layout's form every kept kind's decoder calls: a form is a whole number from 0, and one // below it is refused here, naming the declaration (`what` is its kind and name, such as `state "seen"`). func (k KeptLayout) refuse(what string) error { if k.Form < 0 { return fmt.Errorf("%s: its form is %d; a form is a whole number from 0, which its holder raises when it changes how "+ "it writes it", what, k.Form) } return nil } // 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 }