Experiment-4: Logical Clocks - Vector Clocks Description

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 6

Experiment-4: Logical Clocks – Vector Clocks

Description:

In experiment-3 we studied Lamport’s logical clock, a problem with this clock is that it cannot tell you when two events
are concurrent. For example, in the figure below if we look at the timestamps, we could conclude that event 3 in process
1 happend before event 8 in process 2, but this is not necessarily true.

To see how this could happen, let us say that event 3 takes a few seconds to happen in process 1, this will not affect event
8 in process 2, that is, several events could happen in process 2 before event 3 happens in process 1, thus it is possible for
event 8 in process 2 to be executed before event 3 in process 1. We can verify this by adding a some delay (say 5 seconds)
before executing event 3 in process 1 as follows:

from time import sleepdef process_one(pipe12):


pid = getpid()
counter = 0
counter = event(pid, counter)
counter = send_message(pipe12, pid, counter)
sleep(5)
counter = event(pid, counter)
counter = recv_message(pipe12, pid, counter)
counter = event(pid, counter)

Now, if we run the program of experiment 3 after this modification we get the following output:

Prepared by: Dr Talal A. Edwan


nibras@eagle:~/$ python lamport_clock.py

1:Something happened in 19298 ! (LAMPORT_TIME=1, LOCAL_TIME=2021-12-02 08:48:07.020918)

2:Message sent from 19298 (LAMPORT_TIME=2, LOCAL_TIME=2021-12-02 08:48:07.021387)

3:Message received at 19299 (LAMPORT_TIME=3, LOCAL_TIME=2021-12-02 08:48:07.021692)

4:Message sent from 19299 (LAMPORT_TIME=4, LOCAL_TIME=2021-12-02 08:48:07.021905)

5:Message sent from 19299 (LAMPORT_TIME=5, LOCAL_TIME=2021-12-02 08:48:07.022004)

6:Message received at 19300 (LAMPORT_TIME=6, LOCAL_TIME=2021-12-02 08:48:07.022065)

7:Message sent from 19300 (LAMPORT_TIME=7, LOCAL_TIME=2021-12-02 08:48:07.022198)

8:Message received at 19299 (LAMPORT_TIME=8, LOCAL_TIME=2021-12-02 08:48:07.022238)

9:Something happened in 19298 ! (LAMPORT_TIME=3, LOCAL_TIME=2021-12-02 08:48:12.026018)

10:Message received at 19298 (LAMPORT_TIME=5, LOCAL_TIME=2021-12-02 08:48:12.026225)

11:Something happened in 19298 ! (LAMPORT_TIME=6, LOCAL_TIME=2021-12-02 08:48:12.026256)

nibras@eagle:~/$

Where, process 1 has a pid=19298, process 2 has a pid=19299 and process 3 has a pid=19300. As can be seen from the
output in line 1, an event happened in process 1 and the logical clock was 2. After that several events happened in process
2 and process 3 during 5 seconds, the last was in process 2 when its logical clock was 8 – see line 8.

After 5 seconds (timestamp 12 seconds in line 9) an event happened in process 1 and thus its logical clock becomes 3. So,
in this case the event that happened in process 2 when the logical clock was 8 – see line 8 -- actually happened before the
event that happened in process 1 when the logical clock was 3 – see line 9.

Vector Clocks

Vector Clocks solve this problem by using a vector counter instead of an integer counter. The vector clock of a system
with N processes is a vector of N counters, that is, one counter per process. Vector counters follow these rules:

• Initially, all counters are zero ([0,0,0] in example above).


• Each time a process experiences an event, it increments its own counter in the vector by one.
• Each time a process sends a message, it includes a copy of its own (incremented) vector in the message.
• Each time a process receives a message, it increments its own counter in the vector by one and updates each
element in its vector by taking the maximum of the value in its own vector counter and the value in the vector in
the received message.

When applying vector clocks to the example above, we get a vector for each event as showed in following figure.

Prepared by: Dr Talal A. Edwan


In the previous example, where we compared event 3 (the one that happened when the logical clock was 3) in process 1
with event 8 (the one that happened when the logical clock was 8) in process 2. The vectors read [3,0,0] and [2,4,2] – see
the figure above. In vector clocks, for one event to have happened before another event, all the elements of its vector
need to be smaller or equal to the matching elements in the other vector.

Here, there is clearly a conflict (3>2 and 0<4), and thus we can conclude that these events are concurrent and have not
influenced each other.

In-LAB Assignment:

We are going to modify the source code in experiment 3 so it implements vector clocks. Specifically, we are going to
change the way the new counter is calculated when a message is received. We are going to work with arrays, so we need
to calculate the maximum between the counter in the message and the process’s counter for each element.

We will implement and run three separate processes that can communicate with each other through messages. Each
process has its own internal counter that will be updated with each event. We will write a Python 3 program that will
print a line for each event together with the updated internal counter and also the time on the computer running the
processes. The modified source code is shown below.

Write the following Python 3 program and save it as “vector_clock.py”.

Prepared by: Dr Talal A. Edwan


from multiprocessing import Process, Pipe
from os import getpid
from datetime import datetime

def local_time(counter):
return ' (LAMPORT_TIME={}, LOCAL_TIME={})'.format(counter, datetime.now())

def calc_recv_timestamp(recv_time_stamp, counter):


for id in range(len(counter)):
counter[id] = max(recv_time_stamp[id], counter[id])
return counter

def event(pid, counter):


counter[pid] += 1
print('Something happened in {} !'.\
format(pid) + local_time(counter))
return counter

def send_message(pipe, pid, counter):


counter[pid] += 1
pipe.send(('Empty shell', counter))
print('Message sent from ' + str(pid) + local_time(counter))
return counter

def recv_message(pipe, pid, counter):


message, timestamp = pipe.recv()
counter = calc_recv_timestamp(timestamp, counter)
print('Message received at ' + str(pid) + local_time(counter))
return counter

def process_one(pipe12):
pid = 0
counter = [0,0,0]
counter = event(pid, counter)
counter = send_message(pipe12, pid, counter)
sleep(5)
counter = event(pid, counter)
counter = recv_message(pipe12, pid, counter)
counter = event(pid, counter)

def process_two(pipe21, pipe23):


pid = 1
counter = [0,0,0]
counter = recv_message(pipe21, pid, counter)
counter = send_message(pipe21, pid, counter)
counter = send_message(pipe23, pid, counter)
counter = recv_message(pipe23, pid, counter)

Prepared by: Dr Talal A. Edwan


def process_three(pipe32):
pid = 2
counter = [0,0,0]
counter = recv_message(pipe32, pid, counter)
counter = send_message(pipe32, pid, counter)

if __name__ == '__main__':
oneandtwo, twoandone = Pipe()
twoandthree, threeandtwo = Pipe()

process1 = Process(target=process_one, args=(oneandtwo,))


process2 = Process(target=process_two, args=(twoandone, twoandthree))
process3 = Process(target=process_three, args=(threeandtwo,))

process1.start()
process2.start()
process3.start()

process1.join()
process2.join()
process3.join()

Now we can run the program by typing the following in the command line:

nibras@eagle:~$ python vector_clock.py

Observe the output:

nibras@eagle:~$ python vector_clock.py


Something happened in 0 ! (LAMPORT_TIME=[1, 0, 0], LOCAL_TIME=2021-12-02 10:21:00.822047)

Message sent from 0 (LAMPORT_TIME=[2, 0, 0], LOCAL_TIME=2021-12-02 10:21:00.823006)

Message received at 1 (LAMPORT_TIME=[2, 0, 0], LOCAL_TIME=2021-12-02 10:21:00.823178)

Message sent from 1 (LAMPORT_TIME=[2, 1, 0], LOCAL_TIME=2021-12-02 10:21:00.823502)

Message sent from 1 (LAMPORT_TIME=[2, 2, 0], LOCAL_TIME=2021-12-02 10:21:00.823648)

Message received at 2 (LAMPORT_TIME=[2, 2, 0], LOCAL_TIME=2021-12-02 10:21:00.823827)

Message sent from 2 (LAMPORT_TIME=[2, 2, 1], LOCAL_TIME=2021-12-02 10:21:00.823987)

Message received at 1 (LAMPORT_TIME=[2, 2, 1], LOCAL_TIME=2021-12-02 10:21:00.824045)

Something happened in 0 ! (LAMPORT_TIME=[3, 0, 0], LOCAL_TIME=2021-12-02 10:21:05.826029)

Message received at 0 (LAMPORT_TIME=[3, 1, 0], LOCAL_TIME=2021-12-02 10:21:05.826237)

Something happened in 0 ! (LAMPORT_TIME=[4, 1, 0], LOCAL_TIME=2021-12-02 10:21:05.826267)


nibras@eagle:~$

Prepared by: Dr Talal A. Edwan


Exercise:

a) Explain how the problem was solved. .


b) Modify the code above by introducing a delay of 3 seconds in process two, run the program and explain each line of the
output for process one and process two.

Prepared by: Dr Talal A. Edwan

You might also like