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  (***************************************************************************)