You are on page 1of 38

TECHNISCHE UNIVERSITEIT EINDHOVEN

Department of Mathematics and Computer Science

MASTER’S THESIS

A sliding window protocol


by
Arjan van Leeuwen

Supervisor: dr. ir. R. R. Hoogerwoord

Eindhoven, January 2006


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 dis-
cussions 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 other’s 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.1 Problem description . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Methods used . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Modelling faulty channels 3


2.1 Channel usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Channel interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2.1 Sending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2.2 Receiving . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2.3 Rule of import and export . . . . . . . . . . . . . . . . . . . 4
2.3 Desired features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3.1 Formalization of the desired features . . . . . . . . . . . . . . 5
2.4 Implementation of a reliable channel . . . . . . . . . . . . . . . . . . 5
2.4.1 Send . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.4.2 Receive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.5 Implementation of a faulty channel . . . . . . . . . . . . . . . . . . . 6
2.5.1 Loss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.5.2 Duplication . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.5.3 No FIFO . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.5.4 Rule of import and export . . . . . . . . . . . . . . . . . . . 8
2.6 A faulty channel with bounded buffering . . . . . . . . . . . . . . . . 9
2.7 Function for potential output . . . . . . . . . . . . . . . . . . . . . . 10

3 A sliding window protocol 11


3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Situation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 Transferring N messages . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3.1 Specification . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.3.3 Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.4 Transferring infinitely many messages . . . . . . . . . . . . . . . . . 18
3.4.1 Specification . . . . . . . . . . . . . . . . . . . . . . . . . . 18

iv
3.4.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.4.3 Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5 Recycling indices . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.5.1 Reducing indices on channel F . . . . . . . . . . . . . . . . . 21
3.5.2 Reducing indices on channel G . . . . . . . . . . . . . . . . . 24
3.5.3 Implementing cyclic indices . . . . . . . . . . . . . . . . . . 26
3.6 Limiting the size of sets . . . . . . . . . . . . . . . . . . . . . . . . . 27

4 Summary and conclusions 30


4.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.2 Comparison to existing research . . . . . . . . . . . . . . . . . . . . 30
4.2.1 Research of J.L.A. van de Snepscheut . . . . . . . . . . . . . 30
4.2.2 Research of N.V. Stenning . . . . . . . . . . . . . . . . . . . 31
4.3 Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.4 Recommendations for future research . . . . . . . . . . . . . . . . . 32

v
Chapter 1

Introduction

1.1 Problem description


Between physically separated machines, communication is often only possible over so-
called “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].

1.2 Methods used


The correctness of the protocol is proved using Owicki/Gries theory for parallel pro-
cesses [OG76]. The protocol is developed using the ’proof-by-design’ methods ex-
plored in [FG99].
To use these methods, the protocol is implemented as two processes running in
parallel, albeit with faulty channels as the only way of communication between the
two processes.

1
To be able to completely prove the correctness of the protocol using Owicki/Gries
theory, the faulty channels are first 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 Lan-
guage (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 defined if (∃x :: P) holds.
• Channel names: because multiple channels are used, we distinguish the vari-
ables used by these channels by prefixing 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
prefixed 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

2
Chapter 2

Modelling faulty channels

2.1 Channel usage


Each channel is connected to two processes: the sending process and the receiving
process. The sending process of a channel cannot receive any messages via that chan-
nel, and the receiving process of a channel cannot send any messages via that channel.
A process can be connected to multiple channels, creating a situation where a single
process can be both the sending process of one channel and the receiving process of
another channel.

ii4 F UUUUUU
iiiiii UU*
89:;
?>=< 89:;
?>=<
A jUUUU ii B
UUUU iiii
G t
i i

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 signified
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 Channel interface


2.2.1 Sending
Sending a message is modelled by the Send-operation. The sending process of a chan-
nel F can send an expression b as follows:

F.Send(b)

3
This operation is guaranteed to terminate.

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.2.3 Rule of import and export


To simplify proving certain properties of messages transferred via a faulty channel, we
use the rule of import and export for faulty channels. This rule specifies that in this
program fragment from the receiving process of channel F
F.Recei ve(y)
{Q }
and this fragment from the sending process of channel F
{P }
F.Send(b)
the assertion Q is locally correct, if [ P ⇒ Q(y := b) ] holds.

2.3 Desired features


The faulty channels are modelled using these desired features:
1. No invented messages: every message received via a channel has been sent via
that channel
2. No FIFO: messages can be received in a different order than they were sent
3. Unreliable: every sent message can be lost (will not be received) or duplicated
(will be received multiple times)
4. Finite duplication: a message is not duplicated infinitely many times
5. Finite loss: after sending sufficiently many messages, at least one of these mes-
sages will be received
6. Rule of import and export: the channel respects the rule of import and export, as
described in 2.2.3
Features 4 and 5 make it possible to give progress guarantees about receiving messages.
Without these features, it is impossible to guarantee the transfer of messages in finite
time.

4
2.3.1 Formalization of the desired features
To represent sent messages, we introduce, for each channel, an (unbounded) array C
that contains all sent messages for that channel and a variable ct : N that represents the
number of messages already sent, where ct = 0 initially. The array segment C[0..ct)
represents all sent messages.
A channel has feature 1 if for a variable y, y ∈ C[0..ct) is a correct postassertion
of Recei ve(y).

2.4 Implementation of a reliable channel


We will first implement a reliable channel, that is to say a channel that has feature 1,
receives messages in the same order as they were sent, and that doesn’t lose or duplicate
any messages.

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 fi


; { 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.

5
2.5 Implementation of a faulty channel
2.5.1 Loss
By increasing cb before the guarded skip in the Recei ve-operation, messages with an
index at least the previous value of cb and smaller than the new value of cb will be lost.
We introduce a variable th : N to signify that the next th messages to be delivered will
be lost. This can be established by choosing a value for th and increasing cb by th:

Recei ve(y) : th : 0 ≤ th
; cb := cb + th
; if cb < ct → ski p fi
; { cb < ct }
y := C.cb
; { y ∈ C[0..ct) }
cb := cb + 1
{ y ∈ C[0..ct) }

The channel will not lose infinitely many messages, because th is a natural number. In-
terval [0..cb) now represents the indices of messages that will not be received anymore
(messages that have been received or lost).

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 ve-
operation, 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 fi
; { cb < ct }
y := C.cb
{ y ∈ C[0..ct) }

However, this duplication is not finite. If the value 0 is consistently chosen for th,
message C.cb is duplicated infinitely many times.
To make duplication finite, 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 re-
ceived: 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 fi
; { 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 finite loss and finite 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 fi
; { 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 finite loss and finite 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 finite; because cb is increased by a natural
number, loss is finite.

2.5.4 Rule of import and export


The rule of import and export, as defined in 2.2.3, should apply to the channel imple-
mentation.
To simplify the process of proving that the rule of import and export holds, we
consider a simple system where two processes A and B are respectively the sending
and receiving process of a channel F. Process A sends one message to process B.
What are the proof obligations of adding an arbitrary assertion Q as a postassertion
of the Recei ve-operation in process B? We assume assertion Q does not contain any
variables used by the channels themselves. The only statement in F.Recei ve(y) that
influences the correctness of Q is the assignment to y:
Q(y := C.h)
⇐ {0 ≤ h < ct }
(∀i : 0 ≤ i < ct : Q(y := C.i ) )
We will introduce this assertion as a system invariant:
K 1 : (∀i : 0 ≤ i < ct : Q(y := C.i ) )
This system invariant can be falsified by increasing ct. This gives an extra proof obli-
gation 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.

2.6 A faulty channel with bounded buffering


The faulty channels modelled here can reorder messages. The reordering of messages
can be seen as ’delaying’ messages. In practice, we expect a faulty channel to lose
a message if that message has not been received after a certain amount of time has
passed since it was sent. Time is, however, inconvenient to work with. It is suggested
in [Ste76] to view the loss of delayed messages in the faulty channels in terms of the
number of messages available for reception.
C[cb..ct) contains the messages that have been sent but not yet been received. The
number of messages available for reception can be limited to M (1 ≤ M) by enforcing
this system invariant:

K2 : ct − cb ≤ M

K 2 can be rewritten as:

K2 : ct ≤ M + cb

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 fi

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
fi

This introduces a new ’loss’ of messages, but the loss is finite: ct = M + cb im-
plies cb < ct, causing a Recei ve-operation to either receive a message or increase cb
(establishing ct < M + cb).
The modified 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 fi
; { 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) }

2.7 Function for potential output


To simplify progress discussions of algorithms that use the faulty channels, we intro-
duce for every channel a function Pot that takes a message b as its argument, and
returns a natural number that specifies a maximum to the number of times message b
will be received from that channel.
X
Pot (b) = ( i : 0 ≤ i < ct ∧ C.i = b : D.i )

• 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 6= b, because
that means Recei ve has decreased D.h, where h is such that C.h 6= b.

10
Chapter 3

A sliding window protocol

3.1 Introduction
We derive a protocol that enables the reliable transfer of a data stream from one process
to another process, and that conforms to the requirements from 1.1. The processes are
only allowed to communicate via the faulty channels model described in Chapter 2.
We will first develop an algorithm to transfer a finite stream of data in a finite
amount of time from one process to another process. We will use this algorithm as a
foundation for an algorithm that transfers an inifinite stream of data.

3.2 Situation
Consider two processes, A and B. A is to transfer data to B. The only way of com-
munication 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 figure 2.1.

3.3 Transferring N messages


3.3.1 Specification
Process A has a constant array X[0..N), with 1 ≤ N. This array represents the data
that has to be transferred in finite time to process B. Process B has an array Y [0..N)
to which X is to be copied. The desired postcondition is therefore

R0 : X[0..N) = Y [0..N)

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 : X[0..q) = Y [0..q)
P1 : 0≤q≤N

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 6= 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 6= N →
if q ∈ Ackd → ski p fi
; { ♥ 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 6= N →
; { ? X.r = Y.r ∧ 0 ≤ r < N (note 0) }
Ackd := Ackd ∪ {r }
; if q ∈ Ackd → ski p fi
; { ♥ 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 6= N →
G.Recei ve(r )
; { ♥ X.r = Y.r ∧ 0 ≤ r < N }
Ackd := Ackd ∪ {r }
; if q ∈ Ackd → ski p fi
; { X.q = Y.q }
q := q + 1
od
{q = N }

This construction allows for deadlock: the element added to Ackd does not nec-
essarily equal q. In that case, the process blocks. To avoid this, the guarded skip is
replaced by a loop:

A: do q 6= 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: ∗[ { ? X. p = Y. p ∧ 0 ≤ p < N (note 0) }
G.Send( p)
]

(note 0): The first 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 insufficient; 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 ha, i i, where a is an element of
X, and i is the index of that element.

B: ∗[ F.Recei ve(hm, pi)


; { ♥ X. p = m ∧ 0 ≤ p < N (note 0) }
Y. p := m
; { X. p = Y. p ∧ 0 ≤ p < N }
G.Send( p)
]

(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 6= N → k do q 6= N →
A1 k A2
od k od

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(hb, ti)
(note 0): The first 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(hX.t, ti)
(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 acknowledge-
ment for that message is received. Only then another message will be sent.
It seems more efficient 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 6= ∅ (note 0) }
t : t ∈ [0..N) \ Ackd
; { ♥ X.t = X.t ∧ 0 ≤ t < N }
F.Send(hX.t, ti)

(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 6= ∅ (note 0) }
t : t ∈ [0..N) \ AckdCopy
; { X.t = X.t ∧ 0 ≤ t < N }
F.Send(hX.t, ti)
; AckdCopy := Ackd

15
(note 0): This assertion is established by replacing the guard of the loop that surrounds
A2 by [0..N)\AckdCopy 6= ∅:

A: do q 6= N → k do [0..N)\AckdCopy 6= ∅ →
A1 k A2
od k 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 first prove that there is no individual
deadlock in the components of the system as long as the postcondition R0 is not estab-
lished. This is not enough to prove progress: it doesn’t prove that the repetitions in A
will terminate.
From the structure of A1 it is clear that q = N, which will terminate both repeti-
tions (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 sufficient 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 ’finite loss’ feature of the channels. B
contains an infinite 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 ’finite loss’ feature of the channels.
The component in A that contains A2 is a loop that doesn’t 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:
 X X 
v f = # AckdCopy + # Ackd, −( i : i ∈ Ackd : F.Pot (hX.i, i i) ), −( i : i ∈ Ackd : G.Pot (i ) )

The set of all tuple values for v f is lexicografically ordered.


To prove that the variant function increases while the postcondition is not estab-
lished, it is sufficient to prove that one deadlock and starvation free component in-
creases v f , and no other component decreases v f .
We prove that the subcomponent of A that contains A1 increases the variant func-
tion:

• If statement G.Recei ve(r ) establishes that


Pr ∈ Ackd, then this statement has
increased the variant function, because −( i : i ∈ Ackd : G.Pot (i ) ) has been
increased without decreasing the first 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 onePstatement that can decrease


v f : F.Send(hX.t, ti). This statement decreases −( i : i ∈ Ackd : F.Pot (hX.i, i i) )
if t ∈ Ackd. Considering t ∈/ AckdCopy is a valid preassertion of F.Send(hX.t, ti),
this implies AckdCopy 6= Ackd. A2 as a whole will increase v f , because
# AckdCopy + # Ackd is increased by statement AckdCopy := Ackd.
• Component B containsP 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(hm, pi) has established p ∈ Ackd,


this is a stable condition.
P In that case the body of B seen as a whole in-
creases v f , because −( i : i ∈ Ackd : F.Pot (hX.i, i i) ) is increased by
F.Recei ve(hm, pi), and the first part of v f is not decreased.

17
– If F.Recei ve(hm, pi) 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 finite time.
# AckdCopy and # Ackd both have an upper bound of N (because of the invariance of
P2 and P4).

3.4 Transferring infinitely many messages


3.4.1 Specification
Process A has a constant array X[0..∞). The contents of this array have to be trans-
ferred to process B. Process B has an array Y [0..∞), to which X is to be copied. The
system setup is as described in 3.2.

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), infinitely many messages will
be transferred.
The invariants from A as specified in 3.3 are updated to reflect this change (P1 and
P2 have been weakened):

P0 : X[0..q) = Y [0..q)
P1 : 0≤q
P2 : (∀i : i ∈ Ackd : X.i = Y.i ∧ 0 ≤ i < q + N)
P3 : [0..q) ⊆ Ackd
P4 : AckdCopy ⊆ Ackd
The structure of component A has to be changed, because A doesn’t have to end any-
more:
A : ∗[ k ∗[
A1 k A2
] k ]
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: ∗[ F.Recei ve(hm, pi)
; { X. p = m ∧ 0 ≤ p < q + N (3) }
Y. p := m
; { X. p = Y. p ∧ 0 ≤ p < q + N (2) }
G.Send( p)
]
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 6= ∅ (5) }
t : t ∈ [0 .. q + N) \ AckdCopy
; { X.t = X.t ∧ 0 ≤ t < q + N (4) }
F.Send(hX.t, ti)
; AckdCopy := Ackd
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 6= ∅ → ski p fi
; { ♥ [0 .. q + N)\AckdCopy 6= ∅ (5) }
t : t ∈ [0 .. q + N) \ AckdCopy
; { X.t = X.t ∧ 0 ≤ t < q + N (4) }
F.Send(hX.t, ti)
; 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.
It’s 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 defined
in 3.3.3, it can be proved that q increases.
The changes to the components do not introduce a possibility of individual dead-
lock, 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 there’s no upper bound any-
more to the size of Ackd and AckdCopy and consequently to the variant function; this
corresponds with the changed specification of the problem, because there’s 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.

3.5 Recycling indices


Until now, it has been assumed that the indices used to specify which array element is
sent and as acknowledgements have no upper limit. Is it possible to reuse indices in a
non-ambiguous way, such that an upper limit for the indices is established?
We assume that the faulty channels perform as if bounded by a buffer of size M,
as described in 2.6. To make the derivation easier, we examine a modified version of
the algorithm introduced in 3.4.2, where the messages on channel F consist of just an
index and the actual assignment of values to Y is ignored. The modified algorithm is
as follows:
A : ∗[ k ∗[
A1 k A2
] k ]

20
A1 : G.Recei ve(r )
; {0 ≤ r < q + N }
Ackd := Ackd ∪ {r }
; do q ∈ Ackd →
q := q + 1
od

A2 : if [0 .. q + N)\AckdCopy 6= ∅ → ski p fi
; { [0 .. q + N)\AckdCopy 6= ∅ }
t : t ∈ [0 .. q + N) \ AckdCopy
; {0 ≤ t < q + N }
F.Send(t)
; AckdCopy := Ackd

B: ∗[ F.Recei ve( p)
; {0 ≤ p < q + N }
G.Send( p)
]
The goal is to find 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.

3.5.1 Reducing indices on channel F


First, we establish some system invariants that mostly concern the ’contents’ of channel
F, that is array F.C. In this paragraph, we will use C instead of F.C, cb instead of
F.cb and ct instead of F.ct.
First:

P5 : (∀i : 0 ≤ i < ct : C.i < q + N)

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 6= ∅ → ski p fi
; { [0 .. q + N)\AckdCopy 6= ∅ }
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)
≡ / AckdCopy, P8 }
{t ∈
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 : Rcvd ⊆ C[0..ct)
P10 : [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 defined 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 first 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)
This proves invariance of P11.

3.5.2 Reducing indices on channel G


In this paragraph, an invariant concerning channel G similar to P11 for channel F is
proved. We will use C instead of G.C, cb instead G.cb and ct instead of G.ct in this
paragraph.
To do this, it is first proved that
P12 : q≤s≤q+N
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
doesn’t decrease.
To prove the invariance of the other part of P12, q ≤ s, these invariants are first
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 }
q≤s

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 modified 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
fi
]
The following is now invariant:
P15 : (∀ j : 0 ≤ j < ct : (↑ i : [0..i ) ⊆ C[0 .. j +1) : i ) − N ≤ C. j )
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 ≥ s−N, 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 }
s−N ≤ p
≡ { p ≥ s−N }
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

3.5.3 Implementing cyclic indices


A valid postassertion of the assignment to p in F.Recei ve( p) in B is p ∈ F.C[ (ct −
M) ↑ 0 .. ct ). This implies:
p ∈ F.C[ (ct − M) ↑ 0 .. ct )
⇒ { P14, P11, p < q + N }
s−N −M < p < s+N
≡ {algebr a }
0 < p+ N + M −s < 2N + M
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 + ( p−s) 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 suffices 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

A2 : if [0 .. q + N)\AckdCopy 6= ∅ → ski p fi
; { [0 .. q + N)\AckdCopy 6= ∅ }
t : t ∈ [0 .. q + N) \ AckdCopy
; {0 ≤ t < q + N }
F.Send(t mod (2N + M) )
; AckdCopy, qCopy := Ackd, q

B: ∗[ F.Recei ve( p)
p := s + ( p−s) 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
fi
]

3.6 Limiting the size of sets


Until now, it was assumed that setsAckd, AckdCopy and Rcvd have no upper bound
on their size. Can we limit the size of these sets?
There exists a set Ackd N such that Ackd N = Ackd\[0..q) that never grows larger
than N elements (because of P2). Because [0..q) ⊆ Ackd holds (according to P3),
Ackd = [0..q) ∪ Ackd N and it is sufficient to maintain set Ackd N.
Knowing this, A1 can be changed so that Ackd N is maintained instead of Ackd.
Note that q ∈ [0..q) ∪ Ackd N equals q ∈ Ackd N.

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
fi
; 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 suffices 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 simplified to [qCopy .. q + N) \ AckdCopy N):

A2 : if [qCopy .. q + N) \ AckdCopy N 6= ∅ → ski p fi


; { [qCopy .. q + N) \ AckdCopy N 6= ∅ }
t : t ∈ [qCopy .. q + N) \ AckdCopy N
; { X.t = X.t ∧ 0 ≤ t < q + N }
F.Send(h X.t, t mod (2N + M) i)
; 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 + ( p−s) mod (2N + M)
; {0 ≤ p < q + N }
if p ≥ s → Rcvd N := Rcvd N ∪ {p}
 p < s → ski p
fi
; 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
fi
]

29
Chapter 4

Summary and conclusions

4.1 Summary
In this thesis, we have shown how to model faulty channels that can reorder, lose
and duplicate messages as multiprograms. The modelled channels are ’finitely faulty’;
there is a limit to the number of messages that can be consecutively lost or duplicated.
Using this model, we have derived a provably correct protocol that enables the
reliable transfer of a data stream from one machine to another machine over a faulty
channel. We have proven that the protocol exhibits progress.
Furthermore, we have proven that it is possible to limit the memory requirements
of the protocol by recycling the indices contained in the messages that the protocol
transfers, and by limiting the size of the sets that the protocol maintains.

4.2 Comparison to existing research


We compare our research to two existing papers that give a correctness proof of a
sliding window protocol.

4.2.1 Research of J.L.A. van de Snepscheut


In [Sne95], J.L.A. van de Snepscheut derives a sliding window protocol by developing
a sequential program and distributing the statements and variables of the sequential
program over a number of processes. This has the advantage of being able to use
the usual proof techniques for the sequential program, without worries about global
correctness of assertions. A disadvantage is that this method is not formalized, where
the Owicki/Gries-theory used in this thesis is well-documented (see [OG76], [FG99]).
Van de Snepscheut also gives a program that implements a faulty channel, but it
is assumed that messages sent over such a channel arrive in the order in which they
are sent (the channel has the FIFO-property), where we assume that messages can
be reordered. The program relies on fairness of the scheduler to assure that only a
finite number of messages can be lost or duplicated consecutively, where we make this

30
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 efficient 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 efficiency.
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 first developed,
using a variant function; it is explained that the final, distributed program meets the
progress requirements of the original sequential program, because of the method used
to partition the sequential program into processes.

4.2.2 Research of N.V. Stenning


In [Ste76], N.V. Stenning gives an a posteriori correctness proof of a sliding window
protocol. The protocol uses faulty channels that have the same properties as in this
thesis. The channels are not modeled as programs.
The proof is established using a number of invariants, although most of these in-
variants are not explicitly proven in the paper — this thesis is more complete in that
respect.
These invariants are also used to prove that it is possible recycle indices by reducing
them modulo (tr ansmi twi ndow + ((M + r ecei vewi ndow) ↑ (tr ansmi twi ndow)),
where tr ansmi twi ndow is equal to constant N in this thesis, and r ecei vewi ndow is
the size of a separate “receiver window” that buffers received messages that have not
yet been output (comparable to Y [s .. s + N) in our protocol). This is equal to the con-
clusion in this paper that indices can be reduced modulo 2N + M if r ecei vewi ndow =
tr ansmi twi ndow = N (the author mentions in the conclusion that in practice, M +
tr ansmi twi ndow + r ecei vewi ndow is always a satisfactory cycle period for the in-
dices if one is not concerned with whether a received message lies in the receiver
window).
Stenning gives no proof of progress in his paper.

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, en-
abling a more formal proof of correctness and progress of the final protocol.
• The faulty channels model can be used to prove that the ’rule of import and ex-
port’ applies to faulty channels, which makes it easier to prove properties of the
messages transferred over the channels without introducing more system invari-
ants.
• 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.

4.4 Recommendations for future research


We have mostly ignored discussions about the performance of the protocol in this the-
sis. In particular, the method that is used to choose an element to be sent from the
current window has been left unspecified. Further research is necessary to investigate
how the performance of the protocol is affected by using different methods for choos-
ing this element. Using a set of indices as acknowledgements instead of a single index,
like in [Sne95], could also affect the performance.

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. 99-
110, 1976.

33

You might also like