-
Notifications
You must be signed in to change notification settings - Fork 17
/
ketama.go
70 lines (57 loc) · 1.52 KB
/
ketama.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
package ketama
import (
"crypto/sha1"
"sort"
"strconv"
)
type node struct {
node string
hash uint
}
type tickArray []node
func (p tickArray) Len() int { return len(p) }
func (p tickArray) Less(i, j int) bool { return p[i].hash < p[j].hash }
func (p tickArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p tickArray) Sort() { sort.Sort(p) }
type hashRing struct {
defaultSpots int
ticks tickArray
length int
}
func NewRing(n int) (h *hashRing) {
h = new(hashRing)
h.defaultSpots = n
return
}
// Adds a new node to a hash ring
// n: name of the server
// s: multiplier for default number of ticks (useful when one cache node has more resources, like RAM, than another)
func (h *hashRing) AddNode(n string, s int) {
tSpots := h.defaultSpots * s
hash := sha1.New()
for i := 1; i <= tSpots; i++ {
hash.Write([]byte(n + ":" + strconv.Itoa(i)))
hashBytes := hash.Sum(nil)
n := &node{
node: n,
hash: uint(hashBytes[19]) | uint(hashBytes[18])<<8 | uint(hashBytes[17])<<16 | uint(hashBytes[16])<<24,
}
h.ticks = append(h.ticks, *n)
hash.Reset()
}
}
func (h *hashRing) Bake() {
h.ticks.Sort()
h.length = len(h.ticks)
}
func (h *hashRing) Hash(s string) string {
hash := sha1.New()
hash.Write([]byte(s))
hashBytes := hash.Sum(nil)
v := uint(hashBytes[19]) | uint(hashBytes[18])<<8 | uint(hashBytes[17])<<16 | uint(hashBytes[16])<<24
i := sort.Search(h.length, func(i int) bool { return h.ticks[i].hash >= v })
if i == h.length {
i = 0
}
return h.ticks[i].node
}