sumbur 0.1.0-jruby
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/sumbur.rb +13 -0
- data/lib/sumbur/pure_ruby.rb +31 -0
- data/lib/sumbur/sumbur.jar +0 -0
- data/lib/sumbur/version.rb +3 -0
- data/test/test_sumbur.rb +86 -0
- metadata +61 -0
data/lib/sumbur.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sumbur
|
2
|
+
module PureRuby
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def sumbur(hashed_integer, cluster_capacity)
|
6
|
+
raise ArgumentError, "Sumbur is not applicable to empty cluster" if cluster_capacity == 0
|
7
|
+
raise ArgumentError, "Sumbur accepts only positive 32bit integers" if hashed_integer < 0 || hashed_integer > 0xFFFFFFFF
|
8
|
+
|
9
|
+
l = 0xFFFFFFFF
|
10
|
+
part = l / cluster_capacity
|
11
|
+
|
12
|
+
return 0 if l - hashed_integer < part
|
13
|
+
|
14
|
+
h = hashed_integer
|
15
|
+
n = 1
|
16
|
+
i = 2
|
17
|
+
while i <= cluster_capacity
|
18
|
+
c = l / (i * (i-1))
|
19
|
+
if c <= h
|
20
|
+
h -= c
|
21
|
+
else
|
22
|
+
h += c * (i-n-1)
|
23
|
+
n = i
|
24
|
+
break if l / n - h < part
|
25
|
+
end
|
26
|
+
i += 1
|
27
|
+
end
|
28
|
+
n - 1
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
Binary file
|
data/test/test_sumbur.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
$spread_cache = {}
|
5
|
+
|
6
|
+
HASHED = (1..1_000_000).map{|i|
|
7
|
+
h = i ^ (i >> 16)
|
8
|
+
h = (h * 0x85ebca6b) & 0xFFffFFff
|
9
|
+
h ^= h >> 13
|
10
|
+
h = (h * 0xc2b2ae35) & 0xFFffFFff
|
11
|
+
[h ^ (h >> 16), i]
|
12
|
+
}
|
13
|
+
|
14
|
+
def spread(num, capa, sumbur)
|
15
|
+
start = Time.now
|
16
|
+
#v = $spread_cache[ [num, capa, sumbur] ] ||=
|
17
|
+
v = HASHED[0, num].
|
18
|
+
map{|hash, int| [sumbur.sumbur(hash, capa), int]}.
|
19
|
+
group_by{|serv, int| serv}
|
20
|
+
d = Time.now - start
|
21
|
+
puts format("%s %.4f", [num, capa, sumbur].inspect, d) if d > 0.01
|
22
|
+
v
|
23
|
+
end
|
24
|
+
|
25
|
+
shared_example = proc do
|
26
|
+
it "should spread capacity" do
|
27
|
+
for num, eps in [[100_000, 0.05], [1_000_000, 0.011]]
|
28
|
+
for capa in [2,3,7,8,17,18]
|
29
|
+
spread(num, capa, sumbur).each{|serv, ints|
|
30
|
+
ints.size.must_be_within_epsilon num/capa, eps
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should reshard values cleanly" do
|
37
|
+
for num in [100_000, 1_000_000]
|
38
|
+
for capa in [2,3,7,8,17,18]
|
39
|
+
cur = spread(num, capa, sumbur)
|
40
|
+
nxt = spread(num, capa+1, sumbur)
|
41
|
+
moved = 0
|
42
|
+
for i in 0...capa
|
43
|
+
(nxt[i] - cur[i]).must_be_empty
|
44
|
+
moved += mvd = (cur[i] - nxt[i]).size
|
45
|
+
mvd.must_be_within_epsilon (num/capa - num/(capa+1)), 40000.0/num
|
46
|
+
end
|
47
|
+
moved.must_be_within_epsilon num/(capa+1), 7000.0/num
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'sumbur/pure_ruby'
|
54
|
+
describe "Pure Ruby" do
|
55
|
+
def sumbur
|
56
|
+
Sumbur::PureRuby
|
57
|
+
end
|
58
|
+
class_exec &shared_example
|
59
|
+
end if false
|
60
|
+
|
61
|
+
begin
|
62
|
+
if RUBY_ENGINE == 'jruby'
|
63
|
+
require 'sumbur/sumbur.jar'
|
64
|
+
else
|
65
|
+
require 'sumbur/native_sumbur'
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "Native" do
|
69
|
+
def sumbur
|
70
|
+
if RUBY_ENGINE == 'jruby'
|
71
|
+
Sumbur::Java
|
72
|
+
else
|
73
|
+
Sumbur::NativeSumbur
|
74
|
+
end
|
75
|
+
end
|
76
|
+
class_exec &shared_example
|
77
|
+
|
78
|
+
it "should produce same spread as pure ruby version" do
|
79
|
+
for capa in [2,3,4,7,8,9,17,18,19]
|
80
|
+
spread(1_000_000, capa, sumbur).must_equal spread(1_000_000, capa, Sumbur::PureRuby)
|
81
|
+
end
|
82
|
+
end if false
|
83
|
+
end
|
84
|
+
rescue LoadError
|
85
|
+
puts "Native version is not tested"
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sumbur
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: jruby
|
7
|
+
authors:
|
8
|
+
- Sokolov Yura 'funny-falcon'
|
9
|
+
- Maksim Kalinchenko
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2012-08-10 00:00:00 Z
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: Sumbur - consistent spreading for server balancing
|
18
|
+
email:
|
19
|
+
- funny.falcon@gmail.com
|
20
|
+
- uint32@mail.ru
|
21
|
+
executables: []
|
22
|
+
|
23
|
+
extensions: []
|
24
|
+
|
25
|
+
extra_rdoc_files: []
|
26
|
+
|
27
|
+
files:
|
28
|
+
- lib/sumbur.rb
|
29
|
+
- lib/sumbur/pure_ruby.rb
|
30
|
+
- lib/sumbur/sumbur.jar
|
31
|
+
- lib/sumbur/version.rb
|
32
|
+
- test/test_sumbur.rb
|
33
|
+
homepage: https://github.com/mailru/sumbur-ruby
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.8.15
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Sumbur - consistent spreading for server balancing
|
60
|
+
test_files:
|
61
|
+
- test/test_sumbur.rb
|