/
consistent.go
112 lines (94 loc) · 1.99 KB
/
consistent.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
//一致性哈希
package hash
import (
"fmt"
"hash/crc32"
"sort"
"sync"
)
const VirtualNodesFactor = 256
type node struct {
key string
Data interface{}
weight uint
}
type ConsistentHash struct {
sync.RWMutex
virtualNodes map[uint32]*node
actNodes map[string]*node
sortRing []uint32
}
func NewConsistentHash() *ConsistentHash {
return &ConsistentHash{
virtualNodes: make(map[uint32]*node),
actNodes: make(map[string]*node),
sortRing: []uint32{},
}
}
func (c *ConsistentHash) Add(nk string, nd interface{}, nw uint) bool {
c.Lock()
defer c.Unlock()
if _, ok := c.actNodes[nk]; ok {
return false
}
n := &node{
key: nk,
Data: nd,
weight: nw,
}
count := int(VirtualNodesFactor * nw)
for i := 0; i < count; i++ {
c.virtualNodes[c.hashStr(fmt.Sprintf("%s#%d", nk, i))] = n
}
c.actNodes[nk] = n
c.sortHashRing()
return true
}
func (c *ConsistentHash) Remove(key string) {
c.Lock()
defer c.Unlock()
node, ok := c.actNodes[key]
if !ok {
return
}
delete(c.actNodes, key)
count := int(VirtualNodesFactor * node.weight)
for i := 0; i < count; i++ {
delete(c.virtualNodes, c.hashStr(fmt.Sprintf("%s#%d", key, i)))
}
c.sortHashRing()
}
func (c *ConsistentHash) sortHashRing() {
c.sortRing = []uint32{}
for k := range c.virtualNodes {
c.sortRing = append(c.sortRing, k)
}
sort.Slice(c.sortRing, func(i, j int) bool {
return c.sortRing[i] < c.sortRing[j]
})
}
func (c *ConsistentHash) Get(key string) *node {
hash := c.hashStr(key)
c.RLock()
defer c.RUnlock()
if len(c.virtualNodes) == 0 {
return nil
}
i := c.search(hash)
return c.virtualNodes[c.sortRing[i]]
}
func (c *ConsistentHash) hashStr(key string) uint32 {
return crc32.ChecksumIEEE([]byte(key))
}
func (c *ConsistentHash) search(hash uint32) int {
i := sort.Search(len(c.sortRing), func(i int) bool { return c.sortRing[i] >= hash })
if i < len(c.sortRing) {
if i == len(c.sortRing)-1 {
return 0
} else {
return i
}
} else {
return len(c.sortRing) - 1
}
}