bus5 B5 (A-107): the keeper's process answers mesh-broker's snapshot verbs itself through AnswerSeat
snapshot-get, snapshot-restore, snapshot-restore-cancel and snapshot-remove are answered by the keeper's process with the proved caller; it publishes snapshot-get's chunks and hears their acks on its own subscription, and acts at once with no hand-over through requests (the record of a running restore is written before it runs). The tools bundle keeps its tools, nats_snapshots among them. The protected refusal and the whole test's case (send, restore in place, removal) stay. Builds: design 47 G A-107 (G-20-lead-answers), §681 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -783,9 +783,7 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
|
||||
}
|
||||
ask := func(r Request) Request {
|
||||
r.Caller = "person.jo"
|
||||
put(r)
|
||||
k.ActOnRequests()
|
||||
return get(r.ID)
|
||||
return k.AnswerSnapshot(r)
|
||||
}
|
||||
put(Request{ID: "r20", Verb: VerbDrop, Path: path, Size: 100, Digest: digest, Protected: true, At: k.now(), Done: k.now()})
|
||||
put(Request{ID: "r21", Verb: VerbDrop, Path: path, Size: 100, Digest: "sha256:bad", At: k.now(), Done: k.now()})
|
||||
@@ -837,6 +835,13 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
|
||||
if got := ask(Request{ID: "c2", Verb: VerbSnapshotRestoreCancel, Of: "a3", Why: "w"}); got.Outcome != "error" {
|
||||
t.Errorf("cancel of an ended act: %+v", got)
|
||||
}
|
||||
// A restore written into the state requests is no request of a person's: the keeper answers the verb on the seat alone (A-107).
|
||||
before := len(bus.restored)
|
||||
put(Request{ID: "z1", Verb: VerbSnapshotRestore, Of: "r20", Why: "w", Caller: "person.jo"})
|
||||
k.ActOnRequests()
|
||||
if got := get("z1"); len(bus.restored) != before || got.Outcome == "accepted" || got.Error == "" {
|
||||
t.Errorf("a restore handed through the requests: %+v, restored %v", got, bus.restored)
|
||||
}
|
||||
// A restore a restart cut off is ended at the keeper's start.
|
||||
put(Request{ID: "a5", Verb: VerbSnapshotRestore, Of: "r20", Outcome: "accepted", Done: k.now()})
|
||||
k.EndCutOffRestores()
|
||||
@@ -869,9 +874,7 @@ func TestTheKeeperMakesWhatAVerdictAsksForAndSaysIt(t *testing.T) {
|
||||
put(Request{ID: "s3", Verb: VerbDrop, Snapshot: "/before/g.tar", At: old, Done: old})
|
||||
ask := func(r Request) Request {
|
||||
r.Caller = "person.jo"
|
||||
put(r)
|
||||
k.ActOnRequests()
|
||||
return get(r.ID)
|
||||
return k.AnswerSnapshot(r)
|
||||
}
|
||||
for _, r := range []Request{{ID: "x1", Verb: VerbSnapshotRemove, Why: "w"}, {ID: "x2", Verb: VerbSnapshotRemove, Of: "s1", AllExpired: true, Why: "w"}} {
|
||||
if got := ask(r); got.Outcome != "error" || !strings.Contains(got.Error, "not both and not neither") {
|
||||
|
||||
@@ -97,6 +97,33 @@ func (r Request) Act() occ.Act {
|
||||
return occ.Act{"verb": r.Verb, "module": r.Module, "local": r.Local}
|
||||
}
|
||||
|
||||
// AnswerSnapshot answers one call of the seat mesh-broker's snapshot-restore, snapshot-restore-cancel or snapshot-remove at once, as
|
||||
// the keeper's process answers it (design 47 G §681, A-107): r names the verb, its arguments and the proved caller, and comes back
|
||||
// ended with its Outcome (accepted, busy, verified or error), ActID and Error. Nothing is handed through the state requests but the
|
||||
// record of a restore that runs, which its end and a restart's cut-off read.
|
||||
func (k *Keeper) AnswerSnapshot(r Request) Request {
|
||||
if r.At.IsZero() {
|
||||
r.At = k.now()
|
||||
}
|
||||
var outcome string
|
||||
var err error
|
||||
switch r.Verb {
|
||||
case VerbSnapshotRestore:
|
||||
outcome, err = k.startRestore(&r)
|
||||
case VerbSnapshotRestoreCancel:
|
||||
outcome, err = k.cancelRestore(&r)
|
||||
case VerbSnapshotRemove:
|
||||
outcome, err = k.removeSnapshots(&r)
|
||||
default:
|
||||
outcome, err = "error", fmt.Errorf("%q is no snapshot verb", r.Verb)
|
||||
}
|
||||
r.Done, r.Outcome = k.now(), outcome
|
||||
if err != nil {
|
||||
r.Error = err.Error()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// ErrNoWarrant is a request that waits for the operator's word: kept, acted on once the warrant is held.
|
||||
var ErrNoWarrant = errors.New("the operator has not answered yet")
|
||||
|
||||
@@ -154,14 +181,6 @@ func (k *Keeper) act(r *Request) (string, error) {
|
||||
}
|
||||
return fmt.Sprintf("the first view answered at revision %d", s.Revision), nil
|
||||
}
|
||||
switch r.Verb {
|
||||
case VerbSnapshotRestore:
|
||||
return k.startRestore(r)
|
||||
case VerbSnapshotRestoreCancel:
|
||||
return k.cancelRestore(r)
|
||||
case VerbSnapshotRemove:
|
||||
return k.removeSnapshots(r)
|
||||
}
|
||||
if !k.Viewed() {
|
||||
return "", fmt.Errorf("%w: the keeper holds no first view yet, so it acts on nothing", ErrNoWarrant)
|
||||
}
|
||||
|
||||
@@ -111,6 +111,18 @@ func (k *Keeper) startRestore(r *Request) (string, error) {
|
||||
k.restoring = run
|
||||
k.mu.Unlock()
|
||||
r.ActID = run.act
|
||||
// The act's record is written before the restore runs, as the end of the restore and a restart's cut-off read it; a record that
|
||||
// cannot be written ends the start, so no restore runs that nothing could find again.
|
||||
held := *r
|
||||
held.Done, held.Outcome = k.now(), "accepted"
|
||||
data, _ := json.Marshal(held)
|
||||
if _, err := k.Store.Put(StateRequests, r.ID, data); err != nil {
|
||||
k.mu.Lock()
|
||||
k.restoring = nil
|
||||
k.mu.Unlock()
|
||||
cancel()
|
||||
return "error", fmt.Errorf("the restore's record cannot be written, so nothing is restored: %w", err)
|
||||
}
|
||||
k.record(r, fmt.Sprintf("restores the snapshot of the request %s (%s) in place", rec.ID, rec.Path))
|
||||
go k.restore(ctx, run, rec, r.Caller, r.Why)
|
||||
return "accepted", nil
|
||||
|
||||
Reference in New Issue
Block a user