-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhashring.go
78 lines (69 loc) · 1.9 KB
/
hashring.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
package hashring
import (
"crypto/md5"
"encoding/binary"
"fmt"
"slices"
)
func New(nodes []string, replicas int) HashRing {
nodeHashToAddrs := make(map[uint32]string)
nodeHashes := make([]uint32, len(nodes)*replicas)
count := 0
for _, nodeAddr := range nodes {
for replica := range replicas {
virtualNodeHash := generateKeyHash(fmt.Sprintf("%s-%d", nodeAddr, replica))
nodeHashToAddrs[virtualNodeHash] = nodeAddr
nodeHashes[count] = virtualNodeHash
count++
}
}
slices.Sort(nodeHashes)
return HashRing{
NodeAddrs: nodes,
Replicas: replicas,
NodeHashToAddr: nodeHashToAddrs,
NodesHashList: nodeHashes,
}
}
func (hr *HashRing) AddNode(node string) {
hr.NodeAddrs = append(hr.NodeAddrs, node)
for i := range hr.Replicas {
nodeHash := generateKeyHash(fmt.Sprintf("%s-%d", node, i))
hr.NodeHashToAddr[nodeHash] = node
hr.NodesHashList = append(hr.NodesHashList, nodeHash)
}
slices.Sort(hr.NodesHashList)
}
func (hr *HashRing) RemoveNode(node string) {
for i := range hr.Replicas {
nodeHash := generateKeyHash(fmt.Sprintf("%s-%d", node, i))
hr.NodesHashList = slices.DeleteFunc(hr.NodesHashList, func(hash uint32) bool { return hash == nodeHash })
delete(hr.NodeHashToAddr, nodeHash)
}
}
func (hr HashRing) findNextBiggestHash(lookupValue uint32) uint32 {
n, found := slices.BinarySearch(hr.NodesHashList, lookupValue)
if found {
n++
}
if n > len(hr.NodesHashList)-1 {
return hr.NodesHashList[0]
}
return hr.NodesHashList[n]
}
func (hr HashRing) GetNodeForKey(key string) string {
keyHash := generateKeyHash(key)
nodeHash := hr.findNextBiggestHash(keyHash)
return hr.NodeHashToAddr[nodeHash]
}
func generateKeyHash(key string) uint32 {
hash := md5.Sum([]byte(key))
hashNumber := binary.LittleEndian.Uint32(hash[:])
return hashNumber
}
type HashRing struct {
NodeAddrs []string
Replicas int
NodeHashToAddr map[uint32]string
NodesHashList []uint32
}