Support getting the raw Redis command
Support getting the raw Redis command
Description
-
I'm developing a Redis Real-time Backup using
PSYNC. Simply like this: -
But I realize there is no way to get the raw command from
Event, so I have to switch-case to check each command type and then build the raw command. It's not a nice way to do that. -
So, I'm looking for a way to get the raw command from
Eventin Redis. Is there any way to do that?
Sample code:
- Currently:
public class RealtimeBackup {
public static void main(String[] args) {
try {
Replicator r;
r = new RedisReplicator("redis://127.0.0.1:6379");
r.addEventListener((replicator, event) -> {
handleEvent(event);
});
r.open();
} catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
}
private static void handleEvent(Event event) {
// log the raw command to backup
// System.out.println(event);
// switch-case instance of the command
if (event instanceof MSetCommand) {
MSetCommand mSetCommand = (MSetCommand) event;
// convert key-value pairs (Map<byte[], byte[]>) to string
StringBuilder sb = new StringBuilder();
mSetCommand.getKv().forEach((k, v) -> {
sb.append(new String(k)).append(" ").append(new String(v)).append(" ");
});
System.out.printf("MSET %s\n", sb);
}
if (event instanceof SetCommand) {
SetCommand setCommand = (SetCommand) event;
String key = new String(setCommand.getKey());
String value = new String(setCommand.getValue());
ExistType existType = setCommand.getExistType();
XATType xatType = setCommand.getXatType();
Long xatValue = setCommand.getXatValue();
boolean keepTtl = setCommand.getKeepTtl();
StringBuilder sb = new StringBuilder();
sb.append("SET ").append(key).append(" ").append(value).append(" ");
if (existType != null && existType != ExistType.NONE) {
sb.append(existType).append(" ");
}
// if (get) {
// sb.append("GET ").append(" ");
// }
if (keepTtl) {
sb.append("KEEPTTL").append(" ");
} else if (xatType != null && xatType != XATType.NONE && xatValue != null) {
sb.append(xatType.name()).append(" ").append(xatValue).append(" ");
}
System.out.println(sb.toString().trim());
}
// ... and the other commands
}
}
- Expected:
public class RealtimeBackup {
public static void main(String[] args) {
try {
Replicator r;
r = new RedisReplicator("redis://127.0.0.1:6379");
r.addEventListener((replicator, event) -> {
handleEvent(event);
});
r.open();
} catch (URISyntaxException | IOException e) {
throw new RuntimeException(e);
}
}
private static void handleEvent(Event event) {
// log the raw command to backup
String rawCommand = event.getRawCommand();
System.out.println(rawCommand);
}
}
cc @leonchen83 do you have any ideas for that?
Replicator r;
r = new RedisReplicator("redis://127.0.0.1:6379");
// ignore PING REPLCONF GETACK
r.addCommandParser(CommandName.name("PING"), new PingParser());
r.addCommandParser(CommandName.name("REPLCONF"), new ReplConfParser());
//
r.addCommandParser(CommandName.name("APPEND"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HMSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXPIRE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXPIREAT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GETSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HSETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MSETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PSETEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETRANGE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HDEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPUSHX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LRem"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPUSHX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RENAME"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("INCR"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DECR"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("INCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DECRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PERSIST"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SELECT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FLUSHALL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FLUSHDB"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HINCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZINCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFCOUNT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFMERGE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SDIFFSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SINTERSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SUNIONSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZINTERSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZUNIONSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BRPOPLPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LINSERT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RENAMENX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RESTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PEXPIRE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PEXPIREAT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GEOADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EVAL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EVALSHA"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SCRIPT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PUBLISH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BITOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BITFIELD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETBIT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SREM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("UNLINK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SWAPDB"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MULTI"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXEC"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYSCORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYRANK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYLEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LTRIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SORT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPOPLPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZPOPMIN"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZPOPMAX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XACK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XCLAIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XDEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XGROUP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XTRIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XSETID"), new DefaultCommandParser());
// since redis 6.2
r.addCommandParser(CommandName.name("COPY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BLMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZDIFFSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GEOSEARCHSTORE"), new DefaultCommandParser());
// since redis 7.0
r.addCommandParser(CommandName.name("SPUBLISH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FUNCTION"), new DefaultCommandParser());
r.addEventListener(new EventListener() {
@Override
public void onEvent(Replicator replicator, Event event) {
if (event instanceof DefaultCommand) {
DefaultCommand cmd = (DefaultCommand) event;
System.out.println(cmd.getCommand());
System.out.println(cmd.getArgs());
}
}
});
r.open();
Oh, let me give it a try. Thank you, @leonchen83
I have another question. I want to start on full sync mode PSYNC ? -1. However, I am confused about handling this event type. Many sub-classes inherit KeyValuePair, while I want to get the raw data.
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- REPLCONF ip-address 127.0.0.1
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- OK
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- REPLCONF capa eof
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- OK
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- REPLCONF capa psync2
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- OK
[main] INFO com.moilioncircle.redis.replicator.RedisSocketReplicator -- PSYNC ? -1
service.Backup -- db: 0, key: test_4314, value: [B@117bcfdc, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_4999, value: [B@73a19967, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_350, value: [B@5e746d37, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_7616, value: [B@6e1b9411, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_6404, value: [B@21d1b321, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_5865, value: [B@5ec46cdd, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_1046, value: [B@2324bfe7, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_2576, value: [B@112d1c8e, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_5808, value: [B@3d49fd31, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_4904, value: [B@4016ccc1, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_106, value: [B@46cb98a3, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_1066, value: [B@3ffb3598, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_7566, value: [B@4da9f723, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_5206, value: [B@3b2f4a93, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_7089, value: [B@213bd3d5, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_4205, value: [B@470a659f, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_3565, value: [B@451882b2, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_4702, value: [B@4a23350, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_6710, value: [B@7b78ed6a, expiredType: NONE, expiredValue: null
service.Backup -- db: 0, key: test_4751, value: [B@6fca5907, expiredType: NONE, expiredValue: null
service.Backup -- db: 2, key: k3, value: [B@6ec65b5e, expiredType: NONE, expiredValue: null
service.Backup -- db: 2, key: k1, value: [B@7bebcd65, expiredType: NONE, expiredValue: null
service.Backup -- db: 2, key: k9, value: [B@47447ccf, expiredType: NONE, expiredValue: null
this.replicator = new RedisReplicator(redisUri);
this.replicator.addEventListener(
(r, event) -> {
if (event instanceof CustomCommand cmd) {
handleEvent(cmd);
} else if (event instanceof KeyValuePair kv) {
handleKeyValuePair(kv);
}
});
Hi
Using different RdbVisitor will result in different KeyValuePair events
for example
if you set
replicator.setRdbVisitor(new DumpRdbVisitor(replicator));
you will accept DumpKeyValuePair event, this RdbVisitor can parse rdb to redis dump format. you can use redis RESOTRE command directly migrate source date to target redis.
if you set ValueIterableRdbVisitor
replicator.setRdbVisitor(new new ValueIterableRdbVisitor(replicator));
r.addEventListener(new ValueIterableEventListener(new EventListener() {
@Override
public void onEvent(Replicator replicator, Event event) {
if (event instanceof BatchedKeyValuePair<?, ?>) {
// do something
}
}
}));
you will accept BatchedKey**Value**Pair events that can split large key to small chunks
if you don't set any RdbVisitor that equals set DefaultRdbVisitor
you will accept Key**Value**Pair. this can parse rdb to Human-readable information
is there any way to parse the raw commands to rdb file format?
When starting the application, I will first dump the data to the dump.rdb file. Then I will watch events and add commands to the incr_x file.
After that, I will merge the incr_x file to the dump.rdb file.
But I don't know how to do that.
the example incr_1.txt file:
SELECT 0
APPEND key1 Hello
SET key2 value1
SET key3 value2 PXAT 1717143998448
MSET key4 value3 key5 value4
HSET hash1 field1 value1 field2 value2
HSET hash2 field1 value1
LPUSH list1 initial_value
LSET list1 0 new_value
SET key9 new_value
HSETNX hash3 field value
MSETNX key10 value1 key11 value2
SET key12 value PXAT 1717143941725
SETNX key13 value
SETRANGE key14 6 Redis
DEL key12
LPUSH list3 value1 value2
RPUSH list7 value1 value2
INCR counter1
DECR counter2
INCRBY counter3 5
SELECT 1
FLUSHALL
FLUSHDB
HINCRBY hash5 field 5
ZINCRBY zset4 1 member1
you can use this tool to generate an aof-preamble rdb file. redis can read this file directly.
aof-preamble file can split two part. rdb part and aof part
following is cods snapshot
final OutputStream out = new BufferedOutputStream(new FileOutputStream(new File("/path/to/appendonly.aof")));
final RawByteListener rawByteListener = new RawByteListener() {
@Override
public void handle(byte... rawBytes) {
try {
out.write(rawBytes);
} catch (IOException ignore) {
}
}
};
final Replicator replicator = new RedisReplicator("redis://127.0.0.1:6379");
replicator.setRdbVisitor(new SkipRdbVisitor(replicator));
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
replicator.removeRawByteListener(rawByteListener);
Replicators.closeQuietly(replicator);
}));
replicator.addEventListener(new EventListener() {
@Override
public void onEvent(Replicator replicator, Event event) {
if (event instanceof PreRdbSyncEvent) {
replicator.addRawByteListener(rawByteListener);
}
}
});
replicator.open();
The code backs up only once. I tried adding some keys, however, when I restored the dump.rdb into another Redis, I didn't see them.
That means there are only snapshots, and no incremental
:(
try change target redis parameters
appendonly yes
aof-use-rdb-preamble yes
and change file name dump.rdb to appendonly.aof
try change target redis parameters
appendonly yes aof-use-rdb-preamble yesand change file name
dump.rdbtoappendonly.aof
Oh sorry, my fault.
I want to note that, the main reason I built an app called redis real-time backup was because I didn't want to enable append-only file.
Our application uses Redis as a database (not only for caching), which requires performance and reliability. So we need to back up in real-time without an append-only file enabled, which impacts performance significantly.
if you don't want to change parameters of target redis
you could use following code to restore above aof-preamble file
public static void restore(File file, String targetUri) throws IOException, URISyntaxException {
RedisURI turi = new RedisURI(targetUri);
final ExampleClient target = new ExampleClient(turi.getHost(), turi.getPort());
Configuration tconfig = Configuration.valueOf(turi);
if (tconfig.getAuthPassword() != null) {
Object auth = target.send(AUTH, tconfig.getAuthPassword().getBytes());
System.out.println("AUTH:" + auth);
}
final AtomicInteger dbnum = new AtomicInteger(-1);
Replicator r = dress(new RedisReplicator(file, FileType.MIXED, Configuration.defaultSetting()));
r.addEventListener(new EventListener() {
@Override
public void onEvent(Replicator replicator, Event event) {
// function since redis 7.0
if (event instanceof DumpFunction) {
DumpFunction dfn = (DumpFunction) event;
Object r = target.restoreFunction(dfn.getSerialized(), true);
System.out.println(r);
}
// key value
if (event instanceof DumpKeyValuePair) {
DumpKeyValuePair dkv = (DumpKeyValuePair) event;
// Step1: select db
DB db = dkv.getDb();
int index;
if (db != null && (index = (int) db.getDbNumber()) != dbnum.get()) {
target.send(SELECT, toByteArray(index));
dbnum.set(index);
System.out.println("SELECT:" + index);
}
// Step2: restore dump data
if (dkv.getExpiredMs() == null) {
Object r = target.restore(dkv.getKey(), 0L, dkv.getValue(), true);
System.out.println(r);
} else {
long ms = dkv.getExpiredMs() - System.currentTimeMillis();
if (ms <= 0) return;
Object r = target.restore(dkv.getKey(), ms, dkv.getValue(), true);
System.out.println(r);
}
}
// incremental commands
if (event instanceof DefaultCommand) {
// Step3: sync aof command
DefaultCommand dc = (DefaultCommand) event;
Object r = target.send(dc.getCommand(), dc.getArgs());
System.out.println(r);
}
}
});
r.addCloseListener(new CloseListener() {
@Override
public void handle(Replicator replicator) {
target.close();
}
});
r.open();
}
public static Replicator dress(Replicator r) {
r.setRdbVisitor(new DumpRdbVisitor(r));
// ignore PING REPLCONF GETACK
r.addCommandParser(CommandName.name("PING"), new PingParser());
r.addCommandParser(CommandName.name("REPLCONF"), new ReplConfParser());
//
r.addCommandParser(CommandName.name("APPEND"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HMSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXPIRE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXPIREAT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GETSET"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HSETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MSETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PSETEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETNX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETRANGE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HDEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LPUSHX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LRem"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPUSHX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RENAME"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("INCR"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DECR"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("INCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("DECRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PERSIST"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SELECT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FLUSHALL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FLUSHDB"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("HINCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZINCRBY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFCOUNT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PFMERGE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SDIFFSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SINTERSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SUNIONSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZINTERSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZUNIONSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BRPOPLPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LINSERT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RENAMENX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RESTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PEXPIRE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PEXPIREAT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GEOADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EVAL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EVALSHA"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SCRIPT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("PUBLISH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BITOP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BITFIELD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SETBIT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SREM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("UNLINK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SWAPDB"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("MULTI"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("EXEC"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYSCORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYRANK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZREMRANGEBYLEX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LTRIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("SORT"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("RPOPLPUSH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZPOPMIN"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZPOPMAX"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XACK"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XADD"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XCLAIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XDEL"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XGROUP"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XTRIM"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("XSETID"), new DefaultCommandParser());
// since redis 6.2
r.addCommandParser(CommandName.name("COPY"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("LMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("BLMOVE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("ZDIFFSTORE"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("GEOSEARCHSTORE"), new DefaultCommandParser());
// since redis 7.0
r.addCommandParser(CommandName.name("SPUBLISH"), new DefaultCommandParser());
r.addCommandParser(CommandName.name("FUNCTION"), new DefaultCommandParser());
return r;
}
/*
* Jedis is not a reliable redis client.
* For simplicity we use Jedis to show this example.
* In production you need to replace following code to yours.
*/
public static class ExampleClient implements Closeable {
private Jedis jedis;
public ExampleClient(final String host, final int port) {
DefaultJedisClientConfig.Builder config = DefaultJedisClientConfig.builder();
config.timeoutMillis(10000);
this.jedis = new Jedis(new HostAndPort(host, port), config.build());
}
public Object send(Protocol.Command cmd, final byte[]... args) {
Object r = jedis.sendCommand(cmd, args);
if (r instanceof byte[]) {
return Strings.toString(r);
} else {
return r;
}
}
public Object send(final byte[] cmd, final byte[]... args) {
return send(Protocol.Command.valueOf(Strings.toString(cmd).toUpperCase()), args);
}
public Object restore(byte[] key, long expired, byte[] dumped, boolean replace) {
if (!replace) {
return jedis.restore(key, expired, dumped);
} else {
return jedis.restore(key, expired, dumped, RestoreParams.restoreParams().replace());
}
}
public Object restoreFunction(byte[] dumped, boolean replace) {
if (!replace) {
return jedis.functionRestore(dumped, FunctionRestorePolicy.APPEND);
} else {
return jedis.functionRestore(dumped, FunctionRestorePolicy.REPLACE);
}
}
@Override
public void close() {
if (jedis != null) {
jedis.close();
}
}
}
restore(new File("/path/to/appendonly.aof"), "redis://target:6379")
more details refer to MigrationExample.java
it can directly generate rdb but you should very familiar rdb format, and you could use BaseRdbEncoder.java to generate rdb