package hostclaim import ( "errors" "fmt" ) var ( ErrStaleOp = errors.New("hostclaim: the claim is under a different operation") ErrWrongState = errors.New("hostclaim: transition not legal from the claim's state") ErrPendingChore = errors.New("hostclaim: an obligation is pending in a location this operation writes") // ErrRelocationFinishing is the completion barrier's refusal: the // serving op journals a completed relocation that its box has not yet // discharged. It is always returned wrapped with ErrPendingChore, so a // caller that only knows ErrPendingChore refuses it the same way; the // move door tells the two apart for its sentence. ErrRelocationFinishing = errors.New("hostclaim: a completed relocation is not yet discharged") ) func RequireOp(id string) func(*Claim) error { return func(c *Claim) error { if id == "" || c.Op.ID != id { return fmt.Errorf("%w: have %q, want %q", ErrStaleOp, c.Op.ID, id) } return nil } } // StartGuard is ยง4: one operation at a time, started from serving, and // CC11: never over a chore in a region or box the operation will write. // Region HA N13 (ruling 77): nor while a completed relocation's box has // not discharged its participation (completionBarrier). fencedCompletion // is completionBarrier's fencedSource (ruling 86): a box whose termination // fence the caller has verified (VerifyFence, under a FenceAuthority) for // this start, as a failover's start passes its source. "" when there is // no verified fence: never a box the caller has not verified, and never // one inferred from a missing fence. func StartGuard(c *Claim, regions, boxes []string, fencedCompletion string) error { if c.Holder == nil || c.Op.Kind != KindServing { return fmt.Errorf("%w: kind %q", ErrWrongState, c.Op.Kind) } if err := completionBarrier(c, fencedCompletion); err != nil { return err } inR, inB := set(regions), set(boxes) for _, o := range c.Obligations { if (o.Region != "" && inR[o.Region]) || (o.Box != "" && inB[o.Box]) { return fmt.Errorf("%w: %s %s%s", ErrPendingChore, o.Kind, o.Region, o.Box) } } return nil } func set(xs []string) map[string]bool { m := make(map[string]bool, len(xs)) for _, x := range xs { m[x] = true } return m }