sumbur 0.0.2 → 0.1.2
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/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:
|