@@ -26,20 +26,69 @@ import (
26
26
27
27
type Hash func (data []byte ) uint32
28
28
29
+ const defaultHashExpansion = 6
30
+
29
31
type Map struct {
32
+ // Inputs
33
+
34
+ // hash is the hash function that will be applied to both added
35
+ // keys and fetched keys
30
36
hash Hash
37
+
38
+ // replicas is the number of virtual nodes that will be inserted
39
+ // into the consistent hash ring for each key added
31
40
replicas int
41
+
42
+ // prefixTableExpansion is the multiple of virtual nodes that
43
+ // will be inserted into the internal hash table for O(1) lookups.
32
44
prefixTableExpansion int
33
45
46
+
47
+
48
+ // Internal data
49
+
50
+ // keys is the hash of the virtual nodes, sorted by hash value
34
51
keys []int // Sorted
52
+
53
+ // hashMap maps the hashed keys back to the input strings.
54
+ // Note that all virtual nodes will map back to the same input
55
+ // string
35
56
hashMap map [int ]string
36
57
37
- prefixBits uint32
58
+ // prefixShift is the number of bits an input hash should
59
+ // be right-shifted to act as a lookup in the prefixTable
38
60
prefixShift uint32
61
+
62
+ // prefixTable is a map of the most significant bits of
63
+ // a hash value to output all hashes with that prefix
64
+ // map to. If the result is ambiguous (i.e. there is a
65
+ // hash range split within this prefix) the value will
66
+ // be blank and we should fall back to a binary search
67
+ // through keys to find the exact output
39
68
prefixTable []string
40
69
}
41
70
42
- func New (replicas int , tableExpansion int , fn Hash ) * Map {
71
+ // New returns a blank consistent hash ring that will return
72
+ // the key whos hash comes next after the hash of the input to
73
+ // Get().
74
+ // Increasing the number of replicas will improve the smoothness
75
+ // of the hash ring and reduce the data moved when adding/removing
76
+ // nodes, at the cost of more memory.
77
+ func New (replicas int , fn Hash ) * Map {
78
+ return NewConsistentHash (replicas , defaultHashExpansion , fn )
79
+ }
80
+
81
+
82
+ // NewConsistentHash returns a blank consistent hash ring that will return
83
+ // the key whos hash comes next after the hash of the input to
84
+ // Get().
85
+ // Increasing the number of replicas will improve the smoothness
86
+ // of the hash ring and reduce the data moved when adding/removing
87
+ // nodes.
88
+ // Increasing the tableExpansion will allocate more entries in the
89
+ // internal hash table, reducing the frequency of lg(n) binary
90
+ // searches during Get() calls.
91
+ func NewConsistentHash (replicas int , tableExpansion int , fn Hash ) * Map {
43
92
m := & Map {
44
93
replicas : replicas ,
45
94
hash : fn ,
@@ -69,10 +118,10 @@ func (m *Map) Add(keys ...string) {
69
118
sort .Ints (m .keys )
70
119
71
120
// Find minimum number of bits to hold |keys| * prefixTableExpansion
72
- m . prefixBits = uint32 (bits .Len32 (uint32 (len (m .keys ) * m .prefixTableExpansion )))
73
- m .prefixShift = 32 - m . prefixBits
121
+ prefixBits : = uint32 (bits .Len32 (uint32 (len (m .keys ) * m .prefixTableExpansion )))
122
+ m .prefixShift = 32 - prefixBits
74
123
75
- prefixTableSize := 1 << m . prefixBits
124
+ prefixTableSize := 1 << prefixBits
76
125
m .prefixTable = make ([]string , prefixTableSize )
77
126
78
127
previousKeyPrefix := - 1 // Effectively -Inf
0 commit comments