redis-copy 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +44 -9
- data/lib/redis-copy.rb +2 -3
- data/lib/redis-copy/cli.rb +12 -6
- data/lib/redis-copy/key-emitter.rb +19 -0
- data/lib/redis-copy/version.rb +1 -1
- data/redis-copy.gemspec +4 -0
- data/spec/redis-copy/key-emitter_spec.rb +1 -1
- metadata +4 -2
data/README.md
CHANGED
@@ -1,24 +1,59 @@
|
|
1
1
|
# Redis::Copy
|
2
2
|
|
3
|
-
|
3
|
+
This utility provides a way to move the contents of one redis DB to another
|
4
|
+
redis DB. It is inspired by the [redis-copy.rb script][original] included in
|
5
|
+
the redis source, but supports the following additional features:
|
6
|
+
|
7
|
+
- all known data types (original supported `set`, `list`, and `string`,
|
8
|
+
dropping the others without warning)
|
9
|
+
- if available on both dbs, will use `DUMP`/`RESTORE` commands (redis v2.6+)
|
10
|
+
- support for more than just db0
|
11
|
+
|
12
|
+
[original]: https://github.com/antirez/redis/commits/unstable/utils/redis-copy.rb
|
4
13
|
|
5
14
|
## Installation
|
6
15
|
|
7
|
-
|
16
|
+
$ gem install redis-copy
|
8
17
|
|
9
|
-
|
18
|
+
## Usage
|
10
19
|
|
11
|
-
|
20
|
+
The current options can be grabbed using the `--help` flag.
|
12
21
|
|
13
|
-
|
22
|
+
```
|
23
|
+
$ redis-copy --help
|
24
|
+
redis-copy v0.0.2
|
25
|
+
Usage: redis-copy [options] <source> <destination>
|
26
|
+
<source> and <destination> must be redis connection uris
|
27
|
+
like [redis://]<hostname>[:<port>][/<db>]
|
14
28
|
|
15
|
-
|
29
|
+
Specific options:
|
30
|
+
--strategy STRATEGY Select strategy (auto, new, classic) (default auto)
|
31
|
+
auto: uses new if available, otherwise fallback
|
32
|
+
new: use redis DUMP and RESTORE commands (faster)
|
33
|
+
classic: migrates via multiple type-specific commands
|
34
|
+
--[no-]dry-run Output configuration and exit
|
35
|
+
-d, --[no-]debug Write debug output
|
36
|
+
-t, --[no-]trace Enable backtrace on failure
|
37
|
+
-f, --[no-]fail-fast Abort on first failure
|
38
|
+
-y, --yes Automatically accept any prompts
|
39
|
+
--[no-]allow-nonempty Allow non-empty destination
|
16
40
|
|
17
|
-
|
41
|
+
```
|
18
42
|
|
19
|
-
##
|
43
|
+
## Example:
|
20
44
|
|
21
|
-
|
45
|
+
```
|
46
|
+
$ redis-copy --fail-fast --yes old.redis.host/9 new.redis.host:6380/3
|
47
|
+
Source: redis://old.redis.host:6379/9
|
48
|
+
Destination: redis://new.redis.host:6380/3 (empty)
|
49
|
+
Key Emitter: Default
|
50
|
+
Strategy: New
|
51
|
+
PROGRESS {:success=>1000, :attempt=>1000}
|
52
|
+
PROGRESS {:success=>2000, :attempt=>2000}
|
53
|
+
PROGRESS {:success=>3000, :attempt=>3000}
|
54
|
+
PROGRESS {:success=>4000, :attempt=>4000}
|
55
|
+
DONE: {:success=>4246, :attempt=>4246}
|
56
|
+
```
|
22
57
|
|
23
58
|
## Contributing
|
24
59
|
|
data/lib/redis-copy.rb
CHANGED
@@ -15,7 +15,6 @@ module RedisCopy
|
|
15
15
|
# @param destination [String]
|
16
16
|
# @options options [Hash<Symbol,Object>]
|
17
17
|
def copy(source, destination, options = {})
|
18
|
-
puts options.inspect
|
19
18
|
ui = UI.load(options)
|
20
19
|
|
21
20
|
source = redis_from(source)
|
@@ -35,7 +34,7 @@ module RedisCopy
|
|
35
34
|
Strategy: #{strategem}
|
36
35
|
EODESC
|
37
36
|
|
38
|
-
ui.abort('Destination not empty!') unless dest_empty
|
37
|
+
ui.abort('Destination not empty!') unless dest_empty or options[:allow_nonempty]
|
39
38
|
|
40
39
|
key_emitter.keys.each_with_object(Hash.new {0}) do |key, stats|
|
41
40
|
success = strategem.copy(key)
|
@@ -46,7 +45,7 @@ module RedisCopy
|
|
46
45
|
ui.notify("FAIL: #{key.dump}")
|
47
46
|
ui.abort if options[:fail_fast]
|
48
47
|
end
|
49
|
-
ui.notify(stats.inspect) if (stats[:attempt] % 1000).zero?
|
48
|
+
ui.notify("PROGRESS: #{stats.inspect}") if (stats[:attempt] % 1000).zero?
|
50
49
|
end.tap do |stats|
|
51
50
|
ui.notify("DONE: #{stats.inspect}")
|
52
51
|
end
|
data/lib/redis-copy/cli.rb
CHANGED
@@ -7,11 +7,12 @@ module RedisCopy
|
|
7
7
|
class CLI
|
8
8
|
REDIS_URI = (/\A(?:redis:\/\/)?([a-z0-9\-.]+)(:[0-9]{1,5})?(\/(?:(?:1[0-5])|[0-9]))?\z/i).freeze
|
9
9
|
DEFAULTS = {
|
10
|
-
ui:
|
11
|
-
key_emitter:
|
12
|
-
strategy:
|
13
|
-
fail_fast:
|
14
|
-
yes:
|
10
|
+
ui: :command_line,
|
11
|
+
key_emitter: :default,
|
12
|
+
strategy: :auto,
|
13
|
+
fail_fast: false,
|
14
|
+
yes: false,
|
15
|
+
allow_nonempty: false,
|
15
16
|
}.freeze unless defined?(DEFAULTS)
|
16
17
|
|
17
18
|
def initialize(argv = ARGV)
|
@@ -19,8 +20,9 @@ module RedisCopy
|
|
19
20
|
options = {}
|
20
21
|
|
21
22
|
OptionParser.new do |opts|
|
22
|
-
opts.banner = "Usage: #{opts.program_name} [options] <source> <destination>"
|
23
23
|
opts.version = RedisCopy::VERSION
|
24
|
+
opts.banner = "#{opts.program_name} v#{opts.version}\n" +
|
25
|
+
"Usage: #{opts.program_name} [options] <source> <destination>"
|
24
26
|
|
25
27
|
indent_desc = proc do |desc|
|
26
28
|
desc.split("\n").join("\n#{opts.summary_indent}#{' '*opts.summary_width} ")
|
@@ -62,6 +64,10 @@ module RedisCopy
|
|
62
64
|
options[:yes] = true
|
63
65
|
end
|
64
66
|
|
67
|
+
opts.on('--[no-]allow-nonempty', 'Allow non-empty destination') do |allow_nonempty|
|
68
|
+
options[:allow_nonempty] = allow_nonempty
|
69
|
+
end
|
70
|
+
|
65
71
|
opts.parse!(argv)
|
66
72
|
unless argv.size == 2
|
67
73
|
opts.abort "Source and Destination must be specified\n\n" +
|
@@ -36,6 +36,25 @@ module RedisCopy
|
|
36
36
|
class Default
|
37
37
|
include KeyEmitter
|
38
38
|
|
39
|
+
def initialize(redis, ui, options = {})
|
40
|
+
ui.abort unless ui.confirm? <<-EOWARNING.strip_heredoc
|
41
|
+
WARNING: #{self} key emitter uses redis.keys('*') to
|
42
|
+
get its list of keys.
|
43
|
+
|
44
|
+
The redis keys command [reference](http://redis.io/commands/keys)
|
45
|
+
says this:
|
46
|
+
|
47
|
+
> Warning: consider KEYS as a command that should only be used
|
48
|
+
> in production environments with extreme care. It may ruin
|
49
|
+
> performance when it is executed against large databases.
|
50
|
+
> This command is intended for debugging and special operations,
|
51
|
+
> such as changing your keyspace layout. Don't use KEYS in your
|
52
|
+
> regular application code. If you're looking for a way to find
|
53
|
+
> keys in a subset of your keyspace, consider using sets.
|
54
|
+
EOWARNING
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
39
58
|
def keys
|
40
59
|
@ui.debug "REDIS: #{@redis.client.id} KEYS *"
|
41
60
|
@redis.keys('*').to_enum
|
data/lib/redis-copy/version.rb
CHANGED
data/redis-copy.gemspec
CHANGED
@@ -16,6 +16,10 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.authors = authors_and_emails.map(&:first)
|
17
17
|
spec.email = authors_and_emails.map(&:last)
|
18
18
|
spec.summary = 'Copy the contents of one redis db to another'
|
19
|
+
spec.description = 'A command-line utility built for copying the ' +
|
20
|
+
'contents of one redis db to another over a ' +
|
21
|
+
'network. Supports all data types, persists ttls, ' +
|
22
|
+
'and attempts to be as efficient as possible.'
|
19
23
|
spec.homepage = 'https://github.com/yaauie/redis-copy'
|
20
24
|
spec.license = 'MIT'
|
21
25
|
|
@@ -3,7 +3,7 @@ require 'redis-copy'
|
|
3
3
|
|
4
4
|
describe RedisCopy::KeyEmitter::Default do
|
5
5
|
let(:redis) { double }
|
6
|
-
let(:ui) { double }
|
6
|
+
let(:ui) { double.as_null_object }
|
7
7
|
let(:instance) { RedisCopy::KeyEmitter::Default.new(redis, ui)}
|
8
8
|
let(:connection_uri) { 'redis://12.34.56.78:9000/15' }
|
9
9
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-copy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -91,7 +91,9 @@ dependencies:
|
|
91
91
|
- - ! '>='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
|
-
description:
|
94
|
+
description: A command-line utility built for copying the contents of one redis db
|
95
|
+
to another over a network. Supports all data types, persists ttls, and attempts
|
96
|
+
to be as efficient as possible.
|
95
97
|
email:
|
96
98
|
- ryan@yaauie.com
|
97
99
|
executables:
|