VW3: the view's tiers are the assigner's difference of a source revision's kept revision
view_tiers compares the kept assignment revision whose catalog carries the source revision with the one kept before it, through the seat mesh-wants' verbs revision and difference (view/difference.go, tiers.go Tiers), and reads the tiers and each module's after (module and edge kind) from the answer; the view orders nothing. The manifest invokes the two verbs. Builds: design 47 G §512, §186, A-242
This commit is contained in:
@@ -438,6 +438,7 @@ func main() {
|
||||
r.ConditionsState, r.AttemptsState = read(stdio.State(view.StatusConditionsState)), read(stdio.State(view.StatusAttemptsState))
|
||||
r.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState))
|
||||
r.Sources = view.SourcesOf(stdio.Ask, branches.Followed)
|
||||
r.Assignment, r.Difference = view.AssignmentOf(stdio.Ask), view.DifferenceOf(stdio.Ask)
|
||||
r.ProvisionsState = read(stdio.State(view.ProvisionsRead))
|
||||
r.BuildLog = stdio.Log(builds.BuildLogRead).Since
|
||||
r.Pending = pendingOf
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshdelivery"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
"mesh-delivery-view/internal/view"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -16,9 +17,7 @@ import (
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/graph"
|
||||
)
|
||||
@@ -41,10 +40,6 @@ func short(fp string) string { return fp[:len("src2:")+12] }
|
||||
func tiersToolSaysEachModulesWait(t *testing.T) {
|
||||
fp := func(c string) string { return "src2:" + strings.Repeat(c, 64) }
|
||||
manifest := strings.Repeat("d", 64)
|
||||
mod := func(f string, src uint64) string {
|
||||
b, err := meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{Fp2: f, Manifest: manifest, Src: int64(src), FpSrc: int64(src), Repository: "novox/mesh-catalog", Commit: "c"})
|
||||
return encoded(t, b, err)
|
||||
}
|
||||
node := func(g graph.Node) string {
|
||||
b, err := graph.Encode(g)
|
||||
return encoded(t, b, err)
|
||||
@@ -68,7 +63,35 @@ func tiersToolSaysEachModulesWait(t *testing.T) {
|
||||
return k
|
||||
}
|
||||
since := time.Date(2026, 11, 3, 16, 40, 0, 0, time.UTC)
|
||||
r := fake{"db": mod(fp("a"), 9), "web": mod(fp("b"), 9), "lib": mod(fp("c"), 9), "old": mod(fp("e"), 5)}.reader()
|
||||
r := fake{}.reader()
|
||||
// The tiers are the assigner's difference of the kept revision carrying source revision 9 against the one before it (design
|
||||
// 47 G §512, A-242): db and lib first, web after db by its provisioning edge; the view orders nothing.
|
||||
ref := func(m string) meshwants.NodeEntryRef { return meshwants.NodeEntryRef{Node: "ace", Module: m, Digest: "sha256:" + m} }
|
||||
kept := map[int64]meshwants.AssignmentRevision{
|
||||
3: {Revision: 3, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 2, Source: 5}}},
|
||||
4: {Revision: 4, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 3, Source: 8}}},
|
||||
5: {Revision: 5, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 4, Source: 9}}},
|
||||
6: {Revision: 6, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 4, Source: 9}}},
|
||||
}
|
||||
differences := map[[2]int64]meshwants.Difference{{4, 5}: {From: 4, To: 5,
|
||||
Changes: []meshwants.Change{{Node: "ace", Module: "db", To: fp("a")}, {Node: "ace", Module: "lib", To: fp("c")},
|
||||
{Node: "ace", Module: "web", To: fp("b"), After: []meshwants.ChangeAfterItem{{Node: "ace", Module: "db", Kind: "provisioning"}}}},
|
||||
Tiers: [][]meshwants.NodeEntryRef{{ref("db"), ref("lib")}, {ref("web")}}}}
|
||||
r.Assignment = func(n int64) (meshwants.AssignmentRevision, error) {
|
||||
if n == 0 {
|
||||
n = 6
|
||||
}
|
||||
if rev, ok := kept[n]; ok {
|
||||
return rev, nil
|
||||
}
|
||||
return meshwants.AssignmentRevision{}, errors.New("not kept")
|
||||
}
|
||||
r.Difference = func(from, to int64) (meshwants.Difference, error) {
|
||||
if d, ok := differences[[2]int64{from, to}]; ok {
|
||||
return d, nil
|
||||
}
|
||||
return meshwants.Difference{}, fmt.Errorf("no difference of %d and %d", from, to)
|
||||
}
|
||||
r.GraphState = fake{
|
||||
"db": node(graph.Node{FP: fp("a"), Repository: "novox/mesh-catalog", Provides: []string{"database"}}),
|
||||
"web": node(graph.Node{FP: fp("b"), Repository: "novox/mesh-catalog", Requires: []string{"database"}, Awaits: []string{"database"}}),
|
||||
@@ -103,7 +126,7 @@ func tiersToolSaysEachModulesWait(t *testing.T) {
|
||||
t.Errorf("the first tier = %s, want db with no wait and lib's build waiting for its package", first)
|
||||
}
|
||||
web := got.Tiers[1][0]
|
||||
if web.Module != "web" || !reflect.DeepEqual(web.After, []string{"db"}) || len(web.Waits) != 2 ||
|
||||
if web.Module != "web" || !reflect.DeepEqual(web.After, []view.TierAfter{{Module: "db", Kind: "provisioning"}}) || len(web.Waits) != 2 ||
|
||||
web.Waits[0].Edge != "want" || web.Waits[0].Node != "ace" || web.Waits[0].Rule != meshwantsclient.RuleProvisions || !web.Waits[0].Since.Equal(since) ||
|
||||
web.Waits[1].Edge != "provision database" || !strings.Contains(web.Waits[1].Words, "asked: the build db runs does not offer it") {
|
||||
t.Errorf("web = %+v, want after db, held on ace by the provision rule and its provision asked (g14 is away)", web)
|
||||
@@ -181,17 +204,22 @@ func tiersToolSaysEachModulesWait(t *testing.T) {
|
||||
t.Errorf("web held by %q = %+v, want its want named %s, no wait for a bus-state key and db.loop left out", words, web, edge)
|
||||
}
|
||||
}
|
||||
// The graph not readable: every module in the first tier, said; past 500 modules the answer says it is cut short.
|
||||
r.GraphState = view.StateRead{Keys: func() ([]string, error) { return nil, errors.New("no bucket") }, Get: r.GraphState.Get}
|
||||
if out, err := run(t, r, view.TiersTool, map[string]any{"revision": float64(9)}); err != nil || len(out.(view.Tiers).Tiers) != 1 ||
|
||||
!strings.Contains(out.(view.Tiers).Graph, "cannot be read") {
|
||||
t.Errorf("view_tiers with no graph = %+v, %v", out, err)
|
||||
// No revision kept before the one carrying the source: said, and no module named; past 500 modules the answer says it is cut
|
||||
// short.
|
||||
delete(kept, 4)
|
||||
delete(kept, 3)
|
||||
if out, err := run(t, r, view.TiersTool, map[string]any{"revision": float64(9)}); err != nil || len(out.(view.Tiers).Tiers) != 0 ||
|
||||
!strings.Contains(out.(view.Tiers).Graph, "no assignment revision is kept before") {
|
||||
t.Errorf("view_tiers with no earlier revision = %+v, %v", out, err)
|
||||
}
|
||||
many := fake{}
|
||||
kept[4] = meshwants.AssignmentRevision{Revision: 4, Catalogs: []meshwants.CatalogOf{{Branch: "release", Source: 8}}}
|
||||
big := meshwants.Difference{From: 4, To: 5, Tiers: [][]meshwants.NodeEntryRef{{}}}
|
||||
for i := 0; i < view.TiersMost+2; i++ {
|
||||
many[fmt.Sprintf("m%03d", i)] = mod(fp("a"), 9)
|
||||
m := fmt.Sprintf("m%03d", i)
|
||||
big.Changes = append(big.Changes, meshwants.Change{Node: "ace", Module: m, To: fp("a")})
|
||||
big.Tiers[0] = append(big.Tiers[0], ref(m))
|
||||
}
|
||||
r.State = many.reader().State
|
||||
differences[[2]int64{4, 5}] = big
|
||||
if out, err := run(t, r, view.TiersTool, map[string]any{"revision": "9"}); err != nil || out.(view.Tiers).Modules != view.TiersMost+2 ||
|
||||
!strings.Contains(out.(view.Tiers).Cut, "the first 500") {
|
||||
t.Errorf("view_tiers past its bound = %+v, %v", out.(view.Tiers).Cut, err)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
"git.novox.be/novox/mesh-sdk/go/buscalls"
|
||||
)
|
||||
|
||||
// The seat mesh-wants' verbs revision and difference as the view's invokes names them: the tiers of a source revision are
|
||||
// read through them and worked out nowhere in the view (design 47 G §512, §186, A-242).
|
||||
const (
|
||||
RevisionVerb = "seat:" + meshwants.Seat + "." + meshwants.VerbRevision
|
||||
DifferenceVerb = "seat:" + meshwants.Seat + "." + meshwants.VerbDifference
|
||||
)
|
||||
|
||||
// WalkMost is the most kept assignment revisions a source revision's revision is looked for through, newest first.
|
||||
const WalkMost = 256
|
||||
|
||||
// callSeat asks verb with body through call and reads its declared answer into out.
|
||||
func callSeat(call func(key string, body any) (json.RawMessage, error), verb string, body, out any) error {
|
||||
raw, err := call(verb, body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", verb, err)
|
||||
}
|
||||
answer, said, ok := buscalls.Unwrap(raw)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s answered: %s", verb, said)
|
||||
}
|
||||
if err := json.Unmarshal(answer, out); err != nil {
|
||||
return fmt.Errorf("the answer of %s does not read: %w", verb, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignmentOf asks the seat for one kept assignment graph revision (0: the trunk's newest).
|
||||
func AssignmentOf(call func(key string, body any) (json.RawMessage, error)) func(revision int64) (meshwants.AssignmentRevision, error) {
|
||||
return func(revision int64) (meshwants.AssignmentRevision, error) {
|
||||
var a meshwants.RevisionAnswer
|
||||
err := callSeat(call, RevisionVerb, meshwants.RevisionInput{Revision: revision}, &a)
|
||||
return a.Revision, err
|
||||
}
|
||||
}
|
||||
|
||||
// DifferenceOf asks the seat for the difference of two kept revisions.
|
||||
func DifferenceOf(call func(key string, body any) (json.RawMessage, error)) func(from, to int64) (meshwants.Difference, error) {
|
||||
return func(from, to int64) (meshwants.Difference, error) {
|
||||
var d meshwants.Difference
|
||||
err := callSeat(call, DifferenceVerb, meshwants.DifferenceInput{From: from, To: to}, &d)
|
||||
return d, err
|
||||
}
|
||||
}
|
||||
|
||||
// revisionsOf finds the kept assignment revisions that carry the source revision for a watched branch: to the first of them
|
||||
// (the one whose change it is) and from the revision kept before it, walking back from the newest. A zero from says there is
|
||||
// none before it.
|
||||
func (r Reader) revisionsOf(source uint64) (from, to int64, err error) {
|
||||
if r.Assignment == nil || r.Difference == nil {
|
||||
return 0, 0, fmt.Errorf("the assigner's revisions cannot be read here")
|
||||
}
|
||||
newest, err := r.Assignment(0)
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("the assigner's newest revision: %w", err)
|
||||
}
|
||||
carries := func(rev meshwants.AssignmentRevision) bool {
|
||||
for _, c := range rev.Catalogs {
|
||||
if c.Source > 0 && uint64(c.Source) == source {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
for n, steps := newest.Revision, 0; n >= 1 && steps < WalkMost; n, steps = n-1, steps+1 {
|
||||
rev := newest
|
||||
if n != newest.Revision {
|
||||
if rev, err = r.Assignment(n); err != nil {
|
||||
continue // a revision no longer kept
|
||||
}
|
||||
}
|
||||
if !carries(rev) {
|
||||
if to != 0 {
|
||||
return rev.Revision, to, nil // the kept revision before the first that carries it
|
||||
}
|
||||
continue
|
||||
}
|
||||
to = rev.Revision
|
||||
}
|
||||
if to == 0 {
|
||||
return 0, 0, fmt.Errorf("no kept assignment revision of the assigner carries the source revision %d", source)
|
||||
}
|
||||
return 0, to, nil
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/trunk"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate"
|
||||
@@ -72,6 +73,10 @@ type Reader struct {
|
||||
// Sources is the newest source revision of each watched branch, by branch name, as the seat mesh-delivery's verb source
|
||||
// answers it (design 47 G §507, A-173): what view_tiers given no revision answers per branch. Unset, it must be named.
|
||||
Sources func() (map[string]uint64, error)
|
||||
// Assignment and Difference are the seat mesh-wants' verbs revision and difference (AssignmentOf, DifferenceOf): what
|
||||
// view_tiers works the tiers of a source revision from (design 47 G §512, A-242).
|
||||
Assignment func(revision int64) (meshwants.AssignmentRevision, error)
|
||||
Difference func(from, to int64) (meshwants.Difference, error)
|
||||
// Pending reads the indexer's waits through its tool indexer_pending (ADR 0633 §5); unset names no module held back.
|
||||
Pending func() (takein.PendingAnswer, error)
|
||||
// BuildLog reads the builder's log from a time (stdio.Log(builds.BuildLogRead).Since); unset reads none.
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/graph"
|
||||
)
|
||||
@@ -48,7 +48,6 @@ type Tiers struct {
|
||||
Tiers [][]TierModule `json:"tiers"`
|
||||
Cut string `json:"cut,omitempty"`
|
||||
Graph string `json:"graph,omitempty"`
|
||||
Cycle []string `json:"cycle,omitempty"`
|
||||
Away []string `json:"away,omitempty"`
|
||||
// Pending says why the indexer's waits could not be read, so no module is named held by its revision's indexer (ADR 0633 §5).
|
||||
Pending string `json:"pending,omitempty"`
|
||||
@@ -58,12 +57,18 @@ type Tiers struct {
|
||||
// wait of its own now (no wait is a module that reached every node present), and the verbs it invokes whose edge the
|
||||
// module graph leaves out on a cycle, so nothing waits on them (LeftOut, ADR 0614 §3).
|
||||
type TierModule struct {
|
||||
Module string `json:"module"`
|
||||
FP string `json:"fp,omitempty"`
|
||||
None string `json:"none,omitempty"`
|
||||
After []string `json:"after,omitempty"`
|
||||
Waits []TierWait `json:"waits,omitempty"`
|
||||
LeftOut []string `json:"left-out,omitempty"`
|
||||
Module string `json:"module"`
|
||||
// FP is the build: the fingerprint the difference says the module is to run.
|
||||
FP string `json:"build,omitempty"`
|
||||
After []TierAfter `json:"after,omitempty"`
|
||||
Waits []TierWait `json:"waits,omitempty"`
|
||||
LeftOut []string `json:"left-out,omitempty"`
|
||||
}
|
||||
|
||||
// TierAfter is a module a module is ordered after, with the kind of the edge that orders it (design 47 G §512, §378).
|
||||
type TierAfter struct {
|
||||
Module string `json:"module"`
|
||||
Kind string `json:"kind"`
|
||||
}
|
||||
|
||||
// TierWait is one thing a module waits on: the edge (build, have, provision <name>, or for a want held back want, verb
|
||||
@@ -111,32 +116,47 @@ func (r Reader) Newest() (BranchTiers, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Tiers works out the tiers of one source revision (not 0).
|
||||
// Tiers works out the tiers of one source revision (not 0): the difference of the kept assignment revision that carries it
|
||||
// against the one kept before it, as the assigner's verb difference answers it with its tiers and each change's after
|
||||
// (design 47 G §512, §186, A-242). The view orders nothing itself.
|
||||
func (r Reader) Tiers(revision uint64) (Tiers, error) {
|
||||
if revision == 0 {
|
||||
return Tiers{}, fmt.Errorf("name the source revision")
|
||||
}
|
||||
modules, err := values(r.State)
|
||||
out := Tiers{Revision: revision}
|
||||
from, to, err := r.revisionsOf(revision)
|
||||
if err != nil {
|
||||
return Tiers{}, fmt.Errorf("the indexer's modules: %w", err)
|
||||
return Tiers{}, err
|
||||
}
|
||||
moved := map[string]meshcatalog.ModulesByModuleValue{}
|
||||
for key, raw := range modules {
|
||||
if m, err := meshcatalogclient.DecodeModule(raw); err == nil && uint64(m.FpSrc) == revision {
|
||||
moved[key] = m
|
||||
var d meshwants.Difference
|
||||
if from > 0 {
|
||||
if d, err = r.Difference(from, to); err != nil {
|
||||
return Tiers{}, fmt.Errorf("the assigner's difference of %d and %d: %w", from, to, err)
|
||||
}
|
||||
} else {
|
||||
out.Graph = fmt.Sprintf("no assignment revision is kept before %d, so the difference names nothing", to)
|
||||
}
|
||||
// One module per name, in the highest tier any of its nodes is in; the changes name each module's build and what it is
|
||||
// ordered after.
|
||||
changes := map[string][]meshwants.Change{}
|
||||
for _, c := range d.Changes {
|
||||
changes[c.Module] = append(changes[c.Module], c)
|
||||
}
|
||||
tierOf := map[string]int{}
|
||||
for i, tier := range d.Tiers {
|
||||
for _, ref := range tier {
|
||||
tierOf[ref.Module] = max(tierOf[ref.Module], i)
|
||||
}
|
||||
}
|
||||
out := Tiers{Revision: revision, Modules: len(moved)}
|
||||
names := slices.Sorted(maps.Keys(moved))
|
||||
names := slices.Sorted(maps.Keys(changes))
|
||||
out.Modules = len(names)
|
||||
if len(names) > TiersMost {
|
||||
out.Cut = fmt.Sprintf("the revision moves %d modules: the first %d by name are shown, %s and the %d after it are not",
|
||||
len(names), TiersMost, names[TiersMost], len(names)-TiersMost-1)
|
||||
names = names[:TiersMost]
|
||||
}
|
||||
gr := graph.Graph{}
|
||||
if raws, err := values(r.GraphState); err != nil {
|
||||
out.Graph = "the module graph cannot be read, so no module is ordered after another: " + err.Error()
|
||||
} else {
|
||||
if raws, err := values(r.GraphState); err == nil {
|
||||
for key, raw := range raws {
|
||||
if n, err := graph.Decode(raw); err == nil {
|
||||
gr[key] = n
|
||||
@@ -148,87 +168,45 @@ func (r Reader) Tiers(revision uint64) (Tiers, error) {
|
||||
wants, _ := values(r.WantsState)
|
||||
provided, perr := values(r.ProvisionsState)
|
||||
held, heldAll := r.heldBack(&out)
|
||||
|
||||
// The ordering among the revision's modules: each one's tier is one past the highest of the modules it waits for.
|
||||
in := map[string]bool{}
|
||||
for _, n := range names {
|
||||
in[n] = true
|
||||
}
|
||||
after := map[string][]string{}
|
||||
for _, n := range names {
|
||||
for _, b := range gr.Before(n) {
|
||||
if in[b] {
|
||||
after[n] = append(after[n], b)
|
||||
}
|
||||
}
|
||||
}
|
||||
sub := graph.Graph{}
|
||||
for _, n := range names {
|
||||
if g, ok := gr[n]; ok {
|
||||
sub[n] = g
|
||||
}
|
||||
}
|
||||
out.Cycle = sub.Cycle()
|
||||
tier := map[string]int{}
|
||||
var level func(string, map[string]bool) int
|
||||
level = func(n string, visiting map[string]bool) int {
|
||||
if t, ok := tier[n]; ok {
|
||||
return t
|
||||
}
|
||||
if visiting[n] {
|
||||
return -1
|
||||
}
|
||||
visiting[n] = true
|
||||
t := 0
|
||||
for _, b := range after[n] {
|
||||
lb := level(b, visiting)
|
||||
if lb < 0 {
|
||||
return -1
|
||||
}
|
||||
t = max(t, lb+1)
|
||||
}
|
||||
delete(visiting, n)
|
||||
tier[n] = t
|
||||
return t
|
||||
}
|
||||
top := 0
|
||||
for _, n := range names {
|
||||
if t := level(n, map[string]bool{}); t > top {
|
||||
top = t
|
||||
}
|
||||
}
|
||||
for _, n := range names {
|
||||
if _, ok := tier[n]; !ok {
|
||||
tier[n] = top + 1 // on a cycle: after every tier that is ordered
|
||||
}
|
||||
}
|
||||
for _, n := range names {
|
||||
t := tier[n]
|
||||
t := tierOf[n]
|
||||
for len(out.Tiers) <= t {
|
||||
out.Tiers = append(out.Tiers, nil)
|
||||
}
|
||||
m := moved[n]
|
||||
tm := TierModule{Module: n, FP: m.Fp2, None: m.None2, After: after[n], LeftOut: gr[n].LeftOut}
|
||||
tm.Waits = r.waitsOf(n, m, gr[n], wants, provided, perr, away)
|
||||
tm := TierModule{Module: n, LeftOut: gr[n].LeftOut}
|
||||
seen := map[string]bool{}
|
||||
for _, c := range changes[n] {
|
||||
if tm.FP == "" {
|
||||
tm.FP = c.To
|
||||
}
|
||||
for _, a := range c.After {
|
||||
if k := a.Module + "\x00" + a.Kind; !seen[k] && a.Module != n {
|
||||
seen[k] = true
|
||||
tm.After = append(tm.After, TierAfter{Module: a.Module, Kind: a.Kind})
|
||||
}
|
||||
}
|
||||
}
|
||||
slices.SortFunc(tm.After, func(a, b TierAfter) int { return strings.Compare(a.Module+"\x00"+a.Kind, b.Module+"\x00"+b.Kind) })
|
||||
tm.Waits = r.waitsOf(n, meshcatalog.ModulesByModuleValue{Fp2: tm.FP}, gr[n], wants, provided, perr, away)
|
||||
if w, ok := held[n]; ok {
|
||||
tm.Waits = append(tm.Waits, w)
|
||||
}
|
||||
out.Tiers[t] = append(out.Tiers[t], tm)
|
||||
}
|
||||
// A module the indexer holds back is not at the revision yet, so no tier of it names it: it is named in the first tier with
|
||||
// its wait alone (ADR 0633 §5), with the fingerprint the indexer last took in.
|
||||
// its wait alone (ADR 0633 §5).
|
||||
for _, n := range heldAll {
|
||||
if in[n] {
|
||||
continue
|
||||
}
|
||||
tm := TierModule{Module: n, Waits: []TierWait{held[n]}}
|
||||
if m, err := meshcatalogclient.DecodeModule(modules[n]); err == nil {
|
||||
tm.FP, tm.None = m.Fp2, m.None2
|
||||
}
|
||||
if len(out.Tiers) == 0 {
|
||||
out.Tiers = append(out.Tiers, nil)
|
||||
}
|
||||
out.Tiers[0] = append(out.Tiers[0], tm)
|
||||
out.Tiers[0] = append(out.Tiers[0], TierModule{Module: n, Waits: []TierWait{held[n]}})
|
||||
}
|
||||
compact := out.Tiers[:0]
|
||||
for _, t := range out.Tiers {
|
||||
|
||||
@@ -157,6 +157,8 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7
|
||||
{Verb: "seat:mesh-catalog.seat-definitions"}, // design 47 G A-82, §204: the build seats are read from the seat list
|
||||
{Verb: "seat:mesh-hand-acts.hand-act"}, // the join: its first view asked again by hand is a hand act (views.StatusTools)
|
||||
{Verb: "seat:mesh-module-assigner.assignments"}, // A-82: the holder of each build seat
|
||||
{Verb: "seat:mesh-wants.revision"}, // §512, A-242: view_tiers compares kept assignment revisions
|
||||
{Verb: "seat:mesh-wants.difference"}, // §512, A-242: the tiers and each change's after are the assigner's
|
||||
{Verb: "seat:node-engine.manifest-reads"}}; !reflect.DeepEqual(m.Invokes, want) { // ADR 0618 §3: node_manifest_reads asks the node-engine seat's verb of every node; 1585/T24: view_tiers asks indexer_pending, a verb edge (ADR 0614 §2)
|
||||
t.Errorf("invokes = %v, want %v", m.Invokes, want)
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
"seat:mesh-catalog.seat-definitions",
|
||||
"seat:mesh-hand-acts.hand-act",
|
||||
"seat:mesh-module-assigner.assignments",
|
||||
"seat:mesh-wants.revision",
|
||||
"seat:mesh-wants.difference",
|
||||
"seat:node-engine.manifest-reads"
|
||||
],
|
||||
"reads": [
|
||||
|
||||
Reference in New Issue
Block a user