• No results found

We rely on the following notations and conventions. Variables are typically written in italics. Program( fragment)s are written in amonospaced font. Common data types N and B represent natural numbers and booleans, respectively. We use the common Boolean operator precedence:

• negation ¬ binds tighter than conjunction ∧, • conjunction binds tighter than disjunction ∨, and

• conjunction and disjunction have a higher precedence than implication =⇒ . We use four abstract data structures to describe the formal definitions and spec- ifications of functional behavior, namely tuple, sequence, set and map. A tuple is an ordered finite list of elements represented using angled brackets〈〉.

1.5. Notation The sequence data structure is represented by Seq〈T 〉, with T denoting the type of the sequence elements. Sequences are typically represented as normal variables (e.g., s) or variables of type T with an overbar (e.g., e). An empty sequence is de- noted by[] and · represents sequence concatenation. We also use juxtaposition to represent sequence concatenation when it is clear from the context. The notation

s

pr

s0 means that a sequence s is a prefix of another sequence s0. The function

Pref(s) yields the set of all prefixes of s. The projection operator s↓X produces the

longest subsequence4 of the sequence s that contains sequence elements in X . A sequence s1 is contained within another sequence s2, written s1 ⊆ s2 if there are

s0, s00such that s0·s1·s00= s2. An element e occurs before e0in a sequence s, written e<se0, if there is s0such that e·s0· e0⊆ s. Note that if e or e0occurs multiple times, this predicate behaves positively by picking suitable specific occurrences of e and

e0. The length of a sequence s is denoted by|s|. If s is an infinite sequence, then |s| = ∞. The n-th element on the sequence is retrieved by s[n] provided |s| ≥ n. The notation erepresents a finite sequence containing only of e’s.

The set data structure Set〈T 〉 is a container of values of type T . Set variables are typically written in capital letters (e.g., S). A bold face indicates that the variable is used as a general universe, e.g., N and B as stated above. An empty set is denoted by;. We use the union symbol ∪ and the difference symbol − to represent the insertion and deletion operations to a set, respectively. The power set of a set S is written as 2S. If T is a sequence type, the projection operator can be applied to a set S of type Set〈T 〉, written S↓X , producing the following set: { s↓X | s ∈ S }.

The map data structure Map〈S, T 〉 is an associative container that maps unique keys of type S to values of type T . An empty map is denoted by {}. If m is a map, m[x 7→ y] represents the insertion or update of the key x with value y to m. The operator is naturally extended to m[x17→ y1, . . . , xn7→ yn] to allow a simul- taneous update of distinct keys x1, . . . , xn. The value y of key x is represented by m(x). If m does not have any value associated with x, then m(x) =

undef

. Two maps m1, m2 of the same type Map〈S, T 〉 may be combined when for each key x of type S, either m1(x) =

undef

or m2(x) =

undef

, or both. The com- bination of combinable maps m1 and m2, written m1∪ m2, is m where for each key x, m(x) = m1(x) if m1(x) 6=

undef

, otherwise m(x) = m2(x). The predicate

diffOn(m1, m2, X) for a set of keys X is true if m1may differ from m2with respect to the values of keys in X and other keys are mapped to the same value.

4A sequence s is a subsequence of another sequence s0if s can be derived from s0by deleting some

PART

I.

Language and Component

Framework

C

HAPTER

2

Verification Framework Overview

The main aim of this thesis is to present a chain of verification methods from implementations to system models. This chapter provides an overview of how this chain works through a client-server example derived from an industrial Erlang case study by Arts and Dam[AD99].

Chapter outline. We first start by describing the case study in Section2.1. Then, Section 2.2 discusses its implementation in α

ABS

, which is described in Chap- ter3. Finally, Sections2.3and2.4provide a sketch of the approach to verify the implementation against the requirements. This approach is formalized in PartsII

andIIIwhich feature the client-server example as the running example.

2.1

Description

The case study deals with an implementation of a query mechanism of a dis- tributed database. The database has a single front end which we call the server. The system consists of the server (sub)system and numerous clients. The server receives requests from clients, where each request contains a query. The server has to respond to the requests with the appropriate computation results. To serve each request, the server creates a worker and passes on the query to be computed. If a query can be divided into multiple chunks, more concurrent computations can be introduced in the following way. Before each worker processes the first chunk of the query, it creates another worker to which the rest of the query is passed on. When the computation of the first query chunk is finished, the worker waits for the result from the next worker and merges the computation results together. The merged result is then returned. From the client side, the server is expected to respond to each request with the correct computation result, without having to know how the computation is done. The structure that results from the response of the server to a request is portrayed in Figure2.1where a query can be divided into three chunks.

The requirements for the query mechanism highlights a number of challenges for the implementation. First, the number of clients and the number of requests

Client Server Worker Worker Worker Figure 2.1.: Request processing structure on the server system1

being made to the server are unknown and can happen without any control from the server side. Second, there is no restriction on the size of a query. As a result, the number of workers needed to process a query is unbounded. The server and potentially each worker may need to coordinate the request with the computation result. In particular, the server must eventually respond each request with the correct computation result of the query if it is computed directly as a whole. The communication that happens between different requests must not interfere with or even block each other.