sumbur 0.0.2 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/sumbur/sumbur.c +44 -13
- data/lib/sumbur/pure_ruby.rb +1 -1
- data/lib/sumbur/version.rb +1 -1
- data/test/test_sumbur.rb +31 -12
- metadata +4 -5
data/ext/sumbur/sumbur.c
CHANGED
@@ -1,6 +1,22 @@
|
|
1
1
|
#include "ruby.h"
|
2
2
|
|
3
3
|
#define L 0xFFFFFFFF
|
4
|
+
|
5
|
+
static unsigned int L27_38[] = {L / 27, L / 28, L / 29, L / 30, L / 31, L / 32,
|
6
|
+
L / 33, L / 34, L / 35, L / 36, L / 37, L / 38,
|
7
|
+
L / 39, L / 40, L / 41, L / 42, L / 43, L / 44,
|
8
|
+
L / 45, L / 46, L / 47, L / 48, L / 49, L / 50,
|
9
|
+
L / 51, L / 52, L / 53, L / 54, L / 55, L / 56,
|
10
|
+
L / 57, L / 58, L / 59, L / 60, L / 61, L / 62
|
11
|
+
};
|
12
|
+
static unsigned int LL27_38[] = {L/(26*27), L/(27*28), L/(28*29), L/(29*30), L/(30*31), L/(31*32),
|
13
|
+
L/(32*33), L/(33*34), L/(34*35), L/(35*36), L/(36*37), L/(37*38),
|
14
|
+
L/(38*39), L/(39*40), L/(40*41), L/(41*42), L/(42*43), L/(43*44),
|
15
|
+
L/(44*45), L/(45*46), L/(46*47), L/(47*48), L/(48*49), L/(49*50),
|
16
|
+
L/(50*51), L/(51*52), L/(52*53), L/(53*54), L/(54*55), L/(55*56),
|
17
|
+
L/(56*57), L/(57*58), L/(58*59), L/(59*60), L/(60*61), L/(61*62)
|
18
|
+
};
|
19
|
+
|
4
20
|
static VALUE
|
5
21
|
rb_sumbur(VALUE self, VALUE hashed_int, VALUE capacity)
|
6
22
|
{
|
@@ -8,13 +24,13 @@ rb_sumbur(VALUE self, VALUE hashed_int, VALUE capacity)
|
|
8
24
|
unsigned int capa = NUM2UINT(capacity);
|
9
25
|
unsigned int part, n, i, c;
|
10
26
|
|
11
|
-
if (
|
27
|
+
if (capa == 0) {
|
12
28
|
rb_raise(rb_eArgError, "Sumbur is not applicable to empty cluster");
|
13
29
|
}
|
14
30
|
|
15
31
|
part = L / capa;
|
16
32
|
|
17
|
-
if (L - h
|
33
|
+
if (L - h < part) return INT2FIX(0);
|
18
34
|
|
19
35
|
n = 1;
|
20
36
|
|
@@ -22,9 +38,9 @@ rb_sumbur(VALUE self, VALUE hashed_int, VALUE capacity)
|
|
22
38
|
if (h >= L / 2) h -= L / 2;
|
23
39
|
else {
|
24
40
|
n = 2;
|
25
|
-
if (L / 2 - h < part)
|
41
|
+
if (L / 2 - h < part) return INT2FIX(1);
|
26
42
|
}
|
27
|
-
if (capa == 2)
|
43
|
+
if (capa == 2) return INT2FIX(1);
|
28
44
|
|
29
45
|
#define curslice(i) (L / (i * (i - 1)))
|
30
46
|
#define unroll(i) \
|
@@ -32,17 +48,32 @@ rb_sumbur(VALUE self, VALUE hashed_int, VALUE capacity)
|
|
32
48
|
else { \
|
33
49
|
h += curslice(i) * (i - n - 1); \
|
34
50
|
n = i; \
|
35
|
-
if (L / i - h < part)
|
51
|
+
if (L / i - h < part) return INT2FIX(n-1); \
|
36
52
|
} \
|
37
|
-
if (capa == i)
|
53
|
+
if (capa == i) return INT2FIX(n-1)
|
54
|
+
|
55
|
+
unroll(3); unroll(4); unroll(5);
|
56
|
+
unroll(6); unroll(7); unroll(8);
|
57
|
+
unroll(9); unroll(10); unroll(11);
|
58
|
+
unroll(12); unroll(13); unroll(14);
|
59
|
+
unroll(15); unroll(16); unroll(17);
|
60
|
+
unroll(18); unroll(19); unroll(20);
|
61
|
+
unroll(21); unroll(22); unroll(23);
|
62
|
+
unroll(24); unroll(25); unroll(26);
|
38
63
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
64
|
+
for (i = 27; i <= capa && i <= 62; i++) {
|
65
|
+
c = LL27_38[i-27];
|
66
|
+
if (c <= h) {
|
67
|
+
h -= c;
|
68
|
+
}
|
69
|
+
else {
|
70
|
+
h += c * (i - n - 1);
|
71
|
+
n = i;
|
72
|
+
if (L27_38[i-27] - h < part) return INT2FIX(n-1);
|
73
|
+
}
|
74
|
+
}
|
44
75
|
|
45
|
-
for(i =
|
76
|
+
for(i = 63; i <= capa; i++) {
|
46
77
|
c = L / (i * (i - 1));
|
47
78
|
if (c <= h) {
|
48
79
|
h -= c;
|
@@ -50,7 +81,7 @@ rb_sumbur(VALUE self, VALUE hashed_int, VALUE capacity)
|
|
50
81
|
else {
|
51
82
|
h += c * (i - n - 1);
|
52
83
|
n = i;
|
53
|
-
if (L / i - h < part)
|
84
|
+
if (L / i - h < part) return INT2FIX(n - 1);
|
54
85
|
}
|
55
86
|
}
|
56
87
|
} while(0);
|
data/lib/sumbur/pure_ruby.rb
CHANGED
data/lib/sumbur/version.rb
CHANGED
data/test/test_sumbur.rb
CHANGED
@@ -3,11 +3,18 @@ require 'minitest/autorun'
|
|
3
3
|
|
4
4
|
$spread_cache = {}
|
5
5
|
|
6
|
-
HASHED = (1..1_000_000).map{|i|
|
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
|
+
}
|
7
13
|
|
8
14
|
def spread(num, capa, sumbur)
|
9
15
|
start = Time.now
|
10
|
-
v = $spread_cache[ [num, capa, sumbur] ] ||=
|
16
|
+
#v = $spread_cache[ [num, capa, sumbur] ] ||=
|
17
|
+
v = HASHED[0, num].
|
11
18
|
map{|hash, int| [sumbur.sumbur(hash, capa), int]}.
|
12
19
|
group_by{|serv, int| serv}
|
13
20
|
d = Time.now - start
|
@@ -17,17 +24,17 @@ end
|
|
17
24
|
|
18
25
|
shared_example = proc do
|
19
26
|
it "should spread capacity" do
|
20
|
-
for num in [100_000, 1_000_000]
|
27
|
+
for num, eps in [[100_000, 0.05], [1_000_000, 0.011]]
|
21
28
|
for capa in [2,3,7,8,17,18]
|
22
29
|
spread(num, capa, sumbur).each{|serv, ints|
|
23
|
-
ints.size.must_be_within_epsilon num/capa,
|
30
|
+
ints.size.must_be_within_epsilon num/capa, eps
|
24
31
|
}
|
25
32
|
end
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
29
36
|
it "should reshard values cleanly" do
|
30
|
-
for num in [100_000, 1_000_000]
|
37
|
+
for num, eps in [[100_000, 0.2], [1_000_000, 0.05]]
|
31
38
|
for capa in [2,3,7,8,17,18]
|
32
39
|
cur = spread(num, capa, sumbur)
|
33
40
|
nxt = spread(num, capa+1, sumbur)
|
@@ -35,9 +42,9 @@ shared_example = proc do
|
|
35
42
|
for i in 0...capa
|
36
43
|
(nxt[i] - cur[i]).must_be_empty
|
37
44
|
moved += mvd = (cur[i] - nxt[i]).size
|
38
|
-
mvd.must_be_within_epsilon (num/capa - num/(capa+1)),
|
45
|
+
mvd.must_be_within_epsilon (num/capa - num/(capa+1)), eps
|
39
46
|
end
|
40
|
-
moved.must_be_within_epsilon num/(capa+1),
|
47
|
+
moved.must_be_within_epsilon num/(capa+1), eps
|
41
48
|
end
|
42
49
|
end
|
43
50
|
end
|
@@ -45,20 +52,32 @@ end
|
|
45
52
|
|
46
53
|
require 'sumbur/pure_ruby'
|
47
54
|
describe "Pure Ruby" do
|
48
|
-
|
55
|
+
def sumbur
|
56
|
+
Sumbur::PureRuby
|
57
|
+
end
|
49
58
|
class_exec &shared_example
|
50
59
|
end
|
51
60
|
|
52
61
|
begin
|
53
|
-
|
62
|
+
if RUBY_ENGINE == 'jruby'
|
63
|
+
require 'sumbur/sumbur.jar'
|
64
|
+
else
|
65
|
+
require 'sumbur/native_sumbur'
|
66
|
+
end
|
54
67
|
|
55
68
|
describe "Native" do
|
56
|
-
|
69
|
+
def sumbur
|
70
|
+
if RUBY_ENGINE == 'jruby'
|
71
|
+
Sumbur::Java
|
72
|
+
else
|
73
|
+
Sumbur::NativeSumbur
|
74
|
+
end
|
75
|
+
end
|
57
76
|
class_exec &shared_example
|
58
77
|
|
59
78
|
it "should produce same spread as pure ruby version" do
|
60
|
-
for capa in [2,3,4,7,8,9,17,18,19]
|
61
|
-
spread(1_000_000, capa,
|
79
|
+
for capa in [2,3,4,7,8,9,17,18,19,100]
|
80
|
+
spread(1_000_000, capa, sumbur).must_equal spread(1_000_000, capa, Sumbur::PureRuby)
|
62
81
|
end
|
63
82
|
end
|
64
83
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sumbur
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,9 +10,9 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-08-
|
13
|
+
date: 2012-08-10 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
|
-
description: Sumbur - consistent spreading
|
15
|
+
description: Sumbur - consistent spreading for server balancing
|
16
16
|
email:
|
17
17
|
- funny.falcon@gmail.com
|
18
18
|
- uint32@mail.ru
|
@@ -51,7 +51,6 @@ rubyforge_project:
|
|
51
51
|
rubygems_version: 1.8.24
|
52
52
|
signing_key:
|
53
53
|
specification_version: 3
|
54
|
-
summary: Sumbur - consistent spreading
|
54
|
+
summary: Sumbur - consistent spreading for server balancing
|
55
55
|
test_files:
|
56
56
|
- test/test_sumbur.rb
|
57
|
-
has_rdoc:
|