98 lines
3.5 KiB
Go
98 lines
3.5 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
)
|
|
|
|
// An assignment as the passing of a seat reads it: a module on a machine, with the manifest of the build that machine
|
|
// runs, else the trunk's (novox/hq ADR 0660 §2).
|
|
type Assignment struct {
|
|
Node string
|
|
Manifest Manifest
|
|
// Unread is an assignment whose manifest could not be read at all: it is still assigned, so its holdings stand,
|
|
// and it claims nothing.
|
|
Unread bool
|
|
}
|
|
|
|
// SeatPass is one seat whose holder on record has left it, and the only assignment that can take it.
|
|
type SeatPass struct {
|
|
Seat Seat
|
|
From Held
|
|
To Held
|
|
}
|
|
|
|
// SeatsToPassOn reads the mesh for seats held once whose holder on record has left (novox/hq ADR 0449 §4, ADR 0660).
|
|
//
|
|
// **A holder on record that is assigned on no machine, or whose every assignment's manifest no longer claims the seat
|
|
// (or claims it and cannot hold it, by CanHold), holds nothing.** Of such a seat, exactly one assignment in the mesh
|
|
// able to hold it takes it over: that is a pass, and the caller applies it and says it. An assignment is a module on
|
|
// one node, so one module placed on two nodes is two claimants. With no such assignment the record stays; with two or
|
|
// more nothing is passed and the answer says so, naming two and the `seat --to` that settles it. A holder with an
|
|
// assignment whose manifest still claims the seat changes nothing (ADR 0131), and so does one whose manifest could not
|
|
// be read. Only mesh seats held once are read: a replicated seat's holders are added by an act (ADR 0223), a kinded
|
|
// bench is held by its claims, and a seat with several holders on record is a store that disagrees with the mesh.
|
|
// Nothing here records a pass (ADR 0660 §4).
|
|
func SeatsToPassOn(holdings []Held, assignments []Assignment) ([]SeatPass, []string) {
|
|
bySeat := map[string][]Held{}
|
|
var order []string
|
|
for _, h := range holdings {
|
|
s, ok := SeatNamed(h.Claim)
|
|
if !ok || s.Replicated || s.Scope != ScopeMesh || h.Scope != ScopeMesh || KindedBenches[s.Name] {
|
|
continue
|
|
}
|
|
if _, seen := bySeat[s.Name]; !seen {
|
|
order = append(order, s.Name)
|
|
}
|
|
bySeat[s.Name] = append(bySeat[s.Name], h)
|
|
}
|
|
sort.Strings(order)
|
|
|
|
var passes []SeatPass
|
|
var said []string
|
|
for _, name := range order {
|
|
recs := bySeat[name]
|
|
if len(recs) != 1 {
|
|
continue
|
|
}
|
|
seat, _ := SeatNamed(name)
|
|
holds := false
|
|
for _, a := range assignments {
|
|
if a.Manifest.Module != recs[0].Module {
|
|
continue
|
|
}
|
|
if a.Unread || CanHold(a.Manifest, seat) == nil {
|
|
holds = true
|
|
}
|
|
}
|
|
if holds {
|
|
continue
|
|
}
|
|
var claimants []Held
|
|
for _, a := range assignments {
|
|
if a.Unread || CanHold(a.Manifest, seat) != nil {
|
|
continue
|
|
}
|
|
claimants = append(claimants, Held{Claim: seat.Name, Scope: seat.Scope, Node: a.Node, Module: a.Manifest.Module})
|
|
}
|
|
sort.Slice(claimants, func(i, j int) bool {
|
|
if claimants[i].Node != claimants[j].Node {
|
|
return claimants[i].Node < claimants[j].Node
|
|
}
|
|
return claimants[i].Module < claimants[j].Module
|
|
})
|
|
switch len(claimants) {
|
|
case 0:
|
|
case 1:
|
|
passes = append(passes, SeatPass{Seat: seat, From: recs[0], To: claimants[0]})
|
|
default:
|
|
said = append(said, fmt.Sprintf(
|
|
"%s on %s is on record as the holder of %q and holds it nowhere, and %s on %s and %s on %s both claim it "+
|
|
"— nothing is passed; `seat %s --to <node>/<module>` records the one that holds it",
|
|
recs[0].Module, recs[0].Node, seat.Name, claimants[0].Module, claimants[0].Node,
|
|
claimants[1].Module, claimants[1].Node, seat.Name))
|
|
}
|
|
}
|
|
return passes, said
|
|
}
|