lib/backup/database/redis.rb in backup-3.11.0 vs lib/backup/database/redis.rb in backup-4.0.0rc1
- old
+ new
@@ -3,74 +3,125 @@
module Backup
module Database
class Redis < Base
class Error < Backup::Error; end
+ MODES = [:copy, :sync]
+
##
- # Name of the redis dump file.
+ # Mode of operation.
#
- # This is set in `redis.conf` as `dbfilename`.
- # This must be set to the name of that file without the `.rdb` extension.
- # Default: 'dump'
- attr_accessor :name
+ # [:copy]
+ # Copies the redis dump file specified by {#rdb_path}.
+ # This data will be current as of the last RDB Snapshot
+ # performed by the server (per your redis.conf settings).
+ # You may set {#invoke_save} to +true+ to have Backup issue
+ # a +SAVE+ command to update the dump file with the current
+ # data before performing the copy.
+ #
+ # [:sync]
+ # Performs a dump of your redis data using +redis-cli --rdb -+.
+ # Redis implements this internally using a +SYNC+ command.
+ # The operation is analogous to requesting a +BGSAVE+, then having the
+ # dump returned. This mode is capable of dumping data from a local or
+ # remote server. Requires Redis v2.6 or better.
+ #
+ # Defaults to +:copy+.
+ attr_accessor :mode
##
- # Path to the redis dump file.
+ # Full path to the redis dump file.
#
- # This is set in `redis.conf` as `dir`.
- attr_accessor :path
+ # Required when {#mode} is +:copy+.
+ attr_accessor :rdb_path
##
- # Password for the redis-cli utility to perform the `SAVE` command
- # if +invoke_save+ is set `true`.
- attr_accessor :password
+ # Perform a +SAVE+ command using the +redis-cli+ utility
+ # before copying the dump file specified by {#rdb_path}.
+ #
+ # Only valid when {#mode} is +:copy+.
+ attr_accessor :invoke_save
##
- # Connectivity options for the +invoke_save+ option.
+ # Connectivity options for the +redis-cli+ utility.
attr_accessor :host, :port, :socket
##
- # Determines whether Backup should invoke the `SAVE` command through
- # the `redis-cli` utility to persist the most recent data before
- # copying the dump file specified by +path+ and +name+.
- attr_accessor :invoke_save
+ # Password for the +redis-cli+ utility.
+ attr_accessor :password
##
- # Additional "redis-cli" options
+ # Additional options for the +redis-cli+ utility.
attr_accessor :additional_options
def initialize(model, database_id = nil, &block)
super
instance_eval(&block) if block_given?
- @name ||= 'dump'
+ @mode ||= :copy
+
+ unless MODES.include?(mode)
+ raise Error, "'#{ mode }' is not a valid mode"
+ end
+
+ if mode == :copy && rdb_path.nil?
+ raise Error, '`rdb_path` must be set when `mode` is :copy'
+ end
end
##
- # Copies and optionally compresses the Redis dump file to the
- # +dump_path+ using the +dump_filename+.
+ # Performs the dump based on {#mode} and stores the Redis dump file
+ # to the +dump_path+ using the +dump_filename+.
#
# <trigger>/databases/Redis[-<database_id>].rdb[.gz]
- #
- # If +invoke_save+ is true, `redis-cli SAVE` will be invoked.
def perform!
super
- invoke_save! if invoke_save
- copy!
+ case mode
+ when :sync
+ # messages output by `redis-cli --rdb` on $stderr
+ Logger.configure do
+ ignore_warning(/Transfer finished with success/)
+ ignore_warning(/SYNC sent to master/)
+ end
+ sync!
+ when :copy
+ save! if invoke_save
+ copy!
+ end
log!(:finished)
end
private
- def invoke_save!
- resp = run(redis_save_cmd)
+ def sync!
+ pipeline = Pipeline.new
+ dump_ext = 'rdb'
+
+ pipeline << "#{ redis_cli_cmd } --rdb -"
+
+ model.compressor.compress_with do |command, ext|
+ pipeline << command
+ dump_ext << ext
+ end if model.compressor
+
+ pipeline << "#{ utility(:cat) } > " +
+ "'#{ File.join(dump_path, dump_filename) }.#{ dump_ext }'"
+
+ pipeline.run
+
+ unless pipeline.success?
+ raise Error, "Dump Failed!\n" + pipeline.error_messages
+ end
+ end
+
+ def save!
+ resp = run("#{ redis_cli_cmd } SAVE")
unless resp =~ /OK$/
raise Error, <<-EOS
- Could not invoke the Redis SAVE command.
- Command was: #{ redis_save_cmd }
+ Failed to invoke the `SAVE` command
Response was: #{ resp }
EOS
end
rescue Error
@@ -82,31 +133,30 @@
end
raise
end
def copy!
- src_path = File.join(path, name + '.rdb')
- unless File.exist?(src_path)
+ unless File.exist?(rdb_path)
raise Error, <<-EOS
Redis database dump not found
- File path was #{ src_path }
+ `rdb_path` was '#{ rdb_path }'
EOS
end
dst_path = File.join(dump_path, dump_filename + '.rdb')
if model.compressor
model.compressor.compress_with do |command, ext|
- run("#{ command } -c '#{ src_path }' > '#{ dst_path + ext }'")
+ run("#{ command } -c '#{ rdb_path }' > '#{ dst_path + ext }'")
end
else
- FileUtils.cp(src_path, dst_path)
+ FileUtils.cp(rdb_path, dst_path)
end
end
- def redis_save_cmd
+ def redis_cli_cmd
"#{ utility('redis-cli') } #{ password_option } " +
- "#{ connectivity_options } #{ user_options } SAVE"
+ "#{ connectivity_options } #{ user_options }"
end
def password_option
"-a '#{ password }'" if password
end
@@ -121,21 +171,9 @@
end
def user_options
Array(additional_options).join(' ')
end
-
- attr_deprecate :utility_path, :version => '3.0.21',
- :message => 'Use Backup::Utilities.configure instead.',
- :action => lambda {|klass, val|
- Utilities.configure { redis_cli val }
- }
-
- attr_deprecate :redis_cli_utility, :version => '3.3.0',
- :message => 'Use Backup::Utilities.configure instead.',
- :action => lambda {|klass, val|
- Utilities.configure { redis_cli val }
- }
end
end
end