redis_ring 0.0.2 → 0.1.0

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.
@@ -0,0 +1,174 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Master do
4
+
5
+ describe :is_master do
6
+ before(:each) do
7
+ @master = RedisRing::Master.new(nil, nil, nil)
8
+ end
9
+
10
+ it "should not be master initially" do
11
+ @master.is_master?.should be_false
12
+ end
13
+
14
+ it "should be master after became_master event" do
15
+ @master.became_master
16
+
17
+ @master.is_master?.should be_true
18
+ end
19
+
20
+ it "should not be master after no_longer_is_master" do
21
+ @master.became_master
22
+ @master.no_longer_is_master
23
+
24
+ @master.is_master?.should be_false
25
+ end
26
+ end
27
+
28
+ describe :reassign_shards do
29
+ before(:each) do
30
+ @builder = ClusterBuilder.new do |b|
31
+ b.node("node0").port(6401)
32
+ b.node("node1").port(6402)
33
+ b.node("node2").port(6403)
34
+ b.node("node3").port(6404)
35
+ b.node("node4").port(6405)
36
+ end
37
+
38
+ @started_shards = []
39
+ @stopped_shards = []
40
+ @shards_per_node = Hash.new(0)
41
+ @stopped_on_node = Hash.new(0)
42
+
43
+ @builder.on_start_shard do |node_id, shard_no|
44
+ @started_shards << shard_no
45
+ @shards_per_node[node_id] += 1
46
+ end
47
+
48
+ @builder.on_stop_shard do |node_id, shard_no|
49
+ @stopped_shards << shard_no
50
+ @stopped_on_node[node_id] += 1
51
+ end
52
+
53
+ @master = RedisRing::Master.new(@builder.fake_connection, 16, @builder.fake_provider)
54
+ @master.became_master
55
+ end
56
+
57
+ it "should assign shards fairly to all nodes" do
58
+ @master.nodes_changed(@builder.node_ids)
59
+
60
+ @started_shards.sort.should == (0...16).to_a
61
+ @shards_per_node.values.reduce(&:+).should == 16
62
+ @shards_per_node.values.uniq.sort.should == [3, 4]
63
+ end
64
+
65
+ it "should do nothing when is not a master" do
66
+ @master.no_longer_is_master
67
+
68
+ @master.nodes_changed(@builder.node_ids)
69
+
70
+ @started_shards.should be_empty
71
+ end
72
+
73
+ it "should not reassign anything when nothing has changed" do
74
+ @master.nodes_changed(@builder.node_ids)
75
+ @started_shards = []
76
+ @shards_per_node = Hash.new(0)
77
+
78
+ @master.nodes_changed(@builder.node_ids)
79
+
80
+ @started_shards.should be_empty
81
+ end
82
+
83
+ it "should ignore not joined nodes, without assigning their portion o shards elsewhere" do
84
+ @builder.node("node0").joined(false)
85
+
86
+ @master.nodes_changed(@builder.node_ids)
87
+
88
+ @started_shards.size.should == 12
89
+ @shards_per_node["node0"].should == 0
90
+ end
91
+
92
+ it "should assign shards to the freshly joined node" do
93
+ @builder.node("node0").joined(false)
94
+ @master.nodes_changed(@builder.node_ids)
95
+ @started_shards = []
96
+ @shards_per_node = Hash.new(0)
97
+ @builder.node("node0").joined(true)
98
+
99
+ @master.node_joined("node0")
100
+
101
+ @started_shards.size.should == 4
102
+ @shards_per_node["node0"].should == 4
103
+ end
104
+
105
+ it "should not over-asign nodes if they are already running some shards" do
106
+ @builder.node("node0").running_shards([0, 1, 2])
107
+ @builder.node("node1").running_shards([3, 4, 5, 6])
108
+
109
+ @master.nodes_changed(@builder.node_ids)
110
+
111
+ @started_shards.size.should == 16 - 7
112
+ ((0..6).to_a - @started_shards).should == (0..6).to_a
113
+ @shards_per_node["node0"].should == 1
114
+ @shards_per_node["node1"].should == 0
115
+ end
116
+
117
+ it "should reassign the shards that belonged to a node that crashed" do
118
+ @master.nodes_changed(@builder.node_ids)
119
+ @started_shards = []
120
+ @shards_per_node = Hash.new(0)
121
+ @builder.nodes.delete("node0")
122
+
123
+ @master.nodes_changed(@builder.node_ids)
124
+
125
+ @started_shards.size.should == 4
126
+ @shards_per_node.values.uniq.should == [1]
127
+ end
128
+
129
+ it "should stop shards that are running on more than one node" do
130
+ @builder.node("node0").running_shards([0, 1, 2])
131
+ @builder.node("node1").running_shards([0, 1])
132
+ @builder.node("node2").running_shards([0, 2])
133
+
134
+ @master.nodes_changed(@builder.node_ids)
135
+
136
+ @stopped_shards.uniq.sort.should == [0, 1, 2]
137
+ @stopped_shards.size.should == 4
138
+ ([0, 1, 2] - @started_shards).should == [0, 1, 2]
139
+ end
140
+
141
+ end
142
+
143
+ describe :status do
144
+ before(:each) do
145
+ @builder = ClusterBuilder.new do |b|
146
+ b.node("node0").host("a.example.com").port(6400)
147
+ b.node("node1").host("b.example.com").port(6400)
148
+ end
149
+
150
+ @master = RedisRing::Master.new(@builder.fake_connection, 8, @builder.fake_provider)
151
+ @master.became_master
152
+ @master.nodes_changed(@builder.node_ids)
153
+ end
154
+
155
+ it "should return the ring_size" do
156
+ @master.status[:ring_size].should == 8
157
+ end
158
+
159
+ it "should return the shards" do
160
+ @master.status[:shards].should == {
161
+ 0 => { :host => "a.example.com", :port => 6401, :status => :running },
162
+ 1 => { :host => "a.example.com", :port => 6402, :status => :running },
163
+ 2 => { :host => "a.example.com", :port => 6403, :status => :running },
164
+ 3 => { :host => "a.example.com", :port => 6404, :status => :running },
165
+ 4 => { :host => "b.example.com", :port => 6405, :status => :running },
166
+ 5 => { :host => "b.example.com", :port => 6406, :status => :running },
167
+ 6 => { :host => "b.example.com", :port => 6407, :status => :running },
168
+ 7 => { :host => "b.example.com", :port => 6408, :status => :running }
169
+ }
170
+ end
171
+
172
+ end
173
+
174
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Node do
4
+
5
+ before(:each) do
6
+ @node = RedisRing::Node.new(@slave_rpc = FakeSlaveRPC.new.connection("some_host", 666), "some_host", 666)
7
+
8
+ @slave_rpc.status = {
9
+ "joined" => true,
10
+ "running_shards" => [1, 2, 3],
11
+ "available_shards" => { "1" => 1233, "2" => 4566 }
12
+ }
13
+ end
14
+
15
+ it "should return some sane defults when calling without update_status!" do
16
+ @node.joined?.should be_false
17
+ @node.running_shards.should == []
18
+ @node.available_shards.should == {}
19
+ end
20
+
21
+ it "should only update the data when update_status! is called" do
22
+ @node.update_status!
23
+
24
+ @node.joined?.should be_true
25
+ @node.running_shards.should == [1, 2, 3]
26
+ @node.available_shards.should == {1 => 1233, 2 => 4566}
27
+ end
28
+
29
+ it "should reflect start_shard in running shards without calling update_status!" do
30
+ @node.start_shard(9)
31
+
32
+ @node.running_shards.should == [9]
33
+ end
34
+
35
+ it "should send rpc to slave on start_shard" do
36
+ @node.start_shard(9)
37
+
38
+ @slave_rpc.started_shards.should == [9]
39
+ end
40
+
41
+ it "should reflect stop_shard in running shards without calling update_status!" do
42
+ @node.update_status!
43
+ @node.stop_shard(3)
44
+
45
+ @node.running_shards.should == [1, 2]
46
+ end
47
+
48
+ it "should send rpc to slave on start_shard" do
49
+ @node.stop_shard(9)
50
+
51
+ @slave_rpc.stopped_shards.should == [9]
52
+ end
53
+ end
@@ -0,0 +1,46 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::SlaveRPC do
4
+
5
+ before(:each) do
6
+ @http_client = FakeHttpClient.new
7
+ @host = "example.com"
8
+ @port = 666
9
+ @rpc = RedisRing::SlaveRPC.new(@http_client).connection(@host, @port)
10
+ end
11
+
12
+ describe :join do
13
+ it "should post to joined url" do
14
+ @rpc.join
15
+
16
+ @http_client.sent_post?("http://example.com:666/slave/join").should be_true
17
+ end
18
+ end
19
+
20
+ describe :status do
21
+ it "should get and parse status" do
22
+ @http_client.set_response("http://example.com:666/slave/status", {"parsed" => "yes"}.to_json)
23
+ result = @rpc.status
24
+
25
+ @http_client.sent_get?("http://example.com:666/slave/status").should be_true
26
+ result.should == {"parsed" => "yes"}
27
+ end
28
+ end
29
+
30
+ describe :start_shard do
31
+ it "should get and parse status" do
32
+ @rpc.start_shard(1)
33
+
34
+ @http_client.sent_post?("http://example.com:666/slave/start_shard/1").should be_true
35
+ end
36
+ end
37
+
38
+ describe :stop_shard do
39
+ it "should get and parse status" do
40
+ @rpc.stop_shard(1)
41
+
42
+ @http_client.sent_post?("http://example.com:666/slave/stop_shard/1").should be_true
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,81 @@
1
+ require File.expand_path("../../spec_helper", __FILE__)
2
+
3
+ describe RedisRing::Slave do
4
+ before(:each) do
5
+ @slave = RedisRing::Slave.new(@configuration = RedisRing::Configuration.new,
6
+ @master_rpc = FakeMasterRPC.new,
7
+ @process_manager = FakeProcessManager.new)
8
+ @slave.node_id = "some-node"
9
+ @slave.current_master_host = "localhost"
10
+ @slave.current_master_port = 6400
11
+ end
12
+
13
+ it "should not be joined initially" do
14
+ @slave.should_not be_joined
15
+ end
16
+
17
+ it "should be joined after joining" do
18
+ @slave.join
19
+ @slave.should be_joined
20
+ end
21
+
22
+ it "should tell master to load this node on joining" do
23
+ @slave.join
24
+
25
+ @master_rpc.connection(@slave.current_master_host, @slave.current_master_port).nodes_loaded.should == [@slave.node_id]
26
+ end
27
+
28
+ it "should start shard when asked to" do
29
+ @slave.start_shard(0)
30
+
31
+ @process_manager.started_shards.map(&:shard_number).should == [0]
32
+ end
33
+
34
+ it "should not start shard if already started" do
35
+ @slave.start_shard(0)
36
+ @slave.start_shard(0)
37
+
38
+ @process_manager.started_shards.map(&:shard_number).should == [0]
39
+ end
40
+
41
+ it "should add shard to running when started" do
42
+ @slave.start_shard(0)
43
+ @slave.start_shard(2)
44
+ @slave.start_shard(4)
45
+
46
+ @slave.running_shards.keys.sort.should == [0, 2, 4]
47
+ end
48
+
49
+ it "should stop shard if it is running" do
50
+ @slave.start_shard(0)
51
+ @slave.stop_shard(0)
52
+
53
+ @process_manager.stopped_shards.map(&:shard_number).should == [0]
54
+ end
55
+
56
+ it "should do nothing if requested to stop a shard that is not running" do
57
+ @slave.stop_shard(0)
58
+
59
+ @process_manager.stopped_shards.should be_empty
60
+ end
61
+
62
+ it "it should remove stopped shard from running shards" do
63
+ @slave.start_shard(0)
64
+ @slave.start_shard(1)
65
+ @slave.stop_shard(0)
66
+
67
+ @slave.running_shards.keys.sort.should == [1]
68
+ end
69
+
70
+ it "should return status" do
71
+ 5.times { |n| @slave.start_shard(n) }
72
+ @slave.join
73
+
74
+ status = @slave.status
75
+
76
+ status[:joined].should be_true
77
+ status[:running_shards].should == (0..4).to_a
78
+ status.key?(:available_shards).should be_true
79
+ end
80
+
81
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,26 @@
1
- $:.push File.expand_path("../lib", __FILE__)
1
+ $:.push File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'mocha'
5
+
6
+ require 'simplecov'
7
+ SimpleCov.start
2
8
 
3
9
  require 'redis_ring'
4
10
 
11
+ def require_fake(name)
12
+ require File.expand_path("../fakes/fake_#{name}", __FILE__)
13
+ end
14
+
15
+ require_fake 'master_rpc'
16
+ require_fake 'slave_rpc'
17
+ require_fake 'process_manager'
18
+ require_fake 'zookeeper_connection'
19
+ require_fake 'node_provider'
20
+ require_fake 'http_client'
21
+
22
+ require File.expand_path('../cluster_builder', __FILE__)
23
+
5
24
  RSpec.configure do |c|
6
25
  c.color_enabled = true
7
26
  c.mock_with :mocha
data/spec/test.conf ADDED
@@ -0,0 +1,3 @@
1
+ base_port: 6900
2
+ base_directory: /tmp/redis-ring-spec
3
+ ring_size: 4
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 1
7
8
  - 0
8
- - 2
9
- version: 0.0.2
9
+ version: 0.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Adam Pohorecki
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-03-11 00:00:00 +01:00
17
+ date: 2011-03-21 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -57,7 +57,7 @@ dependencies:
57
57
  type: :runtime
58
58
  version_requirements: *id003
59
59
  - !ruby/object:Gem::Dependency
60
- name: rspec
60
+ name: zookeeper
61
61
  prerelease: false
62
62
  requirement: &id004 !ruby/object:Gem::Requirement
63
63
  none: false
@@ -67,10 +67,10 @@ dependencies:
67
67
  segments:
68
68
  - 0
69
69
  version: "0"
70
- type: :development
70
+ type: :runtime
71
71
  version_requirements: *id004
72
72
  - !ruby/object:Gem::Dependency
73
- name: mocha
73
+ name: rspec
74
74
  prerelease: false
75
75
  requirement: &id005 !ruby/object:Gem::Requirement
76
76
  none: false
@@ -82,6 +82,32 @@ dependencies:
82
82
  version: "0"
83
83
  type: :development
84
84
  version_requirements: *id005
85
+ - !ruby/object:Gem::Dependency
86
+ name: mocha
87
+ prerelease: false
88
+ requirement: &id006 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ type: :development
97
+ version_requirements: *id006
98
+ - !ruby/object:Gem::Dependency
99
+ name: simplecov
100
+ prerelease: false
101
+ requirement: &id007 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ type: :development
110
+ version_requirements: *id007
85
111
  description: RedisRing is a solution to run multiple small Redis instances intead of a single large one.
86
112
  email:
87
113
  - adam@pohorecki.pl
@@ -103,19 +129,41 @@ files:
103
129
  - lib/monkey_patches.rb
104
130
  - lib/redis_ring.rb
105
131
  - lib/redis_ring/application.rb
132
+ - lib/redis_ring/background_thread.rb
106
133
  - lib/redis_ring/cli.rb
107
134
  - lib/redis_ring/configuration.rb
135
+ - lib/redis_ring/http_client.rb
136
+ - lib/redis_ring/master.rb
137
+ - lib/redis_ring/master_rpc.rb
138
+ - lib/redis_ring/node.rb
108
139
  - lib/redis_ring/process_manager.rb
109
140
  - lib/redis_ring/shard.rb
110
141
  - lib/redis_ring/shard_config.rb
142
+ - lib/redis_ring/slave.rb
143
+ - lib/redis_ring/slave_rpc.rb
111
144
  - lib/redis_ring/version.rb
112
145
  - lib/redis_ring/web_interface.rb
146
+ - lib/redis_ring/zookeeper_connection.rb
147
+ - lib/redis_ring/zookeeper_observer.rb
113
148
  - redis_ring.gemspec
149
+ - spec/cluster_builder.rb
150
+ - spec/fakes/fake_http_client.rb
151
+ - spec/fakes/fake_master_rpc.rb
152
+ - spec/fakes/fake_node_provider.rb
153
+ - spec/fakes/fake_process_manager.rb
154
+ - spec/fakes/fake_slave_rpc.rb
155
+ - spec/fakes/fake_zookeeper_connection.rb
114
156
  - spec/redis_ring/application_spec.rb
115
157
  - spec/redis_ring/configuration_spec.rb
158
+ - spec/redis_ring/master_rpc_spec.rb
159
+ - spec/redis_ring/master_spec.rb
160
+ - spec/redis_ring/node_spec.rb
116
161
  - spec/redis_ring/shard_config_spec.rb
117
162
  - spec/redis_ring/shard_spec.rb
163
+ - spec/redis_ring/slave_rpc_spec.rb
164
+ - spec/redis_ring/slave_spec.rb
118
165
  - spec/spec_helper.rb
166
+ - spec/test.conf
119
167
  has_rdoc: true
120
168
  homepage: http://github.com/psyho/redis_ring
121
169
  licenses: []