CAT-D3: mirror answers at once and the holder says the copy's end on the seat's events

A large base could outlast a call's bound. The ask is kept in the state mirrors and the copy runs on that state's
watch, so a copy a restart cut is taken on again; published (or refused, with why) on container-image-registry's
events is the end the caller waits on, the place the seat's contract already gives mirror.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 13:19:46 +01:00
parent e34fcbeda3
commit 9f01b9e79a
5 changed files with 133 additions and 13 deletions
@@ -210,6 +210,34 @@ func learnInto(state casState, module, fp string, attempts int) (bool, error) {
return false, fmt.Errorf("%s was written by another writer first %d times: %w", holder.PublishingKey, attempts, stdio.ErrChanged)
}
// mirrors is the state mirrors: an ask is created once; one already kept is the same copy, taken on already.
type mirrors struct{}
func (mirrors) Ask(key string, r holder.MirrorRequest) error {
if _, err := stdio.State(holder.MirrorsState).Create(key, r); err != nil && !errors.Is(err, stdio.ErrChanged) {
return err
}
return nil
}
func (mirrors) Delete(key string) error { return stdio.State(holder.MirrorsState).Delete(key) }
// followMirrors runs every copy `mirror` took on, on the state's watch: the asks kept when the bundle starts (a copy a
// restart cut) and each new one, one at a time.
func followMirrors(v *holder.Verbs) {
<-stdio.Served()
stdio.State(holder.MirrorsState).Follow("", func(ch stdio.StateChange) error {
if ch.Op != stdio.OpPut {
return nil
}
var r holder.MirrorRequest
if err := json.Unmarshal(ch.Value, &r); err != nil {
logf("the mirror ask %s is no ask (%v): dropped", ch.Key, err)
return stdio.State(holder.MirrorsState).Delete(ch.Key)
}
return v.Mirrored(r)
})
}
func arg[T any](args map[string]any) (T, error) {
var v T
clean := map[string]any{}
@@ -319,7 +347,7 @@ func tools(v *holder.Verbs, windows kept[holder.Window]) []stdio.Tool {
}
return tagsAnswer(v, a), nil
}},
stdio.Tool{Name: holder.ImageSeat + "." + holder.VerbMirror, Description: "Copy an outside image, pinned by its digest, into the store as upstream/<host>/<path> (every platform, only the parts it lacks) and answer its reference; says published (mesh-build-image alone).",
stdio.Tool{Name: holder.ImageSeat + "." + holder.VerbMirror, Description: "Copy an outside image, pinned by its digest, into the store as upstream/<host>/<path> (every platform, only the parts it lacks): answers at once with the reference the copy will have, and says published (or refused, with why) on the seat's events when the copy ends; wait on that event (mesh-build-image alone).",
Input: obj(map[string]any{"source": s("<host>/<path>"), "digest": s("sha256:…")}, "source", "digest"),
Run: func(args map[string]any) (any, error) {
in, err := arg[reg.MirrorInput](args)
@@ -409,7 +437,8 @@ func main() {
store := &holder.OCI{Base: base, Registry: os.Getenv("MESH_REGISTRY_REACH"), Upstream: &holder.Upstream{}}
h := &holder.Holder{Callers: callers, Objects: objects{}, Builder: builderVersions{}, Store: store, Say: say, Finding: finding,
Transfers: kept[holder.Transfer]{state: holder.TransfersState, key: func(t holder.Transfer) string { return t.ID }}}
v := &holder.Verbs{Holder: h, Catalog: store, Holds: kept[holder.Hold]{state: "holds", key: holder.Hold.Key}}
v := &holder.Verbs{Holder: h, Catalog: store, Holds: kept[holder.Hold]{state: "holds", key: holder.Hold.Key}, Mirrors: mirrors{}}
go followMirrors(v)
windows := kept[holder.Window]{state: "windows", key: func(w holder.Window) string { return w.Name }}
closeBootstrap = bootstrapCloser(windows)
if err := stdio.Serve("", tools(v, windows)); err != nil {
@@ -84,8 +84,9 @@ type bed struct {
}
type fakeCatalog struct {
tags map[string]string // name:version -> digest
removed []string
tags map[string]string // name:version -> digest
removed []string
mirrorErr error
}
func (c *fakeCatalog) Versions(name string) ([]string, error) {
@@ -110,8 +111,25 @@ func (c *fakeCatalog) RemoveDigest(name, digest string) error {
return nil
}
func (c *fakeCatalog) Mirror(source, digest string) (string, error) {
return "registry.mesh/upstream/" + source + "@" + digest, nil
if c.mirrorErr != nil {
return "", c.mirrorErr
}
src, _ := ParseSource(source)
return c.Reference(src.Name(), digest), nil
}
func (c *fakeCatalog) Reference(name, digest string) string {
return "registry.mesh/" + name + "@" + digest
}
type memMirrors map[string]MirrorRequest
func (m memMirrors) Ask(k string, r MirrorRequest) error {
if _, ok := m[k]; !ok {
m[k] = r
}
return nil
}
func (m memMirrors) Delete(k string) error { delete(m, k); return nil }
type memHolds map[string]Hold
@@ -135,7 +153,7 @@ func newBed(builderOK bool) *bed {
return nil
},
Finding: func(kind, subject, _ string, raised bool) { b.findings[kind+" "+subject] = raised }}
b.v = &Verbs{Holder: b.h, Catalog: b.cat, Holds: memHolds{}}
b.v = &Verbs{Holder: b.h, Catalog: b.cat, Holds: memHolds{}, Mirrors: memMirrors{}}
return b
}
@@ -412,6 +430,29 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) {
}
}
})
t.Run("mirror answers at once and says the copy's end on the seat's events", func(t *testing.T) {
b := newBed(true)
d := "sha256:" + strings.Repeat("c", 64)
ref, err := b.v.Mirror(ImageSeat, "novox.mesh-build-image", MirrorRequest{Source: "docker.io/library/nats:2", Digest: d})
want := "registry.mesh/upstream/docker.io/library/nats@" + d
key := MirrorsKey("upstream/docker.io/library/nats", d)
asked := b.v.Mirrors.(memMirrors)
if err != nil || ref != want || len(b.said) != 0 || asked[key].By != "novox.mesh-build-image" {
t.Fatalf("mirror = %q, %v, said %v, asks %v: want the reference at once, the copy asked, nothing said yet", ref, err, b.said, asked)
}
if strings.ContainsAny(key, ":@") {
t.Errorf("the ask's key %q holds characters a key may not", key)
}
if err := b.v.Mirrored(asked[key]); err != nil || len(b.said) != 1 || b.said[0].event != EventPublished ||
b.said[0].body.Reference != want || b.said[0].body.Kind != KindUpstream || len(asked) != 0 {
t.Fatalf("the copy's end = %v, said %+v, asks %v: want published with the reference and the ask gone", err, b.said, asked)
}
b.cat.mirrorErr = errors.New("the upstream said 404")
_, _ = b.v.Mirror(ImageSeat, "novox.mesh-build-image", MirrorRequest{Source: "nats", Digest: d})
if err := b.v.Mirrored(asked[key]); err != nil || b.said[1].event != EventRefused || !strings.Contains(b.said[1].body.Reason, "404") || len(asked) != 0 {
t.Errorf("a failed copy = %v, said %+v: want refused with why", err, b.said)
}
})
t.Run("the windows", func(t *testing.T) {
nodes := []NodeRead{
{Node: "ace", Serves: true, Stated: []string{NewNamesCapability}, NamesArtifact: true, BuildModules: map[string]bool{"mesh-build-go": true}},
@@ -295,5 +295,8 @@ func (o *OCI) Mirror(source, digest string) (string, error) {
if err := o.copyManifest(o.Upstream, src, name, digest, 0); err != nil {
return "", err
}
return o.Registry + "/" + name + "@" + digest, nil
return o.Reference(name, digest), nil
}
// Reference is the seat's answer for name at digest: `<registry>/<name>@<digest>`.
func (o *OCI) Reference(name, digest string) string { return o.Registry + "/" + name + "@" + digest }
+48 -6
View File
@@ -20,6 +20,19 @@ type Catalog interface {
RemoveDigest(name, digest string) error
// Mirror copies an outside image, pinned by digest, into upstream/<host>/<path>, answering the reference.
Mirror(source, digest string) (string, error)
// Reference is the seat's answer for name at digest, known before anything is copied.
Reference(name, digest string) string
}
// MirrorsState names the state of the copies `mirror` took on.
const MirrorsState = "mirrors"
// Mirrors is the state mirrors: each copy `mirror` took on, kept until its outcome is said, so a copy cut by a
// restart is taken on again from the state's watch.
type Mirrors interface {
// Ask keeps r under its key; an ask already kept is no fault (the copy is taken on once).
Ask(key string, r MirrorRequest) error
Delete(key string) error
}
// HoldState is distribution's own state holds (bus state, template state; ADR 0617 §2).
@@ -51,6 +64,7 @@ type Verbs struct {
*Holder
Catalog Catalog
Holds HoldState
Mirrors Mirrors
}
// VersionsAnswer is `versions`: the versions the seat holds of name.
@@ -206,13 +220,22 @@ func (v *Verbs) Tags(seat, caller, name string) (VersionsAnswer, error) {
return VersionsAnswer{Seat: seat, Name: name, Versions: got}, nil
}
// MirrorRequest is `mirror`: an outside image by its pinned digest.
// MirrorRequest is `mirror`: an outside image by its pinned digest; By is the proved caller, kept with the ask.
type MirrorRequest struct {
Source string `json:"source"`
Digest string `json:"digest"`
By string `json:"by,omitempty"`
}
// Mirror is `mirror` on the image seat: mesh-build-image alone; an image pinned by no digest is refused.
// MirrorsKey is an ask's key in the state mirrors: the copy's name and digest, in a key's characters.
func MirrorsKey(name, digest string) string {
return strings.NewReplacer(":", "_", "@", "_").Replace(name + "/" + digest)
}
// Mirror is `mirror` on the image seat: mesh-build-image alone; an image pinned by no digest is refused. It answers at
// once with the reference the copy will have and keeps the ask in the state mirrors; the copy runs on that state's
// watch (Mirrored), which says published or refused on the seat's events when it ends. The caller waits on that
// event, not on the call, so a large base never outlasts a call's bound.
func (v *Verbs) Mirror(seat, caller string, r MirrorRequest) (string, error) {
if seat != ImageSeat {
return "", fmt.Errorf("mirror: %s serves no mirror", seat)
@@ -227,11 +250,30 @@ func (v *Verbs) Mirror(seat, caller string, r MirrorRequest) (string, error) {
if err != nil {
return "", err
}
ref, err := v.Catalog.Mirror(r.Source, r.Digest)
if err != nil {
return "", fmt.Errorf("mirror: %s@%s was not copied: %w", r.Source, r.Digest, err)
r.By = caller
if err := v.Mirrors.Ask(MirrorsKey(src.Name(), r.Digest), r); err != nil {
return "", fmt.Errorf("mirror: the copy of %s@%s cannot be taken on: %w", r.Source, r.Digest, err)
}
return ref, v.Say(seat, EventPublished, Event{Name: src.Name(), Kind: KindUpstream, Digest: r.Digest, Holder: Self, Reference: ref, By: caller})
return v.Catalog.Reference(src.Name(), r.Digest), nil
}
// Mirrored runs one asked copy and says its outcome on the image seat's events: published with the reference, or
// refused with the reason; the ask leaves the state either way. An outcome that cannot be said keeps the ask, so the
// next watch takes it on again.
func (v *Verbs) Mirrored(r MirrorRequest) error {
src, err := ParseSource(r.Source)
if err != nil {
return err
}
e := Event{Name: src.Name(), Kind: KindUpstream, Digest: r.Digest, Holder: Self, By: r.By}
event := EventPublished
if e.Reference, err = v.Catalog.Mirror(r.Source, r.Digest); err != nil {
event, e.Reference, e.Reason = EventRefused, "", fmt.Sprintf("%s@%s was not copied: %v", r.Source, r.Digest, err)
}
if err := v.Say(ImageSeat, event, e); err != nil {
return fmt.Errorf("mirror: the outcome of %s@%s cannot be said: %w", r.Source, r.Digest, err)
}
return v.Mirrors.Delete(MirrorsKey(src.Name(), r.Digest))
}
// HeldNow lists the holds, for registry_holds.
+5
View File
@@ -96,6 +96,11 @@
"storage": "key-value",
"template": "state"
},
{
"name": "mirrors",
"storage": "key-value",
"template": "state"
},
{
"name": "findings",
"storage": "key-value",