consistent_hashr 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/consistent_hashr.rb +6 -14
- data/spec/consistent_hashr_spec.rb +26 -4
- metadata +2 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
data/lib/consistent_hashr.rb
CHANGED
@@ -1,26 +1,18 @@
|
|
1
1
|
require 'zlib'
|
2
|
+
module ConsistentHashr
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
##
|
6
|
-
# Creates a new Hasher. Servers should be a hash.
|
7
|
-
def initialize(_servers = {}, _number_of_replicas = 50)
|
8
|
-
@circle = {}
|
9
|
-
@number_of_replicas = _number_of_replicas
|
10
|
-
_servers.each do |name, server|
|
11
|
-
add_server(name, server)
|
12
|
-
end
|
13
|
-
end
|
4
|
+
@circle = {}
|
5
|
+
@number_of_replicas = 20
|
14
6
|
|
15
7
|
##
|
16
8
|
# Computes a key
|
17
|
-
def hash_key(key)
|
9
|
+
def self.hash_key(key)
|
18
10
|
Zlib.crc32("#{key}")
|
19
11
|
end
|
20
12
|
|
21
13
|
##
|
22
14
|
# Adds a server to the circle
|
23
|
-
def add_server(_name, _server)
|
15
|
+
def self.add_server(_name, _server)
|
24
16
|
@number_of_replicas.times do |t|
|
25
17
|
@circle[hash_key("#{_name}+#{t}")] = _server
|
26
18
|
end
|
@@ -28,7 +20,7 @@ class ConsistentHashr
|
|
28
20
|
|
29
21
|
##
|
30
22
|
# Returns the server for the provided key
|
31
|
-
def get(key)
|
23
|
+
def self.get(key)
|
32
24
|
return nil if @circle.empty?
|
33
25
|
return @circle.first.last if @circle.size == 1
|
34
26
|
|
@@ -3,7 +3,9 @@ require File.dirname(__FILE__) + "/spec_helper"
|
|
3
3
|
describe ConsistentHashr do
|
4
4
|
before(:each) do
|
5
5
|
@servers = {:s1 => "s1", :s2 => "s2", :s3 => "s3", :s4 => "s4", :s5 => "s5", :s6 => "s6"}
|
6
|
-
@
|
6
|
+
@servers.each do |n, s|
|
7
|
+
ConsistentHashr.add_server(n,s)
|
8
|
+
end
|
7
9
|
end
|
8
10
|
|
9
11
|
it "should not change more than 75% of keys" do
|
@@ -11,14 +13,34 @@ describe ConsistentHashr do
|
|
11
13
|
1000.times do |idx|
|
12
14
|
keys << rand(100000).to_s
|
13
15
|
end
|
14
|
-
before = keys.map() { |k|
|
16
|
+
before = keys.map() { |k| ConsistentHashr.get(k)}
|
15
17
|
|
16
|
-
|
18
|
+
ConsistentHashr.add_server(:s7, "s7")
|
17
19
|
|
18
|
-
after = keys.map() { |k|
|
20
|
+
after = keys.map() { |k| ConsistentHashr.get(k)}
|
19
21
|
|
20
22
|
diff = before.zip(after).find_all {|a| a[0] == a[1] }.size
|
21
23
|
diff.should > keys.size*0.7
|
22
24
|
end
|
23
25
|
|
26
|
+
it "should distribute keys evenly accross servers" do
|
27
|
+
keys = []
|
28
|
+
10000.times do |idx|
|
29
|
+
keys << rand(100000).to_s
|
30
|
+
end
|
31
|
+
servers = keys.map() { |k| ConsistentHashr.get(k)}
|
32
|
+
|
33
|
+
count_by_server = {}
|
34
|
+
servers.each do |s|
|
35
|
+
count_by_server[s] ||= 0
|
36
|
+
count_by_server[s] += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
min = count_by_server.invert.sort.first.first
|
40
|
+
max = count_by_server.invert.sort.last.first
|
41
|
+
|
42
|
+
max.should < min * 2
|
43
|
+
|
44
|
+
end
|
45
|
+
|
24
46
|
end
|