Files
mesh-controller/internal/inventory/source.go
T
jschoubben e76ba966b3 Merge fix/1121-holds-released: delivery 2 on the builds' new layout (issue 1121)
Delivery 2 deleted the move and chain_moved, so the layout of the builds under their modules is made by the controller's start (LayBuildsOut), recorded by the key layout.done in the builds bucket, retried every half minute with an urgent condition while it fails; the chain on the bus is refused until it exists. Its source readers use the module and pointer reads.
2026-10-18 13:39:24 +02:00

148 lines
5.4 KiB
Go

package inventory
import (
"context"
"github.com/novox/mesh-controller/internal/chain"
)
// A build whose source is unchanged is never a move (novox/hq issue 280).
//
// The builder says what each build was made from, hashed (its source fingerprint). Two successful
// builds of a module with one fingerprint are one build, whatever digests they made — an image is not
// byte-reproducible, and reading a rebuild's new image digest as a new build made a merge that never
// touched the bus demand a planned bus upgrade before anything could be sent to the machine running
// it. So:
//
// - a module's builds, newest request first, fall into runs of one fingerprint; **the oldest build of
// the newest run stands for the run**: its artifacts are the ones the mesh registers and hands
// every module that stands on it (Held), so a rebuild of an unchanged source changes nothing any
// machine is sent, and nothing standing on it moves either;
// - a build that failed its gate ends a run: what was put back is never what a later build stands for;
// - an empty fingerprint — a builder that predates it, a source that does not pin its build — is a
// run of its own, as every build was before.
// sourceRow is one successful build of a module, as the runs are read.
type sourceRow struct {
id, commit, fingerprint string
made []byte
manifest []byte
manifestDigest string
failedGate bool
}
// sourceRows is every successful build of each module (of one module, when named), newest request
// first.
func (i *Inventory) sourceRows(ctx context.Context, module string) (map[string][]sourceRow, []string, error) {
c, err := i.theChain(ctx)
if err != nil {
return nil, nil, err
}
return i.chainSourceRows(ctx, c, module)
}
// standing is, of a module's builds newest first, the index of the build that stands for the build at
// `from`: the oldest of the unbroken run of builds behind it with its source fingerprint.
func standing(builds []sourceRow, from int) int {
at := from
fp := builds[from].fingerprint
if fp == "" || builds[from].failedGate {
return at
}
for j := from + 1; j < len(builds); j++ {
if builds[j].fingerprint != fp || builds[j].failedGate {
break
}
at = j
}
return at
}
// StandingBuild is the build that stands for a module's build (novox/hq issue 280): the oldest build of
// the unbroken run of builds with its source fingerprint, at or before it — itself when its fingerprint
// is empty or it starts the run. Answers its id and the manifest it was recorded with; empty when the
// build is not a successful build of the module on record.
func (i *Inventory) StandingBuild(ctx context.Context, module, build string) (string, []byte, error) {
all, _, err := i.sourceRows(ctx, module)
if err != nil {
return "", nil, err
}
builds := all[module]
for k, b := range builds {
if b.id == build {
s := builds[standing(builds, k)]
if len(s.manifest) == 0 && s.manifestDigest != "" {
// The manifest is kept apart from the record (issue 1121): one Get.
c, err := i.theChain(ctx)
if err != nil {
return "", nil, err
}
raw, err := manifestOfRecord(ctx, c, chain.Build{ID: s.id, ManifestDigest: s.manifestDigest})
return s.id, raw, err
}
return s.id, s.manifest, nil
}
}
return "", nil, nil
}
// SourceFingerprints is, per module, per commit, the source fingerprint of the newest successful build
// from it that has one: module → commit → fingerprint. A commit whose builds carry none is absent.
func (i *Inventory) SourceFingerprints(ctx context.Context) (map[string]map[string]string, error) {
c, err := i.theChain(ctx)
if err != nil {
return nil, err
}
// Read from the commit pointers, which carry each commit's source fingerprint: no record is read (issue 1121).
return i.chainSourceFingerprints(ctx, c)
}
// BuildSourceFingerprints is SourceFingerprints for one module: commit → fingerprint.
func (i *Inventory) BuildSourceFingerprints(ctx context.Context, module string) (map[string]string, error) {
c, err := i.theChain(ctx)
if err != nil {
return nil, err
}
// This module's commit pointers only (issue 1121).
return i.chainBuildSourceFingerprints(ctx, c, module)
}
// heldMade is, per module, what the build standing for its newest successful build made — what Held
// answers (novox/hq issue 280).
func (i *Inventory) heldMade(ctx context.Context) (map[string][]Artifact, error) {
c, err := i.theChain(ctx)
if err != nil {
return nil, err
}
return i.chainHeldMade(ctx, c)
}
// SameSourceCommits is the commits of the builds in a build's run (novox/hq issue 280): the build and
// every build behind it back to the one standing for it, all made from one source. Empty when the
// build stands for itself — no earlier build was made from its source — so a commit alone never says
// two builds are one: a dependent rebuilt because its base moved keeps its commit and is a move.
func (i *Inventory) SameSourceCommits(ctx context.Context, module, build string) (map[string]bool, error) {
all, _, err := i.sourceRows(ctx, module)
if err != nil {
return nil, err
}
builds := all[module]
for k, b := range builds {
if b.id != build {
continue
}
s := standing(builds, k)
if s == k {
return nil, nil
}
out := map[string]bool{}
for j := k; j <= s; j++ {
if builds[j].commit != "" {
out[builds[j].commit] = true
}
}
return out, nil
}
return nil, nil
}