diff --git a/Makefile b/Makefile index 6a784d8..51d8a37 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,18 @@ pidfile /tmp/sentinel3.pid logfile /tmp/sentinel3.log endef +define REDIS_SENTINEL4 +port 26382 +daemonize yes +sentinel monitor mymaster 127.0.0.1 6381 1 +sentinel auth-pass mymaster foobared +sentinel down-after-milliseconds mymaster 2000 +sentinel parallel-syncs mymaster 1 +sentinel failover-timeout mymaster 120000 +pidfile /tmp/sentinel4.pid +logfile /tmp/sentinel4.log +endef + # CLUSTER REDIS NODES define REDIS_CLUSTER_NODE1_CONF daemonize yes @@ -199,6 +211,7 @@ export REDIS7_CONF export REDIS_SENTINEL1 export REDIS_SENTINEL2 export REDIS_SENTINEL3 +export REDIS_SENTINEL4 export REDIS_CLUSTER_NODE1_CONF export REDIS_CLUSTER_NODE2_CONF export REDIS_CLUSTER_NODE3_CONF @@ -219,6 +232,8 @@ start: cleanup echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel @sleep 0.5 echo "$$REDIS_SENTINEL3" > /tmp/sentinel3.conf && redis-server /tmp/sentinel3.conf --sentinel + @sleep 0.5 + echo "$$REDIS_SENTINEL4" > /tmp/sentinel4.conf && redis-server /tmp/sentinel4.conf --sentinel echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server - echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server - @@ -241,6 +256,7 @@ stop: kill `cat /tmp/sentinel1.pid` kill `cat /tmp/sentinel2.pid` kill `cat /tmp/sentinel3.pid` + kill `cat /tmp/sentinel4.pid` kill `cat /tmp/redis_cluster_node1.pid` || true kill `cat /tmp/redis_cluster_node2.pid` || true kill `cat /tmp/redis_cluster_node3.pid` || true diff --git a/build.gradle b/build.gradle index 30af731..3905e3e 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'eclipse' group = 'com.googlecode.jedis' -archiveBaseName = 'jedis' +archivesBaseName = 'jedis' version = '1.5.0' repositories { diff --git a/pom.xml b/pom.xml index 2ad2a55..f2a2a9d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ jar redis.clients jedis - 2.5.2-SNAPSHOT + 2.5.3-SNAPSHOT Jedis Jedis is a blazingly small and sane Redis java client. https://github.com/xetorthio/jedis diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 4d235b2..2668864 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -7,6 +7,7 @@ import redis.clients.util.SafeEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Map.Entry; import static redis.clients.jedis.Protocol.Command.*; @@ -827,6 +828,25 @@ public class BinaryClient extends Connection { args.addAll(params.getParams()); sendCommand(ZINTERSTORE, args.toArray(new byte[args.size()][])); } + + public void zlexcount(final byte[] key, final byte[] min, final byte[] max) { + sendCommand(ZLEXCOUNT, key, min, max); + } + + public void zrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + sendCommand(ZRANGEBYLEX, key, min, max); + } + + public void zrangeByLex(final byte[] key, final byte[] min, final byte[] max, + final int offset, final int count) { + sendCommand(ZRANGEBYLEX, key, min, max, LIMIT.raw, + toByteArray(offset), toByteArray(count)); + } + + public void zremrangeByLex(byte[] key, byte[] min, byte[] max) { + sendCommand(ZREMRANGEBYLEX, key, min, max); + } + public void save() { sendCommand(SAVE); @@ -963,9 +983,6 @@ public class BinaryClient extends Connection { } public void resetState() { - if (isInMulti()) - discard(); - if (isInWatch()) unwatch(); } @@ -1099,11 +1116,6 @@ public class BinaryClient extends Connection { sendCommand(RESTORE, key, toByteArray(ttl), serializedValue); } - @Deprecated - public void pexpire(final byte[] key, final int milliseconds) { - pexpire(key, (long) milliseconds); - } - public void pexpire(final byte[] key, final long milliseconds) { sendCommand(PEXPIRE, key, toByteArray(milliseconds)); } @@ -1165,61 +1177,6 @@ public class BinaryClient extends Connection { sendCommand(HINCRBYFLOAT, key, field, toByteArray(increment)); } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void scan(int cursor, final ScanParams params) { - final List args = new ArrayList(); - args.add(toByteArray(cursor)); - args.addAll(params.getParams()); - sendCommand(SCAN, args.toArray(new byte[args.size()][])); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void hscan(final byte[] key, int cursor, final ScanParams params) { - final List args = new ArrayList(); - args.add(key); - args.add(toByteArray(cursor)); - args.addAll(params.getParams()); - sendCommand(HSCAN, args.toArray(new byte[args.size()][])); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void sscan(final byte[] key, int cursor, final ScanParams params) { - final List args = new ArrayList(); - args.add(key); - args.add(toByteArray(cursor)); - args.addAll(params.getParams()); - sendCommand(SSCAN, args.toArray(new byte[args.size()][])); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void zscan(final byte[] key, int cursor, final ScanParams params) { - final List args = new ArrayList(); - args.add(key); - args.add(toByteArray(cursor)); - args.addAll(params.getParams()); - sendCommand(ZSCAN, args.toArray(new byte[args.size()][])); - } - public void scan(final byte[] cursor, final ScanParams params) { final List args = new ArrayList(); args.add(cursor); diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 781f17f..4166b11 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -17,21 +17,20 @@ import redis.clients.jedis.BinaryClient.LIST_POSITION; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.util.JedisByteHashMap; +import redis.clients.util.JedisURIHelper; import redis.clients.util.SafeEncoder; public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKeyBinaryCommands, AdvancedBinaryJedisCommands, BinaryScriptingCommands, Closeable { protected Client client = null; - + protected Transaction transaction = null; + protected Pipeline pipeline = null; + public BinaryJedis(final String host) { URI uri = URI.create(host); if (uri.getScheme() != null && uri.getScheme().equals("redis")) { - client = new Client(uri.getHost(), uri.getPort()); - client.auth(uri.getUserInfo().split(":", 2)[1]); - client.getStatusCodeReply(); - client.select(Integer.parseInt(uri.getPath().split("/", 2)[1])); - client.getStatusCodeReply(); + initializeClientFromURI(uri); } else { client = new Client(host); } @@ -53,11 +52,28 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, } public BinaryJedis(URI uri) { + initializeClientFromURI(uri); + } + + public BinaryJedis(final URI uri, final int timeout) { + initializeClientFromURI(uri); + client.setTimeout(timeout); + } + + private void initializeClientFromURI(URI uri) { client = new Client(uri.getHost(), uri.getPort()); - client.auth(uri.getUserInfo().split(":", 2)[1]); - client.getStatusCodeReply(); - client.select(Integer.parseInt(uri.getPath().split("/", 2)[1])); - client.getStatusCodeReply(); + + String password = JedisURIHelper.getPassword(uri); + if (password != null) { + client.auth(password); + client.getStatusCodeReply(); + } + + Integer dbIndex = JedisURIHelper.getDBIndex(uri); + if (dbIndex > 0) { + client.select(dbIndex); + client.getStatusCodeReply(); + } } public String ping() { @@ -1753,7 +1769,9 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, public Transaction multi() { client.multi(); - return new Transaction(client); + client.getOne(); // expected OK + transaction = new Transaction(client); + return transaction; } @Deprecated @@ -1767,6 +1785,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, List results = null; jedisTransaction.setClient(client); client.multi(); + client.getOne(); // expected OK jedisTransaction.execute(); results = jedisTransaction.exec(); return results; @@ -1789,9 +1808,23 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, public void resetState() { if (client.isConnected()) { + if (transaction != null) { + transaction.clear(); + } + + if (pipeline != null) { + pipeline.clear(); + } + + if (client.isInWatch()) { + unwatch(); + } + client.resetState(); - client.getAll(); } + + transaction = null; + pipeline = null; } public String watch(final byte[]... keys) { @@ -2207,7 +2240,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, } public Pipeline pipelined() { - Pipeline pipeline = new Pipeline(); + pipeline = new Pipeline(); pipeline.setClient(client); return pipeline; } @@ -2793,6 +2826,35 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, return client.getIntegerReply(); } + @Override + public Long zlexcount(final byte[] key, final byte[] min, final byte[] max) { + checkIsInMulti(); + client.zlexcount(key, min, max); + return client.getIntegerReply(); + } + + @Override + public Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + checkIsInMulti(); + client.zrangeByLex(key, min, max); + return new LinkedHashSet(client.getBinaryMultiBulkReply()); + } + + @Override + public Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max, + final int offset, final int count) { + checkIsInMulti(); + client.zrangeByLex(key, min, max, offset, count); + return new LinkedHashSet(client.getBinaryMultiBulkReply()); + } + + @Override + public Long zremrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + checkIsInMulti(); + client.zremrangeByLex(key, min, max); + return client.getIntegerReply(); + } + /** * Synchronously save the DB on disk. *

@@ -3385,11 +3447,6 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, return client.getStatusCodeReply(); } - @Deprecated - public Long pexpire(final byte[] key, final int milliseconds) { - return pexpire(key, (long) milliseconds); - } - public Long pexpire(final byte[] key, final long milliseconds) { checkIsInMulti(); client.pexpire(key, milliseconds); diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index ada68c2..164c71c 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java @@ -115,6 +115,8 @@ public interface BinaryJedisCommands { byte[] srandmember(byte[] key); + List srandmember(final byte[] key, final int count); + Long strlen(byte[] key); Long zadd(byte[] key, double score, byte[] member); @@ -194,6 +196,15 @@ public interface BinaryJedisCommands { Long zremrangeByScore(byte[] key, double start, double end); Long zremrangeByScore(byte[] key, byte[] start, byte[] end); + + Long zlexcount(final byte[] key, final byte[] min, final byte[] max); + + Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max); + + Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max, + int offset, int count); + + Long zremrangeByLex(final byte[] key, final byte[] min, final byte[] max); Long linsert(byte[] key, Client.LIST_POSITION where, byte[] pivot, byte[] value); diff --git a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java index 5ce2ca5..98ebc73 100644 --- a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java @@ -34,7 +34,7 @@ public interface BinaryRedisPipeline { Response getSet(byte[] key, byte[] value); - Response getrange(byte[] key, long startOffset, long endOffset); + Response getrange(byte[] key, long startOffset, long endOffset); Response hdel(byte[] key, byte[]... field); @@ -206,6 +206,15 @@ public interface BinaryRedisPipeline { Response zrevrank(byte[] key, byte[] member); Response zscore(byte[] key, byte[] member); + + Response zlexcount(final byte[] key, final byte[] min, final byte[] max); + + Response> zrangeByLex(final byte[] key, final byte[] max, final byte[] min); + + Response> zrangeByLex(final byte[] key, final byte[] max, final byte[] min, + int offset, int count); + + Response zremrangeByLex(final byte[] key, final byte[] min, final byte[] max); Response bitcount(byte[] key); diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index 77695e7..c34a574 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -300,6 +300,12 @@ public class BinaryShardedJedis extends Sharded return j.srandmember(key); } + @Override + public List srandmember(byte[] key, int count) { + Jedis j = getShard(key); + return j.srandmember(key, count); + } + public Long zadd(byte[] key, double score, byte[] member) { Jedis j = getShard(key); return j.zadd(key, score, member); @@ -484,6 +490,31 @@ public class BinaryShardedJedis extends Sharded Jedis j = getShard(key); return j.zremrangeByScore(key, start, end); } + + @Override + public Long zlexcount(final byte[] key, final byte[] min, final byte[] max) { + Jedis j = getShard(key); + return j.zlexcount(key, min, max); + } + + @Override + public Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + Jedis j = getShard(key); + return j.zrangeByLex(key, min, max); + } + + @Override + public Set zrangeByLex(final byte[] key, final byte[] min, final byte[] max, + final int offset, final int count) { + Jedis j = getShard(key); + return j.zrangeByLex(key, min, max, offset, count); + } + + @Override + public Long zremrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + Jedis j = getShard(key); + return j.zremrangeByLex(key, min, max); + } public Long linsert(byte[] key, LIST_POSITION where, byte[] pivot, byte[] value) { diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 76d013e..8c119b6 100755 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import redis.clients.util.JedisByteHashMap; import redis.clients.util.SafeEncoder; public class BuilderFactory { @@ -104,6 +105,26 @@ public class BuilderFactory { }; + public static final Builder> PUBSUB_NUMSUB_MAP = new Builder>() { + @SuppressWarnings("unchecked") + public Map build(Object data) { + final List flatHash = (List) data; + final Map hash = new HashMap(); + final Iterator iterator = flatHash.iterator(); + while (iterator.hasNext()) { + hash.put(SafeEncoder.encode((byte[]) iterator.next()), + String.valueOf((Long) iterator.next())); + } + + return hash; + } + + public String toString() { + return "PUBSUB_NUMSUB_MAP"; + } + + }; + public static final Builder> STRING_SET = new Builder>() { @SuppressWarnings("unchecked") public Set build(Object data) { @@ -170,7 +191,7 @@ public class BuilderFactory { @SuppressWarnings("unchecked") public Map build(Object data) { final List flatHash = (List) data; - final Map hash = new HashMap(); + final Map hash = new JedisByteHashMap(); final Iterator iterator = flatHash.iterator(); while (iterator.hasNext()) { hash.put(iterator.next(), iterator.next()); diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 69054ef..9802696 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -585,6 +585,24 @@ public class Client extends BinaryClient implements Commands { } zinterstore(SafeEncoder.encode(dstkey), params, bsets); } + + public void zlexcount(final String key, final String min, final String max) { + zlexcount(SafeEncoder.encode(key), SafeEncoder.encode(min), SafeEncoder.encode(max)); + } + + public void zrangeByLex(final String key, final String min, final String max) { + zrangeByLex(SafeEncoder.encode(key), SafeEncoder.encode(min), SafeEncoder.encode(max)); + } + + public void zrangeByLex(final String key, final String min, final String max, + final int offset, final int count) { + zrangeByLex(SafeEncoder.encode(key), SafeEncoder.encode(min), SafeEncoder.encode(max), + offset, count); + } + + public void zremrangeByLex(final String key, final String min, final String max) { + zremrangeByLex(SafeEncoder.encode(key), SafeEncoder.encode(min), SafeEncoder.encode(max)); + } public void strlen(final String key) { strlen(SafeEncoder.encode(key)); @@ -780,11 +798,6 @@ public class Client extends BinaryClient implements Commands { restore(SafeEncoder.encode(key), ttl, serializedValue); } - @Deprecated - public void pexpire(final String key, final int milliseconds) { - pexpire(key, (long) milliseconds); - } - public void pexpire(final String key, final long milliseconds) { pexpire(SafeEncoder.encode(key), milliseconds); } @@ -841,36 +854,6 @@ public class Client extends BinaryClient implements Commands { increment); } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void hscan(final String key, int cursor, final ScanParams params) { - hscan(SafeEncoder.encode(key), cursor, params); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void sscan(final String key, int cursor, final ScanParams params) { - sscan(SafeEncoder.encode(key), cursor, params); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void zscan(final String key, int cursor, final ScanParams params) { - zscan(SafeEncoder.encode(key), cursor, params); - } - public void scan(final String cursor, final ScanParams params) { scan(SafeEncoder.encode(cursor), params); } @@ -1011,4 +994,8 @@ public void clusterSetSlotStable(final int slot) { public void clusterFailover() { cluster(Protocol.CLUSTER_FAILOVER); } + + public void clusterSlots() { + cluster(Protocol.CLUSTER_SLOTS); + } } diff --git a/src/main/java/redis/clients/jedis/ClusterCommands.java b/src/main/java/redis/clients/jedis/ClusterCommands.java index b77069b..1dac7fe 100644 --- a/src/main/java/redis/clients/jedis/ClusterCommands.java +++ b/src/main/java/redis/clients/jedis/ClusterCommands.java @@ -38,4 +38,6 @@ public interface ClusterCommands { List clusterSlaves(final String nodeId); String clusterFailover(); + + List clusterSlots(); } diff --git a/src/main/java/redis/clients/jedis/Commands.java b/src/main/java/redis/clients/jedis/Commands.java index 93fc55f..9261d6d 100644 --- a/src/main/java/redis/clients/jedis/Commands.java +++ b/src/main/java/redis/clients/jedis/Commands.java @@ -301,38 +301,6 @@ public interface Commands { public void bitop(BitOP op, final String destKey, String... srcKeys); - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void scan(int cursor, final ScanParams params); - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void hscan(final String key, int cursor, final ScanParams params); - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void sscan(final String key, int cursor, final ScanParams params); - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public void zscan(final String key, int cursor, final ScanParams params); - public void scan(final String cursor, final ScanParams params); public void hscan(final String key, final String cursor, final ScanParams params); diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index c50c706..c57b170 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -21,7 +21,6 @@ public class Connection implements Closeable { private Socket socket; private RedisOutputStream outputStream; private RedisInputStream inputStream; - private int pipelinedCommands = 0; private int timeout = Protocol.DEFAULT_TIMEOUT; private boolean broken = false; @@ -78,7 +77,6 @@ public class Connection implements Closeable { try { connect(); Protocol.sendCommand(outputStream, cmd, args); - pipelinedCommands++; return this; } catch (JedisConnectionException ex) { // Any other exceptions related to connection? @@ -91,7 +89,6 @@ public class Connection implements Closeable { try { connect(); Protocol.sendCommand(outputStream, cmd, new byte[0][]); - pipelinedCommands++; return this; } catch (JedisConnectionException ex) { // Any other exceptions related to connection? @@ -180,7 +177,6 @@ public class Connection implements Closeable { protected String getStatusCodeReply() { flush(); - pipelinedCommands--; final byte[] resp = (byte[]) readProtocolWithCheckingBroken(); if (null == resp) { return null; @@ -200,13 +196,11 @@ public class Connection implements Closeable { public byte[] getBinaryBulkReply() { flush(); - pipelinedCommands--; return (byte[]) readProtocolWithCheckingBroken(); } public Long getIntegerReply() { flush(); - pipelinedCommands--; return (Long) readProtocolWithCheckingBroken(); } @@ -217,14 +211,9 @@ public class Connection implements Closeable { @SuppressWarnings("unchecked") public List getBinaryMultiBulkReply() { flush(); - pipelinedCommands--; return (List) readProtocolWithCheckingBroken(); } - public void resetPipelinedCount() { - pipelinedCommands = 0; - } - @SuppressWarnings("unchecked") public List getRawObjectMultiBulkReply() { return (List) readProtocolWithCheckingBroken(); @@ -232,38 +221,17 @@ public class Connection implements Closeable { public List getObjectMultiBulkReply() { flush(); - pipelinedCommands--; return getRawObjectMultiBulkReply(); } @SuppressWarnings("unchecked") public List getIntegerMultiBulkReply() { - flush(); - pipelinedCommands--; - return (List) readProtocolWithCheckingBroken(); - } - - public List getAll() { - return getAll(0); - } - - public List getAll(int except) { - List all = new ArrayList(); - flush(); - while (pipelinedCommands > except) { - try { - all.add(readProtocolWithCheckingBroken()); - } catch (JedisDataException e) { - all.add(e); - } - pipelinedCommands--; - } - return all; + flush(); + return (List) Protocol.read(inputStream); } public Object getOne() { flush(); - pipelinedCommands--; return readProtocolWithCheckingBroken(); } @@ -288,4 +256,17 @@ public class Connection implements Closeable { throw exc; } } + + public List getMany(int count) { + flush(); + List responses = new ArrayList(); + for (int i = 0; i < count; i++) { + try { + responses.add(readProtocolWithCheckingBroken()); + } catch (JedisDataException e) { + responses.add(e); + } + } + return responses; + } } diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index fbf430c..e7abbad 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -35,6 +35,10 @@ public class Jedis extends BinaryJedis implements JedisCommands, super(uri); } + public Jedis(final URI uri, final int timeout) { + super(uri, timeout); + } + /** * Set the string value as value of the key. The string can't be longer than * 1073741824 bytes (1 GB). @@ -547,26 +551,27 @@ public class Jedis extends BinaryJedis implements JedisCommands, /** * INCRBYFLOAT *

- * INCRBYFLOAT commands are limited to double precision floating point values. + * INCRBYFLOAT commands are limited to double precision floating point + * values. *

* Note: this is actually a string operation, that is, in Redis there are * not "double" types. Simply the string stored at the key is parsed as a * base double precision floating point value, incremented, and then - * converted back as a string. There is no DECRYBYFLOAT but providing a + * converted back as a string. There is no DECRYBYFLOAT but providing a * negative value will work as expected. *

* Time complexity: O(1) - * + * * @param key * @param value * @return Double reply, this commands will reply with the new value of key * after the increment. */ public Double incrByFloat(final String key, final double value) { - checkIsInMulti(); - client.incrByFloat(key, value); - String dval = client.getBulkReply(); - return (dval != null ? new Double(dval) : null); + checkIsInMulti(); + client.incrByFloat(key, value); + String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); } /** @@ -763,28 +768,29 @@ public class Jedis extends BinaryJedis implements JedisCommands, /** * Increment the number stored at field in the hash at key by a double - * precision floating point value. If key does not exist, - * a new key holding a hash is created. If field does not - * exist or holds a string, the value is set to 0 before applying the - * operation. Since the value argument is signed you can use this command to - * perform both increments and decrements. + * precision floating point value. If key does not exist, a new key holding + * a hash is created. If field does not exist or holds a string, the value + * is set to 0 before applying the operation. Since the value argument is + * signed you can use this command to perform both increments and + * decrements. *

- * The range of values supported by HINCRBYFLOAT is limited to - * double precision floating point values. + * The range of values supported by HINCRBYFLOAT is limited to double + * precision floating point values. *

* Time complexity: O(1) - * + * * @param key * @param field * @param value - * @return Double precision floating point reply The new value at field after the increment - * operation. + * @return Double precision floating point reply The new value at field + * after the increment operation. */ - public Double hincrByFloat(final String key, final String field, final double value) { - checkIsInMulti(); - client.hincrByFloat(key, field, value); - final String dval = client.getBulkReply(); - return (dval != null ? new Double(dval) : null); + public Double hincrByFloat(final String key, final String field, + final double value) { + checkIsInMulti(); + client.hincrByFloat(key, field, value); + final String dval = client.getBulkReply(); + return (dval != null ? new Double(dval) : null); } /** @@ -1116,8 +1122,8 @@ public class Jedis extends BinaryJedis implements JedisCommands, /** * Atomically return and remove the first (LPOP) or last (RPOP) element of - * the list. For example if the list contains the elements "a","b","c" LPOP - * will return "a" and the list will become "b","c". + * the list. For example if the list contains the elements "a","b","c" RPOP + * will return "c" and the list will become "a","b". *

* If the key does not exist or the list is already empty the special value * 'nil' is returned. @@ -2609,6 +2615,35 @@ public class Jedis extends BinaryJedis implements JedisCommands, client.zinterstore(dstkey, params, sets); return client.getIntegerReply(); } + + @Override + public Long zlexcount(final String key, final String min, final String max) { + checkIsInMulti(); + client.zlexcount(key, min, max); + return client.getIntegerReply(); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max) { + checkIsInMulti(); + client.zrangeByLex(key, min, max); + return new LinkedHashSet(client.getMultiBulkReply()); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max, + final int offset, final int count) { + checkIsInMulti(); + client.zrangeByLex(key, min, max, offset, count); + return new LinkedHashSet(client.getMultiBulkReply()); + } + + @Override + public Long zremrangeByLex(final String key, final String min, final String max) { + checkIsInMulti(); + client.zremrangeByLex(key, min, max); + return client.getIntegerReply(); + } public Long strlen(final String key) { client.strlen(key); @@ -2707,12 +2742,13 @@ public class Jedis extends BinaryJedis implements JedisCommands, client.getrange(key, startOffset, endOffset); return client.getBulkReply(); } - + public Long bitpos(final String key, final boolean value) { return bitpos(key, value, new BitPosParams()); } - - public Long bitpos(final String key, final boolean value, final BitPosParams params) { + + public Long bitpos(final String key, final boolean value, + final BitPosParams params) { client.bitpos(key, value, params); return client.getIntegerReply(); } @@ -3117,11 +3153,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, return client.getStatusCodeReply(); } - @Deprecated - public Long pexpire(final String key, final int milliseconds) { - return pexpire(key, (long) milliseconds); - } - public Long pexpire(final String key, final long milliseconds) { checkIsInMulti(); client.pexpire(key, milliseconds); @@ -3140,7 +3171,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, return client.getIntegerReply(); } - public String psetex(final String key, final int milliseconds, final String value) { checkIsInMulti(); @@ -3180,131 +3210,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, return client.getStatusCodeReply(); } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult scan(int cursor) { - return scan(cursor, new ScanParams()); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult scan(int cursor, final ScanParams params) { - checkIsInMulti(); - client.scan(cursor, params); - List result = client.getObjectMultiBulkReply(); - int newcursor = Integer.parseInt(new String((byte[]) result.get(0))); - List results = new ArrayList(); - List rawResults = (List) result.get(1); - for (byte[] bs : rawResults) { - results.add(SafeEncoder.encode(bs)); - } - return new ScanResult(newcursor, results); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult> hscan(final String key, - int cursor) { - return hscan(key, cursor, new ScanParams()); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult> hscan(final String key, - int cursor, final ScanParams params) { - checkIsInMulti(); - client.hscan(key, cursor, params); - List result = client.getObjectMultiBulkReply(); - int newcursor = Integer.parseInt(new String((byte[]) result.get(0))); - List> results = new ArrayList>(); - List rawResults = (List) result.get(1); - Iterator iterator = rawResults.iterator(); - while (iterator.hasNext()) { - results.add(new AbstractMap.SimpleEntry(SafeEncoder - .encode(iterator.next()), SafeEncoder.encode(iterator - .next()))); - } - return new ScanResult>(newcursor, results); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult sscan(final String key, int cursor) { - return sscan(key, cursor, new ScanParams()); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult sscan(final String key, int cursor, - final ScanParams params) { - checkIsInMulti(); - client.sscan(key, cursor, params); - List result = client.getObjectMultiBulkReply(); - int newcursor = Integer.parseInt(new String((byte[]) result.get(0))); - List results = new ArrayList(); - List rawResults = (List) result.get(1); - for (byte[] bs : rawResults) { - results.add(SafeEncoder.encode(bs)); - } - return new ScanResult(newcursor, results); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult zscan(final String key, int cursor) { - return zscan(key, cursor, new ScanParams()); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult zscan(final String key, int cursor, - final ScanParams params) { - checkIsInMulti(); - client.zscan(key, cursor, params); - List result = client.getObjectMultiBulkReply(); - int newcursor = Integer.parseInt(new String((byte[]) result.get(0))); - List results = new ArrayList(); - List rawResults = (List) result.get(1); - Iterator iterator = rawResults.iterator(); - while (iterator.hasNext()) { - results.add(new Tuple(SafeEncoder.encode(iterator.next()), Double - .valueOf(SafeEncoder.encode(iterator.next())))); - } - return new ScanResult(newcursor, results); - } - public ScanResult scan(final String cursor) { return scan(cursor, new ScanParams()); } @@ -3435,60 +3340,67 @@ public class Jedis extends BinaryJedis implements JedisCommands, client.clusterSetSlotImporting(slot, nodeId); return client.getStatusCodeReply(); } - + public String clusterSetSlotStable(final int slot) { checkIsInMulti(); client.clusterSetSlotStable(slot); return client.getStatusCodeReply(); } - + public String clusterForget(final String nodeId) { checkIsInMulti(); client.clusterForget(nodeId); return client.getStatusCodeReply(); } - + public String clusterFlushSlots() { checkIsInMulti(); client.clusterFlushSlots(); return client.getStatusCodeReply(); } - + public Long clusterKeySlot(final String key) { checkIsInMulti(); client.clusterKeySlot(key); return client.getIntegerReply(); } - + public Long clusterCountKeysInSlot(final int slot) { checkIsInMulti(); client.clusterCountKeysInSlot(slot); return client.getIntegerReply(); } - + public String clusterSaveConfig() { checkIsInMulti(); client.clusterSaveConfig(); return client.getStatusCodeReply(); } - + public String clusterReplicate(final String nodeId) { checkIsInMulti(); client.clusterReplicate(nodeId); return client.getStatusCodeReply(); } - + public List clusterSlaves(final String nodeId) { checkIsInMulti(); client.clusterSlaves(nodeId); return client.getMultiBulkReply(); } - + public String clusterFailover() { checkIsInMulti(); client.clusterFailover(); return client.getStatusCodeReply(); } + + @Override + public List clusterSlots() { + checkIsInMulti(); + client.clusterSlots(); + return client.getObjectMultiBulkReply(); + } public String asking() { checkIsInMulti(); @@ -3511,7 +3423,7 @@ public class Jedis extends BinaryJedis implements JedisCommands, public Map pubsubNumSub(String... channels) { checkIsInMulti(); client.pubsubNumSub(channels); - return BuilderFactory.STRING_MAP + return BuilderFactory.PUBSUB_NUMSUB_MAP .build(client.getBinaryMultiBulkReply()); } @@ -3529,7 +3441,7 @@ public class Jedis extends BinaryJedis implements JedisCommands, } public void setDataSource(Pool jedisPool) { - this.dataSource = jedisPool; + this.dataSource = jedisPool; } public Long pfadd(final String key, final String... elements) { @@ -3546,7 +3458,7 @@ public class Jedis extends BinaryJedis implements JedisCommands, @Override public long pfcount(String... keys) { - checkIsInMulti(); + checkIsInMulti(); client.pfcount(keys); return client.getIntegerReply(); } @@ -3556,4 +3468,31 @@ public class Jedis extends BinaryJedis implements JedisCommands, client.pfmerge(destkey, sourcekeys); return client.getStatusCodeReply(); } + + @Override + public List blpop(int timeout, String key) { + checkIsInMulti(); + List args = new ArrayList(); + args.add(key); + args.add(String.valueOf(timeout)); + client.blpop(args.toArray(new String[args.size()])); + client.setTimeoutInfinite(); + final List multiBulkReply = client.getMultiBulkReply(); + client.rollbackTimeout(); + return multiBulkReply; + } + + @Override + public List brpop(int timeout, String key) { + checkIsInMulti(); + List args = new ArrayList(); + args.add(key); + args.add(String.valueOf(timeout)); + client.brpop(args.toArray(new String[args.size()])); + client.setTimeoutInfinite(); + final List multiBulkReply = client.getMultiBulkReply(); + client.rollbackTimeout(); + return multiBulkReply; + } + } diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 846d9b6..21ab332 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -2,6 +2,7 @@ package redis.clients.jedis; import redis.clients.jedis.BinaryClient.LIST_POSITION; +import java.io.Closeable; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -9,7 +10,7 @@ import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -public class JedisCluster implements JedisCommands, BasicCommands { +public class JedisCluster implements JedisCommands, BasicCommands, Closeable { public static final short HASHSLOTS = 16384; private static final int DEFAULT_TIMEOUT = 1; private static final int DEFAULT_MAX_REDIRECTIONS = 5; @@ -50,6 +51,21 @@ public class JedisCluster implements JedisCommands, BasicCommands { this.timeout = timeout; this.maxRedirections = maxRedirections; } + + @Override + public void close() { + if (connectionHandler != null) { + for (JedisPool pool : connectionHandler.getNodes().values()) { + try { + if (pool != null) { + pool.destroy(); + } + } catch (Exception e) { + // pass + } + } + } + } @Override public String set(final String key, final String value) { @@ -412,7 +428,7 @@ public class JedisCluster implements JedisCommands, BasicCommands { maxRedirections) { @Override public Long execute(Jedis connection) { - return connection.hdel(key); + return connection.hlen(key); } }.run(key); } @@ -641,6 +657,17 @@ public class JedisCluster implements JedisCommands, BasicCommands { }.run(key); } + @Override + public List srandmember(final String key, final int count) { + return new JedisClusterCommand>(connectionHandler, timeout, + maxRedirections) { + @Override + public List execute(Jedis connection) { + return connection.srandmember(key, count); + } + }.run(key); + } + @Override public Long strlen(final String key) { return new JedisClusterCommand(connectionHandler, timeout, @@ -1093,6 +1120,51 @@ public class JedisCluster implements JedisCommands, BasicCommands { } }.run(key); } + + @Override + public Long zlexcount(final String key, final String min, final String max) { + return new JedisClusterCommand(connectionHandler, timeout, + maxRedirections) { + @Override + public Long execute(Jedis connection) { + return connection.zlexcount(key, min, max); + } + }.run(key); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max) { + return new JedisClusterCommand>(connectionHandler, timeout, + maxRedirections) { + @Override + public Set execute(Jedis connection) { + return connection.zrangeByLex(key, min, max); + } + }.run(key); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max, + final int offset, final int count) { + return new JedisClusterCommand>(connectionHandler, timeout, + maxRedirections) { + @Override + public Set execute(Jedis connection) { + return connection.zrangeByLex(key, min, max, offset, count); + } + }.run(key); + } + + @Override + public Long zremrangeByLex(final String key, final String min, final String max) { + return new JedisClusterCommand(connectionHandler, timeout, + maxRedirections) { + @Override + public Long execute(Jedis connection) { + return connection.zremrangeByLex(key, min, max); + } + }.run(key); + } @Override public Long linsert(final String key, final LIST_POSITION where, @@ -1426,58 +1498,6 @@ public class JedisCluster implements JedisCommands, BasicCommands { return null; } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - @Override - public ScanResult> hscan(final String key, - final int cursor) { - return new JedisClusterCommand>>( - connectionHandler, timeout, maxRedirections) { - @Override - public ScanResult> execute(Jedis connection) { - return connection.hscan(key, cursor); - } - }.run(null); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - @Override - public ScanResult sscan(final String key, final int cursor) { - return new JedisClusterCommand>(connectionHandler, - timeout, maxRedirections) { - @Override - public ScanResult execute(Jedis connection) { - return connection.sscan(key, cursor); - } - }.run(null); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - @Override - public ScanResult zscan(final String key, final int cursor) { - return new JedisClusterCommand>(connectionHandler, - timeout, maxRedirections) { - @Override - public ScanResult execute(Jedis connection) { - return connection.zscan(key, cursor); - } - }.run(null); - } - @Override public ScanResult> hscan(final String key, final String cursor) { @@ -1533,4 +1553,26 @@ public class JedisCluster implements JedisCommands, BasicCommands { } }.run(key); } + + @Override + public List blpop(final int timeout, final String key) { + return new JedisClusterCommand>(connectionHandler, + timeout, maxRedirections) { + @Override + public List execute(Jedis connection) { + return connection.blpop(timeout,key); + } + }.run(null); + } + + @Override + public List brpop(final int timeout, final String key) { + return new JedisClusterCommand>(connectionHandler, + timeout, maxRedirections) { + @Override + public List execute(Jedis connection) { + return connection.brpop(timeout,key); + } + }.run(null); + } } diff --git a/src/main/java/redis/clients/jedis/JedisClusterCommand.java b/src/main/java/redis/clients/jedis/JedisClusterCommand.java index 051d5cd..604afca 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterCommand.java +++ b/src/main/java/redis/clients/jedis/JedisClusterCommand.java @@ -63,33 +63,35 @@ public abstract class JedisClusterCommand { // maybe all connection is down throw jce; } - + releaseConnection(connection, true); connection = null; - + // retry with random connection return runWithRetries(key, redirections--, true, asking); } catch (JedisRedirectionException jre) { if (jre instanceof JedisAskDataException) { asking = true; + this.connectionHandler.assignSlotToNode(jre.getSlot(), + jre.getTargetNode()); } else if (jre instanceof JedisMovedDataException) { - // TODO : In antirez's redis-rb-cluster implementation, - // it rebuilds cluster's slot and node cache + // it rebuilds cluster's slot cache + // recommended by Redis cluster specification + this.connectionHandler.renewSlotCache(); + } else { + throw new JedisClusterException(jre); } - this.connectionHandler.assignSlotToNode(jre.getSlot(), - jre.getTargetNode()); - releaseConnection(connection, false); connection = null; - + return runWithRetries(key, redirections - 1, false, asking); } finally { releaseConnection(connection, false); } } - + private void releaseConnection(Jedis connection, boolean broken) { if (connection != null) { if (broken) { diff --git a/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java b/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java index 6a7281a..288d477 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java +++ b/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java @@ -1,131 +1,86 @@ package redis.clients.jedis; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; - -import java.util.*; - import redis.clients.jedis.exceptions.JedisConnectionException; -import redis.clients.util.ClusterNodeInformation; -import redis.clients.util.ClusterNodeInformationParser; + +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import static redis.clients.jedis.JedisClusterInfoCache.getNodeKey; public abstract class JedisClusterConnectionHandler { - public static ClusterNodeInformationParser nodeInfoParser = new ClusterNodeInformationParser(); - - protected Map nodes = new HashMap(); - protected Map slots = new HashMap(); - final protected GenericObjectPoolConfig poolConfig; + protected final JedisClusterInfoCache cache; abstract Jedis getConnection(); - protected void returnConnection(Jedis connection) { - nodes.get(getNodeKey(connection.getClient())) - .returnResource(connection); + public void returnConnection(Jedis connection) { + cache.getNode(getNodeKey(connection.getClient())).returnResource( + connection); } public void returnBrokenConnection(Jedis connection) { - nodes.get(getNodeKey(connection.getClient())).returnBrokenResource( + cache.getNode(getNodeKey(connection.getClient())).returnBrokenResource( connection); } abstract Jedis getConnectionFromSlot(int slot); public JedisClusterConnectionHandler(Set nodes, final GenericObjectPoolConfig poolConfig) { - this.poolConfig = poolConfig; - initializeSlotsCache(nodes); + this.cache = new JedisClusterInfoCache(poolConfig); + initializeSlotsCache(nodes, poolConfig); } public Map getNodes() { - return nodes; + return cache.getNodes(); } - private void initializeSlotsCache(Set startNodes) { + public void assignSlotToNode(int slot, HostAndPort targetNode) { + cache.assignSlotToNode(slot, targetNode); + } + + private void initializeSlotsCache(Set startNodes, GenericObjectPoolConfig poolConfig) { for (HostAndPort hostAndPort : startNodes) { JedisPool jp = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort()); - this.nodes.clear(); - this.slots.clear(); - Jedis jedis = null; try { jedis = jp.getResource(); - discoverClusterNodesAndSlots(jedis); + cache.discoverClusterNodesAndSlots(jedis); break; } catch (JedisConnectionException e) { - if (jedis != null) { - jp.returnBrokenResource(jedis); - jedis = null; - } - // try next nodes } finally { if (jedis != null) { - jp.returnResource(jedis); + jedis.close(); } } } for (HostAndPort node : startNodes) { - setNodeIfNotExist(node); + cache.setNodeIfNotExist(node); } } - private void discoverClusterNodesAndSlots(Jedis jedis) { - String localNodes = jedis.clusterNodes(); - for (String nodeInfo : localNodes.split("\n")) { - ClusterNodeInformation clusterNodeInfo = nodeInfoParser.parse( - nodeInfo, new HostAndPort(jedis.getClient().getHost(), - jedis.getClient().getPort())); - - HostAndPort targetNode = clusterNodeInfo.getNode(); - setNodeIfNotExist(targetNode); - assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), targetNode); - } - } - - public void assignSlotToNode(int slot, HostAndPort targetNode) { - JedisPool targetPool = nodes.get(getNodeKey(targetNode)); - - if (targetPool == null) { - setNodeIfNotExist(targetNode); - targetPool = nodes.get(getNodeKey(targetNode)); - } - slots.put(slot, targetPool); - } - - public void assignSlotsToNode(List targetSlots, - HostAndPort targetNode) { - JedisPool targetPool = nodes.get(getNodeKey(targetNode)); - - if (targetPool == null) { - setNodeIfNotExist(targetNode); - targetPool = nodes.get(getNodeKey(targetNode)); - } - - for (Integer slot : targetSlots) { - slots.put(slot, targetPool); + public void renewSlotCache() { + for (JedisPool jp : cache.getNodes().values()) { + Jedis jedis = null; + try { + jedis = jp.getResource(); + cache.discoverClusterSlots(jedis); + break; + } finally { + if (jedis != null) { + jedis.close(); + } + } } } protected JedisPool getRandomConnection() { - Object[] nodeArray = nodes.values().toArray(); + Object[] nodeArray = cache.getNodes().values().toArray(); return (JedisPool) (nodeArray[new Random().nextInt(nodeArray.length)]); } - protected String getNodeKey(HostAndPort hnp) { - return hnp.getHost() + ":" + hnp.getPort(); - } - - protected String getNodeKey(Client client) { - return client.getHost() + ":" + client.getPort(); - } - - private void setNodeIfNotExist(HostAndPort node) { - String nodeKey = getNodeKey(node); - if (nodes.containsKey(nodeKey)) - return; - - JedisPool nodePool = new JedisPool(poolConfig, node.getHost(), node.getPort()); - nodes.put(nodeKey, nodePool); - } } diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java new file mode 100644 index 0000000..95a3feb --- /dev/null +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -0,0 +1,188 @@ +package redis.clients.jedis; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import redis.clients.util.ClusterNodeInformation; +import redis.clients.util.ClusterNodeInformationParser; +import redis.clients.util.SafeEncoder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class JedisClusterInfoCache { + public static final ClusterNodeInformationParser nodeInfoParser = new ClusterNodeInformationParser(); + + private Map nodes = new HashMap(); + private Map slots = new HashMap(); + + private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final Lock r = rwl.readLock(); + private final Lock w = rwl.writeLock(); + private final GenericObjectPoolConfig poolConfig; + + public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig) { + this.poolConfig = poolConfig; + } + + public void discoverClusterNodesAndSlots(Jedis jedis) { + w.lock(); + + try { + this.nodes.clear(); + this.slots.clear(); + + String localNodes = jedis.clusterNodes(); + for (String nodeInfo : localNodes.split("\n")) { + ClusterNodeInformation clusterNodeInfo = nodeInfoParser.parse( + nodeInfo, new HostAndPort(jedis.getClient().getHost(), + jedis.getClient().getPort())); + + HostAndPort targetNode = clusterNodeInfo.getNode(); + setNodeIfNotExist(targetNode); + assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), + targetNode); + } + } finally { + w.unlock(); + } + } + + public void discoverClusterSlots(Jedis jedis) { + w.lock(); + + try { + this.slots.clear(); + + List slots = jedis.clusterSlots(); + + for (Object slotInfoObj : slots) { + List slotInfo = (List) slotInfoObj; + + if (slotInfo.size() <= 2) { + continue; + } + + List slotNums = getAssignedSlotArray(slotInfo); + + // hostInfos + List hostInfos = (List) slotInfo.get(2); + if (hostInfos.size() <= 0) { + continue; + } + + // at this time, we just use master, discard slave information + HostAndPort targetNode = generateHostAndPort(hostInfos); + + setNodeIfNotExist(targetNode); + assignSlotsToNode(slotNums, targetNode); + } + } finally { + w.unlock(); + } + } + + private HostAndPort generateHostAndPort(List hostInfos) { + return new HostAndPort(SafeEncoder.encode((byte[]) hostInfos.get(0)), + ((Long) hostInfos.get(1)).intValue()); + } + + public void setNodeIfNotExist(HostAndPort node) { + w.lock(); + try { + String nodeKey = getNodeKey(node); + if (nodes.containsKey(nodeKey)) + return; + + JedisPool nodePool = new JedisPool(poolConfig, node.getHost(), node.getPort()); + nodes.put(nodeKey, nodePool); + } finally { + w.unlock(); + } + } + + public void assignSlotToNode(int slot, HostAndPort targetNode) { + w.lock(); + try { + JedisPool targetPool = nodes.get(getNodeKey(targetNode)); + + if (targetPool == null) { + setNodeIfNotExist(targetNode); + targetPool = nodes.get(getNodeKey(targetNode)); + } + slots.put(slot, targetPool); + } finally { + w.unlock(); + } + } + + public synchronized void assignSlotsToNode(List targetSlots, + HostAndPort targetNode) { + w.lock(); + try { + JedisPool targetPool = nodes.get(getNodeKey(targetNode)); + + if (targetPool == null) { + setNodeIfNotExist(targetNode); + targetPool = nodes.get(getNodeKey(targetNode)); + } + + for (Integer slot : targetSlots) { + slots.put(slot, targetPool); + } + } finally { + w.unlock(); + } + } + + public synchronized JedisPool getNode(String nodeKey) { + r.lock(); + try { + return nodes.get(nodeKey); + } finally { + r.unlock(); + } + } + + public synchronized JedisPool getSlotPool(int slot) { + r.lock(); + try { + return slots.get(slot); + } finally { + r.unlock(); + } + } + + public synchronized Map getNodes() { + r.lock(); + try { + return new HashMap(nodes); + } finally { + r.unlock(); + } + } + + public static String getNodeKey(HostAndPort hnp) { + return hnp.getHost() + ":" + hnp.getPort(); + } + + public static String getNodeKey(Client client) { + return client.getHost() + ":" + client.getPort(); + } + + public static String getNodeKey(Jedis jedis) { + return getNodeKey(jedis.getClient()); + } + + private List getAssignedSlotArray(List slotInfo) { + List slotNums = new ArrayList(); + for (int slot = ((Long) slotInfo.get(0)).intValue(); slot <= ((Long) slotInfo + .get(1)).intValue(); slot++) { + slotNums.add(slot); + } + return slotNums; + } + +} diff --git a/src/main/java/redis/clients/jedis/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index d89f508..17dc08d 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -113,6 +113,8 @@ public interface JedisCommands { String srandmember(String key); + List srandmember(String key, int count); + Long strlen(String key); Long zadd(String key, double score, String member); @@ -192,6 +194,15 @@ public interface JedisCommands { Long zremrangeByScore(String key, double start, double end); Long zremrangeByScore(String key, String start, String end); + + Long zlexcount(final String key, final String min, final String max); + + Set zrangeByLex(final String key, final String min, final String max); + + Set zrangeByLex(final String key, final String min, final String max, + final int offset, final int count); + + Long zremrangeByLex(final String key, final String min, final String max); Long linsert(String key, Client.LIST_POSITION where, String pivot, String value); @@ -201,8 +212,12 @@ public interface JedisCommands { Long rpushx(String key, String... string); List blpop(String arg); + + List blpop(int timeout, String key); List brpop(String arg); + + List brpop(int timeout, String key); Long del(String key); @@ -214,30 +229,6 @@ public interface JedisCommands { Long bitcount(final String key, long start, long end); - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - ScanResult> hscan(final String key, int cursor); - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - ScanResult sscan(final String key, int cursor); - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - ScanResult zscan(final String key, int cursor); - ScanResult> hscan(final String key, final String cursor); ScanResult sscan(final String key, final String cursor); diff --git a/src/main/java/redis/clients/jedis/JedisFactory.java b/src/main/java/redis/clients/jedis/JedisFactory.java index 3597d69..c04b43d 100644 --- a/src/main/java/redis/clients/jedis/JedisFactory.java +++ b/src/main/java/redis/clients/jedis/JedisFactory.java @@ -1,5 +1,7 @@ package redis.clients.jedis; +import java.util.concurrent.atomic.AtomicReference; + import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; @@ -8,8 +10,7 @@ import org.apache.commons.pool2.impl.DefaultPooledObject; * PoolableObjectFactory custom impl. */ class JedisFactory implements PooledObjectFactory { - private final String host; - private final int port; + private final AtomicReference hostAndPort = new AtomicReference(); private final int timeout; private final String password; private final int database; @@ -23,14 +24,17 @@ class JedisFactory implements PooledObjectFactory { public JedisFactory(final String host, final int port, final int timeout, final String password, final int database, final String clientName) { super(); - this.host = host; - this.port = port; + this.hostAndPort.set(new HostAndPort(host, port)); this.timeout = timeout; this.password = password; this.database = database; this.clientName = clientName; } + public void setHostAndPort(final HostAndPort hostAndPort) { + this.hostAndPort.set(hostAndPort); + } + @Override public void activateObject(PooledObject pooledJedis) throws Exception { @@ -60,7 +64,8 @@ class JedisFactory implements PooledObjectFactory { @Override public PooledObject makeObject() throws Exception { - final Jedis jedis = new Jedis(this.host, this.port, this.timeout); + final HostAndPort hostAndPort = this.hostAndPort.get(); + final Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort(), this.timeout); jedis.connect(); if (null != this.password) { @@ -86,7 +91,13 @@ class JedisFactory implements PooledObjectFactory { public boolean validateObject(PooledObject pooledJedis) { final BinaryJedis jedis = pooledJedis.getObject(); try { - return jedis.isConnected() && jedis.ping().equals("PONG"); + HostAndPort hostAndPort = this.hostAndPort.get(); + + String connectionHost = jedis.getClient().getHost(); + int connectionPort = jedis.getClient().getPort(); + + return hostAndPort.getHost().equals(connectionHost) && hostAndPort.getPort() == connectionPort && + jedis.isConnected() && jedis.ping().equals("PONG"); } catch (final Exception e) { return false; } diff --git a/src/main/java/redis/clients/jedis/JedisPool.java b/src/main/java/redis/clients/jedis/JedisPool.java index 0fbfdfe..c5e98d3 100644 --- a/src/main/java/redis/clients/jedis/JedisPool.java +++ b/src/main/java/redis/clients/jedis/JedisPool.java @@ -5,6 +5,7 @@ import java.net.URI; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import redis.clients.util.JedisURIHelper; import redis.clients.util.Pool; public class JedisPool extends Pool { @@ -24,8 +25,12 @@ public class JedisPool extends Pool { if (uri.getScheme() != null && uri.getScheme().equals("redis")) { String h = uri.getHost(); int port = uri.getPort(); - String password = uri.getUserInfo().split(":", 2)[1]; - int database = Integer.parseInt(uri.getPath().split("/", 2)[1]); + String password = JedisURIHelper.getPassword(uri); + int database = 0; + Integer dbIndex = JedisURIHelper.getDBIndex(uri); + if (dbIndex != null) { + database = dbIndex.intValue(); + } this.internalPool = new GenericObjectPool( new JedisFactory(h, port, Protocol.DEFAULT_TIMEOUT, password, database, null), @@ -39,13 +44,11 @@ public class JedisPool extends Pool { } public JedisPool(final URI uri) { - String h = uri.getHost(); - int port = uri.getPort(); - String password = uri.getUserInfo().split(":", 2)[1]; - int database = Integer.parseInt(uri.getPath().split("/", 2)[1]); - this.internalPool = new GenericObjectPool(new JedisFactory(h, - port, Protocol.DEFAULT_TIMEOUT, password, database, null), - new GenericObjectPoolConfig()); + this(new GenericObjectPoolConfig(), uri, Protocol.DEFAULT_TIMEOUT); + } + + public JedisPool(final URI uri, final int timeout) { + this(new GenericObjectPoolConfig(), uri, timeout); } public JedisPool(final GenericObjectPoolConfig poolConfig, @@ -79,6 +82,18 @@ public class JedisPool extends Pool { database, clientName)); } + public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri) { + this(poolConfig, uri, Protocol.DEFAULT_TIMEOUT); + } + + public JedisPool(final GenericObjectPoolConfig poolConfig, final URI uri, + final int timeout) { + super(poolConfig, new JedisFactory(uri.getHost(), uri.getPort(), + timeout, JedisURIHelper.getPassword(uri), + JedisURIHelper.getDBIndex(uri) != null ? JedisURIHelper + .getDBIndex(uri) : 0, null)); + } + @Override public Jedis getResource() { Jedis jedis = super.getResource(); @@ -98,4 +113,12 @@ public class JedisPool extends Pool { returnResourceObject(resource); } } + + public int getNumActive() { + if (this.internalPool == null || this.internalPool.isClosed()) { + return -1; + } + + return this.internalPool.getNumActive(); + } } diff --git a/src/main/java/redis/clients/jedis/JedisPubSub.java b/src/main/java/redis/clients/jedis/JedisPubSub.java index 7dfcf07..2ded002 100644 --- a/src/main/java/redis/clients/jedis/JedisPubSub.java +++ b/src/main/java/redis/clients/jedis/JedisPubSub.java @@ -162,12 +162,6 @@ public abstract class JedisPubSub { /* Invalidate instance since this thread is no longer listening */ this.client = null; - - /* - * Reset pipeline count because subscribe() calls would have increased - * it but nothing decremented it. - */ - client.resetPipelinedCount(); } public int getSubscribedChannels() { diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 0ff0dff..b3e6abd 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -65,6 +65,7 @@ public class JedisSentinelPool extends Pool { public JedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) { + this.poolConfig = poolConfig; this.timeout = timeout; this.password = password; @@ -74,6 +75,7 @@ public class JedisSentinelPool extends Pool { initPool(master); } + private volatile JedisFactory factory; private volatile HostAndPort currentHostMaster; public void destroy() { @@ -91,10 +93,18 @@ public class JedisSentinelPool extends Pool { private void initPool(HostAndPort master) { if (!master.equals(currentHostMaster)) { currentHostMaster = master; + if (factory == null) { + factory = new JedisFactory(master.getHost(), master.getPort(), + timeout, password, database); + initPool(poolConfig, factory); + } else { + factory.setHostAndPort(currentHostMaster); + // although we clear the pool, we still have to check the returned object + // in getResource, this call only clears idle instances, not borrowed instances + internalPool.clear(); + } + log.info("Created JedisPool to master at " + master); - initPool(poolConfig, - new JedisFactory(master.getHost(), master.getPort(), - timeout, password, database)); } } @@ -115,19 +125,30 @@ public class JedisSentinelPool extends Pool { log.fine("Connecting to Sentinel " + hap); + Jedis jedis = null; try { - Jedis jedis = new Jedis(hap.getHost(), hap.getPort()); + jedis = new Jedis(hap.getHost(), hap.getPort()); if (master == null) { - master = toHostAndPort(jedis - .sentinelGetMasterAddrByName(masterName)); + List masterAddr = jedis + .sentinelGetMasterAddrByName(masterName); + if (masterAddr == null || masterAddr.size() != 2) { + log.warning("Can not get master addr, master name: " + + masterName + ". Sentinel: " + hap + "."); + continue; + } + + master = toHostAndPort(masterAddr); log.fine("Found Redis master at " + master); - jedis.disconnect(); break outer; } } catch (JedisConnectionException e) { log.warning("Cannot connect to sentinel running @ " + hap + ". Trying next one."); + } finally { + if (jedis != null) { + jedis.close(); + } } } @@ -164,9 +185,22 @@ public class JedisSentinelPool extends Pool { @Override public Jedis getResource() { - Jedis jedis = super.getResource(); - jedis.setDataSource(this); - return jedis; + while (true) { + Jedis jedis = super.getResource(); + jedis.setDataSource(this); + + // get a reference because it can change concurrently + final HostAndPort master = currentHostMaster; + final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), + jedis.getClient().getPort()); + + if (master.equals(connection)) { + // connected to the correct master + return jedis; + } else { + returnBrokenResource(jedis); + } + } } public void returnBrokenResource(final Jedis resource) { diff --git a/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java b/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java index b0fb3b1..6ded228 100644 --- a/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java +++ b/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java @@ -48,14 +48,9 @@ public class JedisSlotBasedConnectionHandler extends throw new JedisConnectionException("no reachable node in cluster"); } - @Override - public void assignSlotToNode(int slot, HostAndPort targetNode) { - super.assignSlotToNode(slot, targetNode); - } - @Override public Jedis getConnectionFromSlot(int slot) { - JedisPool connectionPool = slots.get(slot); + JedisPool connectionPool = cache.getSlotPool(slot); if (connectionPool != null) { // It can't guaranteed to get valid connection because of node assignment return connectionPool.getResource(); @@ -66,7 +61,7 @@ public class JedisSlotBasedConnectionHandler extends private List getShuffledNodesPool() { List pools = new ArrayList(); - pools.addAll(nodes.values()); + pools.addAll(cache.getNodes().values()); Collections.shuffle(pools); return pools; } diff --git a/src/main/java/redis/clients/jedis/MultiKeyCommands.java b/src/main/java/redis/clients/jedis/MultiKeyCommands.java index 3f91ea9..9a464d1 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyCommands.java +++ b/src/main/java/redis/clients/jedis/MultiKeyCommands.java @@ -70,14 +70,6 @@ public interface MultiKeyCommands { Long bitop(BitOP op, final String destKey, String... srcKeys); - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - ScanResult scan(int cursor); - ScanResult scan(final String cursor); String pfmerge(final String destkey, final String... sourcekeys); diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index 4b19b5b..c79c969 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -1,10 +1,10 @@ package redis.clients.jedis; +import redis.clients.jedis.exceptions.JedisDataException; + import java.util.ArrayList; import java.util.List; -import redis.clients.jedis.exceptions.JedisDataException; - public class Pipeline extends MultiKeyPipelineBase { private MultiResponseBuilder currentMulti; @@ -26,7 +26,13 @@ public class Pipeline extends MultiKeyPipelineBase { for (int i = 0; i < list.size(); i++) { Response response = responses.get(i); response.set(list.get(i)); - values.add(response.get()); + Object builtResponse; + try { + builtResponse = response.get(); + } catch (JedisDataException e) { + builtResponse = e; + } + values.add(builtResponse); } return values; } @@ -69,13 +75,25 @@ public class Pipeline extends MultiKeyPipelineBase { return client; } + public void clear() { + if (isInMulti()) { + discard(); + } + + sync(); + } + + public boolean isInMulti() { + return currentMulti != null; + } + /** * Syncronize pipeline by reading all responses. This operation close the * pipeline. In order to get return values from pipelined commands, capture * the different Response of the commands you execute. */ public void sync() { - List unformatted = client.getAll(); + List unformatted = client.getMany(getPipelinedResponseLength()); for (Object o : unformatted) { generateResponse(o); } @@ -90,7 +108,7 @@ public class Pipeline extends MultiKeyPipelineBase { * @return A list of all the responses in the order you executed them. */ public List syncAndReturnAll() { - List unformatted = client.getAll(); + List unformatted = client.getMany(getPipelinedResponseLength()); List formatted = new ArrayList(); for (Object o : unformatted) { @@ -106,7 +124,6 @@ public class Pipeline extends MultiKeyPipelineBase { public Response discard() { if (currentMulti == null) throw new JedisDataException("DISCARD without MULTI"); - client.discard(); currentMulti = null; return getResponse(BuilderFactory.STRING); diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index 3972ad4..58d06e1 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -177,9 +177,9 @@ abstract class PipelineBase extends Queable implements BinaryRedisPipeline, return getResponse(BuilderFactory.BYTE_ARRAY); } - public Response getrange(byte[] key, long startOffset, long endOffset) { + public Response getrange(byte[] key, long startOffset, long endOffset) { getClient(key).getrange(key, startOffset, endOffset); - return getResponse(BuilderFactory.LONG); + return getResponse(BuilderFactory.BYTE_ARRAY); } public Response hdel(String key, String... field) { @@ -1026,6 +1026,56 @@ abstract class PipelineBase extends Queable implements BinaryRedisPipeline, return getResponse(BuilderFactory.DOUBLE); } + @Override + public Response zlexcount(final byte[] key, final byte[] min, final byte[] max) { + getClient(key).zlexcount(key, min, max); + return getResponse(BuilderFactory.LONG); + } + + @Override + public Response zlexcount(final String key, final String min, final String max) { + getClient(key).zlexcount(key, min, max); + return getResponse(BuilderFactory.LONG); + } + + @Override + public Response> zrangeByLex(final byte[] key, final byte[] max, final byte[] min) { + getClient(key).zrangeByLex(key, min, max); + return getResponse(BuilderFactory.BYTE_ARRAY_ZSET); + } + + @Override + public Response> zrangeByLex(final String key, final String max, final String min) { + getClient(key).zrangeByLex(key, min, max); + return getResponse(BuilderFactory.STRING_ZSET); + } + + @Override + public Response> zrangeByLex(final byte[] key, final byte[] max, + final byte[] min, final int offset, final int count) { + getClient(key).zrangeByLex(key, min, max, offset, count); + return getResponse(BuilderFactory.BYTE_ARRAY_ZSET); + } + + @Override + public Response> zrangeByLex(final String key, final String max, + final String min, final int offset, final int count) { + getClient(key).zrangeByLex(key, min, max, offset, count); + return getResponse(BuilderFactory.STRING_ZSET); + } + + @Override + public Response zremrangeByLex(final byte[] key, final byte[] min, final byte[] max) { + getClient(key).zremrangeByLex(key, min, max); + return getResponse(BuilderFactory.LONG); + } + + @Override + public Response zremrangeByLex(final String key, final String min, final String max) { + getClient(key).zremrangeByLex(key, min, max); + return getResponse(BuilderFactory.LONG); + } + public Response bitcount(String key) { getClient(key).bitcount(key); return getResponse(BuilderFactory.LONG); @@ -1098,16 +1148,6 @@ abstract class PipelineBase extends Queable implements BinaryRedisPipeline, return getResponse(BuilderFactory.LONG); } - @Deprecated - public Response pexpire(String key, int milliseconds) { - return pexpire(key, (long) milliseconds); - } - - @Deprecated - public Response pexpire(byte[] key, int milliseconds) { - return pexpire(key, (long) milliseconds); - } - public Response pexpire(String key, long milliseconds) { getClient(key).pexpire(key, milliseconds); return getResponse(BuilderFactory.LONG); diff --git a/src/main/java/redis/clients/jedis/PipelineBlock.java b/src/main/java/redis/clients/jedis/PipelineBlock.java index 50181ba..24bae84 100644 --- a/src/main/java/redis/clients/jedis/PipelineBlock.java +++ b/src/main/java/redis/clients/jedis/PipelineBlock.java @@ -7,5 +7,9 @@ package redis.clients.jedis; * @see https://github.com/xetorthio/jedis/pull/498 */ public abstract class PipelineBlock extends Pipeline { + // For shadowing + @SuppressWarnings("unused") + private Client client; + public abstract void execute(); } diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 3f77b9a..dcc225e 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -59,6 +59,7 @@ public final class Protocol { public static final String CLUSTER_REPLICATE = "replicate"; public static final String CLUSTER_SLAVES = "slaves"; public static final String CLUSTER_FAILOVER = "failover"; + public static final String CLUSTER_SLOTS = "slots"; public static final String PUBSUB_CHANNELS= "channels"; public static final String PUBSUB_NUMSUB = "numsub"; public static final String PUBSUB_NUM_PAT = "numpat"; @@ -217,7 +218,7 @@ public final class Protocol { } public static enum Command { - PING, SET, GET, QUIT, EXISTS, DEL, 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, 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; + PING, SET, GET, QUIT, EXISTS, DEL, 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, 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; public final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/Queable.java b/src/main/java/redis/clients/jedis/Queable.java index 769bf16..2cd5265 100644 --- a/src/main/java/redis/clients/jedis/Queable.java +++ b/src/main/java/redis/clients/jedis/Queable.java @@ -24,4 +24,11 @@ public class Queable { return lr; } + protected boolean hasPipelinedResponse() { + return pipelinedResponses.size() > 0; + } + + protected int getPipelinedResponseLength() { + return pipelinedResponses.size(); + } } diff --git a/src/main/java/redis/clients/jedis/RedisPipeline.java b/src/main/java/redis/clients/jedis/RedisPipeline.java index 6e36d10..63e3257 100644 --- a/src/main/java/redis/clients/jedis/RedisPipeline.java +++ b/src/main/java/redis/clients/jedis/RedisPipeline.java @@ -184,6 +184,15 @@ public interface RedisPipeline { Response zrevrank(String key, String member); Response zscore(String key, String member); + + Response zlexcount(final String key, final String min, final String max); + + Response> zrangeByLex(final String key, final String max, final String min); + + Response> zrangeByLex(final String key, final String max, final String min, + final int offset, final int count); + + Response zremrangeByLex(final String key, final String start, final String end); Response bitcount(String key); diff --git a/src/main/java/redis/clients/jedis/ScanResult.java b/src/main/java/redis/clients/jedis/ScanResult.java index 199689e..84af540 100644 --- a/src/main/java/redis/clients/jedis/ScanResult.java +++ b/src/main/java/redis/clients/jedis/ScanResult.java @@ -8,16 +8,6 @@ public class ScanResult { private byte[] cursor; private List results; - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult(int cursor, List results) { - this(Protocol.toByteArray(cursor), results); - } - public ScanResult(String cursor, List results) { this(SafeEncoder.encode(cursor), results); } @@ -27,21 +17,7 @@ public class ScanResult { this.results = results; } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - * @return int(currently), but will be changed to String, so be careful to prepare! - */ - public int getCursor() { - return Integer.parseInt(getStringCursor()); - } - - /** - * FIXME: This method should be changed to getCursor() on next major release - */ - public String getStringCursor() { + public String getCursor() { return SafeEncoder.encode(cursor); } diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 9691448..333a63e 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -125,12 +125,18 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, Jedis j = getShard(arg); return j.blpop(arg); } - + public List blpop(int timeout,String key){ + Jedis j = getShard(key); + return j.blpop(timeout,key); + } public List brpop(String arg) { Jedis j = getShard(arg); return j.brpop(arg); } - + public List brpop(int timeout,String key) { + Jedis j = getShard(key); + return j.brpop(timeout,key); + } public Long decrBy(String key, long integer) { Jedis j = getShard(key); return j.decrBy(key, integer); @@ -346,6 +352,12 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, return j.srandmember(key); } + @Override + public List srandmember(String key, int count) { + Jedis j = getShard(key); + return j.srandmember(key, count); + } + public Long zadd(String key, double score, String member) { Jedis j = getShard(key); return j.zadd(key, score, member); @@ -530,6 +542,27 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, Jedis j = getShard(key); return j.zremrangeByScore(key, start, end); } + + @Override + public Long zlexcount(final String key, final String min, final String max) { + return getShard(key).zlexcount(key, min, max); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max) { + return getShard(key).zrangeByLex(key, min, max); + } + + @Override + public Set zrangeByLex(final String key, final String min, final String max, + final int offset, final int count) { + return getShard(key).zrangeByLex(key, min, max, offset, count); + } + + @Override + public Long zremrangeByLex(final String key, final String min, final String max) { + return getShard(key).zremrangeByLex(key, min, max); + } public Long linsert(String key, LIST_POSITION where, String pivot, String value) { @@ -547,41 +580,7 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, return j.bitcount(key, start, end); } - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult> hscan(String key, int cursor) { - Jedis j = getShard(key); - return j.hscan(key, cursor); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult sscan(String key, int cursor) { - Jedis j = getShard(key); - return j.sscan(key, cursor); - } - - @Deprecated - /** - * This method is deprecated due to bug (scan cursor should be unsigned long) - * And will be removed on next major release - * @see https://github.com/xetorthio/jedis/issues/531 - */ - public ScanResult zscan(String key, int cursor) { - Jedis j = getShard(key); - return j.zscan(key, cursor); - } - - public ScanResult> hscan(String key, - final String cursor) { + public ScanResult> hscan(String key, final String cursor) { Jedis j = getShard(key); return j.hscan(key, cursor); } @@ -639,4 +638,5 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands, Jedis j = getShard(key); return j.pfcount(key); } + } diff --git a/src/main/java/redis/clients/jedis/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index 69d50d2..e6088ff 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -31,9 +31,16 @@ public class Transaction extends MultiKeyPipelineBase { return client; } + public void clear() { + if (inTransaction) { + discard(); + } + } + public List exec() { + // Discard QUEUED or ERROR + client.getMany(getPipelinedResponseLength()); client.exec(); - client.getAll(1); // Discard all but the last reply List unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { @@ -51,8 +58,9 @@ public class Transaction extends MultiKeyPipelineBase { } public List> execGetResponse() { + // Discard QUEUED or ERROR + client.getMany(getPipelinedResponseLength()); client.exec(); - client.getAll(1); // Discard all but the last reply List unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { @@ -66,11 +74,15 @@ public class Transaction extends MultiKeyPipelineBase { } public String discard() { + client.getMany(getPipelinedResponseLength()); client.discard(); - client.getAll(1); // Discard all but the last reply inTransaction = false; clean(); return client.getStatusCodeReply(); } + public void setClient(Client client) { + this.client = client; + } + } \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/TransactionBlock.java b/src/main/java/redis/clients/jedis/TransactionBlock.java index 86f7c44..c038ac2 100644 --- a/src/main/java/redis/clients/jedis/TransactionBlock.java +++ b/src/main/java/redis/clients/jedis/TransactionBlock.java @@ -9,6 +9,10 @@ import redis.clients.jedis.exceptions.JedisException; * @see https://github.com/xetorthio/jedis/pull/498 */ public abstract class TransactionBlock extends Transaction { + // For shadowing + @SuppressWarnings("unused") + private Client client; + public TransactionBlock(Client client) { super(client); } @@ -19,6 +23,6 @@ public abstract class TransactionBlock extends Transaction { public abstract void execute() throws JedisException; public void setClient(Client client) { - this.client = client; + super.setClient(client); } } diff --git a/src/main/java/redis/clients/jedis/ZParams.java b/src/main/java/redis/clients/jedis/ZParams.java index 7b585f3..6b42174 100644 --- a/src/main/java/redis/clients/jedis/ZParams.java +++ b/src/main/java/redis/clients/jedis/ZParams.java @@ -23,9 +23,15 @@ public class ZParams { private List params = new ArrayList(); - public ZParams weights(final int... weights) { + /** + * Set weights. + * + * @param weights + * weights. + */ + public ZParams weights(final double... weights) { params.add(WEIGHTS.raw); - for (final int weight : weights) { + for (final double weight : weights) { params.add(Protocol.toByteArray(weight)); } diff --git a/src/main/java/redis/clients/util/ClusterNodeInformationParser.java b/src/main/java/redis/clients/util/ClusterNodeInformationParser.java index 995df6f..3c10c95 100644 --- a/src/main/java/redis/clients/util/ClusterNodeInformationParser.java +++ b/src/main/java/redis/clients/util/ClusterNodeInformationParser.java @@ -3,7 +3,6 @@ package redis.clients.util; import redis.clients.jedis.HostAndPort; public class ClusterNodeInformationParser { - private static final String HOST_MYSELF_IDENTIFIER = ":0"; private static final String SLOT_IMPORT_IDENTIFIER = "-<-"; private static final String SLOT_IN_TRANSITION_IDENTIFIER = "["; public static final int SLOT_INFORMATIONS_START_INDEX = 8; @@ -36,13 +35,13 @@ public class ClusterNodeInformationParser { public HostAndPort getHostAndPortFromNodeLine(String[] nodeInfoPartArray, HostAndPort current) { String stringHostAndPort = nodeInfoPartArray[HOST_AND_PORT_INDEX]; - if (HOST_MYSELF_IDENTIFIER.equals(stringHostAndPort)) { - return current; - } String[] arrayHostAndPort = stringHostAndPort.split(":"); - return new HostAndPort(arrayHostAndPort[0], - Integer.valueOf(arrayHostAndPort[1])); + return new HostAndPort( + arrayHostAndPort[0].isEmpty() ? current.getHost() + : arrayHostAndPort[0], + arrayHostAndPort[1].isEmpty() ? current.getPort() : Integer + .valueOf(arrayHostAndPort[1])); } private void fillSlotInformation(String[] slotInfoPartArray, diff --git a/src/main/java/redis/clients/util/JedisURIHelper.java b/src/main/java/redis/clients/util/JedisURIHelper.java new file mode 100644 index 0000000..d2039a8 --- /dev/null +++ b/src/main/java/redis/clients/util/JedisURIHelper.java @@ -0,0 +1,26 @@ +package redis.clients.util; + +import java.net.URI; + +public class JedisURIHelper { + public static String getPassword(URI uri) { + String userInfo = uri.getUserInfo(); + if (userInfo != null) { + return userInfo.split(":", 2)[1]; + } + return null; + } + + public static Integer getDBIndex(URI uri) { + String[] pathSplit = uri.getPath().split("/", 2); + if (pathSplit.length > 1) { + String dbIndexStr = pathSplit[1]; + if (dbIndexStr.isEmpty()) { + return 0; + } + return Integer.parseInt(dbIndexStr); + } else { + return 0; + } + } +} diff --git a/src/main/java/redis/clients/util/Pool.java b/src/main/java/redis/clients/util/Pool.java index 659c731..106f9d5 100644 --- a/src/main/java/redis/clients/util/Pool.java +++ b/src/main/java/redis/clients/util/Pool.java @@ -1,5 +1,7 @@ package redis.clients.util; +import java.io.Closeable; + import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; @@ -7,7 +9,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; -public abstract class Pool { +public abstract class Pool implements Closeable { protected GenericObjectPool internalPool; /** @@ -17,6 +19,15 @@ public abstract class Pool { public Pool() { } + @Override + public void close() { + closeInternalPool(); + } + + public boolean isClosed() { + return this.internalPool.isClosed(); + } + public Pool(final GenericObjectPoolConfig poolConfig, PooledObjectFactory factory) { initPool(poolConfig, factory); diff --git a/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java b/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java new file mode 100644 index 0000000..5717641 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java @@ -0,0 +1,44 @@ +package redis.clients.jedis.tests; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import redis.clients.jedis.Connection; +import redis.clients.jedis.exceptions.JedisConnectionException; + +public class ConnectionCloseTest extends Assert { + + private Connection client; + + @Before + public void setUp() throws Exception { + client = new Connection(); + } + + @After + public void tearDown() throws Exception { + client.close(); + } + + @Test(expected = JedisConnectionException.class) + public void checkUnkownHost() { + client.setHost("someunknownhost"); + client.connect(); + } + + @Test(expected = JedisConnectionException.class) + public void checkWrongPort() { + client.setHost("localhost"); + client.setPort(55665); + client.connect(); + } + + @Test + public void connectIfNotConnectedWhenSettingTimeoutInfinite() { + client.setHost("localhost"); + client.setPort(6379); + client.setTimeoutInfinite(); + } +} diff --git a/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java b/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java index b2c9cf0..e27b0c7 100644 --- a/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java +++ b/src/test/java/redis/clients/jedis/tests/HostAndPortUtil.java @@ -23,6 +23,7 @@ public class HostAndPortUtil { sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2)); + sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3)); clusterHostAndPortList.add(new HostAndPort("localhost", 7379)); clusterHostAndPortList.add(new HostAndPort("localhost", 7380)); diff --git a/src/test/java/redis/clients/jedis/tests/JedisClusterNodeInformationParserTest.java b/src/test/java/redis/clients/jedis/tests/JedisClusterNodeInformationParserTest.java index bc0fd42..14b830f 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisClusterNodeInformationParserTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisClusterNodeInformationParserTest.java @@ -17,7 +17,7 @@ public class JedisClusterNodeInformationParserTest extends Assert { @Test public void testParseNodeMyself() { - String nodeInfo = "9b0d2ab38ee31482c95fdb2c7847a0d40e88d518 :0 myself,master - 0 0 1 connected 0-5460"; + String nodeInfo = "9b0d2ab38ee31482c95fdb2c7847a0d40e88d518 :7379 myself,master - 0 0 1 connected 0-5460"; HostAndPort current = new HostAndPort("localhost", 7379); ClusterNodeInformation clusterNodeInfo = parser .parse(nodeInfo, current); @@ -44,7 +44,7 @@ public class JedisClusterNodeInformationParserTest extends Assert { @Test public void testParseSlotBeingMigrated() { - String nodeInfo = "5f4a2236d00008fba7ac0dd24b95762b446767bd :0 myself,master - 0 0 1 connected 0-5459 [5460->-5f4a2236d00008fba7ac0dd24b95762b446767bd] [5461-<-5f4a2236d00008fba7ac0dd24b95762b446767bd]"; + String nodeInfo = "5f4a2236d00008fba7ac0dd24b95762b446767bd :7379 myself,master - 0 0 1 connected 0-5459 [5460->-5f4a2236d00008fba7ac0dd24b95762b446767bd] [5461-<-5f4a2236d00008fba7ac0dd24b95762b446767bd]"; HostAndPort current = new HostAndPort("localhost", 7379); ClusterNodeInformation clusterNodeInfo = parser .parse(nodeInfo, current); diff --git a/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java b/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java index dca8cfb..d93ed34 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java @@ -2,6 +2,7 @@ package redis.clients.jedis.tests; import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -15,7 +16,13 @@ import org.junit.Test; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.exceptions.*; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.exceptions.JedisAskDataException; +import redis.clients.jedis.exceptions.JedisClusterException; +import redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException; +import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.exceptions.JedisException; +import redis.clients.jedis.exceptions.JedisMovedDataException; import redis.clients.jedis.tests.utils.JedisClusterTestUtil; import redis.clients.util.JedisClusterCRC16; @@ -329,6 +336,33 @@ public class JedisClusterTest extends Assert { jc.set("52", "poolTestValue"); } + @Test + public void testCloseable() { + Set jedisClusterNode = new HashSet(); + jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort())); + + JedisCluster jc = null; + try { + jc = new JedisCluster(jedisClusterNode); + jc.set("51", "foo"); + } finally { + if (jc != null) { + jc.close(); + } + } + + Iterator poolIterator = jc.getClusterNodes().values().iterator(); + while (poolIterator.hasNext()) { + JedisPool pool = poolIterator.next(); + try { + pool.getResource(); + fail("JedisCluster's internal pools should be already destroyed"); + } catch (JedisConnectionException e) { + // ok to go... + } + } + } + private static String getNodeServingSlotRange(String infoOutput) { // f4f3dc4befda352a4e0beccf29f5e8828438705d 127.0.0.1:7380 master - 0 1394372400827 0 connected 5461-10922 for (String infoLine : infoOutput.split("\n")) { diff --git a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index 7d8e611..f8fb2ef 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -27,6 +27,20 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis.get("foo")); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); + } + + @Test + public void checkCloseableConnections() throws Exception { + JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), + hnp.getPort(), 2000); + Jedis jedis = pool.getResource(); + jedis.auth("foobared"); + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + pool.returnResource(jedis); + pool.close(); + assertTrue(pool.isClosed()); } @Test @@ -39,6 +53,7 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis.get("foo")); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -56,6 +71,7 @@ public class JedisPoolTest extends Assert { jedis.incr("foo"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -72,6 +88,7 @@ public class JedisPoolTest extends Assert { jedis.incr("foo"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test(expected = JedisConnectionException.class) @@ -99,6 +116,7 @@ public class JedisPoolTest extends Assert { jedis.set("foo", "bar"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -110,6 +128,7 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis0.get("foo")); pool0.returnResource(jedis0); pool0.destroy(); + assertTrue(pool0.isClosed()); JedisPool pool1 = new JedisPool(new JedisPoolConfig(), hnp.getHost(), hnp.getPort(), 2000, "foobared", 1); @@ -117,6 +136,7 @@ public class JedisPoolTest extends Assert { assertNull(jedis1.get("foo")); pool1.returnResource(jedis1); pool1.destroy(); + assertTrue(pool1.isClosed()); } @Test @@ -144,6 +164,12 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis.get("foo")); } + @Test + public void allowUrlWithNoDBAndNoPassword() throws URISyntaxException { + new JedisPool("redis://localhost:6380"); + new JedisPool(new URI("redis://localhost:6380")); + } + @Test public void selectDatabaseOnActivation() { JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), @@ -163,6 +189,7 @@ public class JedisPoolTest extends Assert { pool.returnResource(jedis1); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -176,6 +203,7 @@ public class JedisPoolTest extends Assert { pool0.returnResource(jedis); pool0.destroy(); + assertTrue(pool0.isClosed()); } @Test @@ -204,6 +232,7 @@ public class JedisPoolTest extends Assert { } pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -238,4 +267,40 @@ public class JedisPoolTest extends Assert { pool.returnResource(null); pool.returnResourceObject(null); } + + @Test + public void getNumActiveIsNegativeWhenPoolIsClosed() { + JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), + hnp.getPort(), 2000, "foobared", 0, "my_shiny_client_name"); + + pool.destroy(); + assertTrue(pool.getNumActive() < 0); + } + + @Test + public void getNumActiveReturnsTheCorrectNumber() { + JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(), + hnp.getPort(), 2000); + Jedis jedis = pool.getResource(); + jedis.auth("foobared"); + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + + assertEquals(1, pool.getNumActive()); + + Jedis jedis2 = pool.getResource(); + jedis.auth("foobared"); + jedis.set("foo", "bar"); + + assertEquals(2, pool.getNumActive()); + + pool.returnResource(jedis); + assertEquals(1, pool.getNumActive()); + + pool.returnResource(jedis2); + + assertEquals(0, pool.getNumActive()); + + pool.destroy(); + } } diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index 205d90a..1fac249 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -2,6 +2,7 @@ package redis.clients.jedis.tests; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.Before; @@ -21,18 +22,63 @@ public class JedisSentinelPoolTest extends JedisTestBase { .get(2); protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers() .get(3); + protected static HostAndPort sentinel1 = HostAndPortUtil .getSentinelServers().get(1); + protected static HostAndPort sentinel2 = HostAndPortUtil + .getSentinelServers().get(3); protected static Jedis sentinelJedis1; + protected static Jedis sentinelJedis2; protected Set sentinels = new HashSet(); @Before public void setUp() throws Exception { sentinels.add(sentinel1.toString()); + sentinels.add(sentinel2.toString()); sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); + sentinelJedis2 = new Jedis(sentinel2.getHost(), sentinel2.getPort()); + } + + @Test + public void errorMasterNameNotThrowException() throws InterruptedException { + final String wrongMasterName = "wrongMasterName"; + new Thread(new Runnable() { + @Override + public void run() { + try { + TimeUnit.SECONDS.sleep(3); + sentinelJedis1.sentinelMonitor(wrongMasterName, + "127.0.0.1", master.getPort(), 2); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + }).start(); + + JedisSentinelPool pool = new JedisSentinelPool(wrongMasterName, + sentinels); + pool.destroy(); + sentinelJedis1.sentinelRemove(wrongMasterName); + } + + + @Test + public void checkCloseableConnections() throws Exception { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + + JedisSentinelPool pool = new JedisSentinelPool( + MASTER_NAME, sentinels, config, 1000, "foobared", 2); + Jedis jedis = pool.getResource(); + jedis.auth("foobared"); + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + pool.returnResource(jedis); + pool.close(); + assertTrue(pool.isClosed()); } @Test @@ -41,6 +87,8 @@ public class JedisSentinelPoolTest extends JedisTestBase { new GenericObjectPoolConfig(), 1000, "foobared", 2); forceFailover(pool); + // after failover sentinel needs a bit of time to stabilize before a new failover + Thread.sleep(100); forceFailover(pool); // you can test failover as much as possible @@ -134,29 +182,25 @@ public class JedisSentinelPoolTest extends JedisTestBase { HostAndPort oldMaster = pool.getCurrentHostMaster(); // jedis connection should be master - Jedis jedis = pool.getResource(); - assertEquals("PONG", jedis.ping()); + Jedis beforeFailoverJedis = pool.getResource(); + assertEquals("PONG", beforeFailoverJedis.ping()); - // It can throw JedisDataException while there's no slave to promote - // There's nothing we can do, so we just pass Exception to make test - // fail fast - sentinelJedis1.sentinelFailover(MASTER_NAME); - waitForFailover(pool, oldMaster); - // JedisSentinelPool recognize master but may not changed internal pool - // yet - Thread.sleep(100); + + Jedis afterFailoverJedis = pool.getResource(); + assertEquals("PONG", afterFailoverJedis.ping()); + assertEquals("foobared", afterFailoverJedis.configGet("requirepass").get(1)); + assertEquals(2, afterFailoverJedis.getDB().intValue()); - jedis = pool.getResource(); - assertEquals("PONG", jedis.ping()); - assertEquals("foobared", jedis.configGet("requirepass").get(1)); - assertEquals(2, jedis.getDB().intValue()); + // returning both connections to the pool should not throw + beforeFailoverJedis.close(); + afterFailoverJedis.close(); } private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) throws InterruptedException { HostAndPort newMaster = JedisSentinelTestUtil - .waitForNewPromotedMaster(sentinelJedis1); + .waitForNewPromotedMaster(MASTER_NAME, sentinelJedis1, sentinelJedis2); waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster); } @@ -166,10 +210,9 @@ public class JedisSentinelPoolTest extends JedisTestBase { throws InterruptedException { while (true) { - String host = pool.getCurrentHostMaster().getHost(); - int port = pool.getCurrentHostMaster().getPort(); + HostAndPort currentHostMaster = pool.getCurrentHostMaster(); - if (host.equals(newMaster.getHost()) && port == newMaster.getPort()) + if (newMaster.equals(currentHostMaster)) break; System.out @@ -179,4 +222,4 @@ public class JedisSentinelPoolTest extends JedisTestBase { } } -} +} \ No newline at end of file diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelTest.java index 822c659..349506b 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelTest.java @@ -85,16 +85,16 @@ public class JedisSentinelTest extends JedisTestBase { public void sentinelFailover() throws InterruptedException { Jedis j = new Jedis(sentinelForFailover.getHost(), sentinelForFailover.getPort()); + Jedis j2 = new Jedis(sentinelForFailover.getHost(), + sentinelForFailover.getPort()); try { List masterHostAndPort = j .sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME); HostAndPort currentMaster = new HostAndPort(masterHostAndPort.get(0), Integer.parseInt(masterHostAndPort.get(1))); - String result = j.sentinelFailover(FAILOVER_MASTER_NAME); - assertEquals("OK", result); - JedisSentinelTestUtil.waitForNewPromotedMaster(j); + JedisSentinelTestUtil.waitForNewPromotedMaster(FAILOVER_MASTER_NAME, j, j2); masterHostAndPort = j .sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME); diff --git a/src/test/java/redis/clients/jedis/tests/JedisTest.java b/src/test/java/redis/clients/jedis/tests/JedisTest.java index 3f5cdf1..3b7a87f 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisTest.java @@ -57,6 +57,14 @@ public class JedisTest extends JedisCommandTestBase { jedis.hmget("foobar", "foo"); } + @Test(expected = JedisConnectionException.class) + public void timeoutConnectionWithURI() throws Exception { + jedis = new Jedis(new URI("redis://:foobared@localhost:6380/2"), 15000); + jedis.configSet("timeout", "1"); + Thread.sleep(2000); + jedis.hmget("foobar", "foo"); + } + @Test(expected = JedisDataException.class) public void failWhenSendingNullValues() { jedis.set("foo", null); @@ -92,7 +100,22 @@ public class JedisTest extends JedisCommandTestBase { assertEquals("PONG", jedis.ping()); assertEquals("bar", jedis.get("foo")); } - + + @Test + public void allowUrlWithNoDBAndNoPassword() { + Jedis jedis = new Jedis("redis://localhost:6380"); + jedis.auth("foobared"); + assertEquals(jedis.getClient().getHost(), "localhost"); + assertEquals(jedis.getClient().getPort(), 6380); + assertEquals(jedis.getDB(), (Long) 0L); + + jedis = new Jedis("redis://localhost:6380/"); + jedis.auth("foobared"); + assertEquals(jedis.getClient().getHost(), "localhost"); + assertEquals(jedis.getClient().getPort(), 6380); + assertEquals(jedis.getDB(), (Long) 0L); + } + @Test public void checkCloseable() { jedis.close(); diff --git a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java index 29b2f86..eb336bd 100755 --- a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java +++ b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java @@ -1,24 +1,14 @@ package redis.clients.jedis.tests; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; - -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Response; -import redis.clients.jedis.Tuple; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisDataException; +import java.io.UnsupportedEncodingException; +import java.util.*; + public class PipeliningTest extends Assert { private static HostAndPort hnp = HostAndPortUtil.getRedisServers().get(0); @@ -52,6 +42,9 @@ public class PipeliningTest extends Assert { jedis.hset("hash", "foo", "bar"); jedis.zadd("zset", 1, "foo"); jedis.sadd("set", "foo"); + jedis.setrange("setrange", 0, "0123456789"); + byte[] bytesForSetRange = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + jedis.setrange("setrangebytes".getBytes(), 0, bytesForSetRange); Pipeline p = jedis.pipelined(); Response string = p.get("string"); @@ -68,8 +61,10 @@ public class PipeliningTest extends Assert { p.sadd("set", "foo"); Response> smembers = p.smembers("set"); Response> zrangeWithScores = p.zrangeWithScores("zset", 0, - -1); - p.sync(); + -1); + Response getrange = p.getrange("setrange", 1, 3); + Response getrangeBytes = p.getrange("setrangebytes".getBytes(), 6, 8); + p.sync(); assertEquals("foo", string.get()); assertEquals("foo", list.get()); @@ -83,6 +78,9 @@ public class PipeliningTest extends Assert { assertNotNull(hgetAll.get().get("foo")); assertEquals(1, smembers.get().size()); assertEquals(1, zrangeWithScores.get().size()); + assertEquals("123", getrange.get()); + byte[] expectedGetRangeBytes = {6, 7, 8}; + assertArrayEquals(expectedGetRangeBytes, getrangeBytes.get()); } @Test @@ -373,4 +371,79 @@ public class PipeliningTest extends Assert { assertNull(result1.get()); assertEquals("13", result2.get()); } + + @Test + public void testPipelinedTransactionResponse() { + + String key1 = "key1"; + String val1 = "val1"; + + String key2 = "key2"; + String val2 = "val2"; + + String key3 = "key3"; + String field1 = "field1"; + String field2 = "field2"; + String field3 = "field3"; + String field4 = "field4"; + + String value1 = "value1"; + String value2 = "value2"; + String value3 = "value3"; + String value4 = "value4"; + + Map hashMap = new HashMap(); + hashMap.put(field1, value1); + hashMap.put(field2, value2); + + String key4 = "key4"; + Map hashMap1 = new HashMap(); + hashMap1.put(field3, value3); + hashMap1.put(field4, value4); + + + jedis.set(key1, val1); + jedis.set(key2, val2); + jedis.hmset(key3, hashMap); + jedis.hmset(key4, hashMap1); + + Pipeline pipeline = jedis.pipelined(); + pipeline.multi(); + + pipeline.get(key1); + pipeline.hgetAll(key2); + pipeline.hgetAll(key3); + pipeline.get(key4); + + Response > response = pipeline.exec(); + pipeline.sync(); + + List result = response.get(); + + assertEquals(4, result.size()); + + assertEquals("val1", result.get(0)); + + assertTrue(result.get(1) instanceof JedisDataException); + + Map hashMapReceived = (Map)result.get(2); + Iterator iterator = hashMapReceived.keySet().iterator(); + String mapKey1 = iterator.next(); + String mapKey2 = iterator.next(); + assertFalse(iterator.hasNext()); + verifyHasBothValues(mapKey1, mapKey2, field1, field2); + String mapValue1 = hashMapReceived.get(mapKey1); + String mapValue2 = hashMapReceived.get(mapKey2); + verifyHasBothValues(mapValue1, mapValue2, value1, value2); + + assertTrue(result.get(3) instanceof JedisDataException); + } + + private void verifyHasBothValues(String firstKey, String secondKey, String value1, String value2) { + assertFalse(firstKey.equals(secondKey)); + assertTrue(firstKey.equals(value1) + || firstKey.equals(value2)); + assertTrue(secondKey.equals(value1) + || secondKey.equals(value2)); + } } diff --git a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java index b1350e9..4b2da9c 100644 --- a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java @@ -55,6 +55,18 @@ public class ShardedJedisPoolTest extends Assert { pool.destroy(); } + @Test + public void checkCloseableConnections() throws Exception { + ShardedJedisPool pool = new ShardedJedisPool( + new GenericObjectPoolConfig(), shards); + ShardedJedis jedis = pool.getResource(); + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + pool.returnResource(jedis); + pool.close(); + assertTrue(pool.isClosed()); + } + @Test public void checkConnectionWithDefaultPort() { ShardedJedisPool pool = new ShardedJedisPool( diff --git a/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java index 2647f07..dfcf490 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java @@ -521,7 +521,7 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase { ScanResult result = jedis.scan(SCAN_POINTER_START); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary @@ -541,7 +541,7 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase { jedis.set("aa", "aa"); ScanResult result = jedis.scan(SCAN_POINTER_START, params); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary diff --git a/src/test/java/redis/clients/jedis/tests/commands/ClusterCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/ClusterCommandsTest.java index 03ebc89..f4b532f 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/ClusterCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/ClusterCommandsTest.java @@ -45,6 +45,8 @@ public class ClusterCommandsTest extends JedisTestBase { node1.clusterDelSlots(1, 2, 3, 4, 5, 500); node1.clusterSetSlotNode(5000, node1Id); node1.clusterDelSlots(5000, 10000); + node1.clusterDelSlots(3000, 3001, 3002); + node2.clusterDelSlots(4000, 4001, 4002); node1.clusterAddSlots(6000); node1.clusterDelSlots(6000); waitForGossip(); @@ -134,5 +136,34 @@ public class ClusterCommandsTest extends JedisTestBase { String status = node1.clusterSetSlotMigrating(5000, nodeId); assertEquals("OK", status); } + + @Test + public void clusterSlots() { + // please see cluster slot output format from below commit + // @see: + // https://github.com/antirez/redis/commit/e14829de3025ffb0d3294e5e5a1553afd9f10b60 + String status = node1.clusterAddSlots(3000, 3001, 3002); + assertEquals("OK", status); + status = node2.clusterAddSlots(4000, 4001, 4002); + assertEquals("OK", status); + + List slots = node1.clusterSlots(); + assertNotNull(slots); + assertTrue(slots.size() > 0); + + for (Object slotInfoObj : slots) { + List slotInfo = (List) slotInfoObj; + assertNotNull(slots); + assertTrue(slots.size() >= 2); + + assertTrue(slotInfo.get(0) instanceof Long); + assertTrue(slotInfo.get(1) instanceof Long); + + if (slots.size() > 2) { + // assigned slots + assertTrue(slotInfo.get(2) instanceof List); + } + } + } } \ No newline at end of file diff --git a/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java index aa86993..a2da021 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java @@ -9,9 +9,11 @@ import java.util.Map; import java.util.Set; import org.junit.Test; - +import redis.clients.jedis.Pipeline; +import redis.clients.jedis.Response; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; + import static redis.clients.jedis.ScanParams.SCAN_POINTER_START; import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY; @@ -316,6 +318,22 @@ public class HashesCommandsTest extends JedisCommandTestBase { assertArrayEquals(bbar, bhash.get(bcar)); } + @Test + public void hgetAllPipeline() { + Map bh = new HashMap(); + bh.put(bbar, bcar); + bh.put(bcar, bbar); + jedis.hmset(bfoo, bh); + Pipeline pipeline = jedis.pipelined(); + Response> bhashResponse = pipeline.hgetAll(bfoo); + pipeline.sync(); + Map bhash = bhashResponse.get(); + + assertEquals(2, bhash.size()); + assertArrayEquals(bcar, bhash.get(bbar)); + assertArrayEquals(bbar, bhash.get(bcar)); + } + @Test public void hscan() { jedis.hset("foo", "b", "b"); @@ -323,7 +341,7 @@ public class HashesCommandsTest extends JedisCommandTestBase { ScanResult> result = jedis.hscan("foo", SCAN_POINTER_START); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary @@ -346,7 +364,7 @@ public class HashesCommandsTest extends JedisCommandTestBase { ScanResult> result = jedis.hscan("foo", SCAN_POINTER_START, params); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary diff --git a/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java index 8687e67..c10572e 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java @@ -466,7 +466,7 @@ public class SetCommandsTest extends JedisCommandTestBase { ScanResult result = jedis.sscan("foo", SCAN_POINTER_START); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary @@ -486,7 +486,7 @@ public class SetCommandsTest extends JedisCommandTestBase { jedis.sadd("foo", "b", "a", "aa"); ScanResult result = jedis.sscan("foo", SCAN_POINTER_START, params); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary diff --git a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java index 3e66642..42ad7e0 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -20,6 +20,10 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { final byte[] ba = { 0x0A }; final byte[] bb = { 0x0B }; final byte[] bc = { 0x0C }; + final byte[] bInclusiveB = { 0x5B, 0x0B }; + final byte[] bExclusiveC = { 0x28, 0x0C }; + final byte[] bLexMinusInf = { 0x2D }; + final byte[] bLexPlusInf = { 0x2B }; final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A }; final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B }; @@ -54,7 +58,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(0, bstatus); } - + @Test public void zrange() { jedis.zadd("foo", 1d, "a"); @@ -91,6 +95,48 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(bexpected, brange); } + + @Test + public void zrangeByLex() { + jedis.zadd("foo", 1, "aa"); + jedis.zadd("foo", 1, "c"); + jedis.zadd("foo", 1, "bb"); + jedis.zadd("foo", 1, "d"); + + Set expected = new LinkedHashSet(); + expected.add("bb"); + expected.add("c"); + + // exclusive aa ~ inclusive c + assertEquals(expected, jedis.zrangeByLex("foo", "(aa", "[c")); + + expected.clear(); + expected.add("bb"); + expected.add("c"); + + // with LIMIT + assertEquals(expected, jedis.zrangeByLex("foo", "-", "+", 1, 2)); + } + + @Test + public void zrangeByLexBinary() { + // binary + jedis.zadd(bfoo, 1, ba); + jedis.zadd(bfoo, 1, bc); + jedis.zadd(bfoo, 1, bb); + + Set bExpected = new LinkedHashSet(); + bExpected.add(bb); + + assertEquals(bExpected, jedis.zrangeByLex(bfoo, bInclusiveB, bExclusiveC)); + + bExpected.clear(); + bExpected.add(ba); + bExpected.add(bb); + + // with LIMIT + assertEquals(bExpected, jedis.zrangeByLex(bfoo, bLexMinusInf, bLexPlusInf, 0, 2)); + } @Test public void zrevrange() { @@ -401,6 +447,40 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(3, bresult); } + + @Test + public void zlexcount() { + jedis.zadd("foo", 1, "a"); + jedis.zadd("foo", 1, "b"); + jedis.zadd("foo", 1, "c"); + jedis.zadd("foo", 1, "aa"); + + long result = jedis.zlexcount("foo", "[aa", "(c"); + assertEquals(2, result); + + result = jedis.zlexcount("foo", "-", "+"); + assertEquals(4, result); + + result = jedis.zlexcount("foo", "-", "(c"); + assertEquals(3, result); + + result = jedis.zlexcount("foo", "[aa", "+"); + assertEquals(3, result); + } + + @Test + public void zlexcountBinary() { + // Binary + jedis.zadd(bfoo, 1, ba); + jedis.zadd(bfoo, 1, bc); + jedis.zadd(bfoo, 1, bb); + + long result = jedis.zlexcount(bfoo, bInclusiveB, bExclusiveC); + assertEquals(1, result); + + result = jedis.zlexcount(bfoo, bLexMinusInf, bLexPlusInf); + assertEquals(3, result); + } @Test public void zrangebyscore() { @@ -739,6 +819,41 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(bexpected, jedis.zrange(bfoo, 0, 100)); } + + @Test + public void zremrangeByLex() { + jedis.zadd("foo", 1, "a"); + jedis.zadd("foo", 1, "b"); + jedis.zadd("foo", 1, "c"); + jedis.zadd("foo", 1, "aa"); + + long result = jedis.zremrangeByLex("foo", "[aa", "(c"); + + assertEquals(2, result); + + Set expected = new LinkedHashSet(); + expected.add("a"); + expected.add("c"); + + assertEquals(expected, jedis.zrangeByLex("foo", "-", "+")); + } + + @Test + public void zremrangeByLexBinary() { + jedis.zadd(bfoo, 1, ba); + jedis.zadd(bfoo, 1, bc); + jedis.zadd(bfoo, 1, bb); + + long bresult = jedis.zremrangeByLex(bfoo, bInclusiveB, bExclusiveC); + + assertEquals(1, bresult); + + Set bexpected = new LinkedHashSet(); + bexpected.add(ba); + bexpected.add(bc); + + assertEquals(bexpected, jedis.zrangeByLex(bfoo, bLexMinusInf, bLexPlusInf)); + } @Test public void zunionstore() { @@ -783,15 +898,15 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "b"); ZParams params = new ZParams(); - params.weights(2, 2); + params.weights(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zunionstore("dst", params, "foo", "bar"); assertEquals(2, result); Set expected = new LinkedHashSet(); - expected.add(new Tuple("b", new Double(8))); - expected.add(new Tuple("a", new Double(6))); + expected.add(new Tuple("b", new Double(9))); + expected.add(new Tuple("a", new Double(7))); assertEquals(expected, jedis.zrangeWithScores("dst", 0, 100)); @@ -802,7 +917,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, bb); ZParams bparams = new ZParams(); - bparams.weights(2, 2); + bparams.weights(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zunionstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); @@ -810,8 +925,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(2, bresult); Set bexpected = new LinkedHashSet(); - bexpected.add(new Tuple(bb, new Double(8))); - bexpected.add(new Tuple(ba, new Double(6))); + bexpected.add(new Tuple(bb, new Double(9))); + bexpected.add(new Tuple(ba, new Double(7))); assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100)); @@ -855,14 +970,14 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "a"); ZParams params = new ZParams(); - params.weights(2, 2); + params.weights(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zinterstore("dst", params, "foo", "bar"); assertEquals(1, result); Set expected = new LinkedHashSet(); - expected.add(new Tuple("a", new Double(6))); + expected.add(new Tuple("a", new Double(7))); assertEquals(expected, jedis.zrangeWithScores("dst", 0, 100)); @@ -872,7 +987,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, ba); ZParams bparams = new ZParams(); - bparams.weights(2, 2); + bparams.weights(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zinterstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); @@ -880,7 +995,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(1, bresult); Set bexpected = new LinkedHashSet(); - bexpected.add(new Tuple(ba, new Double(6))); + bexpected.add(new Tuple(ba, new Double(7))); assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100)); @@ -903,7 +1018,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { ScanResult result = jedis.zscan("foo", SCAN_POINTER_START); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary @@ -926,7 +1041,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("foo", 11, "aa"); ScanResult result = jedis.zscan("foo", SCAN_POINTER_START, params); - assertEquals(SCAN_POINTER_START, result.getStringCursor()); + assertEquals(SCAN_POINTER_START, result.getCursor()); assertFalse(result.getResult().isEmpty()); // binary @@ -970,4 +1085,4 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertFalse(bResult.getResult().isEmpty()); } -} \ No newline at end of file +} diff --git a/src/test/java/redis/clients/jedis/tests/utils/JedisSentinelTestUtil.java b/src/test/java/redis/clients/jedis/tests/utils/JedisSentinelTestUtil.java index dcb9334..a162ce2 100644 --- a/src/test/java/redis/clients/jedis/tests/utils/JedisSentinelTestUtil.java +++ b/src/test/java/redis/clients/jedis/tests/utils/JedisSentinelTestUtil.java @@ -8,7 +8,8 @@ import redis.clients.jedis.JedisPubSub; import redis.clients.jedis.tests.utils.FailoverAbortedException; public class JedisSentinelTestUtil { - public static HostAndPort waitForNewPromotedMaster(Jedis sentinelJedis) + public static HostAndPort waitForNewPromotedMaster(final String masterName, + final Jedis sentinelJedis, final Jedis commandJedis) throws InterruptedException { final AtomicReference newmaster = new AtomicReference( @@ -47,6 +48,7 @@ public class JedisSentinelTestUtil { @Override public void onPSubscribe(String pattern, int subscribedChannels) { + commandJedis.sentinelFailover(masterName); } }, "*");