package moves import "time" // The steps of a StoppedReport, in §5.3's order. StepTree to StepLease // are what stopevidence.Reconstruct observes from the box's durable state; // StepReplica is the caller's (the cut's step 5: the final checkpoint and // the digests), set after the checkpoint. const ( // StepTree: the host's cgroup was killed and drained (or never existed). StepTree = "tree" // StepStray: the agent's own cgroup leaf holds only the agent. StepStray = "stray" // StepFDs: no visible process holds the database, its WAL or its SHM. StepFDs = "fds" // StepLease: the host's lock.json is absent, released, or expired by // more than the lease's renewal margin. StepLease = "lease" // StepReplica: the final checkpoint reached the replica. StepReplica = "replica" ) // treeSteps are §5.3 steps 1 to 4, what `stopping` needs before the final // checkpoint. allSteps adds the replica. var ( treeSteps = [...]string{StepTree, StepStray, StepFDs, StepLease} allSteps = [...]string{StepTree, StepStray, StepFDs, StepLease, StepReplica} ) // StoppedReport is a role's stop evidence for one move operation (§5.3), // written to moves/////stopped-.json. Every // observation is from durable, observable state, so a restarted agent // writes the same report. Steps holds one Check per step id; a step that // never ran is absent, and an absent step is not OK. Stray lists the pids // StepStray found in the agent's leaf besides the agent, for the alert. A 0 // in it marks members the box could not identify (not visible in its pid // namespace). type StoppedReport struct { V int `json:"v"` Role string `json:"role"` Box string `json:"box"` Incarnation string `json:"incarnation"` ClaimGen uint64 `json:"claim_gen"` Host string `json:"host"` OpID string `json:"op_id"` Steps map[string]Check `json:"steps"` Stray []int `json:"stray,omitempty"` FinalTXID uint64 `json:"final_txid"` DBSHA256 string `json:"db_sha256"` FilesPlain string `json:"files_plain"` TimersSHA256 string `json:"timers_sha256"` CheckedAt time.Time `json:"checked_at"` } // TreeStopped reports §5.3 steps 1 to 4 all present and OK: the writer has // fully stopped, so the final checkpoint may run. func (r StoppedReport) TreeStopped() bool { return r.stepsOK(treeSteps[:]) } // Complete reports every step OK, StepReplica included. It fails closed on // any other step recorded in the report and not OK, so a step a later // version adds cannot be ignored by an older reader. func (r StoppedReport) Complete() bool { if !r.stepsOK(allSteps[:]) { return false } for _, c := range r.Steps { if !c.OK { return false } } return true } func (r StoppedReport) stepsOK(ids []string) bool { for _, id := range ids { if c, ok := r.Steps[id]; !ok || !c.OK { return false } } return true }