Specify fenced activation and source credential contracts
Define bounded reservation recovery, exact activation replay fencing, immutable source identities, and deployment-owned secret and target policy boundaries. Align the OpenAPI contract and add a split-store activation safety refinement.
This commit is contained in:
parent
3881514e4b
commit
033cfeaac6
13 changed files with 877 additions and 49 deletions
|
|
@ -14,6 +14,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
@ -42,6 +43,7 @@ PROPERTIES
|
|||
FailureDispositionHonored
|
||||
EventuallyDispatched
|
||||
EventuallyReaped
|
||||
EventuallyAuthorizedResolved
|
||||
EventuallyTerminal
|
||||
EventuallyNonWinnerStagingCleaned
|
||||
EventuallySystemQuiescent
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ EXTENDS Naturals, FiniteSets, TLC
|
|||
|
||||
CONSTANTS
|
||||
Jobs, Workers, InitialWorkers, NoJob, NoWorker,
|
||||
MaxAttempts, MaxProgress, LeaseLimit,
|
||||
MaxAttempts, MaxProgress, LeaseLimit, ReservationLimit,
|
||||
LocalLimit, GlobalLimit, FaultsEnabled, FaultServices,
|
||||
MaxCoordLosses, MaxPartitions
|
||||
|
||||
|
|
@ -40,6 +40,7 @@ ASSUME /\ Jobs # {}
|
|||
/\ MaxAttempts \in Nat \ {0}
|
||||
/\ MaxProgress \in Nat \ {0}
|
||||
/\ LeaseLimit \in Nat \ {0}
|
||||
/\ ReservationLimit \in Nat \ {0}
|
||||
/\ LocalLimit \in Nat \ {0}
|
||||
/\ GlobalLimit \in Nat \ {0}
|
||||
/\ FaultsEnabled \in BOOLEAN
|
||||
|
|
@ -119,7 +120,7 @@ VARIABLES
|
|||
checkpointValid,
|
||||
|
||||
\* CoordinationStore (reconstructible).
|
||||
queued, reservation, leaseState, leaseAge, cancelNotice,
|
||||
queued, reservation, reservationAge, leaseState, leaseAge, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount,
|
||||
|
||||
\* Worker incarnations, per-service links, partition budget.
|
||||
|
|
@ -133,7 +134,7 @@ durableVars ==
|
|||
<<phase, cancelRequested, currentToken, authority, dispatchNeeded,
|
||||
committedAttempt, checkpoint, checkpointValid>>
|
||||
coordinationVars ==
|
||||
<<queued, reservation, leaseState, leaseAge, cancelNotice,
|
||||
<<queued, reservation, reservationAge, leaseState, leaseAge, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
workerVars == <<workerState, links, partitionCount>>
|
||||
attemptVars ==
|
||||
|
|
@ -168,6 +169,7 @@ OtherCapacity(w) ==
|
|||
CoordinationClean(j) ==
|
||||
/\ ~queued[j]
|
||||
/\ reservation[j] = NoWorker
|
||||
/\ reservationAge[j] = 0
|
||||
/\ ~cancelNotice[j]
|
||||
/\ liveProgress[j] = 0
|
||||
/\ liveProgressAttempt[j] = NoAttempt
|
||||
|
|
@ -195,6 +197,7 @@ Init ==
|
|||
/\ checkpointValid = [j \in Jobs |-> FALSE]
|
||||
/\ queued = [j \in Jobs |-> FALSE]
|
||||
/\ reservation = [j \in Jobs |-> NoWorker]
|
||||
/\ reservationAge = [j \in Jobs |-> 0]
|
||||
/\ leaseState = [a \in AttemptIds |-> NoLease]
|
||||
/\ leaseAge = [a \in AttemptIds |-> 0]
|
||||
/\ cancelNotice = [j \in Jobs |-> FALSE]
|
||||
|
|
@ -222,7 +225,7 @@ Enqueue(j) ==
|
|||
/\ reservation[j] = NoWorker
|
||||
/\ queued' = [queued EXCEPT ![j] = TRUE]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<reservation, leaseState, leaseAge, cancelNotice,
|
||||
/\ UNCHANGED <<reservation, reservationAge, leaseState, leaseAge, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -235,6 +238,7 @@ Reserve(j, w) ==
|
|||
/\ CapacityAvailable(w)
|
||||
/\ queued' = [queued EXCEPT ![j] = FALSE]
|
||||
/\ reservation' = [reservation EXCEPT ![j] = w]
|
||||
/\ reservationAge' = [reservationAge EXCEPT ![j] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<leaseState, leaseAge, cancelNotice, liveProgress,
|
||||
liveProgressAttempt, coordLossCount>>
|
||||
|
|
@ -289,6 +293,7 @@ ActivateAttempt(a) ==
|
|||
/\ workerState[w] = WorkerUp
|
||||
/\ CanReach(w, CoordSvc)
|
||||
/\ reservation' = [reservation EXCEPT ![j] = NoWorker]
|
||||
/\ reservationAge' = [reservationAge EXCEPT ![j] = 0]
|
||||
/\ leaseState' = [leaseState EXCEPT ![a] = LeaseLive]
|
||||
/\ leaseAge' = [leaseAge EXCEPT ![a] = 0]
|
||||
/\ liveProgress' = [liveProgress EXCEPT ![j] = attemptProgress[a]]
|
||||
|
|
@ -309,24 +314,44 @@ RenewLease(a) ==
|
|||
/\ CanReach(w, CoordSvc)
|
||||
/\ leaseAge' = [leaseAge EXCEPT ![a] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, leaseState, cancelNotice,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, leaseState, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
||||
Tick ==
|
||||
/\ \E a \in AttemptIds :
|
||||
leaseState[a] = LeaseLive /\ leaseAge[a] < LeaseLimit
|
||||
/\ (\E a \in AttemptIds :
|
||||
leaseState[a] = LeaseLive /\ leaseAge[a] < LeaseLimit)
|
||||
\/ (\E j \in Jobs :
|
||||
reservation[j] # NoWorker /\ reservationAge[j] < ReservationLimit)
|
||||
/\ leaseAge' =
|
||||
[a \in AttemptIds |->
|
||||
IF leaseState[a] = LeaseLive /\ leaseAge[a] < LeaseLimit
|
||||
THEN leaseAge[a] + 1 ELSE leaseAge[a]]
|
||||
/\ reservationAge' =
|
||||
[j \in Jobs |->
|
||||
IF reservation[j] # NoWorker
|
||||
/\ reservationAge[j] < ReservationLimit
|
||||
THEN reservationAge[j] + 1 ELSE reservationAge[j]]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, leaseState, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
||||
\* Reservation expiry is coordination-only. Queued jobs become eligible for
|
||||
\* Enqueue; authorized attempts become eligible for ReapLostAttempt.
|
||||
ExpireReservation(j) ==
|
||||
/\ reservation[j] # NoWorker
|
||||
/\ reservationAge[j] = ReservationLimit
|
||||
/\ reservation' = [reservation EXCEPT ![j] = NoWorker]
|
||||
/\ reservationAge' = [reservationAge EXCEPT ![j] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, leaseState, leaseAge, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
||||
\* Lease expiry does not clear live progress: product may retain a stale
|
||||
\* (attempt, bytes) hint until overwrite, reader discard, or terminal GC.
|
||||
ExpireLease(a) ==
|
||||
|
|
@ -335,7 +360,7 @@ ExpireLease(a) ==
|
|||
/\ leaseState' = [leaseState EXCEPT ![a] = LeaseExpired]
|
||||
/\ leaseAge' = [leaseAge EXCEPT ![a] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, cancelNotice, liveProgress,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, cancelNotice, liveProgress,
|
||||
liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -347,6 +372,7 @@ LoseCoordinationState ==
|
|||
/\ coordLossCount < MaxCoordLosses
|
||||
/\ queued' = [j \in Jobs |-> FALSE]
|
||||
/\ reservation' = [j \in Jobs |-> NoWorker]
|
||||
/\ reservationAge' = [j \in Jobs |-> 0]
|
||||
/\ leaseState' =
|
||||
[a \in AttemptIds |->
|
||||
IF leaseState[a] = LeaseLive THEN LeaseExpired
|
||||
|
|
@ -419,6 +445,7 @@ ReleaseReservation(j) ==
|
|||
\/ (authority[j] # NoAttempt
|
||||
/\ attemptState[authority[j]] # AttemptAuthorized))
|
||||
/\ reservation' = [reservation EXCEPT ![j] = NoWorker]
|
||||
/\ reservationAge' = [reservationAge EXCEPT ![j] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, leaseState, leaseAge, cancelNotice,
|
||||
liveProgress, liveProgressAttempt, coordLossCount>>
|
||||
|
|
@ -502,7 +529,7 @@ PublishCancelNotice(j) ==
|
|||
/\ ~cancelNotice[j]
|
||||
/\ cancelNotice' = [cancelNotice EXCEPT ![j] = TRUE]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, leaseState, leaseAge, liveProgress,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, leaseState, leaseAge, liveProgress,
|
||||
liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -531,7 +558,7 @@ ReleaseLease(a) ==
|
|||
/\ leaseState' = [leaseState EXCEPT ![a] = LeaseExpired]
|
||||
/\ leaseAge' = [leaseAge EXCEPT ![a] = 0]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, cancelNotice, liveProgress,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, cancelNotice, liveProgress,
|
||||
liveProgressAttempt, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -546,7 +573,7 @@ ClearStaleLiveProgress(j) ==
|
|||
/\ liveProgressAttempt' =
|
||||
[liveProgressAttempt EXCEPT ![j] = NoAttempt]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, leaseState, leaseAge,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, leaseState, leaseAge,
|
||||
cancelNotice, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -557,6 +584,7 @@ CleanTerminalCoordination(j) ==
|
|||
\/ liveProgress[j] # 0 \/ liveProgressAttempt[j] # NoAttempt)
|
||||
/\ queued' = [queued EXCEPT ![j] = FALSE]
|
||||
/\ reservation' = [reservation EXCEPT ![j] = NoWorker]
|
||||
/\ reservationAge' = [reservationAge EXCEPT ![j] = 0]
|
||||
/\ cancelNotice' = [cancelNotice EXCEPT ![j] = FALSE]
|
||||
/\ liveProgress' = [liveProgress EXCEPT ![j] = 0]
|
||||
/\ liveProgressAttempt' =
|
||||
|
|
@ -628,7 +656,7 @@ ReportProgress(a) ==
|
|||
/\ liveProgressAttempt' =
|
||||
[liveProgressAttempt EXCEPT ![j] = a]
|
||||
/\ UNCHANGED durableVars
|
||||
/\ UNCHANGED <<queued, reservation, leaseState, leaseAge,
|
||||
/\ UNCHANGED <<queued, reservation, reservationAge, leaseState, leaseAge,
|
||||
cancelNotice, coordLossCount>>
|
||||
/\ UNCHANGED workerVars
|
||||
/\ UNCHANGED attemptVars
|
||||
|
|
@ -774,6 +802,7 @@ Next ==
|
|||
\/ \E a \in AttemptIds : RenewLease(a)
|
||||
\/ Tick
|
||||
\/ \E a \in AttemptIds : ExpireLease(a)
|
||||
\/ \E j \in Jobs : ExpireReservation(j)
|
||||
\/ LoseCoordinationState
|
||||
\/ \E w \in Workers, s \in Services : DropLink(w, s)
|
||||
\/ \E w \in Workers, s \in Services : RestoreLink(w, s)
|
||||
|
|
@ -812,6 +841,7 @@ Fairness ==
|
|||
/\ \A j \in Jobs : SF_vars(ExecuteJob(j))
|
||||
/\ \A a \in AttemptIds : WF_vars(ProcessOutcome(a))
|
||||
/\ \A a \in AttemptIds : WF_vars(ExpireLease(a))
|
||||
/\ \A j \in Jobs : WF_vars(ExpireReservation(j))
|
||||
/\ \A a \in AttemptIds : WF_vars(CooperativeStop(a))
|
||||
/\ \A a \in AttemptIds : WF_vars(ReleaseLease(a))
|
||||
/\ \A a \in AttemptIds : WF_vars(CleanupStage(a))
|
||||
|
|
@ -840,6 +870,7 @@ TypeOK ==
|
|||
/\ checkpointValid \in [Jobs -> BOOLEAN]
|
||||
/\ queued \in [Jobs -> BOOLEAN]
|
||||
/\ reservation \in [Jobs -> Workers \cup {NoWorker}]
|
||||
/\ reservationAge \in [Jobs -> 0..ReservationLimit]
|
||||
/\ leaseState \in [AttemptIds -> LeaseStates]
|
||||
/\ leaseAge \in [AttemptIds -> 0..LeaseLimit]
|
||||
/\ cancelNotice \in [Jobs -> BOOLEAN]
|
||||
|
|
@ -874,6 +905,7 @@ StateConsistency ==
|
|||
/\ (committedAttempt[j] # NoAttempt <=> phase[j] = Succeeded)
|
||||
/\ (phase[j] = Queued => dispatchNeeded[j])
|
||||
/\ (reservation[j] # NoWorker => ~queued[j])
|
||||
/\ (reservation[j] = NoWorker => reservationAge[j] = 0)
|
||||
/\ \A a \in AttemptIds :
|
||||
/\ (attemptState[a] = AttemptUnused <=>
|
||||
attemptWorker[a] = NoWorker)
|
||||
|
|
@ -1024,6 +1056,13 @@ EventuallyReaped ==
|
|||
\A a \in AttemptIds :
|
||||
(CurrentAuthority(a) /\ leaseState[a] # LeaseLive)
|
||||
~> (~CurrentAuthority(a) \/ Terminal(JobOf(a)))
|
||||
EventuallyAuthorizedResolved ==
|
||||
RecoveryAssumption =>
|
||||
\A a \in AttemptIds :
|
||||
(CurrentAuthority(a) /\ attemptState[a] = AttemptAuthorized)
|
||||
~> (attemptState[a] = AttemptExecuting
|
||||
\/ ~CurrentAuthority(a)
|
||||
\/ Terminal(JobOf(a)))
|
||||
EventuallyTerminal ==
|
||||
RecoveryAssumption => \A j \in Jobs : <>Terminal(j)
|
||||
|
||||
|
|
|
|||
28
docs/protocol/RemoraClaimActivation.cfg
Normal file
28
docs/protocol/RemoraClaimActivation.cfg
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
SPECIFICATION Spec
|
||||
|
||||
CHECK_DEADLOCK TRUE
|
||||
|
||||
CONSTANTS
|
||||
Claims = {c1}
|
||||
Fences = {f1, f2}
|
||||
Workers = {w1, w2}
|
||||
Operations = {op1, op2}
|
||||
NoWorker = NoWorker
|
||||
NoOwner = NoOwner
|
||||
NoRequest = NoRequest
|
||||
NoResponse = NoResponse
|
||||
Accepted = Accepted
|
||||
Rejected = Rejected
|
||||
|
||||
INVARIANTS
|
||||
TypeOK
|
||||
LiveLeaseMatchesAuthority
|
||||
ExecutingIsCommitted
|
||||
AcceptedResponseIsExactReplay
|
||||
ConflictIsChangedRequest
|
||||
ReapedClaimHasNoActivationEffect
|
||||
ReapedCoordinationIsClean
|
||||
|
||||
PROPERTIES
|
||||
ActivationAppliesAtMostOnce
|
||||
OperationRequestIsImmutable
|
||||
307
docs/protocol/RemoraClaimActivation.tla
Normal file
307
docs/protocol/RemoraClaimActivation.tla
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
---------------------- MODULE RemoraClaimActivation ----------------------
|
||||
EXTENDS Naturals
|
||||
|
||||
\* Split-store refinement of the atomic JobProtocol ActivateAttempt action.
|
||||
\* Durable execution is the linearization point; lease creation alone is not authority.
|
||||
|
||||
CONSTANTS
|
||||
Claims, Fences, Workers, Operations,
|
||||
NoWorker, NoOwner, NoRequest, NoResponse, Accepted, Rejected
|
||||
|
||||
RequestKeys == Claims \X Fences \X Workers
|
||||
|
||||
ASSUME /\ Claims # {}
|
||||
/\ Fences # {}
|
||||
/\ Workers # {}
|
||||
/\ Operations # {}
|
||||
/\ NoWorker \notin Workers
|
||||
/\ NoRequest \notin RequestKeys
|
||||
|
||||
Authorized == "Authorized"
|
||||
Executing == "Executing"
|
||||
Reaped == "Reaped"
|
||||
DurableStates == {Authorized, Executing, Reaped}
|
||||
|
||||
Idle == "Idle"
|
||||
Validated == "Validated"
|
||||
LeaseCreated == "LeaseCreated"
|
||||
Committed == "Committed"
|
||||
Finished == "Finished"
|
||||
ActivationStages == {Idle, Validated, LeaseCreated, Committed, Finished}
|
||||
|
||||
Activator == "Activator"
|
||||
Recovery == "Recovery"
|
||||
LockOwners == {NoOwner, Activator, Recovery}
|
||||
Responses == {NoResponse, Accepted, Rejected}
|
||||
|
||||
VARIABLES
|
||||
durableState, attemptFence, attemptWorker, reservation, lease,
|
||||
activationStage, durableLock, operationRequest, operationResponse,
|
||||
conflictRequest, activationEffectCount
|
||||
|
||||
vars == <<durableState, attemptFence, attemptWorker, reservation, lease,
|
||||
activationStage, durableLock, operationRequest, operationResponse,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
Request(c, f, w) == <<c, f, w>>
|
||||
ExactRequest(c) == Request(c, attemptFence[c], attemptWorker[c])
|
||||
|
||||
Init ==
|
||||
/\ durableState = [c \in Claims |-> Authorized]
|
||||
/\ attemptFence \in [Claims -> Fences]
|
||||
/\ attemptWorker \in [Claims -> Workers]
|
||||
/\ reservation = attemptWorker
|
||||
/\ lease = [c \in Claims |-> NoWorker]
|
||||
/\ activationStage = [c \in Claims |-> Idle]
|
||||
/\ durableLock = [c \in Claims |-> NoOwner]
|
||||
/\ operationRequest = [op \in Operations |-> NoRequest]
|
||||
/\ operationResponse = [op \in Operations |-> NoResponse]
|
||||
/\ conflictRequest = [op \in Operations |-> NoRequest]
|
||||
/\ activationEffectCount = [c \in Claims |-> 0]
|
||||
|
||||
BindOperation(op, c, f, w) ==
|
||||
/\ operationRequest[op] = NoRequest
|
||||
/\ operationRequest' =
|
||||
[operationRequest EXCEPT ![op] = Request(c, f, w)]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, durableLock, operationResponse,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
RejectOperationReuse(op, c, f, w) ==
|
||||
/\ operationRequest[op] # NoRequest
|
||||
/\ operationRequest[op] # Request(c, f, w)
|
||||
/\ conflictRequest' =
|
||||
[conflictRequest EXCEPT ![op] = Request(c, f, w)]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, durableLock, operationRequest,
|
||||
operationResponse, activationEffectCount>>
|
||||
|
||||
StartActivation(op, c, f, w) ==
|
||||
/\ operationRequest[op] = Request(c, f, w)
|
||||
/\ operationResponse[op] = NoResponse
|
||||
/\ Request(c, f, w) = ExactRequest(c)
|
||||
/\ activationStage[c] = Idle
|
||||
/\ durableState[c] = Authorized
|
||||
/\ reservation[c] = w
|
||||
/\ activationStage' = [activationStage EXCEPT ![c] = Validated]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, durableLock, operationRequest, operationResponse,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
CreateLease(c) ==
|
||||
LET w == attemptWorker[c]
|
||||
IN /\ activationStage[c] = Validated
|
||||
/\ durableState[c] = Authorized
|
||||
/\ reservation[c] = w
|
||||
/\ lease[c] = NoWorker
|
||||
/\ lease' = [lease EXCEPT ![c] = w]
|
||||
/\ activationStage' = [activationStage EXCEPT ![c] = LeaseCreated]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
durableLock, operationRequest, operationResponse,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
AcquireActivationLock(c) ==
|
||||
/\ activationStage[c] = LeaseCreated
|
||||
/\ durableState[c] = Authorized
|
||||
/\ durableLock[c] = NoOwner
|
||||
/\ durableLock' = [durableLock EXCEPT ![c] = Activator]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, operationRequest,
|
||||
operationResponse, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
LoseActivatorLock(c) ==
|
||||
/\ durableLock[c] = Activator
|
||||
/\ durableLock' = [durableLock EXCEPT ![c] = NoOwner]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, operationRequest,
|
||||
operationResponse, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
CommitActivation(c) ==
|
||||
LET w == attemptWorker[c]
|
||||
IN /\ activationStage[c] = LeaseCreated
|
||||
/\ durableLock[c] = Activator
|
||||
/\ durableState[c] = Authorized
|
||||
/\ reservation[c] = w
|
||||
/\ lease[c] = w
|
||||
/\ durableState' = [durableState EXCEPT ![c] = Executing]
|
||||
/\ reservation' = [reservation EXCEPT ![c] = NoWorker]
|
||||
/\ activationStage' = [activationStage EXCEPT ![c] = Committed]
|
||||
/\ durableLock' = [durableLock EXCEPT ![c] = NoOwner]
|
||||
/\ activationEffectCount' =
|
||||
[activationEffectCount EXCEPT ![c] = @ + 1]
|
||||
/\ UNCHANGED <<attemptFence, attemptWorker, lease,
|
||||
operationRequest, operationResponse, conflictRequest>>
|
||||
|
||||
ReplayActivation(op, c, f, w) ==
|
||||
/\ operationRequest[op] = Request(c, f, w)
|
||||
/\ Request(c, f, w) = ExactRequest(c)
|
||||
/\ durableState[c] = Executing
|
||||
/\ lease[c] = w
|
||||
/\ activationEffectCount[c] = 1
|
||||
/\ operationResponse' =
|
||||
[operationResponse EXCEPT ![op] = Accepted]
|
||||
/\ activationStage' = [activationStage EXCEPT ![c] = Finished]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, durableLock, operationRequest, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
RejectPrecondition(op, c, f, w) ==
|
||||
/\ operationRequest[op] = Request(c, f, w)
|
||||
/\ operationResponse[op] = NoResponse
|
||||
/\ \/ Request(c, f, w) # ExactRequest(c)
|
||||
\/ durableState[c] = Reaped
|
||||
\/ /\ durableState[c] = Executing
|
||||
/\ lease[c] # w
|
||||
/\ operationResponse' =
|
||||
[operationResponse EXCEPT ![op] = Rejected]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, durableLock, operationRequest,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
ExpireReservation(c) ==
|
||||
/\ durableState[c] = Authorized
|
||||
/\ reservation[c] # NoWorker
|
||||
/\ lease[c] = NoWorker
|
||||
/\ reservation' = [reservation EXCEPT ![c] = NoWorker]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, lease,
|
||||
activationStage, durableLock, operationRequest,
|
||||
operationResponse, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
ExpireLease(c) ==
|
||||
/\ durableState[c] = Executing
|
||||
/\ lease[c] = attemptWorker[c]
|
||||
/\ lease' = [lease EXCEPT ![c] = NoWorker]
|
||||
/\ operationResponse' =
|
||||
[op \in Operations |->
|
||||
IF operationResponse[op] = Accepted
|
||||
/\ operationRequest[op][1] = c
|
||||
THEN NoResponse ELSE operationResponse[op]]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
activationStage, durableLock, operationRequest,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
AcquireRecoveryLock(c) ==
|
||||
/\ durableState[c] = Authorized
|
||||
/\ durableLock[c] = NoOwner
|
||||
/\ durableLock' = [durableLock EXCEPT ![c] = Recovery]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
lease, activationStage, operationRequest,
|
||||
operationResponse, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
FinishRecovery(c) ==
|
||||
/\ durableLock[c] = Recovery
|
||||
/\ durableState[c] = Authorized
|
||||
/\ durableState' = [durableState EXCEPT ![c] = Reaped]
|
||||
/\ reservation' = [reservation EXCEPT ![c] = NoWorker]
|
||||
/\ lease' = [lease EXCEPT ![c] = NoWorker]
|
||||
/\ durableLock' = [durableLock EXCEPT ![c] = NoOwner]
|
||||
/\ UNCHANGED <<attemptFence, attemptWorker, activationStage,
|
||||
operationRequest, operationResponse, conflictRequest,
|
||||
activationEffectCount>>
|
||||
|
||||
CompensateRejectedActivation(c) ==
|
||||
LET w == attemptWorker[c]
|
||||
IN /\ durableState[c] = Reaped
|
||||
/\ activationStage[c] \in {Validated, LeaseCreated}
|
||||
/\ lease[c] \in {NoWorker, w}
|
||||
/\ lease' = [lease EXCEPT ![c] = NoWorker]
|
||||
/\ activationStage' = [activationStage EXCEPT ![c] = Finished]
|
||||
/\ UNCHANGED <<durableState, attemptFence, attemptWorker, reservation,
|
||||
durableLock, operationRequest, operationResponse,
|
||||
conflictRequest, activationEffectCount>>
|
||||
|
||||
Done ==
|
||||
/\ \A c \in Claims : durableState[c] \in {Executing, Reaped}
|
||||
/\ UNCHANGED vars
|
||||
|
||||
Next ==
|
||||
\/ \E op \in Operations, c \in Claims, f \in Fences, w \in Workers :
|
||||
BindOperation(op, c, f, w)
|
||||
\/ \E op \in Operations, c \in Claims, f \in Fences, w \in Workers :
|
||||
RejectOperationReuse(op, c, f, w)
|
||||
\/ \E op \in Operations, c \in Claims, f \in Fences, w \in Workers :
|
||||
StartActivation(op, c, f, w)
|
||||
\/ \E c \in Claims : CreateLease(c)
|
||||
\/ \E c \in Claims : AcquireActivationLock(c)
|
||||
\/ \E c \in Claims : LoseActivatorLock(c)
|
||||
\/ \E c \in Claims : CommitActivation(c)
|
||||
\/ \E op \in Operations, c \in Claims, f \in Fences, w \in Workers :
|
||||
ReplayActivation(op, c, f, w)
|
||||
\/ \E op \in Operations, c \in Claims, f \in Fences, w \in Workers :
|
||||
RejectPrecondition(op, c, f, w)
|
||||
\/ \E c \in Claims : ExpireReservation(c)
|
||||
\/ \E c \in Claims : ExpireLease(c)
|
||||
\/ \E c \in Claims : AcquireRecoveryLock(c)
|
||||
\/ \E c \in Claims : FinishRecovery(c)
|
||||
\/ \E c \in Claims : CompensateRejectedActivation(c)
|
||||
\/ Done
|
||||
|
||||
Spec == Init /\ [][Next]_vars
|
||||
|
||||
TypeOK ==
|
||||
/\ durableState \in [Claims -> DurableStates]
|
||||
/\ attemptFence \in [Claims -> Fences]
|
||||
/\ attemptWorker \in [Claims -> Workers]
|
||||
/\ reservation \in [Claims -> Workers \cup {NoWorker}]
|
||||
/\ lease \in [Claims -> Workers \cup {NoWorker}]
|
||||
/\ activationStage \in [Claims -> ActivationStages]
|
||||
/\ durableLock \in [Claims -> LockOwners]
|
||||
/\ operationRequest \in [Operations -> RequestKeys \cup {NoRequest}]
|
||||
/\ operationResponse \in [Operations -> Responses]
|
||||
/\ conflictRequest \in [Operations -> RequestKeys \cup {NoRequest}]
|
||||
/\ activationEffectCount \in [Claims -> 0..1]
|
||||
|
||||
LiveLeaseMatchesAuthority ==
|
||||
\A c \in Claims :
|
||||
lease[c] # NoWorker => lease[c] = attemptWorker[c]
|
||||
|
||||
ExecutingIsCommitted ==
|
||||
\A c \in Claims :
|
||||
durableState[c] = Executing =>
|
||||
/\ reservation[c] = NoWorker
|
||||
/\ activationStage[c] \in {Committed, Finished}
|
||||
/\ activationEffectCount[c] = 1
|
||||
|
||||
AcceptedResponseIsExactReplay ==
|
||||
\A op \in Operations :
|
||||
operationResponse[op] = Accepted =>
|
||||
\E c \in Claims :
|
||||
/\ operationRequest[op] = ExactRequest(c)
|
||||
/\ durableState[c] = Executing
|
||||
/\ lease[c] = attemptWorker[c]
|
||||
/\ activationEffectCount[c] = 1
|
||||
|
||||
ConflictIsChangedRequest ==
|
||||
\A op \in Operations :
|
||||
conflictRequest[op] # NoRequest =>
|
||||
/\ operationRequest[op] # NoRequest
|
||||
/\ conflictRequest[op] # operationRequest[op]
|
||||
|
||||
ReapedClaimHasNoActivationEffect ==
|
||||
\A c \in Claims :
|
||||
durableState[c] = Reaped => activationEffectCount[c] = 0
|
||||
|
||||
ReapedCoordinationIsClean ==
|
||||
\A c \in Claims :
|
||||
durableState[c] = Reaped =>
|
||||
/\ reservation[c] = NoWorker
|
||||
/\ lease[c] = NoWorker
|
||||
|
||||
ActivationAppliesAtMostOnceAction ==
|
||||
\A c \in Claims :
|
||||
activationEffectCount[c] = 1 => activationEffectCount'[c] = 1
|
||||
|
||||
ActivationAppliesAtMostOnce == [][ActivationAppliesAtMostOnceAction]_vars
|
||||
|
||||
OperationRequestIsImmutableAction ==
|
||||
\A op \in Operations :
|
||||
operationRequest[op] # NoRequest =>
|
||||
operationRequest'[op] = operationRequest[op]
|
||||
|
||||
OperationRequestIsImmutable == [][OperationRequestIsImmutableAction]_vars
|
||||
|
||||
=============================================================================
|
||||
|
|
@ -14,6 +14,7 @@ CONSTANTS
|
|||
MaxAttempts = 1
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 2
|
||||
FaultsEnabled = FALSE
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = FALSE
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ CONSTANTS
|
|||
MaxAttempts = 3
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ CONSTANTS
|
|||
MaxAttempts = 1
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 2
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = FALSE
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ CONSTANTS
|
|||
MaxAttempts = 1
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 3
|
||||
FaultsEnabled = FALSE
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 2
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ CONSTANTS
|
|||
MaxAttempts = 2
|
||||
MaxProgress = 1
|
||||
LeaseLimit = 1
|
||||
ReservationLimit = 1
|
||||
LocalLimit = 1
|
||||
GlobalLimit = 1
|
||||
FaultsEnabled = TRUE
|
||||
|
|
|
|||
Loading…
Reference in a new issue