Files
mesh-catalog/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reached.go
T

103 lines
3.2 KiB
Go

package main
import (
"fmt"
"strings"
sdk "git.novox.be/novox/mesh-sdk/go/delivery"
)
// Whether a merge is on the machines (novox/hq ADR 0556 clause 4). The gate records only the merge (ADR 0539 §17, ADR 0429
// §1): it reads the delivery view's reach of each repository, which names the repository's reached head (the newest merge every
// node runs a build containing), and derives when asked, for a merged delivery, whether its merge is at or before that head.
// The order of two merges into one trunk is the gate's own: the moment each was merged, the trunk being a line of merges. A
// reached head the gate holds no merge of is said, never asked of the forge.
// reachState is the delivery view's state the gate reads.
const reachState = sdk.ViewModule + ".reach"
// ReachChanged takes one change of the view's reach.
func (h *Holder) ReachChanged(key string, value []byte, deleted bool) {
h.mu.Lock()
defer h.mu.Unlock()
if deleted {
delete(h.reach, key)
return
}
r, err := sdk.DecodeReach(value)
if err != nil {
h.Logf("[mesh-delivery] the view's reach %s is not readable, so its merges read as not known: %v", key, err)
delete(h.reach, key)
return
}
h.reach[key] = r
}
// The words a merged delivery's machines are said in.
const (
onMachines = "on the machines"
notYetOn = "not yet on the machines: "
notKnownWhere = "not known: "
)
// machines says whether a merged delivery's merge is on the machines, derived from the view's reach; empty for a delivery
// that is not merged. Under the lock.
func (h *Holder) machines(d *Delivery) string {
if d.State != Merged || d.MergedAs == "" {
return ""
}
key, err := sdk.RepositoryKey(d.Repository)
if err != nil {
return notKnownWhere + err.Error()
}
r, ok := h.reach[key]
switch {
case !ok:
return notKnownWhere + "the delivery view says no reach of " + d.Repository
}
// A merge that changed a module a node wants and runs nothing countable of is not yet there, whatever the reached head
// (the module holds no head back, ADR 0556 clause 2).
for _, mr := range r.Modules {
if mr.Nodes == 0 || mr.Floor != "" {
continue
}
for _, c := range mr.Changes {
if sameCommit(d.MergedAs, c.Commit) {
return notYetOn + mr.Waiting
}
}
}
switch {
case r.Reached == "":
return notYetOn + holdsSaid(r)
case sameCommit(d.MergedAs, r.Reached):
return onMachines
}
head := h.mergeOf(d.Repository, r.Reached)
switch {
case head == nil:
return notKnownWhere + fmt.Sprintf("the reached head %s of %s is no merge this gate holds", shortOf(r.Reached, 12), d.Repository)
case !d.MergedAt.After(head.MergedAt):
return onMachines
}
return notYetOn + holdsSaid(r)
}
// holdsSaid is what holds a repository's next head, in words.
func holdsSaid(r sdk.Reach) string {
if len(r.Holds) == 0 {
return "the delivery view names nothing that holds it yet"
}
return strings.Join(r.Holds, "; ")
}
// mergeOf is the delivery of a repository that merged as the commit; nil when none does. Under the lock.
func (h *Holder) mergeOf(repository, commit string) *Delivery {
for _, d := range h.deliveries {
if d.MergedAs != "" && strings.EqualFold(d.Repository, repository) && sameCommit(d.MergedAs, commit) {
return d
}
}
return nil
}