diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go index abff8b8..9de33a4 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go @@ -179,7 +179,7 @@ func handle(ctx context.Context, m delivered, ix *index.Indexer, heard index.Sto h.Commit = f.Merge } applied, err := ix.ApplyMessage(ctx, f) - h.Written, h.Kept = applied.Written, applied.Kept + h.Written, h.Late = applied.Written, applied.Late switch { case errors.Is(err, index.ErrUnreadable): logger.Printf("%s: %v; dropped", m.Subject(), err) diff --git a/modules/mesh-delivery-indexer/internal/index/candidates.go b/modules/mesh-delivery-indexer/internal/index/candidates.go index 62edc1c..7f3bbc6 100644 --- a/modules/mesh-delivery-indexer/internal/index/candidates.go +++ b/modules/mesh-delivery-indexer/internal/index/candidates.go @@ -122,18 +122,22 @@ func (ix *Indexer) ApplyMessage(ctx context.Context, f delivery.Forge) (Applied, } if f.Kind == delivery.ForgeMerged && ix.Modules != nil { w, err := ix.applyMerged(ctx, f) - applied = Applied{Written: w.written, Kept: w.refused} + applied = Applied{Written: w.written, Late: w.late} if err != nil { return applied, err } ix.logf("%s", w.said(f.Number)) - if err := ix.writeTaken(ctx, f); err != nil { - return applied, err + if w.late == "" { // a late message leaves the taken key, which names a later merge + if err := ix.writeTakenKnown(ctx, f, w.asked); err != nil { + return applied, err + } } ix.kickRetry(ctx) // a registered module the forge could not read is read again on a merge, in the background (issue 1945) } - if err := ix.applyPlacement(ctx, f); err != nil { - return applied, err + if applied.Late == "" { // a late merged message would write an older placement back + if err := ix.applyPlacement(ctx, f); err != nil { + return applied, err + } } if err := ix.applyPlacementCandidates(ctx, f); err != nil { return applied, err diff --git a/modules/mesh-delivery-indexer/internal/index/heard.go b/modules/mesh-delivery-indexer/internal/index/heard.go index b601bee..0c66225 100644 --- a/modules/mesh-delivery-indexer/internal/index/heard.go +++ b/modules/mesh-delivery-indexer/internal/index/heard.go @@ -39,12 +39,15 @@ type Heard struct { Outcome string `json:"outcome"` Words string `json:"words,omitempty"` // why it was left or dropped Written []string `json:"written,omitempty"` // the modules a merged message wrote - Kept []string `json:"kept,omitempty"` // the modules it did not move back (order.go) + Late string `json:"late,omitempty"` // the taken merge a merged message is older than: nothing of it was written (order.go) } -// Applied is what Apply did with a merged message's modules: the keys written, and those kept because the merge does not -// contain their commit. -type Applied struct{ Written, Kept []string } +// Applied is what Apply did with a merged message's modules: the keys written, and, for a message older than the +// repository's taken merge, that merge (nothing was written). +type Applied struct { + Written []string + Late string +} // WriteHeard writes h as the newest value of heard.forge. func WriteHeard(ctx context.Context, st Store, h Heard) error { diff --git a/modules/mesh-delivery-indexer/internal/index/modules.go b/modules/mesh-delivery-indexer/internal/index/modules.go index 0b20d30..199f125 100644 --- a/modules/mesh-delivery-indexer/internal/index/modules.go +++ b/modules/mesh-delivery-indexer/internal/index/modules.go @@ -25,8 +25,8 @@ import ( // A value the module already holds but for its commit is not written again: its commit stays the one its fingerprint first // appeared at (writeOverlay), so a merge writes only the modules it changes. // -// A merge never moves a module backwards (order.go): a held value whose commit the merge does not contain is neither -// written nor deleted, and said. +// A merge never moves a module backwards (order.go): a merged message older than the repository's taken merge writes and +// deletes nothing, and is said; it is asked once, before anything is written. func (ix *Indexer) applyMerged(ctx context.Context, f delivery.Forge) (*mergeWrite, error) { return ix.applyManifests(ctx, f, true) } @@ -36,6 +36,11 @@ func (ix *Indexer) applyMerged(ctx context.Context, f delivery.Forge) (*mergeWri // drops none. func (ix *Indexer) applyManifests(ctx context.Context, f delivery.Forge, drop bool) (*mergeWrite, error) { w := newMergeWrite(f) + if drop { + if err := ix.lateMerge(ctx, w); err != nil || w.late != "" { + return w, err + } + } digests, err := ix.keepManifests(ctx, f) if err != nil { return w, err @@ -76,14 +81,6 @@ func (ix *Indexer) applyManifests(ctx context.Context, f delivery.Forge, drop bo ix.logf("%s at %s: %q and %q both name the module %s; %q, which the indexer holds, is written", f.Repository, f.Merge, other, dir, name, dir) } dirOf[name] = dir - // Asked before the merge's values are computed, so no module standing on one kept back is computed from it. - if has { - if ok, err := ix.forward(ctx, w, key, cur); err != nil { - return w, err - } else if !ok { - continue - } - } next := delivery.Module{Repository: f.Repository, Commit: f.Merge, Src: ix.srcOf(f.Repository, f.Merge), Manifest: digests[dir], Path: pathOf(dir)} if next.Manifest == "" { next.None2 = "the manifest cannot be read: it cannot be kept as a value" @@ -104,23 +101,9 @@ func (ix *Indexer) applyManifests(ctx context.Context, f delivery.Forge, drop bo // A module of this repository the merge commit holds no module.json for is gone from the trunk, and so is its key // (issue 1900). A message that carries no manifests (an older writer) or one that cannot be read whole says nothing. if drop && len(f.Manifests) > 0 && every { - var orderErr error - stays := func(key string, m delivery.Module) bool { - if named[key] { - return true - } - ok, err := ix.forward(ctx, w, key, m) - if err != nil && orderErr == nil { - orderErr = err - } - return err != nil || !ok - } - if err := ix.dropRemoved(ctx, f.Repository, held, stays); err != nil { + if err := ix.dropRemoved(ctx, f.Repository, held, func(key string, _ delivery.Module) bool { return named[key] }); err != nil { return w, err } - if orderErr != nil { - return w, orderErr - } } // What this merge moved reaches the modules standing on it (a base's tree, build-agent's fingerprint), in the graph's order. return w, ix.recomputeWith(ctx, overlay, w) diff --git a/modules/mesh-delivery-indexer/internal/index/modules_test.go b/modules/mesh-delivery-indexer/internal/index/modules_test.go index 6b06cf9..6027366 100644 --- a/modules/mesh-delivery-indexer/internal/index/modules_test.go +++ b/modules/mesh-delivery-indexer/internal/index/modules_test.go @@ -102,6 +102,9 @@ func TestAnUnchangedModuleWritesNothing(t *testing.T) { // 1239 (unchanged value // err says then fails (the message is left for redelivery); said is a line the indexer's log (or that error) must hold. err bool said string + // contains, when set, is the forge's order, and asks how often then asks it (one question per merged message). + contains func(context.Context, string, string, string) (bool, error) + asks int }{ {name: "the same merge again", writes: 0, commit: map[string]string{"a": merge, "b": merge, "c": merge}, taken: merge, then: func(ix *Indexer) error { return ix.Apply(context.Background(), mergedMsg(repo, three)) }}, @@ -179,7 +182,7 @@ func TestAnUnchangedModuleWritesNothing(t *testing.T) { // 1239 (unchanged value // Issue 1126 note 76: mesh-catalog's merge 9cdac09a was written back over the later 69056948, rolling kernel and // mesh-build-image back on the nodes. A merge never moves a module backwards: the held commit must be in the incoming one. {name: "an earlier merge heard again after a later one moves no module back", writes: 1, commit: map[string]string{"a": next, "b": merge, "c": merge}, taken: next, - said: "modules.a stays at cccccccccccc", + said: "the merged message is older than taken.novox/mesh-delivery at cccccccccccc", then: func(ix *Indexer) error { ix.Contains = func(_ context.Context, _, commit, in string) (bool, error) { return commit == in || commit == merge && in == next, nil @@ -192,7 +195,7 @@ func TestAnUnchangedModuleWritesNothing(t *testing.T) { // 1239 (unchanged value return ix.Apply(context.Background(), mergedMsg(repo, three)) }}, {name: "an earlier merge that lacks a later merge's module deletes nothing", writes: 1, commit: map[string]string{"a": merge, "d": next}, taken: next, - said: "modules.d stays at cccccccccccc", + said: "the merged message is older than taken.novox/mesh-delivery at cccccccccccc", then: func(ix *Indexer) error { ix.Contains = func(_ context.Context, _, commit, in string) (bool, error) { return commit == in || commit == merge && in == next, nil @@ -214,6 +217,25 @@ func TestAnUnchangedModuleWritesNothing(t *testing.T) { // 1239 (unchanged value later.Merge = next return ix.Apply(context.Background(), later) }}, + // Review of 77d738d: only a merge older than the one taken in is kept back. A diverged or rewritten history, or a + // taken merge the forge no longer has, is not older, and one question per message is asked. + {name: "a merge of a diverged history is written, asking the forge once", writes: 1, commit: map[string]string{"a": next, "b": merge, "c": merge}, taken: next, + contains: func(context.Context, string, string, string) (bool, error) { return false, nil }, asks: 1, + then: func(ix *Indexer) error { + later := mergedMsg(repo, map[string]string{"modules/a": "treeA2", "modules/b": "treeB", "modules/c": "treeC"}) + later.Merge = next + return ix.Apply(context.Background(), later) + }}, + {name: "a taken merge the forge no longer has stops no later merge", writes: 1, commit: map[string]string{"a": next, "b": merge, "c": merge}, taken: next, + said: "is not known to be older", + then: func(ix *Indexer) error { + ix.Contains = func(context.Context, string, string, string) (bool, error) { + return false, errors.New("gitea_contains: the forge answered: 404 Not Found") + } + later := mergedMsg(repo, map[string]string{"modules/a": "treeA2", "modules/b": "treeB", "modules/c": "treeC"}) + later.Merge = next + return ix.Apply(context.Background(), later) + }}, {name: "a later source revision of another repository's merge", writes: 0, commit: map[string]string{"a": merge, "b": merge, "c": merge}, taken: merge, then: func(ix *Indexer) error { return ix.ApplySource(context.Background(), 9, delivery.Source{Group: "g", Heads: map[string]string{repo: merge, "novox/mesh-catalog": otherMerge}}) @@ -231,9 +253,19 @@ func TestAnUnchangedModuleWritesNothing(t *testing.T) { // 1239 (unchanged value t.Fatal(err) } writes := mods.writes + asks := 0 + if tc.contains != nil { + ix.Contains = func(ctx context.Context, repo, commit, in string) (bool, error) { + asks++ + return tc.contains(ctx, repo, commit, in) + } + } var said strings.Builder ix.Logf = func(format string, args ...any) { fmt.Fprintf(&said, format+"\n", args...) } err := tc.then(ix) + if tc.contains != nil && asks != tc.asks { + t.Errorf("the forge was asked %d times, want %d", asks, tc.asks) + } if (err != nil) != tc.err { t.Fatalf("then = %v, want an error %v", err, tc.err) } diff --git a/modules/mesh-delivery-indexer/internal/index/order.go b/modules/mesh-delivery-indexer/internal/index/order.go index 0c3ab70..d9044dd 100644 --- a/modules/mesh-delivery-indexer/internal/index/order.go +++ b/modules/mesh-delivery-indexer/internal/index/order.go @@ -2,57 +2,99 @@ package index import ( "context" + "errors" "fmt" "slices" + "strings" "git.novox.be/novox/mesh-sdk/go/delivery" + "git.novox.be/novox/mesh-sdk/go/process" ) // A merge never moves a module backwards (issue 1126, note 76). The indexer wrote mesh-catalog's merge 9cdac09a back over // the later 69056948 for kernel and mesh-build-image: applyManifests and writeOverlay wrote whatever commit a merged -// message carried, so a late or repeated message (or a take-in at an older head) rolled the modules, and the nodes that -// want them, back. Before a value of a merge is written over a held one of the same repository, or a held one is deleted -// because the merge lacks it, the forge says whether the merge commit contains the held commit (Contains). When it does -// not, the held value stands and the log says so with the module, both commits and why. When the forge cannot say, nothing -// of the merge is written and the merge is an error: a merged message is then delivered again by the server, and a take-in -// answers the error. Without a forge to ask (Contains nil) the order is not checked. +// message carried, so a late or repeated message rolled the modules, and the nodes that want them, back. +// +// The question is whether the incoming commit is OLDER: the forge says the incoming commit is in the later one and the +// two differ (Contains(incoming, in: later)). Only then is it kept back. A diverged or rewritten history answers no, and +// is written forward; a commit the forge no longer has (a 404) is not known to be older, is written, and said. A forge +// that cannot say for another reason (a timeout) writes nothing and is an error: the server delivers the message again. +// +// - A merged message asks once, before it writes anything: is its merge older than the repository's taken merge (the +// last merge applied whole, taken.go)? Then the whole message is late: no module is written or deleted, no placement +// is written, the taken key stays, and the log says so. +// - A take-in of a held module asks once for that module: is the source's head older than the module's record +// (takeInHeld)? -// mergeWrite is one merge's write of the modules: its repository and commit, the order the forge said for each held commit, -// and the modules written and refused, for the line the indexer says per applied merged message. +// mergeWrite is one merge's write of the modules: its repository and commit, whether it is late (older than the taken +// merge), the taken merge it was compared with and the answer, and the module keys written, for the line the indexer says +// per applied merged message. type mergeWrite struct { repository, merge string - order map[string]bool // held commit: whether merge contains it - written, refused []string // module keys + late string // the taken merge this one is older than, or "" + asked string // the taken merge the order was asked against, or "" when none was asked + written []string } func newMergeWrite(f delivery.Forge) *mergeWrite { - return &mergeWrite{repository: f.Repository, merge: f.Merge, order: map[string]bool{}} + return &mergeWrite{repository: f.Repository, merge: f.Merge} } -// forward says whether the merge may replace the held value cur of key: cur is of another repository (applyManifests -// leaves those), has no commit, is at the merge, or the merge contains it. A refusal is said once per key. -func (ix *Indexer) forward(ctx context.Context, w *mergeWrite, key string, cur delivery.Module) (bool, error) { - if w == nil || ix.Contains == nil || w.merge == "" || cur.Commit == "" || cur.Commit == w.merge || - !delivery.SameRepository(cur.Repository, w.repository) { - return true, nil +// notFound says the forge answered that a commit it was asked about does not exist (gitea's 404, as readVia reads it). +func notFound(err error) bool { return err != nil && strings.Contains(err.Error(), "404") } + +// older says commit is older than later: the forge says commit is in later and the two differ. A commit the forge does not +// have is not known to be older (false, said); a forge that cannot say otherwise is an error. Without a forge to ask +// (Contains nil) nothing is older. +func (ix *Indexer) older(ctx context.Context, repository, commit, later string) (bool, error) { + if ix.Contains == nil || commit == "" || later == "" || commit == later { + return false, nil } - in, asked := w.order[cur.Commit] - if !asked { - var err error - if in, err = ix.Contains(ctx, w.repository, cur.Commit, w.merge); err != nil { - return false, fmt.Errorf("modules.%s: whether its commit %.12s is in %s at %.12s cannot be read, so nothing of that merge is written (a merge never moves a module backwards, issue 1126): %w", - key, cur.Commit, w.repository, w.merge, err) - } - w.order[cur.Commit] = in + in, err := ix.Contains(ctx, repository, commit, later) + if notFound(err) { + ix.logf("%s: the forge does not have %.12s or %.12s (a rewritten history?), so %.12s is not known to be older and is written: %v", repository, commit, later, commit, err) + return false, nil } - if !in && !slices.Contains(w.refused, key) { - w.refused = append(w.refused, key) - ix.logf("modules.%s stays at %.12s: %s at %.12s does not contain it, so its value is neither written nor deleted (a late or repeated merged message, or a take-in at an older head; a merge never moves a module backwards, issue 1126)", - key, cur.Commit, w.repository, w.merge) + if err != nil { + return false, fmt.Errorf("%s: whether %.12s is older than %.12s cannot be read, so nothing of it is written (a merge never moves a module backwards, issue 1126): %w", repository, commit, later, err) } return in, nil } +// lateMerge asks, before a merged message writes anything, whether its merge is older than the repository's taken merge +// (one forge call). A taken state not on the bus yet, or no taken key, asks nothing. +func (ix *Indexer) lateMerge(ctx context.Context, w *mergeWrite) error { + if ix.Taken == nil || w.merge == "" { + return nil + } + key, err := delivery.RepositoryKey(w.repository) + if err != nil { + return nil // writeTaken says it + } + value, _, found, err := ix.Taken.Get(ctx, key) + if errors.Is(err, process.ErrNotYet) || !found { + return nil + } + if err != nil { + return fmt.Errorf("taken.%s: %w", key, err) + } + cur, err := delivery.DecodeTaken(value) + if err != nil || cur.Merge == "" || cur.Merge == w.merge { + return nil + } + old, err := ix.older(ctx, w.repository, w.merge, cur.Merge) + if err != nil { + return err + } + w.asked = cur.Merge + if old { + w.late = cur.Merge + ix.logf("%s at %.12s: the merged message is older than taken.%s at %.12s, so no module is written or deleted and no placement written (a late or repeated message; a merge never moves a module backwards, issue 1126)", + w.repository, w.merge, key, cur.Merge) + } + return nil +} + // wrote records a module key the merge wrote. func (w *mergeWrite) wrote(key string) { if w != nil && !slices.Contains(w.written, key) { @@ -60,16 +102,14 @@ func (w *mergeWrite) wrote(key string) { } } -// said is the line of an applied merged message: its repository, commit and pull request, the modules written and refused. +// said is the line of an applied merged message: its repository, commit and pull request, and the modules written. func (w *mergeWrite) said(number int) string { + if w.late != "" { + return fmt.Sprintf("%s at %.12s (#%d): merged message applied as late: older than the taken %.12s, nothing written", w.repository, w.merge, number, w.late) + } written := "none" if len(w.written) > 0 { - written = fmt.Sprint(slices.Sorted(slices.Values(w.written))) - written = written[1 : len(written)-1] + written = strings.Join(slices.Sorted(slices.Values(w.written)), ", ") } - line := fmt.Sprintf("%s at %.12s (#%d): merged message applied; modules written: %s", w.repository, w.merge, number, written) - if len(w.refused) > 0 { - line += fmt.Sprintf("; kept as later than this merge: %v", slices.Sorted(slices.Values(w.refused))) - } - return line + return fmt.Sprintf("%s at %.12s (#%d): merged message applied; modules written: %s", w.repository, w.merge, number, written) } diff --git a/modules/mesh-delivery-indexer/internal/index/registered.go b/modules/mesh-delivery-indexer/internal/index/registered.go index 6edcc24..5666beb 100644 --- a/modules/mesh-delivery-indexer/internal/index/registered.go +++ b/modules/mesh-delivery-indexer/internal/index/registered.go @@ -129,15 +129,9 @@ func (ix *Indexer) indexAt(ctx context.Context, r Registration, force, reread bo if l := read.Locks[dir]; len(l) > 0 { f.Locks = map[string]map[string]string{dir: l} } - w, err := ix.applyManifests(ctx, f, false) - if err != nil { + if _, err := ix.applyManifests(ctx, f, false); err != nil { return t, err } - if slices.Contains(w.refused, key) { - // Its record stands at a commit the read one does not contain (a merge heard after the source named this head). - t.why = fmt.Sprintf("its record stands at a later commit than %s at %.12s, so it is not written back (a merge never moves a module backwards)", repository, commit) - return t, nil - } if _, _, found, err := ix.Modules.Get(ctx, key); err != nil { return t, fmt.Errorf("modules.%s: %w", key, err) } else if !found { @@ -319,20 +313,21 @@ func (ix *Indexer) takeInHeld(ctx context.Context, module string) (TakenIn, bool if head == "" || head == cur.Commit { return out, false } - // Only forward: a record at a merge the source does not name yet (a merge applied before the source moved) is never - // written back to the source's older head. Where the order cannot be known, nothing is read. - behind, why := false, "the forge cannot be asked" + // Never backwards (order.go): a source head older than the record (a merge applied before the source moved) is never + // read and written back over it. A diverged or rewritten history, or a record whose commit the forge no longer has, is + // not older and is read; where the forge cannot say otherwise, nothing is read. One forge call. + old, why := true, "the forge cannot be asked" if ix.Contains != nil { var err error - if behind, err = ix.Contains(ctx, cur.Repository, cur.Commit, head); err != nil { - why = err.Error() - } else if !behind { - why = fmt.Sprintf("its record at %.12s is not in %.12s", cur.Commit, head) + if old, err = ix.older(ctx, cur.Repository, head, cur.Commit); err != nil { + old, why = true, err.Error() + } else if old { + why = fmt.Sprintf("%.12s is older than its record at %.12s", head, cur.Commit) } } - if !behind { + if old { out.Held, out.Repository, out.Commit, out.Path = true, cur.Repository, cur.Commit, cur.Path - out.Answer = fmt.Sprintf("held; the source names another head, %.12s, and not one its record is behind (%s), so it is not read again", head, why) + out.Answer = fmt.Sprintf("held; the source names another head, %.12s, and not one newer than its record (%s), so it is not read again", head, why) return out, true } t, err := ix.indexAt(ctx, Registration{Module: module, Repository: cur.Repository, Path: cur.Path, Commit: head}, true, true) diff --git a/modules/mesh-delivery-indexer/internal/index/registered_test.go b/modules/mesh-delivery-indexer/internal/index/registered_test.go index 879c7e5..78101a4 100644 --- a/modules/mesh-delivery-indexer/internal/index/registered_test.go +++ b/modules/mesh-delivery-indexer/internal/index/registered_test.go @@ -123,7 +123,13 @@ func TestARegisteredModuleIsIndexedFromItsRepository(t *testing.T) { // the gran }{ {name: "a held module behind the source's head is read again", moved: true, contains: func(_ context.Context, _, commit, in string) (bool, error) { return commit == merge && in == h2, nil }}, - {name: "a source head older than the record is not read", contains: func(context.Context, string, string, string) (bool, error) { return false, nil }}, + {name: "a source head older than the record is not read", contains: func(_ context.Context, _, commit, in string) (bool, error) { return commit == h2 && in == merge, nil }}, + // Review of 77d738d: a diverged or rewritten history, or a record whose commit the forge no longer has, is not older. + {name: "a source head of a diverged history is read again", moved: true, + contains: func(context.Context, string, string, string) (bool, error) { return false, nil }}, + {name: "a record whose commit the forge no longer has is read again", moved: true, contains: func(context.Context, string, string, string) (bool, error) { + return false, errors.New("gitea_contains: 404 Not Found") + }}, {name: "a forge that cannot say the order reads nothing", contains: func(context.Context, string, string, string) (bool, error) { return false, errors.New("timeout") }}, diff --git a/modules/mesh-delivery-indexer/internal/index/taken.go b/modules/mesh-delivery-indexer/internal/index/taken.go index a6d97e7..89c0293 100644 --- a/modules/mesh-delivery-indexer/internal/index/taken.go +++ b/modules/mesh-delivery-indexer/internal/index/taken.go @@ -20,6 +20,12 @@ import ( // writeTaken writes the repository's taken key for the merge f carries, unless it names that merge or a later one. func (ix *Indexer) writeTaken(ctx context.Context, f delivery.Forge) error { + return ix.writeTakenKnown(ctx, f, "") +} + +// writeTakenKnown is writeTaken where the merge is known not to be older than notOlder (lateMerge asked it, issue 1126): a +// key naming that merge is written over without asking the forge again. +func (ix *Indexer) writeTakenKnown(ctx context.Context, f delivery.Forge, notOlder string) error { if ix.Taken == nil || f.Merge == "" { return nil } @@ -34,7 +40,7 @@ func (ix *Indexer) writeTaken(ctx context.Context, f delivery.Forge) error { if cur.Merge == f.Merge { return nil, false, nil } - if ix.Contains != nil { + if ix.Contains != nil && cur.Merge != notOlder { later, err := ix.Contains(ctx, f.Repository, f.Merge, cur.Merge) if err != nil { ix.logf("%s: whether %s is in %s cannot be read, so taken.%s stays at %s: %v", f.Repository, f.Merge, cur.Merge, key, cur.Merge, err) diff --git a/modules/mesh-delivery-indexer/internal/index/toolchains.go b/modules/mesh-delivery-indexer/internal/index/toolchains.go index 44dc6aa..21e022f 100644 --- a/modules/mesh-delivery-indexer/internal/index/toolchains.go +++ b/modules/mesh-delivery-indexer/internal/index/toolchains.go @@ -332,8 +332,7 @@ func (ix *Indexer) recomputeModules(ctx context.Context, overlay map[string]deli // the held value stands, its commit unchanged, so a catalogue merge touching one module writes one key, not one per module of // the repository, and the controller's take-in hears only that one. The repository's trunk head is the gate's source.main. // -// **A merge never moves a module backwards** (order.go): a held value whose commit the merge does not contain stands. It -// is asked again here, at the write, for a value another writer (a take-in) moved since applyManifests asked. +// A merged message older than the repository's taken merge never reaches here (order.go): it is asked before any write. func (ix *Indexer) writeOverlay(ctx context.Context, overlay, finals map[string]delivery.Module, w *mergeWrite) error { for _, key := range slices.Sorted(maps.Keys(overlay)) { next := overlay[key] @@ -344,13 +343,8 @@ func (ix *Indexer) writeOverlay(ctx context.Context, overlay, finals map[string] err := write(ctx, ix.Modules, key, func(value []byte, found bool) ([]byte, bool, error) { wrote = false if found { - if cur, err := delivery.DecodeModule(value); err == nil { - if sameButWhere(cur, next) { - return nil, false, nil - } - if ok, err := ix.forward(ctx, w, key, cur); err != nil || !ok { - return nil, false, err - } + if cur, err := delivery.DecodeModule(value); err == nil && sameButWhere(cur, next) { + return nil, false, nil } } data, err := delivery.EncodeModule(next) diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go index db5e618..9231f3e 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go @@ -46,8 +46,8 @@ func Tools(r view.Reader, u view.UsageReader) []stdio.Tool { Description: "The forge stream's (FORGE, the forge bridge's) recent messages as the indexer heard them: for each merged, pull, " + "closed or open message it handled, newest first (its last 64), the subject, the stream sequence, how often the server " + "delivered it (a redelivery shows above 1), when it was published and handled, its kind, repository, pull request, " + - "branch and commit (the merge commit, or the head), and what the indexer did: applied (with the modules written, and " + - "those kept because the merge is older than their value), left for redelivery or dropped, with why. Read-only.", + "branch and commit (the merge commit, or the head), and what the indexer did: applied (with the modules written, or, " + + "for a late merged message, the later merge already taken in, when nothing was written), left for redelivery or dropped, with why. Read-only.", Input: map[string]any{"type": "object", "properties": map[string]any{ "limit": map[string]any{"type": "integer", "description": "at most this many messages, newest first (default every one kept)"}}}, Run: func(args map[string]any) (any, error) {