Keep back only a merge older than the one taken in, asked once per message before any write (issue 1126, review)
Asking whether the merge contains the held commit refused forward merges forever on a diverged or rewritten main or a squash-merged registered head, failed every later merge when the forge no longer had the held commit, and cost one forge call per held commit. The question is now the reverse: a merge is kept back only when it is in the taken merge and differs from it. A merged message asks it once, before it writes anything, and a late message writes no module, deletion, placement or taken key. A take-in asks it once for its module. A 404 is not known to be older and is written, and said; any other failure to say leaves the message for redelivery.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user