redis_migrator 0.0.1 → 0.1.1
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/README.md +13 -1
- data/Rakefile +6 -0
- data/lib/redis_migrator/redis_helper.rb +5 -36
- data/lib/redis_migrator/redis_native_migrator.rb +27 -0
- data/lib/redis_migrator/redis_pipe_migrator.rb +66 -0
- data/lib/redis_migrator/redis_populator.rb +1 -1
- data/lib/redis_migrator.rb +19 -20
- data/migrator_benchmark.rb +1 -2
- data/redis_migrator.gemspec +8 -4
- data/spec/different_redis_type_migrator.rb +67 -0
- data/spec/pretested_migrator.rb +47 -0
- data/spec/redis_migrator_spec.rb +41 -0
- data/spec/redis_native_migrator_spec.rb +44 -0
- data/spec/redis_pipe_migrator_spec.rb +51 -0
- data/spec/shared_hosts_context.rb +10 -0
- data/spec/spec_helper.rb +9 -7
- metadata +85 -49
- data/spec/migrator_spec.rb +0 -63
- data/spec/mock_redis/lib/mock_redis/assertions.rb +0 -13
- data/spec/mock_redis/lib/mock_redis/database.rb +0 -432
- data/spec/mock_redis/lib/mock_redis/distributed.rb +0 -6
- data/spec/mock_redis/lib/mock_redis/exceptions.rb +0 -3
- data/spec/mock_redis/lib/mock_redis/expire_wrapper.rb +0 -25
- data/spec/mock_redis/lib/mock_redis/hash_methods.rb +0 -118
- data/spec/mock_redis/lib/mock_redis/list_methods.rb +0 -187
- data/spec/mock_redis/lib/mock_redis/multi_db_wrapper.rb +0 -86
- data/spec/mock_redis/lib/mock_redis/set_methods.rb +0 -126
- data/spec/mock_redis/lib/mock_redis/string_methods.rb +0 -203
- data/spec/mock_redis/lib/mock_redis/transaction_wrapper.rb +0 -80
- data/spec/mock_redis/lib/mock_redis/undef_redis_methods.rb +0 -11
- data/spec/mock_redis/lib/mock_redis/utility_methods.rb +0 -25
- data/spec/mock_redis/lib/mock_redis/version.rb +0 -3
- data/spec/mock_redis/lib/mock_redis/zset.rb +0 -110
- data/spec/mock_redis/lib/mock_redis/zset_methods.rb +0 -210
- data/spec/mock_redis/lib/mock_redis.rb +0 -119
- data/spec/redis_helper_spec.rb +0 -58
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'mock_redis/undef_redis_methods'
|
2
|
-
|
3
|
-
class MockRedis
|
4
|
-
class ExpireWrapper
|
5
|
-
include UndefRedisMethods
|
6
|
-
|
7
|
-
def respond_to?(method, include_private=false)
|
8
|
-
super || @db.respond_to?(method)
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize(db)
|
12
|
-
@db = db
|
13
|
-
end
|
14
|
-
|
15
|
-
def method_missing(method, *args)
|
16
|
-
@db.expire_keys
|
17
|
-
@db.send(method, *args)
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize_copy(source)
|
21
|
-
super
|
22
|
-
@db = @db.clone
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,118 +0,0 @@
|
|
1
|
-
require 'mock_redis/assertions'
|
2
|
-
require 'mock_redis/utility_methods'
|
3
|
-
|
4
|
-
class MockRedis
|
5
|
-
module HashMethods
|
6
|
-
include Assertions
|
7
|
-
include UtilityMethods
|
8
|
-
|
9
|
-
def hdel(key, field)
|
10
|
-
with_hash_at(key) do |hash|
|
11
|
-
hash.delete(field.to_s) ? 1 : 0
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def hexists(key, field)
|
16
|
-
with_hash_at(key) {|h| h.has_key?(field.to_s)}
|
17
|
-
end
|
18
|
-
|
19
|
-
def hget(key, field)
|
20
|
-
with_hash_at(key) {|h| h[field.to_s]}
|
21
|
-
end
|
22
|
-
|
23
|
-
def hgetall(key)
|
24
|
-
with_hash_at(key) {|h| h}
|
25
|
-
end
|
26
|
-
|
27
|
-
def hincrby(key, field, increment)
|
28
|
-
with_hash_at(key) do |hash|
|
29
|
-
field = field.to_s
|
30
|
-
unless can_incr?(data[key][field])
|
31
|
-
raise RuntimeError, "ERR hash value is not an integer"
|
32
|
-
end
|
33
|
-
unless looks_like_integer?(increment.to_s)
|
34
|
-
raise RuntimeError, "ERR value is not an integer or out of range"
|
35
|
-
end
|
36
|
-
|
37
|
-
new_value = (hash[field] || "0").to_i + increment.to_i
|
38
|
-
hash[field] = new_value.to_s
|
39
|
-
new_value
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def hkeys(key)
|
44
|
-
with_hash_at(key, &:keys)
|
45
|
-
end
|
46
|
-
|
47
|
-
def hlen(key)
|
48
|
-
hkeys(key).length
|
49
|
-
end
|
50
|
-
|
51
|
-
def hmget(key, *fields)
|
52
|
-
assert_has_args(fields, 'hmget')
|
53
|
-
fields.map{|f| hget(key, f)}
|
54
|
-
end
|
55
|
-
|
56
|
-
def mapped_hmget(key, *fields)
|
57
|
-
reply = hmget(key, *fields)
|
58
|
-
Hash[*fields.zip(reply).flatten]
|
59
|
-
end
|
60
|
-
|
61
|
-
def hmset(key, *kvpairs)
|
62
|
-
assert_has_args(kvpairs, 'hmset')
|
63
|
-
if kvpairs.length.odd?
|
64
|
-
raise RuntimeError, "ERR wrong number of arguments for HMSET"
|
65
|
-
end
|
66
|
-
|
67
|
-
kvpairs.each_slice(2) do |(k,v)|
|
68
|
-
hset(key, k, v)
|
69
|
-
end
|
70
|
-
'OK'
|
71
|
-
end
|
72
|
-
|
73
|
-
def mapped_hmset(key, hash)
|
74
|
-
kvpairs = hash.to_a.flatten
|
75
|
-
assert_has_args(kvpairs, 'hmset')
|
76
|
-
if kvpairs.length.odd?
|
77
|
-
raise RuntimeError, "ERR wrong number of arguments for 'hmset' command"
|
78
|
-
end
|
79
|
-
|
80
|
-
hmset(key, *kvpairs)
|
81
|
-
end
|
82
|
-
|
83
|
-
def hset(key, field, value)
|
84
|
-
with_hash_at(key) {|h| h[field.to_s] = value.to_s}
|
85
|
-
true
|
86
|
-
end
|
87
|
-
|
88
|
-
def hsetnx(key, field, value)
|
89
|
-
if hget(key, field)
|
90
|
-
false
|
91
|
-
else
|
92
|
-
hset(key, field, value)
|
93
|
-
true
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def hvals(key)
|
98
|
-
with_hash_at(key, &:values)
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
def with_hash_at(key, &blk)
|
104
|
-
with_thing_at(key, :assert_hashy, proc {{}}, &blk)
|
105
|
-
end
|
106
|
-
|
107
|
-
def hashy?(key)
|
108
|
-
data[key].nil? || data[key].kind_of?(Hash)
|
109
|
-
end
|
110
|
-
|
111
|
-
def assert_hashy(key)
|
112
|
-
unless hashy?(key)
|
113
|
-
raise RuntimeError, "ERR Operation against a key holding the wrong kind of value"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
end
|
118
|
-
end
|
@@ -1,187 +0,0 @@
|
|
1
|
-
require 'mock_redis/assertions'
|
2
|
-
require 'mock_redis/utility_methods'
|
3
|
-
|
4
|
-
class MockRedis
|
5
|
-
module ListMethods
|
6
|
-
include Assertions
|
7
|
-
include UtilityMethods
|
8
|
-
|
9
|
-
def blpop(*args)
|
10
|
-
lists, timeout = extract_timeout(args)
|
11
|
-
nonempty_list = first_nonempty_list(lists)
|
12
|
-
|
13
|
-
if nonempty_list
|
14
|
-
[nonempty_list, lpop(nonempty_list)]
|
15
|
-
elsif timeout > 0
|
16
|
-
nil
|
17
|
-
else
|
18
|
-
raise MockRedis::WouldBlock, "Can't block forever"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def brpop(*args)
|
23
|
-
lists, timeout = extract_timeout(args)
|
24
|
-
nonempty_list = first_nonempty_list(lists)
|
25
|
-
|
26
|
-
if nonempty_list
|
27
|
-
[nonempty_list, rpop(nonempty_list)]
|
28
|
-
elsif timeout > 0
|
29
|
-
nil
|
30
|
-
else
|
31
|
-
raise MockRedis::WouldBlock, "Can't block forever"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def brpoplpush(source, destination, timeout)
|
36
|
-
assert_valid_timeout(timeout)
|
37
|
-
|
38
|
-
if llen(source) > 0
|
39
|
-
rpoplpush(source, destination)
|
40
|
-
elsif timeout > 0
|
41
|
-
nil
|
42
|
-
else
|
43
|
-
raise MockRedis::WouldBlock, "Can't block forever"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def lindex(key, index)
|
48
|
-
with_list_at(key) {|l| l[index]}
|
49
|
-
end
|
50
|
-
|
51
|
-
def linsert(key, position, pivot, value)
|
52
|
-
unless %w[before after].include?(position.to_s)
|
53
|
-
raise RuntimeError, "ERR syntax error"
|
54
|
-
end
|
55
|
-
|
56
|
-
assert_listy(key)
|
57
|
-
return 0 unless data[key]
|
58
|
-
|
59
|
-
pivot_position = (0..llen(key) - 1).find do |i|
|
60
|
-
data[key][i] == pivot.to_s
|
61
|
-
end
|
62
|
-
|
63
|
-
return -1 unless pivot_position
|
64
|
-
|
65
|
-
insertion_index = if position.to_s == 'before'
|
66
|
-
pivot_position
|
67
|
-
else
|
68
|
-
pivot_position + 1
|
69
|
-
end
|
70
|
-
|
71
|
-
data[key].insert(insertion_index, value.to_s)
|
72
|
-
llen(key)
|
73
|
-
end
|
74
|
-
|
75
|
-
def llen(key)
|
76
|
-
with_list_at(key, &:length)
|
77
|
-
end
|
78
|
-
|
79
|
-
def lpop(key)
|
80
|
-
with_list_at(key, &:shift)
|
81
|
-
end
|
82
|
-
|
83
|
-
def lpush(key, value)
|
84
|
-
with_list_at(key) {|l| l.unshift(value.to_s)}
|
85
|
-
llen(key)
|
86
|
-
end
|
87
|
-
|
88
|
-
def lpushx(key, value)
|
89
|
-
assert_listy(key)
|
90
|
-
return 0 unless list_at?(key)
|
91
|
-
lpush(key, value)
|
92
|
-
end
|
93
|
-
|
94
|
-
def lrange(key, start, stop)
|
95
|
-
with_list_at(key) {|l| l[start..stop]}
|
96
|
-
end
|
97
|
-
|
98
|
-
def lrem(key, count, value)
|
99
|
-
count = count.to_i
|
100
|
-
value = value.to_s
|
101
|
-
|
102
|
-
with_list_at(key) do |list|
|
103
|
-
indices_with_value = (0..(llen(key) - 1)).find_all do |i|
|
104
|
-
list[i] == value
|
105
|
-
end
|
106
|
-
|
107
|
-
indices_to_delete = if count == 0
|
108
|
-
indices_with_value.reverse
|
109
|
-
elsif count > 0
|
110
|
-
indices_with_value.take(count).reverse
|
111
|
-
else
|
112
|
-
indices_with_value.reverse.take(-count)
|
113
|
-
end
|
114
|
-
|
115
|
-
indices_to_delete.each {|i| list.delete_at(i)}.length
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def lset(key, index, value)
|
120
|
-
assert_listy(key)
|
121
|
-
|
122
|
-
unless list_at?(key)
|
123
|
-
raise RuntimeError, "ERR no such key"
|
124
|
-
end
|
125
|
-
|
126
|
-
unless (0...llen(key)).include?(index)
|
127
|
-
raise RuntimeError, "ERR index out of range"
|
128
|
-
end
|
129
|
-
|
130
|
-
data[key][index] = value.to_s
|
131
|
-
'OK'
|
132
|
-
end
|
133
|
-
|
134
|
-
def ltrim(key, start, stop)
|
135
|
-
with_list_at(key) do |list|
|
136
|
-
list.replace(list[start..stop] || []) if list
|
137
|
-
'OK'
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def rpop(key)
|
142
|
-
with_list_at(key) {|list| list.pop if list}
|
143
|
-
end
|
144
|
-
|
145
|
-
def rpoplpush(source, destination)
|
146
|
-
value = rpop(source)
|
147
|
-
lpush(destination, value)
|
148
|
-
value
|
149
|
-
end
|
150
|
-
|
151
|
-
def rpush(key, value)
|
152
|
-
with_list_at(key) {|l| l.push(value.to_s)}
|
153
|
-
llen(key)
|
154
|
-
end
|
155
|
-
|
156
|
-
def rpushx(key, value)
|
157
|
-
assert_listy(key)
|
158
|
-
return 0 unless list_at?(key)
|
159
|
-
rpush(key, value)
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
def list_at?(key)
|
164
|
-
data[key] && listy?(key)
|
165
|
-
end
|
166
|
-
|
167
|
-
def with_list_at(key, &blk)
|
168
|
-
with_thing_at(key, :assert_listy, proc {[]}, &blk)
|
169
|
-
end
|
170
|
-
|
171
|
-
def listy?(key)
|
172
|
-
data[key].nil? || data[key].kind_of?(Array)
|
173
|
-
end
|
174
|
-
|
175
|
-
def assert_listy(key)
|
176
|
-
unless listy?(key)
|
177
|
-
# Not the most helpful error, but it's what redis-rb barfs up
|
178
|
-
raise RuntimeError, "ERR Operation against a key holding the wrong kind of value"
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def first_nonempty_list(keys)
|
183
|
-
keys.find{|k| llen(k) > 0}
|
184
|
-
end
|
185
|
-
|
186
|
-
end
|
187
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'mock_redis/undef_redis_methods'
|
2
|
-
|
3
|
-
class MockRedis
|
4
|
-
class MultiDbWrapper
|
5
|
-
include UndefRedisMethods
|
6
|
-
|
7
|
-
def initialize(db)
|
8
|
-
@db_index = 0
|
9
|
-
|
10
|
-
@prototype_db = db.clone
|
11
|
-
|
12
|
-
@databases = Hash.new {|h,k| h[k] = @prototype_db.clone}
|
13
|
-
@databases[@db_index] = db
|
14
|
-
end
|
15
|
-
|
16
|
-
def respond_to?(method, include_private=false)
|
17
|
-
super || current_db.respond_to?(method, include_private)
|
18
|
-
end
|
19
|
-
|
20
|
-
def method_missing(method, *args)
|
21
|
-
current_db.send(method, *args)
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize_copy(source)
|
25
|
-
super
|
26
|
-
@databases = @databases.clone
|
27
|
-
@databases.keys.each do |k|
|
28
|
-
@databases[k] = @databases[k].clone
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Redis commands
|
33
|
-
def flushall
|
34
|
-
@databases.values.each(&:flushdb)
|
35
|
-
'OK'
|
36
|
-
end
|
37
|
-
|
38
|
-
def move(key, db_index)
|
39
|
-
src = current_db
|
40
|
-
dest = db(db_index)
|
41
|
-
|
42
|
-
if !src.exists(key) || dest.exists(key)
|
43
|
-
false
|
44
|
-
else
|
45
|
-
case current_db.type(key)
|
46
|
-
when 'hash'
|
47
|
-
dest.hmset(key, *(src.hgetall(key).map{|k,v| [k,v]}.flatten))
|
48
|
-
when 'list'
|
49
|
-
while value = src.rpop(key)
|
50
|
-
dest.lpush(key, value)
|
51
|
-
end
|
52
|
-
when 'set'
|
53
|
-
while value = src.spop(key)
|
54
|
-
dest.sadd(key, value)
|
55
|
-
end
|
56
|
-
when 'string'
|
57
|
-
dest.set(key, src.get(key))
|
58
|
-
when 'zset'
|
59
|
-
src.zrange(key, 0, -1, :with_scores => true).each_slice(2) do |(m,s)|
|
60
|
-
dest.zadd(key, s, m)
|
61
|
-
end
|
62
|
-
else
|
63
|
-
raise ArgumentError,
|
64
|
-
"Can't move a key of type #{current_db.type(key).inspect}"
|
65
|
-
end
|
66
|
-
|
67
|
-
src.del(key)
|
68
|
-
true
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def select(db_index)
|
73
|
-
@db_index = db_index.to_i
|
74
|
-
'OK'
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
def current_db
|
79
|
-
@databases[@db_index]
|
80
|
-
end
|
81
|
-
|
82
|
-
def db(index)
|
83
|
-
@databases[index]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
require 'mock_redis/assertions'
|
2
|
-
require 'mock_redis/utility_methods'
|
3
|
-
|
4
|
-
class MockRedis
|
5
|
-
module SetMethods
|
6
|
-
include Assertions
|
7
|
-
include UtilityMethods
|
8
|
-
|
9
|
-
def sadd(key, member)
|
10
|
-
with_set_at(key) {|s| !!s.add?(member.to_s)}
|
11
|
-
end
|
12
|
-
|
13
|
-
def scard(key)
|
14
|
-
with_set_at(key) {|s| s.length}
|
15
|
-
end
|
16
|
-
|
17
|
-
def sdiff(*keys)
|
18
|
-
assert_has_args(keys, 'sdiff')
|
19
|
-
with_sets_at(*keys) {|*sets| sets.reduce(&:-)}.to_a
|
20
|
-
end
|
21
|
-
|
22
|
-
def sdiffstore(destination, *keys)
|
23
|
-
assert_has_args(keys, 'sdiffstore')
|
24
|
-
with_set_at(destination) do |set|
|
25
|
-
set.replace(sdiff(*keys))
|
26
|
-
end
|
27
|
-
scard(destination)
|
28
|
-
end
|
29
|
-
|
30
|
-
def sinter(*keys)
|
31
|
-
assert_has_args(keys, 'sinter')
|
32
|
-
|
33
|
-
with_sets_at(*keys) do |*sets|
|
34
|
-
sets.reduce(&:&).to_a
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def sinterstore(destination, *keys)
|
39
|
-
assert_has_args(keys, 'sinterstore')
|
40
|
-
with_set_at(destination) do |set|
|
41
|
-
set.replace(sinter(*keys))
|
42
|
-
end
|
43
|
-
scard(destination)
|
44
|
-
end
|
45
|
-
|
46
|
-
def sismember(key, member)
|
47
|
-
with_set_at(key) {|s| s.include?(member.to_s)}
|
48
|
-
end
|
49
|
-
|
50
|
-
def smembers(key)
|
51
|
-
with_set_at(key, &:to_a)
|
52
|
-
end
|
53
|
-
|
54
|
-
def smove(src, dest, member)
|
55
|
-
member = member.to_s
|
56
|
-
|
57
|
-
with_sets_at(src, dest) do |src_set, dest_set|
|
58
|
-
if src_set.delete?(member)
|
59
|
-
dest_set.add(member)
|
60
|
-
true
|
61
|
-
else
|
62
|
-
false
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def spop(key)
|
68
|
-
with_set_at(key) do |set|
|
69
|
-
member = set.first
|
70
|
-
set.delete(member)
|
71
|
-
member
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def srandmember(key)
|
76
|
-
members = with_set_at(key, &:to_a)
|
77
|
-
members[rand(members.length)]
|
78
|
-
end
|
79
|
-
|
80
|
-
def srem(key, member)
|
81
|
-
with_set_at(key) {|s| !!s.delete?(member.to_s)}
|
82
|
-
end
|
83
|
-
|
84
|
-
def sunion(*keys)
|
85
|
-
assert_has_args(keys, 'sunion')
|
86
|
-
with_sets_at(*keys) {|*sets| sets.reduce(&:+).to_a}
|
87
|
-
end
|
88
|
-
|
89
|
-
def sunionstore(destination, *keys)
|
90
|
-
assert_has_args(keys, 'sunionstore')
|
91
|
-
with_set_at(destination) do |dest_set|
|
92
|
-
dest_set.replace(sunion(*keys))
|
93
|
-
end
|
94
|
-
scard(destination)
|
95
|
-
end
|
96
|
-
|
97
|
-
private
|
98
|
-
def with_set_at(key, &blk)
|
99
|
-
with_thing_at(key, :assert_sety, proc {Set.new}, &blk)
|
100
|
-
end
|
101
|
-
|
102
|
-
def with_sets_at(*keys, &blk)
|
103
|
-
if keys.length == 1
|
104
|
-
with_set_at(keys.first, &blk)
|
105
|
-
else
|
106
|
-
with_set_at(keys.first) do |set|
|
107
|
-
with_sets_at(*(keys[1..-1])) do |*sets|
|
108
|
-
blk.call(*([set] + sets))
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def sety?(key)
|
115
|
-
data[key].nil? || data[key].kind_of?(Set)
|
116
|
-
end
|
117
|
-
|
118
|
-
def assert_sety(key)
|
119
|
-
unless sety?(key)
|
120
|
-
# Not the most helpful error, but it's what redis-rb barfs up
|
121
|
-
raise RuntimeError, "ERR Operation against a key holding the wrong kind of value"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|