Skip to content

Commit

Permalink
RESTORE with REPLACE option implementation (#1743)
Browse files Browse the repository at this point in the history
  • Loading branch information
sazzad16 committed Jun 3, 2018
1 parent 42b21ca commit d1fb17c
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 29 deletions.
2 changes: 1 addition & 1 deletion hbase-formatter.xml
Expand Up @@ -255,7 +255,7 @@
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryClient.java
Expand Up @@ -997,6 +997,10 @@ public void restore(final byte[] key, final int ttl, final byte[] serializedValu
sendCommand(RESTORE, key, toByteArray(ttl), serializedValue);
}

public void restoreReplace(final byte[] key, final int ttl, final byte[] serializedValue) {
sendCommand(RESTORE, key, toByteArray(ttl), serializedValue, Keyword.REPLACE.raw);
}

public void pexpire(final byte[] key, final long milliseconds) {
sendCommand(PEXPIRE, key, toByteArray(milliseconds));
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryJedis.java
Expand Up @@ -3441,6 +3441,13 @@ public String restore(final byte[] key, final int ttl, final byte[] serializedVa
return client.getStatusCodeReply();
}

@Override
public String restoreReplace(final byte[] key, final int ttl, final byte[] serializedValue) {
checkIsInMultiOrPipeline();
client.restoreReplace(key, ttl, serializedValue);
return client.getStatusCodeReply();
}

/**
* Set a timeout on the specified key. After the timeout the key will be automatically deleted by
* the server. A key with an associated timeout is said to be volatile in Redis terminology.
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/redis/clients/jedis/BinaryShardedJedis.java
Expand Up @@ -96,6 +96,12 @@ public String restore(final byte[] key, final int ttl, final byte[] serializedVa
return j.restore(key, ttl, serializedValue);
}

@Override
public String restoreReplace(final byte[] key, final int ttl, final byte[] serializedValue) {
Jedis j = getShard(key);
return j.restoreReplace(key, ttl, serializedValue);
}

@Override
public Long expire(final byte[] key, final int seconds) {
Jedis j = getShard(key);
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/redis/clients/jedis/Client.java
Expand Up @@ -839,14 +839,21 @@ public void sentinel(final String... args) {
sentinel(SafeEncoder.encodeMany(args));
}

@Override
public void dump(final String key) {
dump(SafeEncoder.encode(key));
}

@Override
public void restore(final String key, final int ttl, final byte[] serializedValue) {
restore(SafeEncoder.encode(key), ttl, serializedValue);
}

@Override
public void restoreReplace(final String key, final int ttl, final byte[] serializedValue) {
restoreReplace(SafeEncoder.encode(key), ttl, serializedValue);
}

public void pexpire(final String key, final long milliseconds) {
pexpire(SafeEncoder.encode(key), milliseconds);
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/redis/clients/jedis/Jedis.java
Expand Up @@ -3110,6 +3110,13 @@ public String restore(final String key, final int ttl, final byte[] serializedVa
return client.getStatusCodeReply();
}

@Override
public String restoreReplace(final String key, final int ttl, final byte[] serializedValue) {
checkIsInMultiOrPipeline();
client.restoreReplace(key, ttl, serializedValue);
return client.getStatusCodeReply();
}

@Override
public Long pexpire(final String key, final long milliseconds) {
checkIsInMultiOrPipeline();
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/redis/clients/jedis/PipelineBase.java
Expand Up @@ -1389,11 +1389,13 @@ public Response<Long> bitcount(final byte[] key, final long start, final long en
return getResponse(BuilderFactory.LONG);
}

@Override
public Response<byte[]> dump(final String key) {
getClient(key).dump(key);
return getResponse(BuilderFactory.BYTE_ARRAY);
}

@Override
public Response<byte[]> dump(final byte[] key) {
getClient(key).dump(key);
return getResponse(BuilderFactory.BYTE_ARRAY);
Expand Down Expand Up @@ -1473,16 +1475,30 @@ public Response<Long> pttl(final byte[] key) {
return getResponse(BuilderFactory.LONG);
}

@Override
public Response<String> restore(final String key, final int ttl, final byte[] serializedValue) {
getClient(key).restore(key, ttl, serializedValue);
return getResponse(BuilderFactory.STRING);
}

@Override
public Response<String> restore(final byte[] key, final int ttl, final byte[] serializedValue) {
getClient(key).restore(key, ttl, serializedValue);
return getResponse(BuilderFactory.STRING);
}

@Override
public Response<String> restoreReplace(final String key, final int ttl, final byte[] serializedValue) {
getClient(key).restoreReplace(key, ttl, serializedValue);
return getResponse(BuilderFactory.STRING);
}

@Override
public Response<String> restoreReplace(final byte[] key, final int ttl, final byte[] serializedValue) {
getClient(key).restoreReplace(key, ttl, serializedValue);
return getResponse(BuilderFactory.STRING);
}

public Response<Double> incrByFloat(final String key, final double increment) {
getClient(key).incrByFloat(key, increment);
return getResponse(BuilderFactory.DOUBLE);
Expand Down
57 changes: 31 additions & 26 deletions src/main/java/redis/clients/jedis/Protocol.java
Expand Up @@ -19,11 +19,11 @@

public final class Protocol {

private static final String ASK_RESPONSE = "ASK";
private static final String MOVED_RESPONSE = "MOVED";
private static final String CLUSTERDOWN_RESPONSE = "CLUSTERDOWN";
private static final String BUSY_RESPONSE = "BUSY";
private static final String NOSCRIPT_RESPONSE = "NOSCRIPT";
private static final String ASK_PREFIX = "ASK ";
private static final String MOVED_PREFIX = "MOVED ";
private static final String CLUSTERDOWN_PREFIX = "CLUSTERDOWN ";
private static final String BUSY_PREFIX = "BUSY ";
private static final String NOSCRIPT_PREFIX = "NOSCRIPT ";

public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 6379;
Expand Down Expand Up @@ -113,19 +113,19 @@ private static void processError(final RedisInputStream is) {
String message = is.readLine();
// TODO: I'm not sure if this is the best way to do this.
// Maybe Read only first 5 bytes instead?
if (message.startsWith(MOVED_RESPONSE)) {
if (message.startsWith(MOVED_PREFIX)) {
String[] movedInfo = parseTargetHostAndSlot(message);
throw new JedisMovedDataException(message, new HostAndPort(movedInfo[1],
Integer.parseInt(movedInfo[2])), Integer.parseInt(movedInfo[0]));
} else if (message.startsWith(ASK_RESPONSE)) {
} else if (message.startsWith(ASK_PREFIX)) {
String[] askInfo = parseTargetHostAndSlot(message);
throw new JedisAskDataException(message, new HostAndPort(askInfo[1],
Integer.parseInt(askInfo[2])), Integer.parseInt(askInfo[0]));
} else if (message.startsWith(CLUSTERDOWN_RESPONSE)) {
} else if (message.startsWith(CLUSTERDOWN_PREFIX)) {
throw new JedisClusterException(message);
} else if (message.startsWith(BUSY_RESPONSE)) {
} else if (message.startsWith(BUSY_PREFIX)) {
throw new JedisBusyException(message);
} else if (message.startsWith(NOSCRIPT_RESPONSE) ) {
} else if (message.startsWith(NOSCRIPT_PREFIX) ) {
throw new JedisNoScriptException(message);
}
throw new JedisDataException(message);
Expand Down Expand Up @@ -242,21 +242,22 @@ public static final byte[] toByteArray(final double value) {
}

public static enum Command implements ProtocolCommand {
PING, SET, GET, QUIT, EXISTS, DEL, UNLINK, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX,
DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX,
DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS,
HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP,
RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION,
SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK,
ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH,
SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBSUB, ZCOUNT, ZRANGEBYSCORE,
ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, ZLEXCOUNT,
ZRANGEBYLEX, ZREVRANGEBYLEX, ZREMRANGEBYLEX, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN,
INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH,
SETBIT, GETBIT, BITPOS, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT, BITCOUNT, BITOP,
SENTINEL, DUMP, RESTORE, PEXPIRE, PEXPIREAT, PTTL, INCRBYFLOAT, PSETEX, CLIENT, TIME, MIGRATE, HINCRBYFLOAT,
SCAN, HSCAN, SSCAN, ZSCAN, WAIT, CLUSTER, ASKING, PFADD, PFCOUNT, PFMERGE, READONLY, GEOADD, GEODIST,
GEOHASH, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, MODULE, BITFIELD, HSTRLEN, TOUCH, SWAPDB;
PING, SET, GET, QUIT, EXISTS, DEL, UNLINK, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX,
RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX,
MSET, MSETNX, DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET,
HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX,
LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER,
SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY,
ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP,
BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBSUB, ZCOUNT,
ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE,
ZLEXCOUNT, ZRANGEBYLEX, ZREVRANGEBYLEX, ZREMRANGEBYLEX, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE,
SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT,
DEBUG, BRPOPLPUSH, SETBIT, GETBIT, BITPOS, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG,
OBJECT, BITCOUNT, BITOP, SENTINEL, DUMP, RESTORE, PEXPIRE, PEXPIREAT, PTTL, INCRBYFLOAT,
PSETEX, CLIENT, TIME, MIGRATE, HINCRBYFLOAT, SCAN, HSCAN, SSCAN, ZSCAN, WAIT, CLUSTER, ASKING,
PFADD, PFCOUNT, PFMERGE, READONLY, GEOADD, GEODIST, GEOHASH, GEOPOS, GEORADIUS,
GEORADIUSBYMEMBER, MODULE, BITFIELD, HSTRLEN, TOUCH, SWAPDB;

private final byte[] raw;

Expand All @@ -271,7 +272,11 @@ public byte[] getRaw() {
}

public static enum Keyword {
AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, REWRITE, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME, GETNAME, SETNAME, LIST, MATCH, COUNT, PING, PONG, UNLOAD;
AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE,
PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES,
RESETSTAT, REWRITE, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME,
GETNAME, SETNAME, LIST, MATCH, COUNT, PING, PONG, UNLOAD, REPLACE;

public final byte[] raw;

Keyword() {
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/redis/clients/jedis/ShardedJedis.java
Expand Up @@ -82,6 +82,12 @@ public String restore(final String key, final int ttl, final byte[] serializedVa
return j.restore(key, ttl, serializedValue);
}

@Override
public String restoreReplace(final String key, final int ttl, final byte[] serializedValue) {
Jedis j = getShard(key);
return j.restoreReplace(key, ttl, serializedValue);
}

@Override
public Long expire(final String key, final int seconds) {
Jedis j = getShard(key);
Expand Down
Expand Up @@ -31,6 +31,8 @@ public interface BinaryJedisCommands {

String restore(byte[] key, int ttl, byte[] serializedValue);

String restoreReplace(byte[] key, int ttl, byte[] serializedValue);

Long expire(byte[] key, int seconds);

Long pexpire(byte[] key, long milliseconds);
Expand Down
Expand Up @@ -247,6 +247,12 @@ Response<Set<byte[]>> zrevrangeByLex(byte[] key, byte[] max, byte[] min,

Response<Long> pfcount(byte[] key);

Response<byte[]> dump(byte[] key);

Response<String> restore(byte[] key, int ttl, byte[] serializedValue);

Response<String> restoreReplace(byte[] key, int ttl, byte[] serializedValue);

// Geo Commands

Response<Long> geoadd(byte[] key, double longitude, double latitude, byte[] member);
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/redis/clients/jedis/commands/Commands.java
Expand Up @@ -307,6 +307,12 @@ void zrevrangeByScoreWithScores(String key, String max, String min,

void bitop(BitOP op, String destKey, String... srcKeys);

void dump(String key);

void restore(String key, int ttl, byte[] serializedValue);

void restoreReplace(String key, int ttl, byte[] serializedValue);

void scan(String cursor, ScanParams params);

void hscan(String key, String cursor, ScanParams params);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/redis/clients/jedis/commands/JedisCommands.java
Expand Up @@ -30,6 +30,8 @@ public interface JedisCommands {

String restore(String key, int ttl, byte[] serializedValue);

String restoreReplace(String key, int ttl, byte[] serializedValue);

Long expire(String key, int seconds);

Long pexpire(String key, long milliseconds);
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/redis/clients/jedis/commands/RedisPipeline.java
Expand Up @@ -243,6 +243,12 @@ Response<Set<String>> zrevrangeByLex(String key, String max, String min,

Response<Long> hstrlen(String key, String field);

Response<byte[]> dump(String key);

Response<String> restore(String key, int ttl, byte[] serializedValue);

Response<String> restoreReplace(String key, int ttl, byte[] serializedValue);

// Geo Commands

Response<Long> geoadd(String key, double longitude, double latitude, String member);
Expand Down
Expand Up @@ -6,20 +6,25 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
import static redis.clients.jedis.params.SetParams.setParams;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.junit.Test;
import redis.clients.jedis.Jedis;

import redis.clients.jedis.Protocol.Keyword;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.util.SafeEncoder;
import redis.clients.jedis.exceptions.JedisDataException;

public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
Expand Down Expand Up @@ -609,10 +614,40 @@ public void echo() {

@Test
public void dumpAndRestore() {
jedis.set("foo1", "bar1");
jedis.set("foo1", "bar");
byte[] sv = jedis.dump("foo1");
jedis.restore("foo2", 0, sv);
assertTrue(jedis.exists("foo2"));
assertEquals("bar", jedis.get("foo2"));
}

@Test
public void restoreReplace() {
// take a separate instance
Jedis jedis2 = new Jedis(hnp.getHost(), 6380, 500);
jedis2.auth("foobared");
jedis2.flushAll();

jedis2.set("foo", "bar");

Map<String, String> map = new HashMap<String, String>();
map.put("a", "A");
map.put("b", "B");

jedis.hset("from", map);
byte[] serialized = jedis.dump("from");

try {
jedis2.restore("foo", 0, serialized);
fail("Simple restore on a existing key should fail");
} catch(JedisDataException e) {
// should be here
}
assertEquals("bar", jedis2.get("foo"));

jedis2.restoreReplace("foo", 0, serialized);
assertEquals(map, jedis2.hgetAll("foo"));

jedis2.close();
}

@Test
Expand Down

0 comments on commit d1fb17c

Please sign in to comment.