| index dc0fc914c..601b493dc 100644 |
| --- a/internal/host/movesoffline_return.go |
| +++ b/internal/host/movesoffline_return.go |
| @@ -10,7 +10,8 @@ package host |
| // index of its own region (moves.ReturnIndexPrefix: one LIST, whatever the |
| // number of hosts), which the console's return door writes beside each |
| // request. For each pending return it reads the forward's open record once |
| -// (cached, and a record it may not answer for cached as a negative), lists |
| +// (cached, and a record it knows it may not answer for cached as a |
| +// negative; with its own instance id not known yet, neither), lists |
| // that forward's requests, takes the current one |
| // (moves.CurrentReturnRequest) and, when no report of this box answers it |
| // yet, writes one create-only; then it deletes the index entry if it is |
| @@ -44,9 +45,11 @@ import ( |
| const offlineReturnScanEvery = time.Minute |
| |
| // returnState is the worker's memory of the scan, under pass: the open |
| -// records of the pending returns, and the pending returns this box may not |
| -// answer for, both by "<host>/<forward id>" and both pruned to the index |
| -// each scan. |
| +// records of the pending returns not known to be another box's (answered, |
| +// or waiting for this box's instance id), and the pending returns this box |
| +// may not answer for, both by "<host>/<forward id>" and both pruned to the |
| +// index each scan. A negative is cached only once it is known: the |
| +// instance id cannot change under a running process. |
| type returnState struct { |
| scanned time.Time |
| opens map[string]*moves.OpenRecord |
| @@ -62,14 +65,29 @@ func (w *movesWorker) returnScanDue(now time.Time) bool { |
| return every < 0 || w.returns.scanned.IsZero() || now.Sub(w.returns.scanned) >= every |
| } |
| |
| -// mayAnswer reports whether this box may answer returns of the forward o. |
| -func (w *movesWorker) mayAnswer(o *moves.OpenRecord) bool { |
| +// mayAnswer reports whether this box may answer returns of the forward o, |
| +// and whether it knows: a source participant pinned by this box's id and |
| +// an instance id cannot be judged while this box's own instance id is not |
| +// known yet (the metadata service has not answered), and the scan then |
| +// decides nothing for o until it is. |
| +func (w *movesWorker) mayAnswer(o *moves.OpenRecord) (may, known bool) { |
| cfg := w.cfg |
| if o.Participants != nil { |
| - return moves.ReturnParticipant(*o, cfg.BoxID, cfg.instance(), "") |
| + instance := cfg.instance() |
| + if moves.ReturnParticipant(*o, cfg.BoxID, instance, "") { |
| + return true, true |
| + } |
| + if instance == "" { |
| + for _, p := range o.Participants.Source { |
| + if p.BoxID != "" && p.BoxID == cfg.BoxID && p.InstanceID != "" { |
| + return false, false |
| + } |
| + } |
| + } |
| + return false, true |
| } |
| here := cfg.parkRegion() |
| - return here != "" && regionname.PlacementMatches(cfg.ParkHomeRegion, o.From, here) |
| + return here != "" && regionname.PlacementMatches(cfg.ParkHomeRegion, o.From, here), true |
| } |
| |
| // offlineReturns is the pass's return step, a scan when one is due: |
| @@ -111,12 +129,22 @@ func (w *movesWorker) offlineReturns(ctx context.Context, s release.Store) { |
| w.notice(k+"#offline-return", "moves: %s: the open record of %s: %v", host, fwd, err) |
| continue |
| } |
| - if o == nil || !w.mayAnswer(o) { |
| + if o == nil { |
| negatives[k] = true |
| continue |
| } |
| } |
| + // Judged every scan (the record is cached, the judgement is not): |
| + // an answer not known yet is neither a negative nor an answer. |
| + may, known := w.mayAnswer(o) |
| + if known && !may { |
| + negatives[k] = true |
| + continue |
| + } |
| opens[k] = o |
| + if !known { |
| + continue |
| + } |
| if err := w.answerReturn(ctx, s, o, key); err != nil { |
| w.notice(k+"#offline-return", "moves: %s: the return of %s: %v", host, fwd, err) |
| } |