Escolar Documentos
Profissional Documentos
Cultura Documentos
MASTERS THESIS
Acknowledgements
I would like to thank ir. W.H.J. Feijen for introducing me and many others to the art of programming, for teaching an inspiring course in Design of Multiprograms, for giving me a direction to pursue and for suggesting me to ask dr.ir. R.R. Hoogerwoord as my supervisor. I would like to thank dr.ir. R.R. Hoogerwoord for many stimulating technical discussions and for always being able to give me new ideas and things to try. Thanks also go to my parents for supporting me, to Leon for our discussions about each others projects, to Fons and Tim for being fantastic roommates and to Maurice, Walter and everybody at Dynamic Solutions for giving me a great job during my study.
iii
Contents
1 Introduction 1.1 Problem description 1.2 Methods used . . . 1.3 Notation . . . . . . 1.4 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 1 2 2 3 3 3 3 4 4 4 5 5 5 5 6 6 6 7 8 9 10 11 11 11 11 11 12 16 18 18
2 Modelling faulty channels 2.1 Channel usage . . . . . . . . . . . . . . . . . 2.2 Channel interface . . . . . . . . . . . . . . . 2.2.1 Sending . . . . . . . . . . . . . . . . 2.2.2 Receiving . . . . . . . . . . . . . . . 2.2.3 Rule of import and export . . . . . . 2.3 Desired features . . . . . . . . . . . . . . . . 2.3.1 Formalization of the desired features . 2.4 Implementation of a reliable channel . . . . . 2.4.1 Send . . . . . . . . . . . . . . . . . 2.4.2 Receive . . . . . . . . . . . . . . . . 2.5 Implementation of a faulty channel . . . . . . 2.5.1 Loss . . . . . . . . . . . . . . . . . . 2.5.2 Duplication . . . . . . . . . . . . . . 2.5.3 No FIFO . . . . . . . . . . . . . . . 2.5.4 Rule of import and export . . . . . . 2.6 A faulty channel with bounded buffering . . . 2.7 Function for potential output . . . . . . . . . 3 A sliding window protocol 3.1 Introduction . . . . . . . . . . . . . . 3.2 Situation . . . . . . . . . . . . . . . . 3.3 Transferring N messages . . . . . . . 3.3.1 Specication . . . . . . . . . 3.3.2 Implementation . . . . . . . . 3.3.3 Progress . . . . . . . . . . . . 3.4 Transferring innitely many messages 3.4.1 Specication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . .
iv
3.5
3.6
3.4.2 Implementation . . . . . . . . . 3.4.3 Progress . . . . . . . . . . . . . Recycling indices . . . . . . . . . . . . 3.5.1 Reducing indices on channel F . 3.5.2 Reducing indices on channel G . 3.5.3 Implementing cyclic indices . . Limiting the size of sets . . . . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
18 20 20 21 24 26 27 30 30 30 30 31 31 32
4 Summary and conclusions 4.1 Summary . . . . . . . . . . . . . . . . . . . 4.2 Comparison to existing research . . . . . . . 4.2.1 Research of J.L.A. van de Snepscheut 4.2.2 Research of N.V. Stenning . . . . . . 4.3 Conclusions . . . . . . . . . . . . . . . . . . 4.4 Recommendations for future research . . . .
Chapter 1
Introduction
1.1 Problem description
Between physically separated machines, communication is often only possible over socalled faulty channels i.e., an asynchronous channel that can lose and duplicate messages and can receive messages in an order different from the one in which the messages were sent. Our main goal is to derive a protocol that enables the reliable transfer of a data stream from one machine to another machine over a faulty channel, i.e., the receiving side outputs a data stream that is equal to the data stream input on the sending side. Furthermore, the following is demanded from the protocol: the protocol should not hamper throughput unnecessarily, the protocol must be provably correct, and the protocol must exhibit progress. This problem is usually solved by a so-called sliding window protocol [Ste76, Sne95]. We will derive such a sliding window protocol and prove that it complies to all the given demands. We also show that our protocol is more general than [Sne95], and that the proof is more complete than [Ste76].
To be able to completely prove the correctness of the protocol using Owicki/Gries theory, the faulty channels are rst modelled as a set of program operations in Chapter 2. This model is then used to derive the protocol in Chapter 3.
1.3 Notation
The program notation used in this thesis is derived from the Guarded Command Language (GCL), and is the same as the notation used in [FG99]. In addition, these notations are used: Intervals of integers: for integers a and b, [a..b) denotes the set {i | a i < b }. Array segments: for any array X and natural numbers a and b that are at most the size of X, X[a..b) denotes the array segment that contains all array elements of X with an index in interval [a..b). Assignments using a proposition: x : P is a statement that assigns a value to variable x such that proposition P holds. It is only dened if (x :: P) holds. Channel names: because multiple channels are used, we distinguish the variables used by these channels by prexing variables and procedures that operate on these variables with a channel name, e.g., F.ct is a different variable from G.ct, and F.Recei ve is equal to the procedure Recei ve with all variable names prexed by F.
1.4 Terminology
This terminology is used throughout the document: Message: unit of communication over channels Sending: The action of posting a message to a channel by the sending process Receiving: The action of assigning a message, sent earlier, to a local variable of the receiving process Transferring: Sending and receiving a message
Chapter 2
4 U iiii F UUUUUUU iiii * 89:; 89:; ?>=< jUU B A UU i?>=< UUUU iiii i G tii Figure 2.1: Two processes connected by two channels Figure 2.1 shows an example setup, consisting of two processes, A and B, and two channels, F and G. The direction of the communication over the channels is signied by the arrows: A is the sending process of F and the receiving process of G, B is the receiving process of F and the sending process of G.
2.2.2 Receiving
Receiving a message is modelled by the Recei ve-operation. Receiving a message from a channel F into variable y can be implemented by the receiving process as follows: F.Recei ve(y) This operation is not guaranteed to terminate: Recei ve will not end until a message is received.
2.4.1 Send
The Send-operation is easy to implement, given the array C and variable ct introduced in 2.3.1. Sending a message b is implemented by: Send(b) : ; C.ct := b ct := ct + 1
2.4.2 Receive
C[0..ct) contains all sent messages. We introduce a variable cb : N that represents how many message have already been received. Initially, cb = 0. As messages will be received in the same order as they are sent, cb also represents the index of the next message to be received. Receiving a message in variable y can be implemented as follows: Recei ve(y) : ; ; if cb < ct ski p { cb < ct } y := C.cb { y C[0..ct) } cb := cb + 1 { y C[0..ct) } Note that the Recei ve-operation establishes the desired postassertion y C[0..ct), and that none of the assertions in the operation can be disturbed by a Send-operation, making them globally correct.
2.5.2 Duplication
Receiving a message always increases cb, making it impossible for message cb to be received multiple times. By omitting the increase of cb at the end of the Recei veoperation, messages can be duplicated: if th = 0, cb is not increased, and C.cb can be received again. Recei ve(y) : ; ; ; th : 0 th cb := cb + th if cb < ct ski p { cb < ct } y := C.cb { y C[0..ct) } However, this duplication is not nite. If the value 0 is consistently chosen for th, message C.cb is duplicated innitely many times. To make duplication nite, we introduce an unbounded array D[0..) of natural numbers, which is assumed to initially contain an arbitrary number larger than 0 for every possible index. Array D represents the number of times a message can be received: a message C.i will be received at most D.i times. Every number in array D is initially larger than 0 in order to keep losing and duplicating messages separate. 6
Finite duplication can now be implemented in the Recei ve-operation by decreasing D.cb after receiving a message, and increasing cb if D.cb = 0. Recei ve(y) : ; ; ; ; ; th : 0 th cb := cb + th do D.cb = 0 cb := cb + 1 od { (note 0) } { D.cb > 0 } if cb < ct ski p { cb < ct } { D.cb > 0 } y := C.cb { cb < ct } { D.cb > 0 } { y C[0..ct) } D.cb := D.cb 1 { y C[0..ct) } The added assertions are globally correct, because Send does not modify D. This implementation keeps K0 : (i : ct i : D.i > 0)
invariant. K 0 holds initially, because all elements of D are initially larger than 0. Statement ct := ct + 1 in Send does not disturb K 0. Statement D.cb := D.cb 1 in Recei ve does not disturb K 0, because cb < ct is a valid preassertion of that statement. (note 0): This loop terminates. To see this, consider this variant function: ( i : cb i D.i > 0 : i ) cb The domain of the minimum in this variant function is not empty, because of K 0. The value of this variant function is not changed by the Send-operation. Every iteration of the loop decreases the variant function by 1, and if it is 0, this implies D.cb > 0.
2.5.3 No FIFO
Because the Recei ve-operation always receives the message with index cb and because cb is only increasing, values are received in the same order as they are sent. It is of course possible to receive a message with an arbitrary index from [0..ct), but that would give too much freedom: in paragraph 2.5.1, we concluded that [0..cb) represented the indices of messages that would not be received anymore. The method for losing messages is based on this property. Messages with an index i for which D.i = 0 should also not be received anymore. To keep the previously introduced features of nite loss and nite duplication, but lose the FIFO property, an arbitrary index h is chosen, such that cb h < ct and D.h > 0. To accomplish this, we introduce local variable h : N. Recei ve(y) : th : 0 th 7
; ; ; ; ; ;
cb := cb + th do D.cb = 0 cb := cb + 1 od { D.cb > 0 } if cb < ct ski p { cb < ct } { D.cb > 0 } h : cb h < ct D.h > 0 y := C.h D.h := D.h 1 { y C[0..ct) }
This change will allow messages to be received in a different order than the one in which they were sent. The nite loss and nite duplication features that were added earlier are still present: messages can be lost because cb is increased, and messages can be duplicated because one index can be selected more than once. Because D is an array of natural numbers, duplication is nite; because cb is increased by a natural number, loss is nite.
We will introduce this assertion as a system invariant: K 1 : (i : 0 i < ct : Q(y := C.i ) ) This system invariant can be falsied by increasing ct. This gives an extra proof obligation in the Send-operation: Send(b) : ; { ? Q(y := b) } C.ct := b { Q(y := C.ct) (note 0) } ct := ct + 1
(note 0): The global correctness of this assertion is irrelevant, because Send(b) can be seen as an atomic statement that only changes private variables. 8
The queried preassertion Q(y := b) indicates that the rule of import and export applies to this implementation of faulty channels.
The only statement that disturbs K 2 is the increase of ct in the Send-operation: Send(b) : ; C.ct := b { ? ct < M + cb } ct := ct + 1
The queried assertion can be established by using an extra guard: Send(b) : ; C.ct := b if ct < M + cb ct := ct + 1
This means that Send is able to block the calling process, which is not desired. To avoid this, the oldest message in the buffer is removed when the buffer is full, by increasing cb: Send(b) : ; C.ct := b if ct < M + cb ct := ct + 1 ct = M + cb ct, cb := ct + 1, cb + 1
This introduces a new loss of messages, but the loss is nite: ct = M + cb implies cb < ct, causing a Recei ve-operation to either receive a message or increase cb (establishing ct < M + cb). The modied Send-operation can disturb assertion D.cb > 0 in Recei ve. Luckily, this assertion can safely be replaced by (i : cb i < ct : D.i > 0) which is locally correct in Recei ve. This assertion is not disturbed by assignment ct, cb := 9
ct + 1, cb + 1 in Send, because that assignment establishes D.(ct 1) > 0 due to the invariance of K 0. Recei ve(y) : ; ; ; ; ; ; th : 0 th cb := cb + th do D.cb = 0 cb := cb + 1 od { (i : cb i < ct : D.i > 0) } if cb < ct ski p { cb < ct } { (i : cb i < ct : D.i > 0) } h : cb h < ct D.h > 0 y := C.h D.h := D.h 1 { y C[0..ct) }
Send(b) increases Pot (b): Send(b) increases ct, establishing C.(ct 1) = b and D.(ct 1) > 0 (because of K 0), which increases Pot (b). Recei ve(y) decreases Pot (b) if this operation establishes y = b, because that means Recei ve has decreased D.h, where h is such that 0 h < ct C.h = b. Recei ve(y) does not change Pot (b) if this operation establishes y = b, because that means Recei ve has decreased D.h, where h is such that C.h = b.
10
Chapter 3
3.2 Situation
Consider two processes, A and B. A is to transfer data to B. The only way of communication that is allowed between A and B is the usage of faulty channels. Because the channels are faulty, at least two channels are needed: one channel for A to transfer data to B, and one channel that allows B to acknowledge reception of data. The types of the messages that are transferred over the channels is not important at this moment. The two channels are named F and G. Process A is the sending process of F and the receiving process of G, process B is the receiving process of F and the sending process of G. The situation is the same as the one depicted in gure 2.1.
11
We consider R0 to be a postcondition of A; if the postcondition has been established, A can stop sending messages.
3.3.2 Implementation
An obvious suggestion for an invariant for A is: P0 P1 : X[0..q) = Y [0..q) : 0qN
where q is a local variable of A. P0 and P1 hold initially if q = 0. Postcondition R0 is established if q = N. Invariant P0 suggests this structure for A: A: do q = N { ? X.q = Y.q (note 0) } q := q + 1 od {q = N }
(note 0): Y is a local variable of B and can neither be inspected nor changed by A. The assertion can therefore not be established by inspecting or changing Y . Assume that the indices i for which X.i = Y.i holds are known. We introduce a set Ackd of natural numbers that contains these indices. This can be captured in an invariant: P2 : (i : i Ackd : X.i = Y.i 0 i < N)
Using P2, the queried assertion X.q = Y.q can be established assuming global correctness will not be disturbed by other components by using a guarded skip: A: do q = N if q Ackd ski p ; { X.q = Y.q } q := q + 1 od {q = N }
This implementation will give us the next invariant for free: P3 : [0..q) Ackd
To enable progress, elements will have to be added to Ackd. We will not introduce a new component to do this; expanding Ackd can be done synchronously with q := q+1, because test q Ackd is only useful after changing Ackd. The value of a new local
12
variable of A, r : N, is added to Ackd: A: do q = N ; { ? X.r = Y.r 0 r < N (note 0) } Ackd := Ackd {r } ; if q Ackd ski p ; { X.q = Y.q } q := q + 1 od {q = N }
(note 0): This assertion is necessary to keep P2 invariant. A can only communicate with B via channels F and G. This means that this assertion can only be established locally by applying the rule of import and export on channel G. Global correctness is established by never assigning a value other than X.i to Y.i , for i : 0 i < N. What is the type of the messages transferred via channel G? The simplest form of an acknowledgement is the single index i , that represents the boolean value X.i = Y.i . We decide to use single indices as acknowledgements. This allows messages received via G to be added directly to Ackd: A: do q = N G.Recei ve(r ) ; { X.r = Y.r 0 r < N } Ackd := Ackd {r } ; if q Ackd ski p ; { X.q = Y.q } q := q + 1 od {q = N }
This construction allows for deadlock: the element added to Ackd does not necessarily equal q. In that case, the process blocks. To avoid this, the guarded skip is replaced by a loop: A: do q = N G.Recei ve(r ) ; { X.r = Y.r 0 r < N } Ackd := Ackd {r } ; do q Ackd { X.q = Y.q } ; q := q + 1 od od {q = N }
To allow for progress in A, B will have to send indices via G. Applying the rule of
13
import and export suggests this structure for B, where p is a local variable of B. B: [ ] (note 0): The rst conjunct of this assertion can be established by assignment Y. p := X. p, but X is a local variable of A and can neither be inspected nor changed by B. Therefore, a new local variable m of B is introduced. The value of m is assigned to Y. p: B: [ { ? X. p = m 0 p < N (note 1) } Y. p := m ; { X. p = Y. p 0 p < N (note 0) } G.Send( p) ] (note 0): This assertion is globally correct, because Y and p are local variables, and X is a constant. (note 1): This assertion can only be established by communication with A, because X is a local variable of A. Locally, this assertion can be established by applying the rule of import and export on channel F. What is the type of the messages transferred via channel F? A single element of X is insufcient; how can the value of p be extracted from this element? The value i for which X.i = m holds has to be available for that. To accomplish this, we assume that all messages received via channel F consist of a pair a, i , where a is an element of X, and i is the index of that element. B: [ ; ; ] (note 0): This assertion is globally correct, because p and m are local variables, and X is a constant. To allow for progress in B, A will have to send messages via F. This can be done in parallel with receiving the acknowledgements in A. The structure of A is changed to obtain a parallel composition with two components: A: do q = N A1 od do q = N A2 od F.Recei ve( m, p ) { X. p = m 0 p < N (note 0) } Y. p := m { X. p = Y. p 0 p < N } G.Send( p) { ? X. p = Y. p 0 p < N (note 0) } G.Send( p)
where A1 is the program fragment that processes the acknowledgements (the code is equal to the code previously assigned to A):
14
A1 : ; ;
G.Recei ve(r ) { X.r = Y.r 0 r < N } Ackd := Ackd {r } do q Ackd { X.q = Y.q } ; q := q + 1 od
A2 sends messages via F. The rule of import and export dictates the following structure for A2: A2 : { ? X.t = b 0 t < N (note 0) } F.Send( b, t ) (note 0): The rst conjunct of this assertion can of course be established by replacing b with X.t. A2 : { ? X.t = X.t 0 t < N (note 0) } F.Send( X.t, t ) (note 0): The second conjunct of this assertion is established by assigning a suitable value to t. A possible choice for t is q, but that would be unnecessarily hampering the throughput: it would mean that every message is sent repeatedly until an acknowledgement for that message is received. Only then another message will be sent. It seems more efcient to allow other messages than X.q to be sent; it also allows for more strategic freedom in choosing the value to be sent. It is useless to resend messages for which an acknowledgement has already been received. Therefore, a value for t is chosen from [0..N) \ Ackd. A2 : ; { ? [0..N)\Ackd = (note 0) } t : t [0..N) \ Ackd { X.t = X.t 0 t < N } F.Send( X.t, t )
(note 0): This assertion can be established locally by using a guarded skip, but is not globally correct, because elements are added to Ackd in A1. To avoid deadlock, we introduce a new set AckdCopy, to which Ackd is copied by A2, causing invariance of P4 : AckdCopy Ackd
This holds initially if AckdCopy = , and can be used in A2: A2 : ; ; { ? [0..N)\AckdCopy = (note 0) } t : t [0..N) \ AckdCopy { X.t = X.t 0 t < N } F.Send( X.t, t ) AckdCopy := Ackd
15
(note 0): This assertion is established by replacing the guard of the loop that surrounds A2 by [0..N)\AckdCopy = : A: do q = N A1 od do [0..N)\AckdCopy = A2 od
Does this hamper progress? Consider: [0..N)\AckdCopy = { set theor y } [0..N) AckdCopy { P4, tr ansi ti vi t y o f } [0..N) Ackd { P2 } (i : 0 i < N : X.i = Y.i ) { de f R0 } R0
The postcondition is implied if [0..N)\AckdCopy = , meaning that the loop can end without affecting the progress. Moreover, the loop ends if q = N, because q = N [0..N) Ackd holds because of the invariance of P3; the loop will end after copying Ackd to AckdCopy.
3.3.3 Progress
To prove progress in this implementation, we will rst prove that there is no individual deadlock in the components of the system as long as the postcondition R0 is not established. This is not enough to prove progress: it doesnt prove that the repetitions in A will terminate. From the structure of A1 it is clear that q = N, which will terminate both repetitions (see the end of the previous section), will be established if Ackd = [0..N) holds. This can only be established if the set Ackd is expanded, which cannot be concluded from the assertions in A1. This is why we present a variant function that increases in all situations and has an upper bound that implies Ackd = [0..N). Because there is no individual deadlock, the variant function will increase, assuring progress. It is sufcient to only consider individual deadlock; starvation does not occur, because all guards become stably true. 3.3.3.1 No individual deadlock While R0 holds, there is no individual deadlock in the system. This can be proved: There is no danger of individual deadlock in A1, as long as B repeatedly sends messages over channel G, because of the nite loss feature of the channels. B contains an innite loop, and sends one message in every iteration of that loop. There is no deadlock in A if there is no deadlock in B. 16
There is no danger of individual deadlock in B, as long as A repeatedly sends messages over channel F, because of the nite loss feature of the channels. The component in A that contains A2 is a loop that doesnt terminate until [0..N)\AckdCopy = , which implies R0 (see 3.3.2). A2 sends one message in every iteration of that loop. There is no deadlock in B if there is no deadlock in A2. There is no danger of individual deadlock in A2, because there are no blocking statements. 3.3.3.2 Variant function We claim that this is a variant function for our algorithm: v f = # AckdCopy + # Ackd, ( i : i Ackd : F.Pot ( X.i, i ) ), ( i : i Ackd : G.Pot (i ) )
The set of all tuple values for v f is lexicogracally ordered. To prove that the variant function increases while the postcondition is not established, it is sufcient to prove that one deadlock and starvation free component increases v f , and no other component decreases v f . We prove that the subcomponent of A that contains A1 increases the variant function: If statement G.Recei ve(r ) establishes that r Ackd, then this statement has increased the variant function, because ( i : i Ackd : G.Pot (i ) ) has been increased without decreasing the rst two parts of v f . If statement G.Recei ve(r ) establishes that r Ackd, statement Ackd := Ackd / {r } will increase the variant function. There are no statements in A1 that decrease v f . Additionally, we prove that none of the other components decrease v f : The subcomponent of A that uses A2 contains one statement that can decrease v f : F.Send( X.t, t ). This statement decreases ( i : i Ackd : F.Pot ( X.i, i ) ) if t Ackd. Considering t AckdCopy is a valid preassertion of F.Send( X.t, t ), / this implies AckdCopy = Ackd. A2 as a whole will increase v f , because # AckdCopy + # Ackd is increased by statement AckdCopy := Ackd. Component B contains one statement that can decrease v f : G.Send( p). This statement decreases ( i : i Ackd : G.Pot (i ) ) if p Ackd. If the preceding statement F.Recei ve( m, p ) has established p Ackd, this is a stable condition. In that case the body of B seen as a whole increases v f , because ( i : i Ackd : F.Pot ( X.i, i ) ) is increased by F.Recei ve( m, p ), and the rst part of v f is not decreased.
17
If F.Recei ve( m, p ) has established p Ackd, this is not a stable con/ dition, but it can only be changed by expanding Ackd, which means an increase of v f . Because the last two parts of v f have an upper bound of 0, and the variant function increases with every execution of A1, # AckdCopy +# Ackd will increase in nite time. # AckdCopy and # Ackd both have an upper bound of N (because of the invariance of P2 and P4).
3.4.2 Implementation
The algorithm from 3.3 is changed to transfer elements with indices [0 .. q+N) instead of [0..N). If q increases (that is to say there is progress), innitely many messages will be transferred. The invariants from A as specied in 3.3 are updated to reect this change (P1 and P2 have been weakened): P0 P1 P2 P3 P4 : : : : : X[0..q) = Y [0..q) 0q (i : i Ackd : X.i = Y.i 0 i < q + N) [0..q) Ackd AckdCopy Ackd
The structure of component A has to be changed, because A doesnt have to end anymore: A : [ [ A1 A2 ] ] Component A1 is updated as follows (only assertion (1) has been weakened, because P2 has been weakened): A1 : ; ; G.Recei ve(r ) {X.r = Y.r 0 r < q + N (1)} Ackd := Ackd {r } do q Ackd {X.q = Y.q (0)} ; q := q + 1 od 18
Weakening assertion (1) in A1 allows us to weaken assertions (2) and (3) in component B (because of the rule of import and export): B: [ ; ; ] In A2, it is now allowed (by the rule of import and export) to weaken assertion (4), because assertion (3) in B has been weakened. This allows for an expansion of the domain from which t is selected to [0 .. q + N). A2 : ; ; { ? [0 .. q + N)\AckdCopy = (5) } t : t [0 .. q + N) \ AckdCopy { X.t = X.t 0 t < q + N (4) } F.Send( X.t, t ) AckdCopy := Ackd F.Recei ve( m, p ) { X. p = m 0 p < q + N (3) } Y. p := m { X. p = Y. p 0 p < q + N (2) } G.Send( p)
Assertion (5) is no longer established by the guard of the loop in A. It can be established by using a guarded skip: A2 : ; ; ; if [0 .. q + N)\AckdCopy = ski p { [0 .. q + N)\AckdCopy = (5) } t : t [0 .. q + N) \ AckdCopy { X.t = X.t 0 t < q + N (4) } F.Send( X.t, t ) AckdCopy := Ackd
Assertion (5) is globally correct: the only statement that can falsify it is q := q + 1 in A1. A valid postassertion of q := q + 1 is q 1 + N AckdCopy: / (q 1 + N AckdCopy) (q := q + 1) / {substi tuti on } q + N AckdCopy / { P4 } q + N Ackd / { pr edi cate logi c } P2 The guarded skip does not cause deadlock, because [0 .. q + N)\AckdCopy = {set theor y } [0 .. q + N) AckdCopy { P4 } [0 .. q + N) Ackd { N 1, set theor y } q Ackd 19
If q Ackd, A1 will increase q until q Ackd, which implies q AckdCopy and / / will cause the guard to be stably true. Its now possible to speak of a sliding window protocol: A sends elements from X that have indices in a certain integer interval, the window, where q is the start of the window and the window size is N. All elements that are before the window, with indices less than q, have already been received (see P3). Whenever q is increased, the window progresses.
3.4.3 Progress
According to 3.4.2, there is progress if q increases. Using the variant function dened in 3.3.3, it can be proved that q increases. The changes to the components do not introduce a possibility of individual deadlock, as described above. With the same arguments as in paragraph 3.3.3, it can now be proved that v f increases. The only difference is that theres no upper bound anymore to the size of Ackd and AckdCopy and consequently to the variant function; this corresponds with the changed specication of the problem, because theres no upper bound to the array that is to be transferred. The invariance of P2 guarantees that expanding Ackd means that q is increasing. If v f increases over time, this implies that # Ackd increases over time, because the last two parts of v f have an upper bound of 0 and # AckdCopy can not increase without an increase of # Ackd (because of P4). We conclude that the set Ackd grows because v f increases, which means q increases and there is progress.
20
A1 : ; ;
G.Recei ve(r ) {0 r < q + N } Ackd := Ackd {r } do q Ackd q := q + 1 od if [0 .. q + N)\AckdCopy = ski p { [0 .. q + N)\AckdCopy = } t : t [0 .. q + N) \ AckdCopy {0 t < q + N } F.Send(t) AckdCopy := Ackd F.Recei ve( p) {0 p < q + N } G.Send( p)
A2 : ; ; ; B: [ ; ]
The goal is to nd expressions k and m such that k p < k + m is a valid postassertion of F.Recei ve( p) in B and k r < k + m is a valid postassertion of G.Recei ve(r ) in A1. This means that the indices transferred via the channels may be reduced modulo m.
This is easily seen by taking into account that t < q + N is a preassertion of F.Send(t) in A2 and the fact that q never decreases. P6 : Ackd G.C[0 .. G.ct)
This is trivial to prove, because r G.C[0 .. G.ct) is a valid postassertion of G.Recei ve(r ), and therefore a valid preassertion of Ackd := Ackd {r }. P7 : (i, j : 0 i j < ct : C.i N < C. j )
To prove this invariant, we add a dummy variable qCopy : N to A2, which acts as a local copy of q just like AckdCopy is a local copy of Ackd. Initially qCopy = q = 0,
21
and it is updated whenever AckdCopy is updated: A2 : ; ; ; if [0 .. q + N)\AckdCopy = ski p { [0 .. q + N)\AckdCopy = } t : t [0 .. q + N) \ AckdCopy {0 t < q + N } F.Send(t) AckdCopy, qCopy := Ackd, q
Note that the last assignment establishes (i : 0 i < ct : C.i < qCopy + N) (because of P5), which also holds initially and is therefore a loop invariant of the loop that contains A2, only disturbed by the increase of ct in F.Send(t). Also note that P8 : [0 .. qCopy) AckdCopy is invariant: it holds initially, and the assignment AckdCopy, qCopy := Ackd, q does not disturb it because of P3. Initially P7 holds, and it is only disturbed by the increase of ct in F.Send(t), which has C.ct = t and t [0 .. q + N)\AckdCopy as valid preassertions. We derive: P7(ct := ct + 1) {substi tuti on } (i, j : 0 i j < ct + 1 : C.i N < C. j ) {spli t o f f j = ct, P7 } (i : 0 i ct : C.i N < C.ct) {1 N C.ct N < C.ct } (i : 0 i < ct : C.i N < C.ct) {loop i nvari ant (i : 0 i < ct : C.i < qCopy + N) } (i : 0 i < ct : qCopy 1 < C.ct) {C.ct = t } (i : 0 i < ct : qCopy 1 < t) {t AckdCopy, P8 } / tr ue which proves the invariance of P7. Variable q is a local variable of A, and is therefore not available to B. We introduce variable s : N, local to B, that represents the smallest index that has not yet been received. To update this variable, we introduce a set Rcvd, in which all the indices of received array elements are stored (analogous to Ackd in A). These invariants should hold: P9 : P10 : Rcvd C[0..ct) [0..s) Rcvd
Initially, Rcvd = and s = 0 satisfy the invariants. The updating of Rcvd and s in B
22
can occur in a manner very similar to the updating of Ackd and q in A: B: [ ; ; F.Recei ve( p) {0 p < q + N } Rcvd := Rcvd {p} do s Rcvd s := s + 1 od G.Send( p)
] It is trivial to see that P9 and P10 are not disturbed by these assignments. With the help of the previously dened and proved invariants, it is now possible to prove the main invariant of this section, that together with P5 will enable the use of recycable indices on channel F: P11 : (i : (ct M) 0 i < ct : s N (M 1) C.i )
For ct M, the invariant is trivial to prove because P9 P10 ct M s M s N (M 1) 0, and C consists of natural numbers. For ct > M, this invariant is proved via induction on M. We rst provide a proof for P11(M := 1): P11(M := 1) {substi tuti on, ct > M } (i : ct 1 i < ct : s N C.i ) {one poi nt domai n } s N C.(ct 1) {algebr a } s 1 N < C.(ct 1) { P9 P10 s 1 C[0..ct), P7( j := ct 1) } tr ue
Assuming P11 holds, we now prove for P11(M := M +1): P11(M := M + 1) {substi tuti on, ct M +1 } (i : ct M 1 i < ct : s N M C.i ) {spli t o f f i = ct M 1, P11 } s N M C.(ct M 1) {algebr a } s (C.(ct M 1) + N) M {set theor y } [C.(ct M 1)+ N .. s) C[ct M .. ct) {note (0) } [0..s) C[0..ct) { P9, P10 } tr ue 23
note (0): [0..s) C[0..ct) {set theor y } [0..s) C[0 .. ct M) C[ct M .. ct) {set theor y } [C.(ct M 1)+ N .. s) C[0 .. ct M) C[ct M .. ct) { P7( j := ct M 1) [C.(ct M 1)+ N .. s) C[0 .. ct M) = } [C.(ct M 1)+ N .. s) C[ct M .. ct)
is invariant. One part of P12, s q + N, holds because s < q + N is a correct preassertion of s := s + 1: all elements added to Rcvd are smaller than q + N, and q doesnt decrease. To prove the invariance of the other part of P12, q s, these invariants are rst proved: P13 : C[0..ct) Rcvd P14 : ( j : [0.. j ) C[0...ct) : j s) The proof for the invariance of P13 is trivial, since p Rcvd is a valid preassertion of G.Send( p), and set Rcvd never shrinks. Invariant P14 holds initially and can be disturbed by increasing ct, as happens in G.Send( p). Valid preassertions of the increase of ct are s Rcvd, p Rcvd and / C.ct = p. P14(ct := ct + 1) {substi tuti on } ( j : [0.. j ) C[0 .. ct +1) : j s) { P13 C.ct Rcvd } ( j : [0.. j ) Rcvd : j s) { P10, s Rcvd, set theor y } / tr ue which proves the invariance of P14. The remaining part of P12 is easy to prove with P14: P14 { P6 } ( j : [0.. j ) Ackd : j s) { P3 } qs 24
Using P12, some unnecessary content can be removed from channel G: since s q + N and [0..q) Ackd (see P3), it is not necessary to send acknowledgements for indices smaller than s N. Therefore B is modied as follows: B: [ ; ; F.Recei ve( p) {0 p < q + N } Rcvd := Rcvd {p} do s Rcvd s := s + 1 od if p s N G.Send( p) p < s N ski p
Invariant P15 holds initially, and is not disturbed by the increase of ct in G.Send( p) (valid preassertions of that increase are C.ct = p, p sN, p Rcvd and s Rcvd): / P15(ct := ct + 1) {substi tuti on } ( j : 0 j < ct +1 : ( i : [0..i ) C[0 .. j +1) : i ) N C. j ) {spli t o ff j = ct, P15 } ( i : [0..i ) C[0 .. ct +1) : i ) N C.ct { P12 C.ct = p p Rcvd } ( i : [0..i ) Rcvd : i ) N p { P10 s Rcvd } / sN p { p sN } tr ue
P15 can be used to prove that this invariant holds: P16 : (i : (ct M) 0 i < ct : q N M C.i )
For ct M the invariance of P16 is easy to see, because P3 P6 ct M q M q N M < 0, and C contains only natural numbers. For ct > M, The proof is by induction on M. For P16(M := 1): P16(M := 1) {substi tuti on, ct > M } (i : ct 1 i < ct : q N 1 C.i ) {si ngle poi nt domai n } q N 1 C.(ct 1) { P3 P6 } ( i : [0..i ) C[0 .. ct) : i ) N 1 C.(ct 1) { P15 } tr ue 25
For P16(M := M +1), assuming P16 holds: P16(M := M +1) {substi tuti on, ct M +1 } (i : ct M 1 i < ct : q N M 1 C.i ) {spli t o f f i = ct M 1, P16 } q N M 1 C.(ct M 1) { P15 } q N M 1 ( i : [0..i ) C[0 .. ct M) : i ) N {algebr a } q ( i : [0..i ) C[0 .. ct M) : i ) 1 M {set theor y } [ ( i : [0..i ) C[0 .. ct M) : i )+1 .. q ) C[ct M .. ct) {de f. , set theor y } [ ( i : [0..i ) C[0 .. ct M) : i )+1 .. q ) C[0..ct) ( P3 P6 } tr ue
Knowing this, an important coassertion can be derived: p = = = = = {algebr a } s (N + M) + ( p+ N + M s) {0 < p+ N + M s < 2N + M } s (N + M) + ( p+ N + M s) mod (2N + M) {0 < N + M < 2N + M } s ((N + M) mod (2N + M)) + ( p+ N + M s) mod (2N + M) {modular ari thmeti c } s + ( ps) mod (2N + M) {modular ari thmeti c } s + ( p mod (2N + M)s) mod (2N + M)
In other words, p can be calculated from p mod (2N + M). Because P16 is invariant, a similar assertion r = q + (r mod (2N +M)q) mod (2N +M) can be derived from the postassertion r G.C[ct M .. ct) of the assignment to r in G.Recei ve(r ) in A1. It therefore sufces to send indices over channels F and G that are reduced modulo (2N + M): 26
A1 : ; ; ;
G.Recei ve(r ) r := q + (r q) mod (2N + M) {0 r < q + N } Ackd := Ackd {r } do q Ackd q := q + 1 od if [0 .. q + N)\AckdCopy = ski p { [0 .. q + N)\AckdCopy = } t : t [0 .. q + N) \ AckdCopy {0 t < q + N } F.Send(t mod (2N + M) ) AckdCopy, qCopy := Ackd, q F.Recei ve( p) p := s + ( ps) mod (2N + M) {0 p < q + N } Rcvd := Rcvd {p} do s Rcvd s := s + 1 od if p s N G.Send( p mod (2N + M) ) p < s N ski p
A2 : ; ; ; B: [ ; ;
27
A1 : ; ;
G.Recei ve(r ) r := q + (r q) mod (2N + M) { X.r = Y.r 0 r < q + N } if q r Ackd N := Ackd N {r } q > r ski p do q Ackd N { X.q = Y.q } ; q, Ackd N := q + 1, Ackd N\{q} od
The size of set AckdCopy can be limited in the same way: it is obvious that there exists a set AckdCopy N = AckdCopy\[0..qCopy), where AckdCopy = AckdCopy N [0..qCopy) (because of P8), and it sufces to maintain AckdCopy N. The only statement in A that affects AckdCopy N is AckdCopy, qCopy := Ackd N [0..q), q, for which this holds: = = = AckdCopy N( AckdCopy, qCopy := Ackd N [0..q), q ) { De f. AckdCopy N, substi tuti on } (Ackd N [0..q)) \ [0..q) {set theor y } Ackd N\[0..q) {de f. Ackd N } Ackd N
A2 can now be rewritten to (note that [0 .. q+N) \ AckdCopy = [0 .. q+N) \ ( AckdCopy N [0..qCopy) ) can be simplied to [qCopy .. q + N) \ AckdCopy N): A2 : ; ; ; if [qCopy .. q + N) \ AckdCopy N = ski p { [qCopy .. q + N) \ AckdCopy N = } t : t [qCopy .. q + N) \ AckdCopy N { X.t = X.t 0 t < q + N } F.Send( X.t, t mod (2N + M) ) AckdCopy N, qCopy := Ackd N, q
Because AckdCopy N is a copy of Ackd N, it will contain at most N elements. The same tactic used to create the Ackd N set can also be used to create a set Rcvd N = Rcvd\[0..s), where Rcvd = Rcvd N [0..s) because of P10. Rcvd N will contain at most N elements, because P9 P5 P12 (i : i Rcvd : i < s + N).
28
Rcvd N is maintained as follows: B : [ ; F.Recei ve( p) p := s + ( ps) mod (2N + M) {0 p < q + N } if p s Rcvd N := Rcvd N {p} p < s ski p do s Rcvd N s, Rcvd N := s + 1, Rcvd N\s od if p s N G.Send( p mod (2N + M) ) p < s N ski p
29
Chapter 4
explicit by using natural numbers that represent the number of messages that can be lost and duplicated consecutively (see 2.5.1 and 2.5.2). The protocol developed in [Sne95] sends a (reduced) set of all received indices as an acknowledgement, while our protocol sends only a single index. Sending a set could be a more efcient solution, because if an acknowledgement is lost, the next received acknowledgement will contain a superset of the lost acknowledgement (because the channels are FIFO). Even if the channels are not FIFO, the acknowledgements still carry more information and might increase efciency. Van de Snepscheut also proves that indices can be reduced modulo 2N; the result can be compared to our own result of 2N + M if we use M = 1 (which is equal to a FIFO-channel). The difference of 1 can be explained by taking into account that only channel G requires the wider 2N + M reduction (channel F will do with 2N +(M 1), as can be seen from invariants P11, P5 and P12). If the assumption is made that F and G are both FIFO, G can also be reduced modulo 2N. There is a proof of progress given for the sequential program that is rst developed, using a variant function; it is explained that the nal, distributed program meets the progress requirements of the original sequential program, because of the method used to partition the sequential program into processes.
4.3 Conclusions
The proof-by-design methods explored in [FG99] can be employed to develop a sliding window protocol, and lead to a complete proof of correctness. By using a step-by-step approach to developing the protocol, working from the
31
desired result to the solution, an elegant implementation can be obtained where the structure of the design can be explained in a clear manner. By modelling the faulty channels, their properties have been formalized, enabling a more formal proof of correctness and progress of the nal protocol. The faulty channels model can be used to prove that the rule of import and export applies to faulty channels, which makes it easier to prove properties of the messages transferred over the channels without introducing more system invariants. Proving that indices can be recycled requires proving a substantial number of invariants that are not necessary to prove the correctness of the protocol when indices are not recycled.
32
Bibliography
[OG76] S. Owicki and D. Gries, An Axiomatic Proof Technique for Parallel Programs I, Acta Informatica, Vol. 6, pp. 319-340, 1976. [FG99] W.H.J. Feijen and A.J.M. van Gasteren, On a method of multiprogramming, Springer Verlag, 1999. [Sne95] J.L.A. van de Snepscheut, The Sliding-Window Protocol Revisited, Formal Aspects of Computing, Vol. 7, pp. 3-17, 1995. [Ste76] N.V. Stenning, A data transfer protocol, Computer Networks, Vol. 1, pp. 99110, 1976.
33