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.
- data/.gitignore +3 -0
- data/Gemfile.lock +9 -3
- data/config/redis.conf.erb +4 -6
- data/lib/redis_ring/application.rb +29 -29
- data/lib/redis_ring/background_thread.rb +45 -0
- data/lib/redis_ring/cli.rb +3 -6
- data/lib/redis_ring/configuration.rb +2 -1
- data/lib/redis_ring/http_client.rb +23 -0
- data/lib/redis_ring/master.rb +154 -0
- data/lib/redis_ring/master_rpc.rb +33 -0
- data/lib/redis_ring/node.rb +66 -0
- data/lib/redis_ring/process_manager.rb +33 -19
- data/lib/redis_ring/shard_config.rb +18 -0
- data/lib/redis_ring/slave.rb +62 -0
- data/lib/redis_ring/slave_rpc.rb +42 -0
- data/lib/redis_ring/version.rb +1 -1
- data/lib/redis_ring/web_interface.rb +63 -2
- data/lib/redis_ring/zookeeper_connection.rb +73 -0
- data/lib/redis_ring/zookeeper_observer.rb +47 -0
- data/lib/redis_ring.rb +11 -0
- data/redis_ring.gemspec +2 -0
- data/spec/cluster_builder.rb +224 -0
- data/spec/fakes/fake_http_client.rb +39 -0
- data/spec/fakes/fake_master_rpc.rb +20 -0
- data/spec/fakes/fake_node_provider.rb +2 -0
- data/spec/fakes/fake_process_manager.rb +19 -0
- data/spec/fakes/fake_slave_rpc.rb +36 -0
- data/spec/fakes/fake_zookeeper_connection.rb +2 -0
- data/spec/redis_ring/application_spec.rb +15 -13
- data/spec/redis_ring/master_rpc_spec.rb +20 -0
- data/spec/redis_ring/master_spec.rb +174 -0
- data/spec/redis_ring/node_spec.rb +53 -0
- data/spec/redis_ring/slave_rpc_spec.rb +46 -0
- data/spec/redis_ring/slave_spec.rb +81 -0
- data/spec/spec_helper.rb +20 -1
- data/spec/test.conf +3 -0
- metadata +54 -6
@@ -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("
|
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
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
|
-
|
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-
|
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:
|
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: :
|
70
|
+
type: :runtime
|
71
71
|
version_requirements: *id004
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
|
-
name:
|
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: []
|