can improve the performance, but there is a question ... sistency checking between clients and servers. .... ãop,W ã from a client must check whether its state is.
Version Vector Protocols Implementing Session Guarantees∗ Anna Kobusi´nska Marek Libuda
Cezary Sobaniec Dariusz Wawrzyniak
Institute of Computing Science Pozna´n University of Technology, Poland {Anna.Kobusinska,Marek.Libuda,Cezary.Sobaniec,Dariusz.Wawrzyniak}@cs.put.poznan.pl
Abstract This paper analyses different protocols of session guarantees. Session guarantees (also known as client-centric consistency models) are one of the class of consistency models of replicated shared data, besides data-centric consistency models. The presentations comprises details of the data structures for the information maintained locally and passed to check consistency conditions, as well as the algorithms to process the information. The protocols are also discussed with respect to accuracy and data overhead. Keywords: consistency models, session guarantees, coherence protocols.
1.
Introduction
The construction of DSM systems is usually based on replication. However, multiple copies of the same data raise the problem of consistency. From the viewpoint of an application, strict consistency enables transparency of replication. On the other hand, it reduces concurrency, thereby performance. Loose consistency can improve the performance, but there is a question whether it meets the requirements of the application. In other words, there is a question about the guarantees of consistency provided by the system to the application. The guarantees are formally specified by a consistency model. Consistency models belong to two main categories: data-centric and client-centric [12]. Data-centric models offer certain guarantees about the behaviour of the system, as long as the application follows some access rules [1, 2, 11]. One of these rules states that a given process is bound to the same replica all the time. As for the replicated data themselves, data-centric models define the order in which the access operations appear to ∗ This work was supported in part by the State Committee for Scientific Research (KBN), Poland, under grant KBN 3 T11C 073 28
the clients. Client-centric models, in turn, provide some guarantees to the process that switches between replicas. They stem from mobile computing [13] and are originally called session guarantees. The relationships between these two classes of consistency models have been analysed in [4, 5]. The formulation of session guarantees is based on the history of interaction between a given application process (client) and the system. Thus, to simplify the reasoning about the access to replicated data in mobile environment, the client-server model of distributed application is assumed, in which data are stored (replicated) on servers, and clients access them by joining one of the servers. In terms of the client-server model session guarantees specify the set of operations that are expected to be executed by a given server when a client connects to it to issue an operation. This paper analyses different consistency protocols of session guarantees. Each protocol defines data structures to maintain and exchange the information for consistency checking between clients and servers. It also presents the algorithms to process this information both at the client side and at the server side. One of the analysed approaches is based on set algebra, the others on version vectors. The approach based on set algebra directly follows the definitions of session guarantees introduced in [13]. The protocol using server-based version vectors has been described in [13], the other two approaches are novel proposals.
2.
Session guarantees
2.1. System model In this paper a weakly consistent replicated storage system will be considered. The system consists of a number of servers holding a full copy of a set of shared objects, and clients running applications that access the objects. Clients are separated from servers, i.e. a client application may run on a separate computer than the server.
ation r is a set of writes that has influenced the current state of objects observed by the read r.
C1
S1
S2 C2
S3
S4
The exact meaning of relevant writes will strongly depend on the characteristics of a given system or application. For example, in case of simple isolated objects (i.e. objects with methods that access their internal fields), relevant writes of a read on object x may be represented by all previous writes on object x.
2.3. Definition of session guarantees Figure 1: Replication servers and client accessing them
A client may access a shared object after selecting a single server and sending a request to the server. Clients are mobile, i.e. they can switch from one server to another during application execution. Session guarantees are expected to take care of data consistency observed by a migrating client. The set of shared objects replicated by the servers does not imply any particular data model or organisation. Operations performed on shared objects are divided into reads and writes. A read does not change states of the shared objects, while a write does. A write may cause update of an object, it may create a new object, or delete an existing one. Servers periodically exchange information about operations performed in the past. This process eventually causes total propagation of all operations. It does not influence safety of the protocol but rather its liveness, therefore it will not be deeply discussed in this paper. In contrast with [13] we do not assume total ordering of non-commutative operations which is treated by us as an orthogonal problem.
2.2. Notation and basic definitions
Formal definitions of session guarantees specify the consistency conditions of the state of replicas that must hold at a server to execute an operation requested by a given client. Four guarantees have been distinguished: Read Your Writes, Monotonic Writes, Writes Follow Reads, and Monotonic Reads. Session guarantees have been presented in [13]. The following more formal definitions are based on those concepts. The definitions assume that operations are unique, i.e. they are labeled by some internal unique identifiers. D EFINITION 2. Read Your Writes (RYW) session guarantee is defined as follows: Sj Ci ∀Ci ∀S j w + r|S j ⇒ w r D EFINITION 3. Monotonic Writes session guarantee is defined as follows: Sj C ∀Ci ∀S j w1 +i w2 |S j ⇒ w1 w2 D EFINITION 4. Monotonic Reads session guarantee is defined as follows: Sj Ci ∀Ci ∀S j r1 + r2 |S j ⇒ ∀wk ∈ RW (r1 ) : wk r2
Operations on shared objects issued by a client Ci are orC
dered by a relation +i called client issue order. Clients are assumed to be sequential processes, so the relation C
+i determines total order on the set of operations issued by Ci . A server S j performs operations in the order rep-
D EFINITION 5. Writes Follow Reads session guarantee is defined as follows: Sj C ∀Ci ∀S j r +i w|S j ⇒ ∀wk ∈ RW (r) : wk w
Sj
resented by a relation . As the operations are performed one at a time, the relation is also a total order. Operations on objects will be denoted by w or r (with an optional index) depending on the type of operation (write or read). A read operation performed by a server S j will be denoted by r|S j . Definitions of session guarantees depend on the notion of relevant writes: D EFINITION 1. Relevant writes RW (r) of a read oper-
3.
Logical implementation
Usual implementation scheme of a protocol for the client-server model embraces two kinds of messages: requests and replies. Four events connected with these messages are essential for the implementation of coherence protocol for session guarantees (see Fig. 2): request dispatch at the client side, request receipt at the client
Client
Server
send of a request receipt of a request
the operation execution send of a reply receipt of a reply time
Figure 2: Request interception
side, reply receipt at the server side, reply dispatch at the server side. Logical implementation directly follows the definitions of session guarantees. The core structure in the implementation is a set of writes. By means of a request message, a client passes a set of writes that are expected to be executed by a server before the request is processed. The server sends back, if necessary, a set of identifiers of operations that influenced the result of the access. Consistency manager at the client side maintains two sets of writes WCi and RCi . WCi contains writes issued by the client Ci , while RCi contains writes that have influenced results of reads issued by the client. A client requesting an operation to be performed sends a message hop, SGi to the currently selected server. The message consists of a description op of the operation to be performed, and a set of session guarantees SG required for the operation. The message is intercepted by the consistency manager at the client side in order to supplement the message with a set of writes W required by the client. The set is initially empty, and depending on the set of session guarantees SG required by the client, and the type of operation (checked by a function iswrite(op)), it will be filled with writes from sets WCi and RCi (lines 1–9 of Alg. 1). Finally, a message hop, W i substituting previous message hop, SGi is sent to the server. The server S j that receives the request message hop, W i from a client must check whether its state is sufficiently up to date to meet the client’s expectations. The set of writes W sent by the client contains writes that must be performed by the server before proceeding to the current operation op. Every server S j maintains a set of writes OS j performed by the server in the past. The writes that belong to OS j come from direct requests sent by clients, or are incorporated from other servers dur-
On send of request message hop, SGi from Ci to S j 1: W ← 0/ 2: if (iswrite(op) and MW ∈ SG) 3: or (not iswrite(op) and RYW ∈ SG) then 4: W ← W ∪ WCi 5: end if 6: if (iswrite(op) and WFR ∈ SG) 7: or (not iswrite(op) and MR ∈ SG) then 8: W ← W ∪ RCi 9: end if 10: send hop, W i to S j On receipt of request message hop, W i from client Ci at server S j 11: while not OS j ⊇ W do 12: wait 13: end while 14: perform op and store results in res 15: if iswrite(op) then 16: OS j ← OS j ∪ {op} 17: W ← {op} 18: else 19: W ← RW (op) 20: end if 21: send hop, res, W i to Ci On receipt of reply message hop, res, W i from server S j at client Ci 22: if iswrite(op) then 23: WCi ← WCi ∪ W 24: else 25: RCi ← RCi ∪ W 26: end if 27: deliver res On receipt of update msg hSk , Oi at server S j 28: foreach wi ∈ O do 29: if not wi ∈ O then 30: perform wi 31: OS j ← OS j ∪ {wi } 32: end if 33: end for 34: signal Every ∆t at server S j 35: foreach S k 6= S j do 36: send S j , OS j to Sk 37: end for Algorithm 1: Logical protocol implementing session guarantees
ing synchronization of servers. The condition at line 11 checks whether the set OS j is a superset of W , which means that the server has already performed all writes requested by the client. A request that cannot be performed by the server is suspended (line 12), and will be resumed after synchronization with some other server (line 34). A server that has suspended a request can proceed to the next request. After execution of a write operation op, the server adds it to the set OS j . Finally, a reply message hop, res, W i is sent back to the client. The results of the operation are included in the res field. The set W of the reply message represents effects of the operation just performed, and is used to update the client’s data structures. In case of writes W contains only the operation just performed, and in case of reads it contains all writes relevant to the current read (line 19). After receipt of the reply message hop, res, W i the client updates the sets of writes: WCi in case of writes, and RCi in case of reads, by calculating a sum of the previous value of appropriate set, and the set W . Finally, the received results res of the operation op are delivered to the client application. The servers periodically exchange information about writes requested by clients in order to propagate changes. The procedure may be activated on a time basis, after every modification, or anyhow otherwise — it does not affect correctness of the protocol but rather its liveness. The modifications submitted by clients may be also propagated in different orders at different servers because we do not assume ordering of non-commutative operations. This may lead to inconsistent state after total propagation of all writes. However, this problem is orthogonal to session guarantees — some implementations may enforce ordering of non-commutative operations, and achieve eventual consistency in that way. The object-based version vector implementation (see subsection 4.2) totally orders writes on given objects which is a form of ordering of non-commutative operations in case of isolated objects. The pseudo-code presented in Alg. 1 is a very simple example of possible synchronization procedure. Every server S j periodically sends the set OS j of writes it has performed to all other servers in the system. After receipt of an update message, servers iterate through writes contained in the message, perform the writes that are new, and add them to their local sets of writes. After applying new writes the synchronization procedure restarts threads that were waiting for the server to update (line 34). More complex synchronization procedures can be found in [10].
4.
Version vector implementations
Logical implementation is rather impractical because the size of data structures (thereby the size of messages) rises ad infinitum. Therefore, for the purpose of efficient representation of sets of writes, version vectors are used. Version vectors are maintained by servers in a similar way to vector clocks [3]. The idea of vector clocks has been proposed in [9] and [7] to improve logical clocks introduced by Lamport [8]. Depending on the kind of the version vector, each position represents the number of operations preformed by the corresponding server, or issued by the corresponding client, or performed on the corresponding object. The following subsections present these three approaches. Every server records writes performed by the server in a local history HS j , which is a totally ordered set of writes OS j with version vectors associated with every write. The version vectors associated with writes uniquely identify the writes. They can be retrieved by a function T : OS j 7→ V . From now on, the set of writes WCi performed by client Ci will be represented by a version vector WCi , and the set of writes RCi that have influenced reads performed by a client Ci will be represented by a version vector RCi .
4.1. Server-based version vectors Server-based version vectors have the following form: V = v1 v2 . . . vNS . The size of the vector is NS which is the total number of servers in the system. A single position v j represents the number of writes performed by a server S j . The VsSG protocol, presented in Alg. 2, uses server-based version vectors for efficient representation of sets of wrties. Because of the change of representation of sets of writes, the messages exchanged between clients and servers have different form. Clients send a message hop, SGi, that is later substituted by hop,W i, where W is a version vector representing the set of writes required by the client. Servers reply with a message hop, res,W i, where W is a version vector representing effects of the operation just performed. After receipt of a request from a client, a server S j checks whether it is sufficiently up to date by comparing its version vector VS j with the version vector W of the request message (line 11). The server’s version vector VS j must dominate the vector W , which is denoted by VS j ≥ W , and takes place when ∀i : VS j [i] ≥ W [i]. The version vectors WCi and RCi maintained by clients are updated by calculating a maximum of the current value, and a value sent in a reply message. The maximum of two vectors V1 and V2 is a vector V = max (V1 ,V2 ), such that V [i] = max (V1 [i],V2 [i]).
On send of request message hop, SGi from Ci to S j 1: W ← 0 2: if (iswrite(op) and MW ∈ SG) 3: or (not iswrite(op) and RYW ∈ SG) then 4: W ← max (W,WCi ) 5: end if 6: if (iswrite(op) and WFR ∈ SG) 7: or (not iswrite(op) and MR ∈ SG) then 8: W ← max (W, RCi ) 9: end if 10: send hop,W i to S j On receipt of request message hop,W i from client Ci at server Sj 11: while VS j 6≥ W do 12: wait 13: end while 14: perform op and store results in res 15: if iswrite(op) then 16: VS j [ j] ← VS j [ j] + 1 17: timestamp op with VS j 18: HS j ← HS j ∪ {op} 19: end if
20: send op, res,VS j to Ci On receipt of reply message hop, res,W i from server S j at client Ci 21: if iswrite(op) then 22: WCi ← max (WCi ,W ) 23: else 24: RCi ← max (RCi ,W ) 25: end if 26: deliver hresi On receipt of update msg hSk , Hi at server S j 27: foreach wi ∈ H do 28: if VS j 6≥ T (wi ) then 29: perform wi 30: VS j ← max VS j , T (wi ) 31: HS j ← HS j ∪ {wi } 32: end if 33: end for 34: signal Every ∆t at server S j 35: foreach S k 6= S j do 36: send S j , HS j to Sk 37: end for Algorithm 2: VsSG protocol of session guarantees. The protocol uses server-based version vectors.
On receipt of request message hop,W i from client Ci at server Sj 1: while VS j 6≥ W do 2: wait 3: end while 4: perform op and store results in res 5: if iswrite(op) then 6: VS j [ j] ← VS j [ j] + 1 7: timestamp op with VS j 8: HS j ← HS j ∪ {op}
9: send op, res,VS j [ j] to Ci 10: else
11: send op, res,VS j to Ci 12: end if On receipt of reply message hop, res,W i from server S j at client Ci 13: if iswrite(op) then 14: WCi [ j] ← W [ j] 15: else 16: RCi ← max (RCi ,W ) 17: end if 18: deliver hresi Algorithm 3: VsOSG protocol of session guarantees. Only event handlers that differ from VsSG protocol are shown.
Optimization. The interaction between clients and servers can be optimized for write requests by reducing the size of reply messages. By default the server returns the whole version vector after performing the write (line 20 of Alg. 2). However, the real change in the server version vector VS j , that is relevant to the current write, take place at position j. Value VS j [ j] represents the current write. The other positions of server VS j refer to writes performed at different servers. The optimized version of server-based version vector protocol, called VsOSG, is presented in Alg. 3. The algorithm shows only event handlers that have changed comparing to the VsSG protocol. As a result of the optimization the size of server replies in case of writes is considerably smaller. On the other hand, the accuracy of the client version vector WCi is increased (see also Section 5). Synchronization procedure. The synchronisation procedure presented in Alg. 2 assumes transfer of whole histories. The histories monotonically increase therefore the implementation seems to be impractical in the same manner as logical implementation of session guarantees did. However, a server may send only the part of its history that the destination server is not aware of. Servers may maintain approximations of version
vectors of all other servers, and send only those parts of their histories that are not dominated by appropriate approximation. The approximation may be updated during every interaction with a given server.
4.2. Object-based version vectors Object-based version vectors have the following form: V = v1 v2 . . . vNO , where each position vi represents the number of writes performed on an object xi . Thus, the size of the vector is NO , which is the total number of objects in the system. Apart from the structure of version vector itself, main data structures maintained at the server side and at the client side are similar to the case of server-based vectors. However, the structure of the reply message hop, res, seqi is different because only a single position seq of a server version vector is passed instead of the whole vector. The VoSG protocol is presented in Alg. 4. The presentation uses a function id(op), that returns numerical identifier of an object accessed by operation op. Version vectors are used for identification of writes, therefore they must be unique. In case of object-based version vectors this assumption is not true if they are processed in the same way as server-based version vectors. Let us consider an example execution shown in Fig. 3, where two different write requests related to the same object are processed concurrently by different servers. Let us assume that the initial values of the server version vectors were 0 0 (there are 2 different objects x, and y). After the first write to object x (operation w(x)1 represents a write of value 1 to object x), the server version vector VS1 = 1 0 . After the second write w(x)2 the other server version vector VS2 = 1 0 , and hence WC2 = 1 0 . Client C2 then switches from server S2 to S1 , and issues a read operation on object x. The operation can be performed because VS1 ≥ WC2 . However the operation violates RYW session guaran-
C1 S1
C2 RYW
[1 0] [1 0]
w(x)2
On receipt of request message hop,W i from client Ci at server S j 11: seq ← 0 12: if iswrite(op) then 13: seq ← getSeqNumber(id(op)) 14: end if 15: while VS j 6≥ W ∨ seq > VS j [id(op)] + 1 do 16: wait 17: end while 18: perform op and store results in res 19: if iswrite(op) then 20: VS j [id(op)] ← VS j [id(op)] + 1 21: timestamp op with VS j 22: HS j ← HS j ∪ {op} 23: signal 24: end if
25: send op, res,VS j [id(op)] to Ci On receipt of reply message hop, res, seqi from server S j at client Ci 26: if iswrite(op) then 27: WCi [id(op)] ← seq 28: else 29: RCi [id(op)] ← seq 30: end if Algorithm 4: VoSG protocol of session guarantees. The protocol uses object-based version vectors.
w(x)1
S2
On send of request message hop, SGi from Ci to S j 1: W ← 0 2: if (iswrite(op) and MW ∈ SG) 3: or (not iswrite(op) and RYW ∈ SG) then 4: W ← max (W,WCi ) 5: end if 6: if (iswrite(op) and WFR ∈ SG) 7: or (not iswrite(op) and MR ∈ SG) then 8: W ← max (W, RCi ) 9: end if 10: send hop,W i to S j
r(x)1
Figure 3: Object-based version vectors and cache consistency
tee required by the client because the server S1 has not performed the previous write w(x)2 yet. This anomaly results from indistinguishableness of version vectors associated with the writes. To avoid this, writes on a given object must be performed in the same order on all servers, which forces cache consistency. To this end, consecutive sequence numbers are assigned (line 13 of Alg. 4), representing the next write on a given object. The value of the sequence number is then checked in line 15 to ensure that all previous writes on a given object have been performed. The exact implementation of the function getSeqNumber(), which generates the se-
quence numbers, is beyond the scope of the paper. It can be implemented for example by means of adaptation of some distributed mutual exclusion algorithms.
4.3. Client-based version vectors Client-based version vectors have the following form: V = v1 v2 . . . vNC . The size of the vector is NC , which is the total number of clients in the system. A single position vi represents the number of writes issued by a client Ci . Client-based version vectors, if they are managed in a similar way to server-based version vectors, do not guarantee uniqueness. Fig. 4 shows an execution in which writes coming from the same client are not globally ordered, and, as a result, MR guarantee is not provided despite requested. Client C1 performs the first write at server S1 , and then the second write at server S2 . Let us assume that the initial values of the server version vectors were 0 0 (there are two clients). After the first write the server version vector VS1 = 1 0 . After the second write VS2 = 1 0 . Client C2 requires MR, therefore after the first read at server S1 its version vector RC2 = 1 0 . Next, the client switches to server S2 and issues another read operation on the same object. Because VS2 ≥ RC2 the operation can be performed resulting in MR violation. In order to avoid this anomaly, writes requested by a given client must be totally ordered, which effectively means that MW session guarantee must be provided for all clients. Alg. 5 presents VcSG protocol using client-based version vectors. Global ordering of write requests is forced by setting W [i] to the current number of writes performed by a client Ci (line 3). As a result, the server that performs the write must first perform all previous writes of the client (line 10). It is easy to notice that the management of client version vector WCi is somehow degenerated. The i-th posiC1 S1
w(x)1
w(y)2
[1 0]
S2 C2 MR Figure 4:
[1 0] r(x)1
r(x)0
Client-based version vectors and Monotonic Writes
On send of request message hop, SGi from Ci to S j 1: W ← 0 2: if iswrite(op) or RYW ∈ SG then 3: W [i] ← WCi [i] 4: end if 5: if (iswrite(op) and WFR ∈ SG) 6: or (not iswrite(op) and MR ∈ SG) then 7: W ← max (W, RCi ) 8: end if 9: send hop,W i to S j On receipt of request message hop,W i from client Ci at server Sj 10: while VS j 6≥ W do 11: wait 12: end while 13: perform op and store results in res 14: if iswrite(op) then 15: VS j [i] ← VS j [i] + 1 16: timestamp op with VS j 17: HS j ← HS j ∪ {op} 18: send hop, res, 0i / to Ci 19: else
20: send op, res,VS j to Ci 21: end if On receipt of reply message hop, res,W i from server S j at client Ci 22: if iswrite(op) then 23: WCi [i] ← WCi [i] + 1 24: else 25: RCi ← max (RCi ,W ) 26: end if Algorithm 5: VcSG protocol of session guarantees. The protocol uses client-based version vectors.
tion of a version vector WCi is the only position that is really used, and it represents the number of writes performed by the client Ci . On the other hand, the replies sent to clients after performing writes do not contain any version vector information (line 18), because the client has to update only its local write count WCi [i], and it knows how to update the variable in advance. The RCi version vector is updated in a regular manner.
5.
Discussion
In the version vector implementation the sets of writes resulting from the definitions of session guarantees are approximated by appropriate version vectors. The sets of writes represented by version vectors are supersets of the exact sets resulting from appropriate definitions.
This is necessary for the protocols to be safe [6]. This way version vectors provide sufficient information to check session guarantees, however, the protocols are excessive in some cases. The accuracy of the representation of sets of writes is therefore an important factor of a protocol implementing session guarantees that influences its performance. The accuracy of a version vector may be measured during synchronisation between servers by comparing the exact number of additional writes required by a client with the number of additional writes actually performed at a server S j before the condition VS j ≥ W can be fulfilled. This problem is currently considered, and appropriate simulation experiments are being prepared. Based on some preliminary simulation results the best accuracy can be expected from objectbased version vectors, then client-based version vectors. In general the accuracy will be higher for WCi (RYW and MW session guarantees) than for RCi (MR and WFR). The accuracy will also depend on the relation between number of servers, clients, and objects, and on other factors of the system like: modification frequency, client migration frequency, etc. Another aspect of the version vector implementation is the structure of the version vector. The size of the version vector corresponds to the number of items (either servers, objects, or clients) in the system. From this point of view, server-based version vectors seems to be most stable, because, in practice, the changes in server infrastructure are rather rare. The changes in the set of clients seem to be more common, which complicates dealing with client-based version vectors. As for the object-based version vector, its size is usually greater than other kinds of version vectors. Moreover, depending on the characteristic of an application, the size can change frequently, as objects are created and destroyed.
6.
Conclusions
In this paper we have presented different consistency protocols of session guarantees using version vectors. The definitions of session guarantees refer to sets of writes that must be efficiently represented in a protocol. Because precise representation leads to inefficiency, we sacrifice accuracy of the representation in search of a better performance. Version vectors provide sufficient checks for ensuring session guarantees, but usually require more synchronism of servers. Depending on the characteristics of a given system or application, the system designer can choose from server-based, clientbased, or object-based version vectors.
References [1] M. Ahamad, R. A. Bazzi, R. John, P. Kohli, and G. Neiger. The power of processor consistency (extended abstract). In Proc. of the 5th ACM Annual Symp. on Parallel Algorithms and Architectures (SPAA’93), pages 251–260, June 1993. [2] M. Ahamad, G. Neiger, P. Kohli, J. E. Burns, and P. W. Hutto. Casual memory: Definitions, implementation and programming. Distributed Computing, 9:37–49, 1995. [3] R. Baldoni and M. Raynal. Fundamentals of distributed computing: A practical tour of vector clock systems. IEEE Distributed Systems Online, 3(2), February 2002. [4] J. Brzezi´nski, C. Sobaniec, and D. Wawrzyniak. Session guarantees to achieve PRAM consistency of replicated shared objects. In Proc. of the Fifth Int’l Conf. on Parallel Processing and Applied Mathematics (PPAM’2003), LNCS 3019, pages 1–8, Cz˛estochowa, Poland, September 2003. [5] J. Brzezi´nski, C. Sobaniec, and D. Wawrzyniak. From session causality to causal consistency. In Proc. of 12th Euromicro Conf. on Parallel, Distributed and Network-Based Processing (PDP2004), pages 152–158, A Coruña, Spain, February 2004. [6] J. Brzezi´nski, C. Sobaniec, and D. Wawrzyniak. Safety of a server-based version vector protocol implementing session guarantees. In Proc. of Int’l Conf. on Computational Science (ICCS2005), LNCS 3516, pages 423–430, Atlanta, USA, May 2005. [7] C. Fidge. Logical time in distributed computing systems. Computer, 24(8):28–33, August 1991. [8] L. Lamport. Time, clocks, and the ordering of events in a distributed system. Communications of the ACM, 21(7):558–565, July 1978. [9] F. Mattern. Virtual time and global states of distributed systems. In Cosnard, Quinton, Raynal, and Robert, editors, Proc. of the Int’l. Conf. on Parallel and Distributed Algorithms, pages 215–226. Elsevier Science Publishers B. V., October 1988. [10] K. Petersen, M. J. Spreitzer, D. B. Terry, M. M. Theimer, and A. J. Demers. Flexible update propagation for weakly consistent replication. In Proc. of the 16th ACM Symposium on Operating Systems Principles (SOSP-16), pages 288–301, Saint Malo, France, October 1997. [11] M. Raynal and A. Schiper. A suite of formal definitions for consistency criteria in shared memories. In Proc. of the 9th Int’l Conf. on Parallel and Distributed Computing Systems (PDCS’96), pages 125–131, September 1996. [12] A. S. Tanenbaum and M. van Steen. Distributed Systems — Principles and Paradigms. Prentice Hall, New Jersey, 2002. [13] Douglas B. Terry, Alan J. Demers, Karin Petersen, Mike Spreitzer, Marvin Theimer, and Brent W. Welch. Session guarantees for weakly consistent replicated data. In Proceedings of the Third International Conference on Parallel and Distributed Information Systems (PDIS 94), Austin, Texas, September 28-30, 1994, pages 140–149. IEEE Computer Society, 1994.