-
Notifications
You must be signed in to change notification settings - Fork 0
/
peer.go
123 lines (102 loc) · 2.71 KB
/
peer.go
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package raft
import (
"math"
"sort"
"github.com/coreos/etcd/raft"
"github.com/coreos/etcd/raft/raftpb"
)
const maxId = math.MaxUint64
type Peers struct {
redundancy int
p []string
thisPeer int // without raft offset (i.e. if this peer is first, then thisPeer == 0)
idxPerPeer uint64
}
func NewPeerList(cfg Config) *Peers {
peers := cfg.AllPeers
p := make([]string, len(peers))
copy(p, peers)
sort.Strings(p)
return &Peers{
redundancy: cfg.Redundancy,
p: p,
thisPeer: sort.SearchStrings(p, cfg.ThisPeer),
idxPerPeer: maxId / uint64(len(p)),
}
}
func (p Peers) Len() int {
return len(p.p)
}
// ForEach will call the function for every available peer. If the
// function returns a non-nil error, the iterations will be stopped immediately
// and the error will be returned directly.
func (p Peers) ForEach(f func(peer string) error) error {
for _, p := range p.p {
if err := f(p); err != nil {
return err
}
}
return nil
}
// PeersWithFile will return the peers which are supposed to hold the provided fileId.
// It will exclude this peer from that list
func (p Peers) PeersWithFile(id uint64) []string {
peers := make([]string, 0, p.redundancy)
for _, peerIndex := range p.peersWithFile(id) {
if peerIndex == p.thisPeer {
continue
}
peers = append(peers, p.p[peerIndex])
}
return peers
}
func (p Peers) peersWithFile(id uint64) []int {
numPeers := uint64(p.Len())
peerIndices := make([]int, 0, p.redundancy)
for i := uint64(0); i < uint64(p.redundancy); i++ {
peerIdx := (i + id/p.idxPerPeer) % numPeers
peerIndices = append(peerIndices, int(peerIdx))
}
return peerIndices
}
func (p Peers) IsLocalFile(id uint64) bool {
peersWithFile := p.peersWithFile(id)
for _, peerIndex := range peersWithFile {
if p.thisPeer == peerIndex {
return true
}
}
return false
}
// raft doesn't take 0 as a valid peer id, so the returned raft peers have their indexes offset by +1
func (p Peers) raftPeers() []raft.Peer {
rp := make([]raft.Peer, p.Len())
for i := range p.p {
rp[i] = raft.Peer{ID: uint64(i + 1)}
}
return rp
}
func (p Peers) confState() raftpb.ConfState {
nodes := make([]uint64, p.Len())
for i := range p.p {
nodes[i] = uint64(i + 1)
}
return raftpb.ConfState{Nodes: nodes}
}
func (p Peers) getPeer(id int) string {
if id >= p.Len() || id < 0 {
return ""
}
return p.p[id]
}
// GetPeerRaft is used for compliance with the type of raft id's being uint64 and 0 not being an acceptable peer id
func (p Peers) GetPeerRaft(id uint64) string {
return p.getPeer(int(id - 1))
}
// thisPeerRaftId returns the raft id for this peer
func (p Peers) thisPeerRaftId() uint64 {
return uint64(p.thisPeer + 1)
}
func (p Peers) ThisPeer() string {
return p.p[p.thisPeer]
}