Deletes the placement and candidate writes, the reread tool and its forge reads, the two buckets and the placement-changed event. D1a and D1b are one commit: the index package, the named reads, the tools and the manifest do not compile apart.
119 lines
5.4 KiB
Go
119 lines
5.4 KiB
Go
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 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, 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, 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
|
|
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}
|
|
}
|
|
|
|
// notFound says the forge answered that a commit it was asked about does not exist: gitea's status ": 404 ", matched as
|
|
// readVia matches it (cmd/mesh-delivery-indexer named.go). A bare "404" is not enough: the error's words carry both shas,
|
|
// and a 502 naming a sha with 404 in it would read as not older and write a late message backwards. The thorough form,
|
|
// a typed not-found answered by gitea_contains, is noted on issue 1126.
|
|
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, 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 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 (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) {
|
|
w.written = append(w.written, key)
|
|
}
|
|
}
|
|
|
|
// 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 = strings.Join(slices.Sorted(slices.Values(w.written)), ", ")
|
|
}
|
|
return fmt.Sprintf("%s at %.12s (#%d): merged message applied; modules written: %s", w.repository, w.merge, number, written)
|
|
}
|