redis_migrator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/README.md +35 -0
- data/lib/redis_migrator/redis_helper.rb +52 -0
- data/lib/redis_migrator/redis_populator.rb +63 -0
- data/lib/redis_migrator.rb +96 -0
- data/migrator_benchmark.rb +22 -0
- data/redis_migrator.gemspec +20 -0
- data/spec/migrator_spec.rb +63 -0
- data/spec/mock_redis/lib/mock_redis/assertions.rb +13 -0
- data/spec/mock_redis/lib/mock_redis/database.rb +432 -0
- data/spec/mock_redis/lib/mock_redis/distributed.rb +6 -0
- data/spec/mock_redis/lib/mock_redis/exceptions.rb +3 -0
- data/spec/mock_redis/lib/mock_redis/expire_wrapper.rb +25 -0
- data/spec/mock_redis/lib/mock_redis/hash_methods.rb +118 -0
- data/spec/mock_redis/lib/mock_redis/list_methods.rb +187 -0
- data/spec/mock_redis/lib/mock_redis/multi_db_wrapper.rb +86 -0
- data/spec/mock_redis/lib/mock_redis/set_methods.rb +126 -0
- data/spec/mock_redis/lib/mock_redis/string_methods.rb +203 -0
- data/spec/mock_redis/lib/mock_redis/transaction_wrapper.rb +80 -0
- data/spec/mock_redis/lib/mock_redis/undef_redis_methods.rb +11 -0
- data/spec/mock_redis/lib/mock_redis/utility_methods.rb +25 -0
- data/spec/mock_redis/lib/mock_redis/version.rb +3 -0
- data/spec/mock_redis/lib/mock_redis/zset.rb +110 -0
- data/spec/mock_redis/lib/mock_redis/zset_methods.rb +210 -0
- data/spec/mock_redis/lib/mock_redis.rb +119 -0
- data/spec/redis_helper_spec.rb +58 -0
- data/spec/spec_helper.rb +29 -0
- metadata +107 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
class MockRedis
|
5
|
+
class Zset
|
6
|
+
include Enumerable
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :members, :scores
|
10
|
+
|
11
|
+
def_delegators :members, :empty?, :include?, :size
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@members = Set.new
|
15
|
+
@scores = Hash.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize_copy(source)
|
19
|
+
super
|
20
|
+
@members = @members.clone
|
21
|
+
@scores = @scores.clone
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(score, member)
|
25
|
+
members.add(member)
|
26
|
+
if score.to_f.to_i == score.to_f
|
27
|
+
scores[member] = score.to_f.to_i
|
28
|
+
else
|
29
|
+
scores[member] = score.to_f
|
30
|
+
end
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete?(member)
|
35
|
+
scores.delete(member)
|
36
|
+
members.delete?(member) and self
|
37
|
+
end
|
38
|
+
|
39
|
+
def each
|
40
|
+
members.each {|m| yield score(m), m}
|
41
|
+
end
|
42
|
+
|
43
|
+
def in_range(min, max)
|
44
|
+
in_from_the_left = case min
|
45
|
+
when "-inf"
|
46
|
+
lambda {|_| true }
|
47
|
+
when "+inf"
|
48
|
+
lambda {|_| false }
|
49
|
+
when /\((.*)$/
|
50
|
+
val = $1.to_f
|
51
|
+
lambda {|x| x.to_f > val }
|
52
|
+
else
|
53
|
+
lambda {|x| x.to_f >= min.to_f }
|
54
|
+
end
|
55
|
+
|
56
|
+
in_from_the_right = case max
|
57
|
+
when "-inf"
|
58
|
+
lambda {|_| false }
|
59
|
+
when "+inf"
|
60
|
+
lambda {|_| true }
|
61
|
+
when /\((.*)$/
|
62
|
+
val = $1.to_f
|
63
|
+
lambda {|x| x.to_f < val }
|
64
|
+
else
|
65
|
+
lambda {|x| x.to_f <= max.to_f }
|
66
|
+
end
|
67
|
+
|
68
|
+
sorted.find_all do |(score, member)|
|
69
|
+
in_from_the_left[score] && in_from_the_right[score]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def intersection(other)
|
74
|
+
if !block_given?
|
75
|
+
intersection(other, &:+)
|
76
|
+
else
|
77
|
+
self.members.intersection(other.members).reduce(self.class.new) do |acc, m|
|
78
|
+
new_score = yield(self.score(m), other.score(m))
|
79
|
+
acc.add(new_score, m)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def score(member)
|
85
|
+
scores[member]
|
86
|
+
end
|
87
|
+
|
88
|
+
def sorted
|
89
|
+
members.map do |m|
|
90
|
+
[score(m), m]
|
91
|
+
end.sort_by(&:first)
|
92
|
+
end
|
93
|
+
|
94
|
+
def sorted_members
|
95
|
+
sorted.map(&:last)
|
96
|
+
end
|
97
|
+
|
98
|
+
def union(other)
|
99
|
+
if !block_given?
|
100
|
+
union(other, &:+)
|
101
|
+
else
|
102
|
+
self.members.union(other.members).reduce(self.class.new) do |acc, m|
|
103
|
+
new_score = yield(self.score(m), other.score(m))
|
104
|
+
acc.add(new_score, m)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'mock_redis/assertions'
|
2
|
+
require 'mock_redis/utility_methods'
|
3
|
+
require 'mock_redis/zset'
|
4
|
+
|
5
|
+
class MockRedis
|
6
|
+
module ZsetMethods
|
7
|
+
include Assertions
|
8
|
+
include UtilityMethods
|
9
|
+
|
10
|
+
def zadd(key, score, member)
|
11
|
+
assert_scorey(score)
|
12
|
+
|
13
|
+
retval = !zscore(key, member)
|
14
|
+
with_zset_at(key) {|z| z.add(score, member.to_s)}
|
15
|
+
retval
|
16
|
+
end
|
17
|
+
|
18
|
+
def zcard(key)
|
19
|
+
with_zset_at(key, &:size)
|
20
|
+
end
|
21
|
+
|
22
|
+
def zcount(key, min, max)
|
23
|
+
assert_scorey(min, 'min or max')
|
24
|
+
assert_scorey(max, 'min or max')
|
25
|
+
|
26
|
+
with_zset_at(key) do |z|
|
27
|
+
z.count do |score, _|
|
28
|
+
score >= min && score <= max
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def zincrby(key, increment, member)
|
34
|
+
assert_scorey(increment)
|
35
|
+
member = member.to_s
|
36
|
+
with_zset_at(key) do |z|
|
37
|
+
old_score = z.include?(member) ? z.score(member) : 0
|
38
|
+
new_score = old_score + increment
|
39
|
+
z.add(new_score, member)
|
40
|
+
new_score.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def zinterstore(destination, keys, options={})
|
45
|
+
assert_has_args(keys, 'zinterstore')
|
46
|
+
|
47
|
+
data[destination] = combine_weighted_zsets(keys, options, :intersection)
|
48
|
+
zcard(destination)
|
49
|
+
end
|
50
|
+
|
51
|
+
def zrange(key, start, stop, options={})
|
52
|
+
with_zset_at(key) do |z|
|
53
|
+
to_response(z.sorted[start..stop] || [], options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def zrangebyscore(key, min, max, options={})
|
58
|
+
with_zset_at(key) do |zset|
|
59
|
+
all_results = zset.in_range(min, max)
|
60
|
+
to_response(apply_limit(all_results, options[:limit]), options)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def zrank(key, member)
|
65
|
+
with_zset_at(key) {|z| z.sorted_members.index(member.to_s) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def zrem(key, member)
|
69
|
+
with_zset_at(key) {|z| !!z.delete?(member.to_s)}
|
70
|
+
end
|
71
|
+
|
72
|
+
def zrevrange(key, start, stop, options={})
|
73
|
+
with_zset_at(key) do |z|
|
74
|
+
to_response(z.sorted.reverse[start..stop], options)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def zremrangebyrank(key, start, stop)
|
79
|
+
zrange(key, start, stop).
|
80
|
+
each {|member| zrem(key, member)}.
|
81
|
+
size
|
82
|
+
end
|
83
|
+
|
84
|
+
def zremrangebyscore(key, min, max)
|
85
|
+
zrangebyscore(key, min, max).
|
86
|
+
each {|member| zrem(key, member)}.
|
87
|
+
size
|
88
|
+
end
|
89
|
+
|
90
|
+
def zrevrangebyscore(key, max, min, options={})
|
91
|
+
with_zset_at(key) do |zset|
|
92
|
+
to_response(
|
93
|
+
apply_limit(
|
94
|
+
zset.in_range(min, max).reverse,
|
95
|
+
options[:limit]),
|
96
|
+
options)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def zrevrank(key, member)
|
101
|
+
with_zset_at(key) {|z| z.sorted_members.reverse.index(member.to_s) }
|
102
|
+
end
|
103
|
+
|
104
|
+
def zscore(key, member)
|
105
|
+
with_zset_at(key) do |z|
|
106
|
+
score = z.score(member.to_s)
|
107
|
+
score.to_s if score
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def zunionstore(destination, keys, options={})
|
112
|
+
assert_has_args(keys, 'zunionstore')
|
113
|
+
|
114
|
+
data[destination] = combine_weighted_zsets(keys, options, :union)
|
115
|
+
zcard(destination)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def apply_limit(collection, limit)
|
120
|
+
if limit
|
121
|
+
if limit.is_a?(Array) && limit.length == 2
|
122
|
+
offset, count = limit
|
123
|
+
collection.drop(offset).take(count)
|
124
|
+
else
|
125
|
+
raise RuntimeError, "ERR syntax error"
|
126
|
+
end
|
127
|
+
else
|
128
|
+
collection
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def to_response(score_member_pairs, options)
|
133
|
+
score_member_pairs.map do |(score,member)|
|
134
|
+
if options[:with_scores] || options[:withscores]
|
135
|
+
[member, score.to_s]
|
136
|
+
else
|
137
|
+
member
|
138
|
+
end
|
139
|
+
end.flatten
|
140
|
+
end
|
141
|
+
|
142
|
+
def combine_weighted_zsets(keys, options, how)
|
143
|
+
weights = options.fetch(:weights, keys.map { 1 })
|
144
|
+
if weights.length != keys.length
|
145
|
+
raise RuntimeError, "ERR syntax error"
|
146
|
+
end
|
147
|
+
|
148
|
+
aggregator = case options.fetch(:aggregate, :sum).to_s.downcase.to_sym
|
149
|
+
when :sum
|
150
|
+
proc {|a,b| [a,b].compact.reduce(&:+)}
|
151
|
+
when :min
|
152
|
+
proc {|a,b| [a,b].compact.min}
|
153
|
+
when :max
|
154
|
+
proc {|a,b| [a,b].compact.max}
|
155
|
+
else
|
156
|
+
raise RuntimeError, "ERR syntax error"
|
157
|
+
end
|
158
|
+
|
159
|
+
with_zsets_at(*keys) do |*zsets|
|
160
|
+
zsets.zip(weights).map do |(zset, weight)|
|
161
|
+
zset.reduce(Zset.new) do |acc, (score, member)|
|
162
|
+
acc.add(score * weight, member)
|
163
|
+
end
|
164
|
+
end.reduce do |za, zb|
|
165
|
+
za.send(how, zb, &aggregator)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
def with_zset_at(key, &blk)
|
172
|
+
with_thing_at(key, :assert_zsety, proc {Zset.new}, &blk)
|
173
|
+
end
|
174
|
+
|
175
|
+
def with_zsets_at(*keys, &blk)
|
176
|
+
if keys.length == 1
|
177
|
+
with_zset_at(keys.first, &blk)
|
178
|
+
else
|
179
|
+
with_zset_at(keys.first) do |set|
|
180
|
+
with_zsets_at(*(keys[1..-1])) do |*sets|
|
181
|
+
blk.call(*([set] + sets))
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def zsety?(key)
|
188
|
+
data[key].nil? || data[key].kind_of?(Zset)
|
189
|
+
end
|
190
|
+
|
191
|
+
def assert_zsety(key)
|
192
|
+
unless zsety?(key)
|
193
|
+
raise RuntimeError,
|
194
|
+
"ERR Operation against a key holding the wrong kind of value"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def looks_like_float?(x)
|
199
|
+
# ugh, exceptions for flow control.
|
200
|
+
!!Float(x) rescue false
|
201
|
+
end
|
202
|
+
|
203
|
+
def assert_scorey(value, what='value')
|
204
|
+
unless looks_like_float?(value)
|
205
|
+
raise RuntimeError, "ERR #{what} is not a double"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'mock_redis/assertions'
|
4
|
+
require 'mock_redis/database'
|
5
|
+
require 'mock_redis/distributed'
|
6
|
+
require 'mock_redis/expire_wrapper'
|
7
|
+
require 'mock_redis/multi_db_wrapper'
|
8
|
+
require 'mock_redis/transaction_wrapper'
|
9
|
+
require 'mock_redis/undef_redis_methods'
|
10
|
+
|
11
|
+
class MockRedis
|
12
|
+
include UndefRedisMethods
|
13
|
+
|
14
|
+
attr_reader :options
|
15
|
+
|
16
|
+
DEFAULTS = {
|
17
|
+
:scheme => "redis",
|
18
|
+
:host => "127.0.0.1",
|
19
|
+
:port => 6379,
|
20
|
+
:path => nil,
|
21
|
+
:timeout => 5.0,
|
22
|
+
:password => nil,
|
23
|
+
:db => 0,
|
24
|
+
}
|
25
|
+
|
26
|
+
def initialize(*args)
|
27
|
+
@options = _parse_options(args.first)
|
28
|
+
|
29
|
+
@db = TransactionWrapper.new(
|
30
|
+
ExpireWrapper.new(
|
31
|
+
MultiDbWrapper.new(
|
32
|
+
Database.new(*args))))
|
33
|
+
end
|
34
|
+
|
35
|
+
def id
|
36
|
+
"redis://#{self.host}:#{self.port}/#{self.db}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(command, &block)
|
40
|
+
self.send(*command)
|
41
|
+
end
|
42
|
+
|
43
|
+
def host
|
44
|
+
self.options[:host]
|
45
|
+
end
|
46
|
+
|
47
|
+
def port
|
48
|
+
self.options[:port]
|
49
|
+
end
|
50
|
+
|
51
|
+
def db
|
52
|
+
self.options[:db]
|
53
|
+
end
|
54
|
+
|
55
|
+
def client
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def respond_to?(method, include_private=false)
|
60
|
+
super || @db.respond_to?(method, include_private)
|
61
|
+
end
|
62
|
+
|
63
|
+
def method_missing(method, *args, &block)
|
64
|
+
@db.send(method, *args, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize_copy(source)
|
68
|
+
super
|
69
|
+
@db = @db.clone
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def _parse_options(options)
|
76
|
+
return {} if options.nil?
|
77
|
+
|
78
|
+
defaults = DEFAULTS.dup
|
79
|
+
|
80
|
+
url = options[:url] || ENV["REDIS_URL"]
|
81
|
+
|
82
|
+
# Override defaults from URL if given
|
83
|
+
if url
|
84
|
+
require "uri"
|
85
|
+
|
86
|
+
uri = URI(url)
|
87
|
+
|
88
|
+
if uri.scheme == "unix"
|
89
|
+
defaults[:path] = uri.path
|
90
|
+
else
|
91
|
+
# Require the URL to have at least a host
|
92
|
+
raise ArgumentError, "invalid url" unless uri.host
|
93
|
+
|
94
|
+
defaults[:scheme] = uri.scheme
|
95
|
+
defaults[:host] = uri.host
|
96
|
+
defaults[:port] = uri.port if uri.port
|
97
|
+
defaults[:password] = uri.password if uri.password
|
98
|
+
defaults[:db] = uri.path[1..-1].to_i if uri.path
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
options = defaults.merge(options)
|
103
|
+
|
104
|
+
if options[:path]
|
105
|
+
options[:scheme] = "unix"
|
106
|
+
options.delete(:host)
|
107
|
+
options.delete(:port)
|
108
|
+
else
|
109
|
+
options[:host] = options[:host].to_s
|
110
|
+
options[:port] = options[:port].to_i
|
111
|
+
end
|
112
|
+
|
113
|
+
options[:timeout] = options[:timeout].to_f
|
114
|
+
options[:db] = options[:db].to_i
|
115
|
+
|
116
|
+
options
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe Redis::Helper do
|
2
|
+
before do
|
3
|
+
Redis.should_receive(:new).any_number_of_times {|options|
|
4
|
+
MockRedis.new(options)
|
5
|
+
}
|
6
|
+
|
7
|
+
@migrator = Redis::Migrator.new(["redis://localhost:6379"],
|
8
|
+
["redis://localhost:6377"])
|
9
|
+
|
10
|
+
@r1 = @migrator.old_cluster
|
11
|
+
@r2 = @migrator.new_cluster
|
12
|
+
@migrator.stub!(:redis).and_return(@r1)
|
13
|
+
@pipe = PipeMock.new(@r2)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should copy a string" do
|
17
|
+
@r1.set("a", "some_string")
|
18
|
+
@migrator.copy_string(@pipe, "a")
|
19
|
+
|
20
|
+
@r2.get("a").should == "some_string"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should copy a hash" do
|
24
|
+
@r1.hmset("myhash",
|
25
|
+
"first_name", "James",
|
26
|
+
"last_name", "Randi",
|
27
|
+
"age", "83")
|
28
|
+
|
29
|
+
@migrator.copy_hash(@pipe, "myhash")
|
30
|
+
|
31
|
+
@r2.hgetall("myhash").should == {"first_name" => "James", "last_name" => "Randi", "age" => "83"}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should copy a list" do
|
35
|
+
('a'..'z').to_a.each { |val| @r1.lpush("mylist", val) }
|
36
|
+
|
37
|
+
@migrator.copy_list(@pipe, "mylist")
|
38
|
+
|
39
|
+
@r2.lrange("mylist", 0, -1).should == ('a'..'z').to_a
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should copy a set" do
|
43
|
+
('a'..'z').to_a.each { |val| @r1.sadd("myset", val) }
|
44
|
+
|
45
|
+
@migrator.copy_set(@pipe, "myset")
|
46
|
+
|
47
|
+
@r2.smembers("myset").should == ('a'..'z').to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should copy zset" do
|
51
|
+
('a'..'z').to_a.each { |val| @r1.zadd("myzset", rand(100), val) }
|
52
|
+
|
53
|
+
@migrator.copy_zset(@pipe, "myzset")
|
54
|
+
|
55
|
+
@r2.zrange("myzset", 0, -1, :with_scores => true).sort.should == @r1.zrange("myzset", 0, -1, :with_scores => true).sort
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "mock_redis/lib"))
|
2
|
+
|
3
|
+
require_relative "../lib/redis_migrator.rb"
|
4
|
+
|
5
|
+
# include patched version of mock_redis
|
6
|
+
# that works with Redis::Distributed
|
7
|
+
require "mock_redis.rb"
|
8
|
+
|
9
|
+
class PipeMock
|
10
|
+
def initialize(redis)
|
11
|
+
@redis = redis
|
12
|
+
end
|
13
|
+
|
14
|
+
def close; true; end
|
15
|
+
|
16
|
+
def <<(val)
|
17
|
+
val[0] = val[0].downcase.to_sym
|
18
|
+
@redis.send(*val)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
class Redis
|
24
|
+
module Helper
|
25
|
+
def to_redis_proto(*cmd)
|
26
|
+
cmd
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis_migrator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Artem Yankov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-05 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: &70245281843860 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.2.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70245281843860
|
25
|
+
description: Redis-migrator takes a list of nodes for your old cluster and list of
|
26
|
+
nodes for your new cluster and determines for which keys routes were changed. Then
|
27
|
+
it moves those keys to new nodes.
|
28
|
+
email:
|
29
|
+
- artem.yankov@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- .rspec
|
36
|
+
- README.md
|
37
|
+
- lib/redis_migrator.rb
|
38
|
+
- lib/redis_migrator/redis_helper.rb
|
39
|
+
- lib/redis_migrator/redis_populator.rb
|
40
|
+
- migrator_benchmark.rb
|
41
|
+
- redis_migrator.gemspec
|
42
|
+
- spec/migrator_spec.rb
|
43
|
+
- spec/mock_redis/lib/mock_redis.rb
|
44
|
+
- spec/mock_redis/lib/mock_redis/assertions.rb
|
45
|
+
- spec/mock_redis/lib/mock_redis/database.rb
|
46
|
+
- spec/mock_redis/lib/mock_redis/distributed.rb
|
47
|
+
- spec/mock_redis/lib/mock_redis/exceptions.rb
|
48
|
+
- spec/mock_redis/lib/mock_redis/expire_wrapper.rb
|
49
|
+
- spec/mock_redis/lib/mock_redis/hash_methods.rb
|
50
|
+
- spec/mock_redis/lib/mock_redis/list_methods.rb
|
51
|
+
- spec/mock_redis/lib/mock_redis/multi_db_wrapper.rb
|
52
|
+
- spec/mock_redis/lib/mock_redis/set_methods.rb
|
53
|
+
- spec/mock_redis/lib/mock_redis/string_methods.rb
|
54
|
+
- spec/mock_redis/lib/mock_redis/transaction_wrapper.rb
|
55
|
+
- spec/mock_redis/lib/mock_redis/undef_redis_methods.rb
|
56
|
+
- spec/mock_redis/lib/mock_redis/utility_methods.rb
|
57
|
+
- spec/mock_redis/lib/mock_redis/version.rb
|
58
|
+
- spec/mock_redis/lib/mock_redis/zset.rb
|
59
|
+
- spec/mock_redis/lib/mock_redis/zset_methods.rb
|
60
|
+
- spec/redis_helper_spec.rb
|
61
|
+
- spec/spec_helper.rb
|
62
|
+
homepage: http://rubygems.org/gems/redis_migrator
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.17
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A tool to redistribute keys in your redis cluster when its topography has
|
86
|
+
changed
|
87
|
+
test_files:
|
88
|
+
- spec/migrator_spec.rb
|
89
|
+
- spec/mock_redis/lib/mock_redis.rb
|
90
|
+
- spec/mock_redis/lib/mock_redis/assertions.rb
|
91
|
+
- spec/mock_redis/lib/mock_redis/database.rb
|
92
|
+
- spec/mock_redis/lib/mock_redis/distributed.rb
|
93
|
+
- spec/mock_redis/lib/mock_redis/exceptions.rb
|
94
|
+
- spec/mock_redis/lib/mock_redis/expire_wrapper.rb
|
95
|
+
- spec/mock_redis/lib/mock_redis/hash_methods.rb
|
96
|
+
- spec/mock_redis/lib/mock_redis/list_methods.rb
|
97
|
+
- spec/mock_redis/lib/mock_redis/multi_db_wrapper.rb
|
98
|
+
- spec/mock_redis/lib/mock_redis/set_methods.rb
|
99
|
+
- spec/mock_redis/lib/mock_redis/string_methods.rb
|
100
|
+
- spec/mock_redis/lib/mock_redis/transaction_wrapper.rb
|
101
|
+
- spec/mock_redis/lib/mock_redis/undef_redis_methods.rb
|
102
|
+
- spec/mock_redis/lib/mock_redis/utility_methods.rb
|
103
|
+
- spec/mock_redis/lib/mock_redis/version.rb
|
104
|
+
- spec/mock_redis/lib/mock_redis/zset.rb
|
105
|
+
- spec/mock_redis/lib/mock_redis/zset_methods.rb
|
106
|
+
- spec/redis_helper_spec.rb
|
107
|
+
- spec/spec_helper.rb
|