Вы находитесь на странице: 1из 7

15-440 Distributed Systems

Homework 1
Due: October 9, In class.
October 15, 2012

1. In this scenario, three nodes, named Schenley, Frick, and Carnegie are working on a job for a user.
The sequence of events is given:
e1 ) C a r n e g i e s e n d s sync r e q u e s t t o F r i c k
e2 ) F r i c k r e c e i v e s sync r e q u e s t from C a r n e g i e
e3 ) C a r n e g i e s e n d s sync r e q u e s t t o S c h e n l e y
e4 ) F r i c k s e n d s sync r e q u e s t t o S c h e n l e y
e5 ) S c h e n l e y r e c e i v e s sync r e q u e s t from C a r n e g i e
e6 ) S c h e n l e y s e n d s sync acknowledgement t o C a r n e g i e
e7 ) C a r n e g i e r e c e i v e s j o b from u s e r
e8 ) C a r n e g i e r e c e i v e s sync acknowledgement from S c h e n l e y
e9 ) F r i c k s e n d s sync acknowledgement t o C a r n e g i e
e10 ) C a r n e g i e s e n d s work t o S c h e n l e y
e11 ) S c h e n l e y r e c e i v e s work from C a r n e g i e and b e g i n s p r o c e s s i n g
e12 ) C a r n e g i e r e c e i e v e s sync acknowledgement from F r i c k
e13 ) S c h e n l e y s e n d s sync acknowledgement t o F r i c k
e14 ) S c h e n l e y s e n d s work t o F r i c k
e15 ) F r i c k r e c e i v e s work from S c h e n l e y and b e g i n s p r o c e s s i n g
e16 ) S c h e n l e y c o m p l e t e s p r o c e s s i n g and w a i t s f o r r e s u l t s from F r i c k
e17 ) F r i c k c o m p l e t e s p r o c e s s i n g and s e n d s r e s u l t s t o S c h e n l e y
e18 ) S c h e n l e y r e c e i v e s r e s u l t s from F r i c k
e19 ) S c h e n l e y combines r e s u l t s and s e n d s them t o C a r n e g i e
e20 ) C a r n e g i e r e c e i v e s r e s u l t s
e21 ) C a r n e g i e s e n d s c l o s e t o S c h e n l e y
e22 ) C a r n e g i e s e n d s c l o s e t o F r i c k
Using this sequence of events:
(a) Write out the Lamport Clock representation of each timestep, using the notation L([event]) =
[Lamport Timestep]. For example, L(e1) = 1.
(b) Write out the vector time representation of each timestep.
Solution: See next page

Page 2


Lamport Timestep

Vector Timestep
[Carnegie Frick Schenley]
[1 0 0]
[1 1 0]
[2 0 0]
[1 2 0]
[2 0 1]
[2 0 2]
[3 0 0]
[4 0 2]
[1 3 0]
[5 0 2]
[5 0 3]
[6 3 2]
[5 0 4]
[5 0 5]
[5 4 5]
[5 0 6]
[5 5 5]
[5 5 7]
[5 5 8]
[7 5 8]
[8 5 8]
[9 5 8]
One way to check this is to simulate this in code, such as the following:
package main
import "fmt"
type Clock struct {
id int
lamport int
vector []int
var g_event int
func max(a, b int) int {
if a > b {
return a
return b
func (c *Clock) send() *Clock {
// Trigger event
// Copy new clock data into message
m := &Clock{0, c.lamport, make([]int, len(c.vector))}
copy(m.vector, c.vector)
return m

Page 3

func (c *Clock) recv(m *Clock) {

// Take max of lamport and vector clocks
c.lamport = max(c.lamport, m.lamport)
for i := 0; i < len(c.vector); i++ {
c.vector[i] = max(c.vector[i], m.vector[i])
// Trigger event
func (c *Clock) event() {
// Update lamport and vector clocks
// Increment global event counter and print
fmt.Printf("e%d: %d, %v \n", g_event, c.lamport, c.vector)
func main() {
// Create clocks
num_processes := 3
clocks := make([]*Clock, num_processes)
for i := 0; i < num_processes; i++ {
clocks[i] = &Clock{i, 0, make([]int, num_processes)}
// Create aliases for clocks
C := clocks[0]
F := clocks[1]
S := clocks[2]
// Event list
m1 := C.send() //e1
m3 := C.send() //e3
m6 := S.send() //e6
m9 := F.send() //e9
m10 := C.send() //e10
m14 := S.send() //e14
m17 := F.send() //e17
m19 := S.send() //e19

Page 4

2. In class, we examined the problem of distributed mutual exclusion: Guaranteeing that only a single
process can be in a particular critical section at one time.
The lecture notes discuss four algorithms: The use of a central lock server; Ricart & Agrawalas algorithm;
Lamports Algorithm; and a Token Ring.
(a) Easy warm-up: What are the two requirements we discussed in class?
Solution: Safety and fairness.
(b) In Lamports algorithm, a node first puts its lock request in its own queue. It then sends a request
to every other node and waits to hear replies from all of those nodes. Messages must be processed
in-order. A node wont grant itself the lock until it has heard REPLIES from all other nodes
containing a timestamp greater than the timestamp of its own request.
What is the fairness provided by Lamports algorithm compared to the fairness provided by the
token-ring algorithm?
Solution: Lamports algorithm provides fairness by using a queue to process requests from
multiple nodes. Requests are granted strictly in the order they are made.
The token ring provides a weaker form of fairness. It provides round-robin ordering on the
nodes, but it does not guarantee that requests are granted in the strict order of arrival. To
see this, consider the case when a node requests the mutex immediately after it has passed the
token... there are many opportunities for its predecessor in the ring to request the mutex, and
receive it, first.
(c) The solutions presented in class did not consider the problem of a machine failing. Using Lamports
Distributed Mutual Exclusion algorithm, there are two obvious consequences of a machine failure:
A machine dies holding a lock forever; and the inability to make forward progress because a machine
fails to respond to messages.
How would you solve the first problem, of a machine dying and holding a lock forever?
Solution: By providing a timed lease on the lock, the node will have a predetermined amount
of time that it may hold the lock before renewing the lease. At the end of the lease, if the node
has not requested a lease renewal then the lock is revoked and other nodes may now hold the
(d) Token Ring is also vulnerable to a node failure: Node N will try to send the token to node N+1. If
its connection to N+1 fails, N+1 fails, the token will get stuck at node N. Improve this algorithm
so that it is robust to connection failures and to the failure of a node that is not currently holding
the token.
Give a description of your algorithmic changes and why they work. Code is not needed. You may
assume that the network is modestly-sized enough that you dont need an O(1) algorithm - using
up to or less than O(N) memory and CPU is fine.
Solution: Each node must know the successor of every other node. If a node tries to pass
the token to its successor and does not recieve an ACK after a certain amount of time, it will
attempt to pass the token to its successors successor. It will continue doing so until it recieves
an ACK from the node.
This solution ensures that the system is robust as long as there is a single node left holding the
The major drawback to this approach is that if node N is wrong about node N + 1 not being
alive, it will unfairly deprive node N + 1 of the chance to grab the lock.

Page 5

(e) If you were particularly concerned about the death of one machine preventing progress, which of
the discussed solutions to distributed mutual exclusion would you use? Explain briefly why.
Solution: There are several correct answers to this question. You may consider the number of
messages required to acquire a lock, how the fairness of the algorithm behaves, the complexity
of implementing the system, and the algorithms robustness to failure.
The solutions we had in mind were:
A central coordinator is less likely to stop working if a single random node dies. Instead
of being cripped by the death of any of N nodes, now only N1 nodes can kill things.
The central coordinator can be made more robust by running multiple coordinators and
using a distributed election (or replication) scheme to determine which one is the head.
This is the scheme used most often in reality.
A token ring with the aforementioned changes, both leasing and the skip-a-dead-neighbor
trick, is a good start to building a more robust system. The drawbacks of the token ring
approach many messages, and potentially long delays until you hold the lock remain,
3. Dropbox is, at its heart, a distributed filesystem. See this page in the dropbox docs: https://www.
(a) Allowing such conflicts to happen is a deliberate design decision in Dropbox. Briefly explain how this
differs from AFS, and how AFS handles concurrent modifications to a file. (Briefly: 3-4 sentences)
Solution: Dropbox handles write conflicts by creating new files for each client with a different
name. While AFS client writes through at file close and the server immediately informs other
clients that have cached the same file. Thus the application needs to cooperate and perform
necessary synchronization.
(b) Why do you think Dropbox chose its design over AFSs design? What advantage does it confer to
Solution: Dropbox was primarily designed to help each user share and synchronize files among
different computers and devices, so it is less likely to have two clients modifying the same file
concurrently. Advantage of Dropboxs design includes: it is simple to design and implement;
and it ensures no version is overwritten.
(c) In what way is caching in dropbox more similar to AFS than it is to NFS?
Solution: Dropbox and AFS both cache the whole files while NFS only caches blocks of the
4. Some questions about RPC.
(a) RPC is designed to reduce programmer effort in writing distributed systems by making remote
function calls as easy to use as local function calls. Identify three different ways in which this
abstraction does not hold true.
Solution: There are four basic drawbacks for RPC over local calls: Connectivity loss (a local
function call typically cant fail in the same ways); Latency; Increased Total Overhead; No
hardware or local caching advantages.

Page 6

(b) Hit the web to answer this one: Briefly identify two advantages and one disadvantage of using
Googles protobuf format instead of the JSON format youre using for marshaling in Project 1.
Solution: Two general advantages: JSON is more widely used; JSON is more easily human
readable, and so doesnt require much, or any code or implementation context to userstand/verify/debug a JSON packet. JSON is very, very easy to use from javascript, making it an easy
choice for communicating between browsers and servers.
Protobuf is much more compact than JSON, particularly for numbers and arrays. Protobufs
are faster than JSON serialization. Protobufs include explicit versioning information to help
adapt to future needs.
(c) Your code in Project 1 handles the problem of preventing duplicate RPCs by using what networking
people call Stop and Wait: It has one message outstanding at a time. If a message with a sequence
number lower than the next-expected sequence number is received, the system will throw it away.
Imagine using your system to talk between CMU and the machine at UW from micro-quiz 1.
Assume the RTT from here to UW is 70ms. How many RPC calls can you execute per second using
a single client connection from here to UW?
Solution: RPC is independent of the underlying transport layer. Stop and Wait means that
a new Data Packet cannot be sent until the ACK for the previous packet is received. Thus,
sending the data packet out and waiting for its ACK require at least one RTT (round-trip
time). With this at 70ms to UW, the rate of data sent is capped at 1 request per 70ms, or only
14 RPCs per second.
(d) Briefly sketch out how you would improve this design to handle having multiple RPCs in flight at
a time.
Solution: Technically an open question. The common case is to add caching to Data both
seen and sent, and release the incomming data to the user once the appropriate data packet has
sucessfully been ackd. Allowing EpochHandler() to still resend appropriate packets to recover
unacknoledged and missing messages. So Client and Server will retain all advantages of LSP,
but with the ability to send off new packets wihtout waiting on an Ack. This is a feature of

Page 7