github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/tla/2pc.tla (about) 1 (***************************************************************************) 2 (* This specification is discussed in "Two-Phase Commit", Lecture 6 of the *) 3 (* TLA+ Video Course. It describes the Two-Phase Commit protocol, in *) 4 (* which a transaction manager (TM) coordinates the resource managers *) 5 (* (RMs) to implement the Transaction Commit specification of module *) 6 (* TCommit. In this specification, RMs spontaneously issue Prepared *) 7 (* messages. We ignore the Prepare messages that the TM can send to the *) 8 (* RMs. *) 9 (* *) 10 (* For simplicity, we also eliminate Abort messages sent by an RM when it *) 11 (* decides to abort. Such a message would cause the TM to abort the *) 12 (* transaction, an event represented here by the TM spontaneously deciding *) 13 (* to abort. *) 14 (***************************************************************************) 15 CONSTANT RM \* The set of resource managers 16 17 VARIABLES 18 rmState, \* rmState[r] is the state of resource manager r. 19 tmState, \* The state of the transaction manager. 20 tmPrepared, \* The set of RMs from which the TM has received "Prepared" 21 \* messages. 22 msgs 23 (***********************************************************************) 24 (* In the protocol, processes communicate with one another by sending *) 25 (* messages. For simplicity, we represent message passing with the *) 26 (* variable msgs whose value is the set of all messages that have been *) 27 (* sent. A message is sent by adding it to the set msgs. An action *) 28 (* that, in an implementation, would be enabled by the receipt of a *) 29 (* certain message is here enabled by the presence of that message in *) 30 (* msgs. For simplicity, messages are never removed from msgs. This *) 31 (* allows a single message to be received by multiple receivers. *) 32 (* Receipt of the same message twice is therefore allowed; but in this *) 33 (* particular protocol, that's not a problem. *) 34 (***********************************************************************) 35 36 Messages == 37 (*************************************************************************) 38 (* The set of all possible messages. Messages of type "Prepared" are *) 39 (* sent from the RM indicated by the message's rm field to the TM. *) 40 (* Messages of type "Commit" and "Abort" are broadcast by the TM, to be *) 41 (* received by all RMs. The set msgs contains just a single copy of *) 42 (* such a message. *) 43 (*************************************************************************) 44 [type : {"Prepared"}, rm : RM] \cup [type : {"Commit", "Abort"}] 45 46 TPTypeOK == 47 (*************************************************************************) 48 (* The type-correctness invariant *) 49 (*************************************************************************) 50 /\ rmState \in [RM -> {"working", "prepared", "committed", "aborted"}] 51 /\ tmState \in {"init", "done"} 52 /\ tmPrepared \subseteq RM 53 /\ msgs \subseteq Messages 54 55 TPInit == 56 (*************************************************************************) 57 (* The initial predicate. *) 58 (*************************************************************************) 59 /\ rmState = [r \in RM |-> "working"] 60 /\ tmState = "init" 61 /\ tmPrepared = {} 62 /\ msgs = {} 63 ----------------------------------------------------------------------------- 64 (***************************************************************************) 65 (* We now define the actions that may be performed by the processes, first *) 66 (* the TM's actions, then the RMs' actions. *) 67 (***************************************************************************) 68 TMRcvPrepared(r) == 69 (*************************************************************************) 70 (* The TM receives a "Prepared" message from resource manager r. We *) 71 (* could add the additional enabling condition r \notin tmPrepared, *) 72 (* which disables the action if the TM has already received this *) 73 (* message. But there is no need, because in that case the action has *) 74 (* no effect; it leaves the state unchanged. *) 75 (*************************************************************************) 76 /\ tmState = "init" 77 /\ [type |-> "Prepared", rm |-> r] \in msgs 78 /\ tmPrepared' = tmPrepared \cup {r} 79 /\ UNCHANGED <<rmState, tmState, msgs>> 80 81 TMCommit == 82 (*************************************************************************) 83 (* The TM commits the transaction; enabled iff the TM is in its initial *) 84 (* state and every RM has sent a "Prepared" message. *) 85 (*************************************************************************) 86 /\ tmState = "init" 87 /\ tmPrepared = RM 88 /\ tmState' = "done" 89 /\ msgs' = msgs \cup {[type |-> "Commit"]} 90 /\ UNCHANGED <<rmState, tmPrepared>> 91 92 TMAbort == 93 (*************************************************************************) 94 (* The TM spontaneously aborts the transaction. *) 95 (*************************************************************************) 96 /\ tmState = "init" 97 /\ tmState' = "done" 98 /\ msgs' = msgs \cup {[type |-> "Abort"]} 99 /\ UNCHANGED <<rmState, tmPrepared>> 100 101 RMPrepare(r) == 102 (*************************************************************************) 103 (* Resource manager r prepares. *) 104 (*************************************************************************) 105 /\ rmState[r] = "working" 106 /\ rmState' = [rmState EXCEPT ![r] = "prepared"] 107 /\ msgs' = msgs \cup {[type |-> "Prepared", rm |-> r]} 108 /\ UNCHANGED <<tmState, tmPrepared>> 109 110 RMChooseToAbort(r) == 111 (*************************************************************************) 112 (* Resource manager r spontaneously decides to abort. As noted above, r *) 113 (* does not send any message in our simplified spec. *) 114 (*************************************************************************) 115 /\ rmState[r] = "working" 116 /\ rmState' = [rmState EXCEPT ![r] = "aborted"] 117 /\ UNCHANGED <<tmState, tmPrepared, msgs>> 118 119 RMRcvCommitMsg(r) == 120 (*************************************************************************) 121 (* Resource manager r is told by the TM to commit. *) 122 (*************************************************************************) 123 /\ [type |-> "Commit"] \in msgs 124 /\ rmState' = [rmState EXCEPT ![r] = "committed"] 125 /\ UNCHANGED <<tmState, tmPrepared, msgs>> 126 127 RMRcvAbortMsg(r) == 128 (*************************************************************************) 129 (* Resource manager r is told by the TM to abort. *) 130 (*************************************************************************) 131 /\ [type |-> "Abort"] \in msgs 132 /\ rmState' = [rmState EXCEPT ![r] = "aborted"] 133 /\ UNCHANGED <<tmState, tmPrepared, msgs>> 134 135 TPNext == 136 \/ TMCommit \/ TMAbort 137 \/ \E r \in RM : 138 TMRcvPrepared(r) \/ RMPrepare(r) \/ RMChooseToAbort(r) 139 \/ RMRcvCommitMsg(r) \/ RMRcvAbortMsg(r) 140 ----------------------------------------------------------------------------- 141 (***************************************************************************) 142 (* The material below this point is not discussed in Video Lecture 6. It *) 143 (* will be explained in Video Lecture 8. *) 144 (***************************************************************************) 145 146 TPSpec == TPInit /\ [][TPNext]_<<rmState, tmState, tmPrepared, msgs>> 147 (*************************************************************************) 148 (* The complete spec of the Two-Phase Commit protocol. *) 149 (*************************************************************************) 150 151 THEOREM TPSpec => []TPTypeOK 152 (*************************************************************************) 153 (* This theorem asserts that the type-correctness predicate TPTypeOK is *) 154 (* an invariant of the specification. *) 155 (*************************************************************************) 156 ----------------------------------------------------------------------------- 157 (***************************************************************************) 158 (* We now assert that the Two-Phase Commit protocol implements the *) 159 (* Transaction Commit protocol of module TCommit. The following statement *) 160 (* imports all the definitions from module TCommit into the current *) 161 (* module. *) 162 (***************************************************************************) 163 INSTANCE TCommit 164 165 THEOREM TPSpec => TCSpec 166 (*************************************************************************) 167 (* This theorem asserts that the specification TPSpec of the Two-Phase *) 168 (* Commit protocol implements the specification TCSpec of the *) 169 (* Transaction Commit protocol. *) 170 (*************************************************************************) 171 (***************************************************************************) 172 (* The two theorems in this module have been checked with TLC for six *) 173 (* RMs, a configuration with 50816 reachable states, in a little over a *) 174 (* minute on a 1 GHz PC. *) 175 (***************************************************************************)