Class: Redis::Dump

Inherits:
Object
  • Object
show all
Extended by:
ClassMethods
Defined in:
lib/redis/dump.rb,
lib/redis/dump/version.rb

Defined Under Namespace

Modules: ClassMethods Classes: Problem

Constant Summary collapse

VALID_TYPES =
['string', 'set', 'list', 'zset', 'hash', 'none'].freeze
VERSION =
"0.6.1"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ClassMethods

dump_strings, set_value, set_value_hash, set_value_list, set_value_none, set_value_set, set_value_string, set_value_zset, stringify, stringify_hash, stringify_list, stringify_none, stringify_set, stringify_string, stringify_zset, type, value, value_hash, value_list, value_none, value_set, value_string, value_zset

Constructor Details

#initialize(dbs = nil, uri = "redis://#{Redis::Dump.host}:#{Redis::Dump.port}") ⇒ Dump

Returns a new instance of Dump.



47
48
49
50
51
52
53
54
55
# File 'lib/redis/dump.rb', line 47

def initialize(dbs=nil, uri="redis://#{Redis::Dump.host}:#{Redis::Dump.port}")
  @redis_connections = {}
  @uri = uri
  unless dbs.nil?
    @dbs = Range === dbs ? dbs : (dbs..dbs)
    @dbs = (@dbs.first.to_i..@dbs.last.to_i) # enforce integers
    @dbs.to_a.each { |db| redis(db) } # open_all_connections
  end
end

Class Attribute Details

.chunk_sizeObject

Returns the value of attribute chunk_size.



29
30
31
# File 'lib/redis/dump.rb', line 29

def chunk_size
  @chunk_size
end

.debugObject

Returns the value of attribute debug.



29
30
31
# File 'lib/redis/dump.rb', line 29

def debug
  @debug
end

.encoderObject

Returns the value of attribute encoder.



29
30
31
# File 'lib/redis/dump.rb', line 29

def encoder
  @encoder
end

.hostObject

Returns the value of attribute host.



29
30
31
# File 'lib/redis/dump.rb', line 29

def host
  @host
end

.parserObject

Returns the value of attribute parser.



29
30
31
# File 'lib/redis/dump.rb', line 29

def parser
  @parser
end

.passwordObject

Returns the value of attribute password.



29
30
31
# File 'lib/redis/dump.rb', line 29

def password
  @password
end

.portObject

Returns the value of attribute port.



29
30
31
# File 'lib/redis/dump.rb', line 29

def port
  @port
end

.safeObject

Returns the value of attribute safe.



29
30
31
# File 'lib/redis/dump.rb', line 29

def safe
  @safe
end

.timeoutObject

Returns the value of attribute timeout.



29
30
31
# File 'lib/redis/dump.rb', line 29

def timeout
  @timeout
end

.with_base64Object

Returns the value of attribute with_base64.



29
30
31
# File 'lib/redis/dump.rb', line 29

def with_base64
  @with_base64
end

.with_optimizationsObject

Returns the value of attribute with_optimizations.



29
30
31
# File 'lib/redis/dump.rb', line 29

def with_optimizations
  @with_optimizations
end

Instance Attribute Details

#dbsObject

Returns the value of attribute dbs.



45
46
47
# File 'lib/redis/dump.rb', line 45

def dbs
  @dbs
end

#redis_connectionsObject (readonly)

Returns the value of attribute redis_connections.



46
47
48
# File 'lib/redis/dump.rb', line 46

def redis_connections
  @redis_connections
end

#uriObject

Returns the value of attribute uri.



45
46
47
# File 'lib/redis/dump.rb', line 45

def uri
  @uri
end

Class Method Details

.check_utf8=(check) ⇒ Object



39
40
41
42
43
# File 'lib/redis/dump.rb', line 39

def check_utf8=(check)
  if check == false
    @parser = Yajl::Parser.new(:check_utf8 => false)
  end
end

.ld(msg) ⇒ Object



33
34
35
# File 'lib/redis/dump.rb', line 33

def ld(msg)
  STDERR.puts "#%.4f: %s" % [Time.now.utc.to_f, msg] if debug
end

.le(msg) ⇒ Object



30
31
32
# File 'lib/redis/dump.rb', line 30

def le(msg)
  STDERR.puts "#%.4f: %s" % [Time.now.utc.to_f, msg]
end

.memory_usageObject



36
37
38
# File 'lib/redis/dump.rb', line 36

def memory_usage
  `ps -o rss= -p #{Process.pid}`.to_i # in kb
end

Instance Method Details

#connect(this_uri) ⇒ Object



59
60
61
62
63
64
65
66
67
# File 'lib/redis/dump.rb', line 59

def connect(this_uri)
  self.class.ld 'CONNECT: ' << this_uri
  opts = {
    :url => this_uri
  }
  opts[:password] = Redis::Dump.password if Redis::Dump.password
  opts[:timeout] = Redis::Dump.timeout if Redis::Dump.timeout
  Redis.new **opts
end

#dump(filter = nil) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/redis/dump.rb', line 75

def dump filter=nil
  filter ||= '*'
  entries = []
  each_database do |redis|
    chunk_entries = []
    Redis::Dump.ld "[db#{redis.connection[:db]}] Memory before: #{Redis::Dump.memory_usage}kb"
    dump_keys = redis.keys(filter)
    dump_keys_size = dump_keys.size
    Redis::Dump.ld "[db#{redis.connection[:db]}] Dumping #{dump_keys_size} keys: #{dump_keys.join(', ')}"
    dump_keys.each_with_index do |key,idx|
      entry, idxplus = key, idx+1
      if block_given?
        chunk_entries << entry
        process_chunk idx, dump_keys_size do |count|
          Redis::Dump.ld " dumping #{chunk_entries.size} (#{count}) from #{redis.connection[:id]}"
          output_buffer = []
          chunk_entries = chunk_entries.select do |key|
            type = Redis::Dump.type(redis, key)
            if self.class.with_optimizations && type == 'string'
              true
            else
              output_buffer.push self.class.encoder.encode(Redis::Dump.dump(redis, key, type))
              false
            end
          end
          unless output_buffer.empty?
            yield output_buffer
          end
          unless chunk_entries.empty?
            yield Redis::Dump.dump_strings(redis, chunk_entries) { |obj| self.class.encoder.encode(obj) }
          end
          output_buffer.clear
          chunk_entries.clear
        end
      else
        entries << self.class.encoder.encode(Redis::Dump.dump(redis, entry))
      end
    end

    Redis::Dump.ld "[db#{redis.connection[:db]}] Memory after: #{Redis::Dump.memory_usage}kb"
  end
  entries
end

#each_databaseObject



69
70
71
72
73
# File 'lib/redis/dump.rb', line 69

def each_database
  @redis_connections.keys.sort.each do |redis_uri|
    yield redis_connections[redis_uri]
  end
end

#load(string_or_stream, &each_record) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/redis/dump.rb', line 152

def load(string_or_stream, &each_record)
  count = 0
  Redis::Dump.ld " LOAD SOURCE: #{string_or_stream}"
  Redis::Dump.parser.parse string_or_stream do |obj|
    unless @dbs.member?(obj["db"].to_i)
      Redis::Dump.ld "db out of range: #{obj["db"]}"
      next
    end
    this_redis = redis(obj["db"])
    Redis::Dump.ld "load[#{this_redis.hash}, #{obj}]"
    if each_record.nil?
      if Redis::Dump.safe && this_redis.exists(obj['key'])
        Redis::Dump.ld " record exists (no change)"
        next
      end
      begin
        val, type = obj['value'], obj['type']
        Redis::Dump.ld " > load `#{val}`"
        if Redis::Dump.with_base64 && type === 'string'
          Redis::Dump.ld " > load+decode64 for `#{val}`"
          val = Base64.decode64 val
        end
        ret = Redis::Dump.set_value this_redis, obj['key'], type, val, obj['ttl']
      rescue => ex
        Redis::Dump.le '(key: %s) %s' % [obj['key'], ex.message]
      end
    else
      each_record.call obj
    end
    count += 1
  end
  count
end

#redis(db) ⇒ Object



56
57
58
# File 'lib/redis/dump.rb', line 56

def redis(db)
  redis_connections["#{uri}/#{db}"] ||= connect("#{uri}/#{db}")
end

#report(filter = '*') ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/redis/dump.rb', line 125

def report filter='*'
  values = []
  total_size, dbs = 0, {}
  each_database do |redis|
    chunk_entries = []
    dump_keys = redis.keys(filter)
    dump_keys_size = dump_keys.size
    dump_keys.each_with_index do |key,idx|
      entry, idxplus = Redis::Dump.report(redis, key), idx+1
      chunk_entries << entry
      process_chunk idx, dump_keys_size do |count|
        Redis::Dump.ld " reporting on #{chunk_entries.size} (#{idxplus}) from #{redis.connection[:id]}"
        chunk_entries.each do |e|
          puts record if obj.global.verbose >= 1
          dbs[e['db']] ||= 0
          dbs[e['db']] += e['size']
          total_size += e['size']
        end
        chunk_entries.clear
      end
    end
  end
  puts dbs.keys.sort.collect { |db| "  db#{db}: #{dbs[db].to_bytes}" }
  puts "total: #{total_size.to_bytes}"
  values
end