Skip to content

Commit 3a41824

Browse files
committed
Add a base RDB::Dumper module and implement an AOF dumper.
This version of `RDB::Dumpers::AOF` is actually a basic one, we should improve it to leverage the variadic version of commands such as LPUSH, SADD and ZADD to produce a more compact (and faster to ingest) AOF file when generating a file for Redis >= 2.4.
1 parent a58eec7 commit 3a41824

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
*.gem
2+
*.aof

examples/aof_dumper.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
$:.unshift File.expand_path('../lib', File.dirname(__FILE__))
2+
3+
require 'rdb'
4+
5+
source = 'test/rdb/database_multiple_logical_dbs.rdb'
6+
destination = File.basename(source, '.rdb') + '.aof'
7+
8+
RDB::Dumpers::AOF.new(source, destination).dump

lib/rdb.rb

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
require 'rdb/callbacks'
77
require 'rdb/reader-state'
88
require 'rdb/reader'
9+
require 'rdb/dumper'
10+
require 'rdb/dumpers/aof'

lib/rdb/dumper.rb

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module RDB
2+
module Dumper
3+
include ReaderCallbacks
4+
5+
def initialize(source, destination, options = {})
6+
@source = source
7+
@destination = destination
8+
@options = options
9+
@output = nil
10+
end
11+
12+
def <<(buffer)
13+
@output << buffer unless @output.nil?; nil
14+
end
15+
16+
def with_streams(&block)
17+
input = open(@source, 'rb') unless @source.kind_of? IO
18+
output = open(@destination, 'wb') unless @source.kind_of? IO
19+
20+
begin
21+
block.call(input, output)
22+
rescue
23+
input.close
24+
output.close
25+
end
26+
end
27+
28+
def dump
29+
raise RuntimeException, 'Output stream already opened' if @output
30+
31+
with_streams do |input, output|
32+
@output = output
33+
Reader.read(input, callbacks: self)
34+
end
35+
end
36+
end
37+
end

lib/rdb/dumpers/aof.rb

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
module RDB
2+
module Dumpers
3+
#
4+
# TODO: we should actually make the dumper configurable with the
5+
# level of compatibility of the AOF file being produced against
6+
# a specific Redis version. For example PEXPIREAT is unsupported
7+
# on Redis <= 2.4. Also, Redis >= 2.4 can ingest AOF files using
8+
# variadic LPUSH, SADD and ZADD.
9+
#
10+
class AOF
11+
include Dumper
12+
13+
def start_database(database)
14+
self << serialize_command(:select, [database])
15+
end
16+
17+
def pexpireat(key, expiration, state)
18+
self << serialize_command(:pexpireat, [key, expiration])
19+
end
20+
21+
def set(key, value, state)
22+
self << serialize_command(:set, [key, value])
23+
end
24+
25+
def rpush(key, value, state)
26+
self << serialize_command(:rpush, [key, value])
27+
end
28+
29+
def sadd(key, value, state)
30+
self << serialize_command(:sadd, [key, value])
31+
end
32+
33+
def zadd(key, score, value, state)
34+
self << serialize_command(:zadd, [key, score, value])
35+
end
36+
37+
def hset(key, field, value, state)
38+
self << serialize_command(:hset, [key, field, value])
39+
end
40+
41+
def serialize_command(command, arguments)
42+
buffer = "*#{arguments.length + 1}\r\n$#{command.length}\r\n#{command.upcase}\r\n"
43+
buffer << arguments.map { |arg| "$#{arg.to_s.length}\r\n#{arg}\r\n" }.join
44+
end
45+
end
46+
end
47+
end

0 commit comments

Comments
 (0)