-
Notifications
You must be signed in to change notification settings - Fork 5
/
ClockSync5.tla
158 lines (139 loc) · 4.7 KB
/
ClockSync5.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
154
155
156
157
158
------------------------------ MODULE ClockSync5 ------------------------------
(*
* Incremental TLA+ specification of the clock synchronization algorithm from:
*
* Hagit Attiya, Jennifer Welch. Distributed Computing. Wiley Interscience, 2004,
* p. 147, Algorithm 20.
*
* Assumptions: timestamps are natural numbers, not reals.
*
* Version 5: Ignoring the message by the process itself
* Version 4: Adjusting clock values (test 4 + invariant violation)
* Version 3: Receiving messages (test 3)
* Version 2: Sending messages (test 2)
* Version 1: Setting up the clocks (test 1)
*)
EXTENDS Integers, FiniteSets
CONSTANTS
\* minimum message delay
\* @type: Int;
t_min,
\* maximum message delay
\* @type: Int;
t_max
ASSUME(t_min >= 0 /\ t_max > t_min)
VARIABLES
\* the reference clock, inaccessible to the processes
\* @type: Int;
time,
\* hardware clock of a process
\* @type: Str -> Int;
hc,
\* clock adjustment of a process
\* @type: Str -> Int;
adj,
\* clock diff for process j, as seen by a process j
\* @type: <<Str, Str>> -> Int;
diff,
\* messages sent by the processes
\* @type: Set([src: Str, ts: Int]);
msgs,
\* messages received by the processes
\* @type: Str -> Set([src: Str, ts: Int]);
rcvd,
\* the control state of a process
\* @type: Str -> Str;
state
(***************************** DEFINITIONS *********************************)
\* we fix the set to contain two processes
Proc == { "p1", "p2" }
\* the number of processes
NProc == Cardinality(Proc)
\* control states
State == { "init", "sent", "sync" }
\* the adjusted clock of process i
AC(i) == hc[i] + adj[i]
(*************************** INITIALIZATION ********************************)
\* Initialization
Init ==
/\ time \in Nat
/\ hc \in [ Proc -> Nat ]
/\ adj = [ p \in Proc |-> 0 ]
/\ diff = [ <<p, q>> \in Proc \X Proc |-> 0 ]
/\ state = [ p \in Proc |-> "init" ]
/\ msgs = {}
/\ rcvd = [ p \in Proc |-> {} ]
(******************************* ACTIONS ***********************************)
\* send the value of the hardware clock
SendMsg(p) ==
/\ state[p] = "init"
/\ msgs' = msgs \union { [ src |-> p, ts |-> hc[p] ] }
/\ state' = [ state EXCEPT ![p] = "sent" ]
/\ UNCHANGED <<time, hc, adj, diff, rcvd>>
\* If the process has received a message from all processes (but p),
\* then adjust the clock. Otherwise, accumulate the difference.
\* @type: (Str, <<Str, Str>> -> Int,
\* Set([src: Str, ts: Int])) => Bool;
AdjustClock(p, newDiff, newRcvd) ==
LET fromAll == { m.src: m \in newRcvd } = Proc \ { p } IN
IF fromAll
THEN
\* Assuming that Proc = { "p1", "p2" }.
\* See ClockSync5 for the general case.
/\ adj' = [ adj EXCEPT ![p] = (newDiff[p, "p1"] + newDiff[p, "p2"]) \div 2 ]
/\ state' = [ state EXCEPT ![p] = "sync" ]
ELSE
UNCHANGED <<adj, state>>
\* Receive a message sent by another process.
\* Adjust the clock if the message has been received from all processes.
ReceiveMsg(p) ==
/\ state[p] = "sent"
/\ \E m \in msgs:
/\ m \notin rcvd[p]
/\ m.src /= p \* ignore the message by p itself
\* the message cannot be received earlier than after t_min
/\ hc[m.src] >= m.ts + t_min
\* accumulate the difference and adjust the clock if possible
/\ LET delta == m.ts - hc[p] + (t_min + t_max) \div 2 IN
LET newDiff == [ diff EXCEPT ![p, m.src] = delta ] IN
LET newRcvd == rcvd[p] \union { m } IN
/\ AdjustClock(p, newDiff, newRcvd)
/\ rcvd' = [ rcvd EXCEPT ![p] = newRcvd ]
/\ diff' = newDiff
/\ UNCHANGED <<time, hc, msgs>>
\* let the time flow
AdvanceClocks(delta) ==
/\ delta > 0
\* clocks can be advanced only if there is no pending message
/\ \A m \in msgs:
hc[m.src] + delta > t_max =>
\A p \in Proc:
m \in rcvd[m.src]
\* clocks are advanced uniformly
/\ time' = time + delta
/\ hc' = [ p \in Proc |-> hc[p] + delta ]
/\ UNCHANGED <<adj, diff, msgs, state, rcvd>>
\* all actions together
Next ==
\/ \E delta \in Int:
AdvanceClocks(delta)
\/ \E p \in Proc:
\/ SendMsg(p)
\/ ReceiveMsg(p)
(******************************* PROPERTIES **********************************)
\* Theorem 6.15 from AW04:
\* Algorithm achieves u * (1 - 1/n)-synchronization for n processors.
SkewInv ==
LET allSync ==
\A p \in Proc: state[p] = "sync"
IN
LET boundedSkew ==
LET bound == (t_max - t_min) * (NProc - 1)
IN
\A p, q \in Proc:
LET df == AC(p) - AC(q)
IN
-bound <= df * NProc /\ df * NProc <= bound
IN
allSync => boundedSkew
===============================================================================