1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package membership
16
17 import (
18 "crypto/sha1"
19 "encoding/binary"
20 "fmt"
21 "math/rand"
22 "sort"
23 "strings"
24 "time"
25
26 "go.etcd.io/etcd/client/pkg/v3/types"
27 )
28
29
30 type RaftAttributes struct {
31
32
33 PeerURLs []string `json:"peerURLs"`
34
35 IsLearner bool `json:"isLearner,omitempty"`
36 }
37
38
39 type Attributes struct {
40 Name string `json:"name,omitempty"`
41 ClientURLs []string `json:"clientURLs,omitempty"`
42 }
43
44 type Member struct {
45 ID types.ID `json:"id"`
46 RaftAttributes
47 Attributes
48 }
49
50
51
52 func NewMember(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
53 memberId := computeMemberId(peerURLs, clusterName, now)
54 return newMember(name, peerURLs, memberId, false)
55 }
56
57
58
59 func NewMemberAsLearner(name string, peerURLs types.URLs, clusterName string, now *time.Time) *Member {
60 memberId := computeMemberId(peerURLs, clusterName, now)
61 return newMember(name, peerURLs, memberId, true)
62 }
63
64 func computeMemberId(peerURLs types.URLs, clusterName string, now *time.Time) types.ID {
65 peerURLstrs := peerURLs.StringSlice()
66 sort.Strings(peerURLstrs)
67 joinedPeerUrls := strings.Join(peerURLstrs, "")
68 b := []byte(joinedPeerUrls)
69
70 b = append(b, []byte(clusterName)...)
71 if now != nil {
72 b = append(b, []byte(fmt.Sprintf("%d", now.Unix()))...)
73 }
74
75 hash := sha1.Sum(b)
76 return types.ID(binary.BigEndian.Uint64(hash[:8]))
77 }
78
79 func newMember(name string, peerURLs types.URLs, memberId types.ID, isLearner bool) *Member {
80 m := &Member{
81 RaftAttributes: RaftAttributes{
82 PeerURLs: peerURLs.StringSlice(),
83 IsLearner: isLearner,
84 },
85 Attributes: Attributes{Name: name},
86 ID: memberId,
87 }
88 return m
89 }
90
91
92
93 func (m *Member) PickPeerURL() string {
94 if len(m.PeerURLs) == 0 {
95 panic("member should always have some peer url")
96 }
97 return m.PeerURLs[rand.Intn(len(m.PeerURLs))]
98 }
99
100 func (m *Member) Clone() *Member {
101 if m == nil {
102 return nil
103 }
104 mm := &Member{
105 ID: m.ID,
106 RaftAttributes: RaftAttributes{
107 IsLearner: m.IsLearner,
108 },
109 Attributes: Attributes{
110 Name: m.Name,
111 },
112 }
113 if m.PeerURLs != nil {
114 mm.PeerURLs = make([]string, len(m.PeerURLs))
115 copy(mm.PeerURLs, m.PeerURLs)
116 }
117 if m.ClientURLs != nil {
118 mm.ClientURLs = make([]string, len(m.ClientURLs))
119 copy(mm.ClientURLs, m.ClientURLs)
120 }
121 return mm
122 }
123
124 func (m *Member) IsStarted() bool {
125 return len(m.Name) != 0
126 }
127
128
129 type MembersByID []*Member
130
131 func (ms MembersByID) Len() int { return len(ms) }
132 func (ms MembersByID) Less(i, j int) bool { return ms[i].ID < ms[j].ID }
133 func (ms MembersByID) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
134
135
136 type MembersByPeerURLs []*Member
137
138 func (ms MembersByPeerURLs) Len() int { return len(ms) }
139 func (ms MembersByPeerURLs) Less(i, j int) bool {
140 return ms[i].PeerURLs[0] < ms[j].PeerURLs[0]
141 }
142 func (ms MembersByPeerURLs) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
143
View as plain text