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.
@@ -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 (capacity == 0) {
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 <= part) return INT2FIX(0);
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) break;
41
+ if (L / 2 - h < part) return INT2FIX(1);
26
42
  }
27
- if (capa == 2) break;
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) break; \
51
+ if (L / i - h < part) return INT2FIX(n-1); \
36
52
  } \
37
- if (capa == i) break
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
- unroll(3); unroll(4); unroll(5); unroll(6); unroll(7);
40
- unroll(8); unroll(9); unroll(10); unroll(11); unroll(12);
41
- unroll(13); unroll(14); unroll(15); unroll(16); unroll(17);
42
- unroll(18); unroll(19); unroll(20); unroll(21); unroll(22);
43
- unroll(23); unroll(24);
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 = 25; i <= capa; 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) break;
84
+ if (L / i - h < part) return INT2FIX(n - 1);
54
85
  }
55
86
  }
56
87
  } while(0);
@@ -9,7 +9,7 @@ module Sumbur
9
9
  l = 0xFFFFFFFF
10
10
  part = l / cluster_capacity
11
11
 
12
- return 0 if l - hashed_integer <= part
12
+ return 0 if l - hashed_integer < part
13
13
 
14
14
  h = hashed_integer
15
15
  n = 1
@@ -1,3 +1,3 @@
1
1
  module Sumbur
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -3,11 +3,18 @@ require 'minitest/autorun'
3
3
 
4
4
  $spread_cache = {}
5
5
 
6
- HASHED = (1..1_000_000).map{|i| [i.hash & 0xFFFFFFFF, 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] ] ||= HASHED[0, num].
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, 7000.0/num
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)), 40000.0/num
45
+ mvd.must_be_within_epsilon (num/capa - num/(capa+1)), eps
39
46
  end
40
- moved.must_be_within_epsilon num/(capa+1), 7000.0/num
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
- let(:sumbur){ Sumbur::PureRuby }
55
+ def sumbur
56
+ Sumbur::PureRuby
57
+ end
49
58
  class_exec &shared_example
50
59
  end
51
60
 
52
61
  begin
53
- require 'sumbur/native_sumbur'
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
- let(:sumbur) { Sumbur::NativeSumbur }
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, Sumbur::NativeSumbur).must_equal spread(1_000_000, capa, Sumbur::PureRuby)
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.0.2
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-03 00:00:00.000000000 Z
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: