Files
mesh-delivery/modules/mesh-delivery-assigner/internal/acting/acting.go
T
jschoubben cd51fec81a B2l AS17 (4): §298's three order edges are acting waits of the assigner under order.
The new node-backup and bus module holders run before a module whose kept data's form changes moves; at a revert the node-engine goes
back last on its node; the reverted assigner and gate are wanted only once take-in.taken names the trunk's head (A-260). Kept in the
state waits, said as wait-held and wait-ended, read and released by assigner_waits and assigner_release. The manifest consumes the
indexer's take-in.taken and its version is 0.3 (A-245).

Builds: design 47 G §298, A-245, A-258, A-259, A-260
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 09:49:25 +01:00

141 lines
5.8 KiB
Go

// Package acting is the assigner's wait for an acting part's new version (design 47 G §266, §268, §276): an entry of the assignment
// graph whose edge of kind acting names a step the assigner holds (composing, placing) waits until the acting part's version runs
// on the node of the edge, with the bound of the rule that gave the edge, or the step's default. The package holds the rules and
// the kept record; the assigner's process reads what runs, says the events and keeps the records in its state `waits`.
package acting
import (
"encoding/json"
"fmt"
"strings"
"time"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
"git.novox.be/novox/mesh-sdk/go/seatdef"
)
// HowNow is the `how` of assigner_release for a wait for an acting part: the entry is wanted now, with the version running.
const HowNow = "now"
// The ways a wait ends, as `wait-ended` says them.
const (
HowRan = "ran"
HowReleased = "released"
HowReplaced = "replaced"
)
// Prefix opens the key of an acting wait in the state, apart from the outside waits' `<node>.<module>.<fingerprint hex>`.
const Prefix = "acting."
// OrderPrefix opens the key of an order wait (design 47 G §298, A-259): a want held for the order of a delivery that crosses a form change,
// kept beside the acting waits in the state `waits`, as `order.<node>.<module>.<part>`.
const OrderPrefix = "order."
// The three order edges of §298, as a kept wait's Order names them.
const (
// OrderBackup: the new versions of the node-backup holder and of the holder of the bus module's seat run before a module whose kept
// data's form changes is moved.
OrderBackup = "backup-and-broker-first"
// OrderEngineLast: at a revert a node's node-engine goes back last on that node.
OrderEngineLast = "node-engine-last"
// OrderTakenIn: the reverted assigner and gate are wanted only once the reverted indexer took in the trunk's head.
OrderTakenIn = "taken-in-first"
)
// Held says whether the assigner holds the entries of step: composing and placing (§276's table).
func Held(step string) bool { return step == seatdef.StepCompose || step == seatdef.StepPlace }
// Wait is one wait as kept: Module's entry on Node waits for Part's version Fp to run on PartNode, in Step.
type Wait struct {
V int `json:"v"`
Step string `json:"step"`
Node string `json:"node"`
Module string `json:"module"`
Part string `json:"part"`
PartNode string `json:"part-node"`
Fp string `json:"fp"`
Entry string `json:"entry"`
Since time.Time `json:"since"`
ClockFrom time.Time `json:"clock-from"`
Bound string `json:"bound"`
// Released is a release by hand: the entry moves on with the part's old version; EndSaid says wait-ended was said for it.
// Order is which of §298's edges the wait stands on; empty for an acting wait.
Order string `json:"order,omitempty"`
Released bool `json:"released,omitempty"`
EndSaid bool `json:"end-said,omitempty"`
By string `json:"by,omitempty"`
Why string `json:"why,omitempty"`
}
// Key is the key of a wait in the state.
func Key(node, module, part string) string { return Prefix + node + "." + module + "." + part }
// OrderKey is the key of an order wait in the state.
func OrderKey(node, module, part string) string {
return OrderPrefix + node + "." + module + "." + part
}
// IsOrder says a kept value is an order wait's record.
func IsOrder(key string) bool { return strings.HasPrefix(key, OrderPrefix) }
// Is says a kept value is an acting wait's record.
func Is(key string) bool { return strings.HasPrefix(key, Prefix) }
// Encode is w as JSON.
func Encode(w Wait) ([]byte, error) { w.V = 1; return json.Marshal(w) }
// Decode reads a kept wait.
func Decode(raw []byte) (Wait, error) {
var w Wait
if err := json.Unmarshal(raw, &w); err != nil {
return w, err
}
if w.V != 1 || w.Step == "" || w.Node == "" || w.Module == "" || w.Part == "" {
return w, fmt.Errorf("acting: %q is not a kept acting wait", raw)
}
return w, nil
}
// BoundOf is the bound of the edge's wait: its rule's, else its step's default (seatdef.ActingRule.Wait).
func BoundOf(e meshwants.Edge) time.Duration {
return seatdef.ActingRule{Step: e.Step, Bound: e.Bound}.Wait()
}
// Pending are the acting edges of the assigner's steps whose part's version does not run yet: runs says the edge's part runs
// its version on the edge's node.
func Pending(edges []meshwants.Edge, runs func(e meshwants.Edge) bool) []meshwants.Edge {
var out []meshwants.Edge
for _, e := range edges {
if e.Kind == "acting" && Held(e.Step) && !runs(e) {
out = append(out, e)
}
}
return out
}
// Body is the wait as the seat mesh-wants says it.
func Body(w Wait, owner string) meshwants.Wait {
since, from := w.Since.UTC(), w.ClockFrom.UTC()
return meshwants.Wait{Step: w.Step, Owner: owner, Node: w.Node, Module: w.Module, Part: w.Part, Fp: w.Fp, Since: since, ClockFrom: &from, Bound: w.Bound,
Words: words(w)}
}
func words(w Wait) string {
switch w.Order {
case OrderBackup:
return fmt.Sprintf("%s on %s moves its kept data across a form change: it waits in %s for %s at %s to run on %s, which the restore point needs", w.Module, w.Node, w.Step, w.Part, short(w.Fp), w.PartNode)
case OrderEngineLast:
return fmt.Sprintf("%s on %s goes back last on its node: it waits in %s for %s at %s to run on %s, restored", w.Module, w.Node, w.Step, w.Part, short(w.Fp), w.PartNode)
case OrderTakenIn:
return fmt.Sprintf("%s on %s goes back only once the indexer took in the trunk's head: it waits in %s for source revision %s to be taken in", w.Module, w.Node, w.Step, w.Fp)
}
return fmt.Sprintf("%s on %s waits in %s for %s at %s to run on %s", w.Module, w.Node, w.Step, w.Part, short(w.Fp), w.PartNode)
}
func short(fp string) string {
if len(fp) > 19 {
return fp[:19]
}
return fp
}