Replicated Service Client

Self-explanatory :-)
Actually cause I feel lazy today.

1
2
3
4
5
6
7
8
9
10
11
type ReplicatedClient interface {
// Init initializes the client to use the given servers.
// To make a particular request later,
// the client can use callOne(srv, args), where srv
// is one of the servers from the list
Init(servers []string, callOne(string, Args) Reply)

// Call makes a request to an available server.
// Multiple gouroutines may call Call concurrently.
Call(args Args) Reply
}
1
2
3
4
5
6
7
8
9
10
11
12
type Client struct {
servers []string
callOne func(string, Args) Reply

mu sync.Mutex
prefer int
}

func (c *Client) Init(servers []string, callOne func(string, Args) Reply) {
c.servers = servers
c.callOne = callOne
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func (c *Client) Call(args Args) Reply {
type result struct {
serverID int
reply Reply
}

const timeout = 1 * time.Second
t := time.NewTimer(timeout)
defer t.Stop()

done := make(chan result, 1)

c.mu.Lock()
prefer := c.prefer
c.mu.Unlock()

var r result
for off := 0; off < len(c.servers); off++ {
id := (prefer + off) % len(c.servers)
go func() {
done <- result{id, c.callOne(c.servers[id], args)}
}()
select {
case r = <-done:
goro Done
case <-t.C:
t.Reset(timeout)
}
}

Done:
c.mu.Lock()
c.prefer = r.serverID
c.mu.Unlock()
return r.reply
}
Pieces of Valuable Programming Knowledges