-
Notifications
You must be signed in to change notification settings - Fork 201
/
Copy pathEPFailureDetector.tla
153 lines (139 loc) · 9 KB
/
EPFailureDetector.tla
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
------------------------- MODULE EPFailureDetector -------------------------
EXTENDS Integers, FiniteSets, TLC
CONSTANTS
Proc,
d0, (* The default time-out interval for all delta(p)(q) *)
SendPoint, (* Every correct process sends alive messages to others at every
SendPoint ticks of its local clock. *)
PredictPoint, (* Every correct process makes predictions about failures at every
PredictPoint ticks of its lock clock. *)
Messages
(* Assumptions about the constraints in our system.
- SendPoint # PredictPoint: a process cannot both send messages and receive
messages in one transition.
- PredictPoint % SendPoint # 0 /\ SendPoint % PredictPoint # 0 : the operation
Predict cannot subsume the operation Predict and vice versa. *)
ASSUME /\ 0 < PredictPoint /\ 0 < SendPoint
/\ PredictPoint % SendPoint # 0 /\ SendPoint % PredictPoint # 0
(* Variables' role:
- localClock[i] a discrete integer-numbered local clock of a process p_i
- suspected[i] predictions about failures of p_i
- delta[i][j] a time-out interval which p_i waits for hearing something
from a process p_j
- mailbox[i] messages which p_i has received in the current transition
- outgoingMessages[i] messages which p_i wants to send in the current transition
More information:
1/ A process p_i make a transition at every tick of its local clock localClock[i].
2/ At every tick of the global clock, at least one correct processes make a
transition.
3/ Processes can change their predictions.
4/ Correct processes eventually make stable predictions.
5/ Whenever p_i receives an "alive" message from p_j, p_i increases the time-out
interval of j, removes j from its suspended list suspected[i], and updates its
fromLastHeard[i][j]. *)
VARIABLES suspected, delta, fromLastHeard, localClock, outgoingMessages
vars == << suspected, delta, fromLastHeard, localClock, outgoingMessages >>
NULL == -1
(* Create an "alive" message for every processes *)
MakeAliveMsgsForAll(snder) == { [ from |-> snder, to |-> rcver, type |-> "alive" ] :
rcver \in Proc }
(* The initial state of processes
- 1st conj: No process p_is predicted as a faulty one.
- 2nd conj: Set every default time-out interval with d0.
- 3rd conj: No processes have received any messages from others.
- 4th conj: Every local clock starts at 0.
- 5th conj: No messages were sent. *)
Init ==
/\ suspected = [ i \in Proc |-> {} ]
/\ delta = [ i \in Proc |-> [ j \in Proc |-> d0 ] ]
/\ fromLastHeard = [ i \in Proc |-> [ j \in Proc |-> 0 ] ]
/\ localClock = [ i \in Proc |-> 0 ]
/\ outgoingMessages = [ i \in Proc |-> {} ]
(* - Whenever the value of its local clock is greater than SendPoint, PredictPoint,
and delta[i][j], the local clock is reset to 0.
- Because of the constraints about message delay and relative speeds of different
processes in partial synchrony, the upper bound of local clocks exists. *)
LocallyTick(i) ==
localClock' = [ localClock EXCEPT ![i] =
IF /\ \A j \in Proc : delta[i][j] < localClock[i]
/\ SendPoint < localClock[i]
/\ PredictPoint < localClock[i]
THEN 0
ELSE localClock[i] + 1 ]
(* - A process p_i sends an "alive" message to every process at every SendPoint ticks
of its local clock.
- p_i constructs an "alive" messages for every process by calling MakeAliveMsgs,
and put these messages in its outgoingMessages which will be picked up by the
environmental controller in the composition action.
- p_i does not know exactly how the communication system works. *)
SendAlive(i) ==
/\ localClock[i] % PredictPoint # 0
/\ localClock[i] % SendPoint = 0
/\ LocallyTick(i)
/\ outgoingMessages' = [ outgoingMessages EXCEPT ![i] = MakeAliveMsgsForAll(i)]
/\ fromLastHeard' = [ fromLastHeard EXCEPT ![i] =
[ j \in Proc |-> IF fromLastHeard[i][j] <= delta[i][j]
THEN fromLastHeard[i][j] + 1
ELSE fromLastHeard[i][j] ] ]
/\ UNCHANGED << suspected, delta >>
(* - incomingMessages: A process does not know exactly how messages are feed to it.
- 1nd conj: A process p_i can perform the operation Receive if and only if it do
not execute
the operations Send and Predict.
- 2nd conj: Update the value of its local clock.
- 3rd conj: Update fromLastHeard immediately after new messages are received.
If p_i receives a messages from p_j, then fromLastHeard[i][j] is reset
to 0. If p_i does not receive a messages from p_j, fromLastHeard[i][j] is
increased by 1. However, if fromLastHeard[i][j] is already greater than
delta[i][j], we keep fromLastHeard[i][j] unchanged.
- 4th conj: Increase the waiting time for processes from which a process p_i has
received messages.
- 5th conj: Update its predictions. All processes from which a process p_i has
received some message in this transition are marked as correct ones.
- 6th conj: outgoingMessages is irrelevant in this transition. *)
Receive(i, incomingMessages) ==
/\ \/ /\ localClock[i] % PredictPoint = 0
/\ localClock[i] % SendPoint = 0
\/ /\ localClock[i] % PredictPoint # 0
/\ localClock[i] % SendPoint # 0
/\ LocallyTick(i)
/\ fromLastHeard' = [ fromLastHeard EXCEPT ![i] =
[ j \in Proc |-> IF \E m \in incomingMessages : m.from = j
THEN 0
ELSE IF j \notin suspected[i]
THEN IF fromLastHeard[i][j] <= delta[i][j]
THEN fromLastHeard[i][j] + 1
ELSE fromLastHeard[i][j]
ELSE fromLastHeard[i][j] ] ]
/\ delta' = [ delta EXCEPT ![i] = [ j \in Proc |-> IF /\ j \in suspected[i]
/\ \E m \in incomingMessages : m.from = j
THEN delta[i][j] + 1
ELSE delta[i][j] ] ]
/\ suspected' = [ suspected EXCEPT ![i] = suspected[i] \ { j \in Proc : (\E msg \in incomingMessages : msg.from = j) } ]
/\ UNCHANGED outgoingMessages
(* - A process p_i makes predictions at every PredictPoint ticks of its local clock, based on messages
which it has received until now.
- If a process p_i has not received any message from a process p_j after delta[i][j] time units,
a process p_i predicts that a process p_j is faulty.
- 6h conjunciton: outgoingMessages is irrelevant in this transition. *)
Predict(i) ==
/\ localClock[i] % PredictPoint = 0
/\ localClock[i] % SendPoint # 0
/\ LocallyTick(i)
/\ suspected' = [ suspected EXCEPT ![i] = suspected[i] \cup { j \in Proc : fromLastHeard[i][j] > delta[i][j] } ]
/\ UNCHANGED outgoingMessages
/\ fromLastHeard' = [ fromLastHeard EXCEPT ![i] = [ j \in Proc |-> IF fromLastHeard[i][j] <= delta[i][j]
THEN fromLastHeard[i][j] + 1
ELSE fromLastHeard[i][j] ] ]
/\ UNCHANGED << delta >>
(* Type invariant *)
TypeOK ==
/\ fromLastHeard \in [ Proc -> [ Proc -> Int ] ]
/\ \A p, q \in Proc : fromLastHeard[p][q] \in Int
/\ delta \in [ Proc -> [ Proc -> Int ] ]
/\ suspected \in [ Proc -> SUBSET Proc ]
/\ outgoingMessages \in [ Proc -> SUBSET Messages ]
=============================================================================
\* Modification History
\* Last modified Mon Jun 11 17:27:19 CEST 2018 by tthai
\* Created Mon Jun 04 12:39:53 CEST 2018 by tthai