Ask mesh-delivery whether a merge's group still assembles (hq issue 525)
A merge from any head waited for the window because the controller could not see a group's members, so the window skip changed nothing in production and unrelated merges walked one after another. The controller now asks mesh-delivery's groups, within 3 s and before the plans are held: a merge waits only when its head's group has another member whose pull request is open and whose merge it does not keep yet (ADR 0306 §2). No answer means it waits, and its batch says why. A headed merge in no waiting group and related to no batch is cut at once, as one from no head is (ADR 0304 §1, ADR 0306 §3). The controller's grant names mesh-delivery.groups. The installer's first user list in mesh-host must carry it too before the genesis test can pass.
This commit is contained in:
@@ -178,6 +178,11 @@ func (f following) hearMerge(ctx context.Context, m link.SourceMoved, now time.T
|
||||
fmt.Printf("%s merged into %s (%.8s); nothing the mesh holds reads it\n", repository, m.Base, m.Commit)
|
||||
return nil
|
||||
}
|
||||
// **Its delivery group's word, before the plans are held** (ADR 0306 decision 2): a slow answer holds up no walk.
|
||||
waits, err := groupWait(ctx, inv, m, deliverySeatHeld(entries))
|
||||
if err != nil {
|
||||
return notNow(err)
|
||||
}
|
||||
release, err := inv.HoldPlans(ctx, true)
|
||||
if err != nil {
|
||||
return notNow(err)
|
||||
@@ -223,7 +228,7 @@ func (f following) hearMerge(ctx context.Context, m link.SourceMoved, now time.T
|
||||
return cutBatchesHeld(ctx, f.open, now)
|
||||
}
|
||||
|
||||
batch, why, err := batchToJoin(ctx, inv, heard, entries, read, now, own)
|
||||
batch, why, err := batchToJoin(ctx, inv, heard, entries, read, now, own, waits)
|
||||
if err != nil {
|
||||
return notNow(err)
|
||||
}
|
||||
@@ -331,13 +336,14 @@ func ownPath(touches []inventory.Entry) bool {
|
||||
// - an assembling or queued batch of its kind it is related to (related.go): it joins it and waits for the
|
||||
// window, which its coming restarts. Related to two or more, the newer are folded into the oldest, which
|
||||
// answers all their merges: a merge never waits in two windows, and what it shares with each walks in one.
|
||||
// - none, and its delivery group may have a member still to merge (stillAssembles): a new batch, which waits
|
||||
// for the window as every batch did before ADR 0304, beside the ones it shares nothing with.
|
||||
// - none, and its delivery group has a member still to merge, or mesh-delivery could not say (groupWait, waits
|
||||
// names why): a new batch, which waits for the window, beside the ones it shares nothing with; its words say
|
||||
// why.
|
||||
// - none, and no member of its group is still to merge: a new batch whose window is closed at once. Cut at
|
||||
// once means only that: walks stay one at a time (ADR 0276 decision 4), so with a walk open the batch is
|
||||
// queued behind it as any closed batch is.
|
||||
func batchToJoin(ctx context.Context, inv *inventory.Inventory, heard inventory.BatchedMerge, entries []inventory.Entry,
|
||||
read map[string][]inventory.ReadRepository, now time.Time, own bool) (inventory.Plan, string, error) {
|
||||
read map[string][]inventory.ReadRepository, now time.Time, own bool, waits string) (inventory.Plan, string, error) {
|
||||
edges, err := inv.Dependencies(ctx)
|
||||
if err != nil {
|
||||
return inventory.Plan{}, "", err
|
||||
@@ -366,28 +372,14 @@ func batchToJoin(ctx context.Context, inv *inventory.Inventory, heard inventory.
|
||||
into.Delivery.Batch.CutAtOnce = false
|
||||
return into, why, nil
|
||||
}
|
||||
if waits, why := stillAssembles(heard); waits {
|
||||
if waits != "" {
|
||||
// Its own window, beside the batches it shares nothing with: waiting is for its group's members, which
|
||||
// are related to it by their head and join it (ADR 0306 decision 2).
|
||||
b, err := newBatch(ctx, inv, heard, now, own, false)
|
||||
return b, why + ", it waits for the window in a batch of its own", err
|
||||
b, err := newBatch(ctx, inv, heard, now, own, false, waits)
|
||||
return b, waits + ", it waits for the window in a batch of its own", err
|
||||
}
|
||||
b, err := newBatch(ctx, inv, heard, now, own, true)
|
||||
return b, "it shares nothing with a batch assembling and is cut at once", err
|
||||
}
|
||||
|
||||
// stillAssembles says a merge's delivery group may have a member still to merge, so the merge waits for the
|
||||
// merge window whether or not a batch is assembling (novox/hq ADR 0306 decision 2), and why in words.
|
||||
//
|
||||
// Which members a group has and which of them are merged is mesh-delivery's record, not the controller's: the
|
||||
// controller hears a merge's head branch, which is its group's name, and nothing of the pull requests still open
|
||||
// on that branch in other repositories. So every merge from a head waits, as every merge did before ADR 0304:
|
||||
// the safe error is to wait (issue 525). Only a merge that names no head is known to be no group's.
|
||||
func stillAssembles(m inventory.BatchedMerge) (bool, string) {
|
||||
if h := announcedOf(m).Head; h != "" {
|
||||
return true, "group " + h + " may have a member still to merge"
|
||||
}
|
||||
return false, ""
|
||||
b, err := newBatch(ctx, inv, heard, now, own, true, "")
|
||||
return b, "it shares nothing with a batch assembling and no member of a group is still to merge: it is cut at once", err
|
||||
}
|
||||
|
||||
// relatedBatches are the batches not yet cut of a kind, oldest first, parted into those related to merges (with
|
||||
@@ -536,13 +528,13 @@ func foldInto(ctx context.Context, inv *inventory.Inventory, into *inventory.Pla
|
||||
}
|
||||
|
||||
// newBatch is a new batch of a kind, kept before its first merge names it: a merge never names a plan the store
|
||||
// does not hold. cutAtOnce closes its window at once.
|
||||
// does not hold. cutAtOnce closes its window at once; waits says why it waits for its group, when it does.
|
||||
func newBatch(ctx context.Context, inv *inventory.Inventory, first inventory.BatchedMerge, now time.Time, own,
|
||||
cutAtOnce bool) (inventory.Plan, error) {
|
||||
cutAtOnce bool, waits string) (inventory.Plan, error) {
|
||||
b := inventory.Plan{ID: fmt.Sprintf("plan-%d", now.UnixNano()), Repository: first.Repository, Branch: first.Branch,
|
||||
Commit: first.Commit, Merged: first.Merged, Created: now, State: inventory.PlanAssembling,
|
||||
Tiers: [][]string{}, Modules: map[string]*inventory.PlanModule{},
|
||||
Delivery: &inventory.PlanDelivery{Batch: &inventory.PlanBatch{Own: own, CutAtOnce: cutAtOnce}}}
|
||||
Delivery: &inventory.PlanDelivery{Batch: &inventory.PlanBatch{Own: own, CutAtOnce: cutAtOnce, Waits: waits}}}
|
||||
if err := inv.SavePlan(ctx, &b); err != nil {
|
||||
return inventory.Plan{}, err
|
||||
}
|
||||
@@ -576,12 +568,14 @@ func keepBatch(ctx context.Context, inv *inventory.Inventory, b *inventory.Plan,
|
||||
b.Delivery.Merges = named
|
||||
var closed, cutAtOnce bool
|
||||
var withheld []string
|
||||
var waits string
|
||||
if was := b.Delivery.Batch; was != nil {
|
||||
closed, withheld = was.Closed, was.Withheld // a stop's, which no look takes back (novox/hq ADR 0299)
|
||||
cutAtOnce = was.CutAtOnce // the merge's, until another joins it (ADR 0304 decision 1)
|
||||
waits = was.Waits // its group's, as said when it was made (ADR 0306 decision 2)
|
||||
}
|
||||
b.Delivery.Batch = &inventory.PlanBatch{ClosesAt: closes, AtMost: latest, Behind: behind, Own: b.OwnPath(),
|
||||
Closed: closed, Withheld: withheld, CutAtOnce: cutAtOnce}
|
||||
Closed: closed, Withheld: withheld, CutAtOnce: cutAtOnce, Waits: waits}
|
||||
b.State = inventory.PlanAssembling
|
||||
if behind != "" && windowClosed(*b, now) {
|
||||
b.State = inventory.PlanQueued
|
||||
@@ -1366,8 +1360,12 @@ func batchWords(b inventory.Plan, now time.Time) string {
|
||||
if left < 0 {
|
||||
left = 0
|
||||
}
|
||||
return fmt.Sprintf("assembling: %s left (at the latest %s); grouped: %s; plan not yet calculated",
|
||||
secondsWords(left), w.AtMost.Local().Format("15:04:05"), grouped)
|
||||
waits := ""
|
||||
if w.Waits != "" {
|
||||
waits = " — " + w.Waits
|
||||
}
|
||||
return fmt.Sprintf("assembling: %s left (at the latest %s)%s; grouped: %s; plan not yet calculated",
|
||||
secondsWords(left), w.AtMost.Local().Format("15:04:05"), waits, grouped)
|
||||
}
|
||||
|
||||
// groupedWords is a batch's commits, each with the earlier merges it answers.
|
||||
|
||||
Reference in New Issue
Block a user