From f7bd9c8313096d2402afbeb8d3478f2b81a0027b Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 20 Jan 2014 00:28:00 +0900 Subject: [PATCH 01/52] Refactor Pipeline / Transaction to consume responses based on their requests, not rely on pipelinedCommands * remove pipelinedCommands field at Connection class ** it was a risky state value *** it was under 0 or over 0(though all commands are executed) while some situation * remove Connection.getAll(), Connection.getAll(int except) --- .../java/redis/clients/jedis/Connection.java | 28 ------------------- .../java/redis/clients/jedis/Pipeline.java | 24 ++++++++++------ .../java/redis/clients/jedis/Queable.java | 7 +++++ .../java/redis/clients/jedis/Transaction.java | 27 ++++++++++++++++-- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 1c42b94..7c55f9a 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 { private Socket socket; private RedisOutputStream outputStream; private RedisInputStream inputStream; - private int pipelinedCommands = 0; private int timeout = Protocol.DEFAULT_TIMEOUT; public Socket getSocket() { @@ -81,14 +80,12 @@ public class Connection { protected Connection sendCommand(final Command cmd, final byte[]... args) { connect(); Protocol.sendCommand(outputStream, cmd, args); - pipelinedCommands++; return this; } protected Connection sendCommand(final Command cmd) { connect(); Protocol.sendCommand(outputStream, cmd, new byte[0][]); - pipelinedCommands++; return this; } @@ -161,7 +158,6 @@ public class Connection { protected String getStatusCodeReply() { flush(); - pipelinedCommands--; final byte[] resp = (byte[]) Protocol.read(inputStream); if (null == resp) { return null; @@ -181,13 +177,11 @@ public class Connection { public byte[] getBinaryBulkReply() { flush(); - pipelinedCommands--; return (byte[]) Protocol.read(inputStream); } public Long getIntegerReply() { flush(); - pipelinedCommands--; return (Long) Protocol.read(inputStream); } @@ -198,45 +192,23 @@ public class Connection { @SuppressWarnings("unchecked") public List getBinaryMultiBulkReply() { flush(); - pipelinedCommands--; return (List) Protocol.read(inputStream); } @SuppressWarnings("unchecked") public List getObjectMultiBulkReply() { flush(); - pipelinedCommands--; return (List) Protocol.read(inputStream); } @SuppressWarnings("unchecked") public List getIntegerMultiBulkReply() { flush(); - pipelinedCommands--; return (List) Protocol.read(inputStream); } - public List getAll() { - return getAll(0); - } - - public List getAll(int except) { - List all = new ArrayList(); - flush(); - while (pipelinedCommands > except) { - try{ - all.add(Protocol.read(inputStream)); - }catch(JedisDataException e){ - all.add(e); - } - pipelinedCommands--; - } - return all; - } - public Object getOne() { flush(); - pipelinedCommands--; return Protocol.read(inputStream); } } diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index 98cab69..786ef8c 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -62,17 +62,24 @@ public class Pipeline extends MultiKeyPipelineBase { protected Client getClient(String key) { return client; } - + + public Object getOneWithJedisDataException() { + try { + return client.getOne(); + } catch (JedisDataException e) { + return e; + } + } + /** * 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(); - for (Object o : unformatted) { - generateResponse(o); - } + while (hasPipelinedResponse()) { + generateResponse(getOneWithJedisDataException()); + } } /** @@ -84,12 +91,11 @@ 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 formatted = new ArrayList(); - for (Object o : unformatted) { - try { - formatted.add(generateResponse(o).get()); + while (hasPipelinedResponse()) { + try { + formatted.add(generateResponse(getOneWithJedisDataException()).get()); } catch (JedisDataException e) { formatted.add(e); } diff --git a/src/main/java/redis/clients/jedis/Queable.java b/src/main/java/redis/clients/jedis/Queable.java index b8ff0e5..d6ae31f 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/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index 949f541..4d88932 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -30,9 +30,26 @@ public class Transaction extends MultiKeyPipelineBase { return client; } + public Object getOneWithJedisDataException() { + try { + return client.getOne(); + } catch (JedisDataException e) { + return e; + } + } + + private void consumeResponse(int count) { + for (int i = 0 ; i < count ; i++) + getOneWithJedisDataException(); + } + public List exec() { + // Discard multi + consumeResponse(1); + // Discard QUEUED or ERROR + consumeResponse(getPipelinedResponseLength()); + client.exec(); - client.getAll(1); // Discard all but the last reply List unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { @@ -50,8 +67,12 @@ public class Transaction extends MultiKeyPipelineBase { } public List> execGetResponse() { + // Discard multi + consumeResponse(1); + // Discard QUEUED or ERROR + consumeResponse(getPipelinedResponseLength()); + client.exec(); - client.getAll(1); // Discard all but the last reply List unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { @@ -65,8 +86,8 @@ public class Transaction extends MultiKeyPipelineBase { } public String discard() { + consumeResponse(getPipelinedResponseLength()); client.discard(); - client.getAll(1); // Discard all but the last reply inTransaction = false; clean(); return client.getStatusCodeReply(); From 5bf29b43ee520309faf8bc4695f03337e4b88799 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 20 Jan 2014 07:31:13 +0900 Subject: [PATCH 02/52] Let BinaryJedis.multi() consumes "OK" message * Transaction doesn't have to consume "multi"'s response --- src/main/java/redis/clients/jedis/BinaryJedis.java | 2 ++ src/main/java/redis/clients/jedis/Transaction.java | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index f08633f..af5a395 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -1679,6 +1679,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey public Transaction multi() { client.multi(); + client.getOne(); // expected OK return new Transaction(client); } @@ -1687,6 +1688,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey jedisTransaction.setClient(client); try { client.multi(); + client.getOne(); // expected OK jedisTransaction.execute(); results = jedisTransaction.exec(); } catch (Exception ex) { diff --git a/src/main/java/redis/clients/jedis/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index 4d88932..11bb14a 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -44,8 +44,6 @@ public class Transaction extends MultiKeyPipelineBase { } public List exec() { - // Discard multi - consumeResponse(1); // Discard QUEUED or ERROR consumeResponse(getPipelinedResponseLength()); @@ -67,8 +65,6 @@ public class Transaction extends MultiKeyPipelineBase { } public List> execGetResponse() { - // Discard multi - consumeResponse(1); // Discard QUEUED or ERROR consumeResponse(getPipelinedResponseLength()); From 2267c3318ce6a157e98d43b7c53011868420c09b Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 20 Jan 2014 11:36:24 +0900 Subject: [PATCH 03/52] Implemented Client.getMany(int count) to remove multiple flush while getting responses at once --- .../java/redis/clients/jedis/Connection.java | 13 ++++++++++ .../java/redis/clients/jedis/Pipeline.java | 26 ++++++------------- .../java/redis/clients/jedis/Transaction.java | 19 +++----------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index 7c55f9a..bb12079 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -211,4 +211,17 @@ public class Connection { flush(); return Protocol.read(inputStream); } + + public List getMany(int count) { + flush(); + List responses = new ArrayList(); + for (int i = 0 ; i < count ; i++) { + try { + responses.add(Protocol.read(inputStream)); + } catch (JedisDataException e) { + responses.add(e); + } + } + return responses; + } } diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index 786ef8c..7df2a63 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -63,23 +63,16 @@ public class Pipeline extends MultiKeyPipelineBase { return client; } - public Object getOneWithJedisDataException() { - try { - return client.getOne(); - } catch (JedisDataException e) { - return e; - } - } - /** * 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() { - while (hasPipelinedResponse()) { - generateResponse(getOneWithJedisDataException()); - } + List unformatted = client.getMany(getPipelinedResponseLength()); + + for (Object resp : unformatted) + generateResponse(resp); } /** @@ -91,15 +84,12 @@ public class Pipeline extends MultiKeyPipelineBase { * @return A list of all the responses in the order you executed them. */ public List syncAndReturnAll() { + List unformatted = client.getMany(getPipelinedResponseLength()); List formatted = new ArrayList(); - while (hasPipelinedResponse()) { - try { - formatted.add(generateResponse(getOneWithJedisDataException()).get()); - } catch (JedisDataException e) { - formatted.add(e); - } - } + for (Object resp : unformatted) + formatted.add(generateResponse(resp).get()); + return formatted; } diff --git a/src/main/java/redis/clients/jedis/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index 11bb14a..d8cf9de 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -30,22 +30,9 @@ public class Transaction extends MultiKeyPipelineBase { return client; } - public Object getOneWithJedisDataException() { - try { - return client.getOne(); - } catch (JedisDataException e) { - return e; - } - } - - private void consumeResponse(int count) { - for (int i = 0 ; i < count ; i++) - getOneWithJedisDataException(); - } - public List exec() { // Discard QUEUED or ERROR - consumeResponse(getPipelinedResponseLength()); + client.getMany(getPipelinedResponseLength()); client.exec(); @@ -66,7 +53,7 @@ public class Transaction extends MultiKeyPipelineBase { public List> execGetResponse() { // Discard QUEUED or ERROR - consumeResponse(getPipelinedResponseLength()); + client.getMany(getPipelinedResponseLength()); client.exec(); @@ -82,7 +69,7 @@ public class Transaction extends MultiKeyPipelineBase { } public String discard() { - consumeResponse(getPipelinedResponseLength()); + client.getMany(getPipelinedResponseLength()); client.discard(); inTransaction = false; clean(); From bc7cc5eddba1f49ae513f468fbd22c4e6a6e12a2 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 20 Jan 2014 14:35:42 +0900 Subject: [PATCH 04/52] Shadow client field from PipelineBlock and TransactionBlock * it prevent from user accessing BinaryClient, while it is not treated to pipeline command ** it could make troubles when reading responses --- src/main/java/redis/clients/jedis/PipelineBlock.java | 4 ++++ src/main/java/redis/clients/jedis/Transaction.java | 4 ++++ .../java/redis/clients/jedis/TransactionBlock.java | 10 +++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/PipelineBlock.java b/src/main/java/redis/clients/jedis/PipelineBlock.java index 9afc391..fbf9c7f 100644 --- a/src/main/java/redis/clients/jedis/PipelineBlock.java +++ b/src/main/java/redis/clients/jedis/PipelineBlock.java @@ -2,5 +2,9 @@ package redis.clients.jedis; 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/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index d8cf9de..8e14fad 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -76,4 +76,8 @@ public class Transaction extends MultiKeyPipelineBase { 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 e784e19..792eae3 100644 --- a/src/main/java/redis/clients/jedis/TransactionBlock.java +++ b/src/main/java/redis/clients/jedis/TransactionBlock.java @@ -3,6 +3,10 @@ package redis.clients.jedis; import redis.clients.jedis.exceptions.JedisException; public abstract class TransactionBlock extends Transaction { + // For shadowing + @SuppressWarnings("unused") + private Client client; + public TransactionBlock(Client client) { super(client); } @@ -13,6 +17,10 @@ public abstract class TransactionBlock extends Transaction { public abstract void execute() throws JedisException; public void setClient(Client client) { - this.client = client; + super.setClient(client); + } + + public String discard() { + return super.discard(); } } From 360e25e07128771b4e11dbc3cca58370bb49c816 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 20 Jan 2014 14:50:02 +0900 Subject: [PATCH 05/52] Remove unused discard() method --- src/main/java/redis/clients/jedis/TransactionBlock.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/TransactionBlock.java b/src/main/java/redis/clients/jedis/TransactionBlock.java index 792eae3..36c7015 100644 --- a/src/main/java/redis/clients/jedis/TransactionBlock.java +++ b/src/main/java/redis/clients/jedis/TransactionBlock.java @@ -19,8 +19,4 @@ public abstract class TransactionBlock extends Transaction { public void setClient(Client client) { super.setClient(client); } - - public String discard() { - return super.discard(); - } } From 0aacd48c814fcbf110ab41bfbc4703463e221c7f Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 10 Feb 2014 07:28:46 +0900 Subject: [PATCH 06/52] Remove all @Deprecated things about *scan * remove all @Deprecated methods about *scan * rename ScanResult.getStringCursor() to ScanResult.getCursor() ** its original name * let unit tests follow this change --- .../redis/clients/jedis/BinaryClient.java | 55 -------- src/main/java/redis/clients/jedis/Client.java | 30 ----- .../java/redis/clients/jedis/Commands.java | 32 ----- src/main/java/redis/clients/jedis/Jedis.java | 125 ------------------ .../redis/clients/jedis/JedisCluster.java | 52 -------- .../redis/clients/jedis/JedisCommands.java | 24 ---- .../redis/clients/jedis/MultiKeyCommands.java | 8 -- .../java/redis/clients/jedis/ScanResult.java | 27 +--- .../redis/clients/jedis/ShardedJedis.java | 33 ----- .../commands/AllKindOfValuesCommandsTest.java | 4 +- .../tests/commands/HashesCommandsTest.java | 4 +- .../jedis/tests/commands/SetCommandsTest.java | 4 +- .../tests/commands/SortedSetCommandsTest.java | 4 +- 13 files changed, 9 insertions(+), 393 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index a8c12d8..e1f0385 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -1150,61 +1150,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/Client.java b/src/main/java/redis/clients/jedis/Client.java index 64f6f5c..3e7a19f 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -833,36 +833,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); } diff --git a/src/main/java/redis/clients/jedis/Commands.java b/src/main/java/redis/clients/jedis/Commands.java index a104ca9..5d2ea3b 100644 --- a/src/main/java/redis/clients/jedis/Commands.java +++ b/src/main/java/redis/clients/jedis/Commands.java @@ -297,38 +297,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/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 545fece..3b53f20 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3096,131 +3096,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, return (relpy != null ? new Double(relpy) : 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 - */ - 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()); } diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index bec2574..8e99b04 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -1396,58 +1396,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() { - return connectionHandler.getConnection().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() { - return connectionHandler.getConnection().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() { - return connectionHandler.getConnection().zscan(key, cursor); - } - }.run(null); - } - @Override public ScanResult> hscan(final String key, final String cursor) { diff --git a/src/main/java/redis/clients/jedis/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index 5952bdb..85c46eb 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -211,30 +211,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/MultiKeyCommands.java b/src/main/java/redis/clients/jedis/MultiKeyCommands.java index f03f82c..c0340c0 100644 --- a/src/main/java/redis/clients/jedis/MultiKeyCommands.java +++ b/src/main/java/redis/clients/jedis/MultiKeyCommands.java @@ -70,13 +70,5 @@ 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); } diff --git a/src/main/java/redis/clients/jedis/ScanResult.java b/src/main/java/redis/clients/jedis/ScanResult.java index 9afe27d..f055395 100644 --- a/src/main/java/redis/clients/jedis/ScanResult.java +++ b/src/main/java/redis/clients/jedis/ScanResult.java @@ -6,37 +6,12 @@ public class ScanResult { private String 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.cursor = String.valueOf(cursor); - this.results = results; - } - public ScanResult(String cursor, List results) { this.cursor = cursor; 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(cursor); - } - - /** - * FIXME: This method should be changed to getCursor() on next major release - */ - public String getStringCursor() { + public String getCursor() { return cursor; } diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 7235cfe..b734793 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -523,39 +523,6 @@ 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) { Jedis j = getShard(key); return j.hscan(key, cursor); 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 057537c..a1eb2c6 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/AllKindOfValuesCommandsTest.java @@ -513,7 +513,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()); } @@ -527,7 +527,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()); } 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 5f9ac4e..5a5dd7a 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java @@ -298,7 +298,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()); } @@ -313,7 +313,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()); } 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 2149feb..8f3f8ac 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SetCommandsTest.java @@ -460,7 +460,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()); } @@ -472,7 +472,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()); } 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 90b4c20..1dd46e2 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -897,7 +897,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()); } @@ -911,7 +911,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()); } From dc054268fa158600806ce3d38185e670369d2a18 Mon Sep 17 00:00:00 2001 From: Henning Schmiedehausen Date: Thu, 20 Feb 2014 18:22:44 -0800 Subject: [PATCH 07/52] Add Closeable to JedisPool. This allows JedisPool instances to also participate in try-with-resources. Adds tests (both for JedisPool and the Jedis code itself). --- src/main/java/redis/clients/util/Pool.java | 15 +++++- .../redis/clients/jedis/tests/Closer.java | 39 ++++++++++++++ .../jedis/tests/ConnectionCloseTest.java | 51 +++++++++++++++++++ .../clients/jedis/tests/JedisPoolTest.java | 24 +++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/test/java/redis/clients/jedis/tests/Closer.java create mode 100644 src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java diff --git a/src/main/java/redis/clients/util/Pool.java b/src/main/java/redis/clients/util/Pool.java index 09d8ebb..4ac3524 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); @@ -81,4 +92,4 @@ public abstract class Pool { throw new JedisException("Could not destroy the pool", e); } } -} \ No newline at end of file +} diff --git a/src/test/java/redis/clients/jedis/tests/Closer.java b/src/test/java/redis/clients/jedis/tests/Closer.java new file mode 100644 index 0000000..5c7d801 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tests/Closer.java @@ -0,0 +1,39 @@ +package redis.clients.jedis.tests; + +import java.io.Closeable; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +class Closer implements Closeable { + private final Set elements = new HashSet(); + + synchronized T register(T element) { + if (element != null) { + elements.add(element); + } + return element; + } + + public synchronized void close() throws IOException { + Throwable caught = null; + + for (Closeable element : elements) { + try { + element.close(); + } + catch (Throwable t) { + caught = t; + } + } + + elements.clear(); + + if (caught != null) { + if (caught instanceof IOException) { + throw (IOException) caught; + } + throw (RuntimeException) caught; + } + } +} 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..77cb48d --- /dev/null +++ b/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java @@ -0,0 +1,51 @@ +package redis.clients.jedis.tests; + +import java.io.Closeable; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +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 final Closer closer = new Closer(); + + private Connection client; + + @Before + public void setUp() throws Exception { + client = closer.register(new Connection()); + } + + @After + public void tearDown() throws Exception { + closer.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/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index a501024..d24f5be 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -27,6 +27,21 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis.get("foo")); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); + } + + @Test + public void checkCloseableConnections() throws Exception { + Closer closer = new Closer(); + JedisPool pool = closer.register(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); + closer.close(); + assertTrue(pool.isClosed()); } @Test @@ -39,6 +54,7 @@ public class JedisPoolTest extends Assert { assertEquals("bar", jedis.get("foo")); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -56,6 +72,7 @@ public class JedisPoolTest extends Assert { jedis.incr("foo"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -72,6 +89,7 @@ public class JedisPoolTest extends Assert { jedis.incr("foo"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test(expected = JedisConnectionException.class) @@ -99,6 +117,7 @@ public class JedisPoolTest extends Assert { jedis.set("foo", "bar"); pool.returnResource(jedis); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -110,6 +129,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 +137,7 @@ public class JedisPoolTest extends Assert { assertNull(jedis1.get("foo")); pool1.returnResource(jedis1); pool1.destroy(); + assertTrue(pool1.isClosed()); } @Test @@ -163,6 +184,7 @@ public class JedisPoolTest extends Assert { pool.returnResource(jedis1); pool.destroy(); + assertTrue(pool.isClosed()); } @Test @@ -176,6 +198,7 @@ public class JedisPoolTest extends Assert { pool0.returnResource(jedis); pool0.destroy(); + assertTrue(pool0.isClosed()); } @Test @@ -197,5 +220,6 @@ public class JedisPoolTest extends Assert { assertEquals("jedis", jedis2.get("hello")); pool.returnResource(jedis2); pool.destroy(); + assertTrue(pool.isClosed()); } } From 92f6785a5836670005923ad597ff715c579643d7 Mon Sep 17 00:00:00 2001 From: Aniket Schneider Date: Wed, 5 Mar 2014 16:59:11 -0500 Subject: [PATCH 08/52] Remove deprecated pexpire(key, int) methods --- src/main/java/redis/clients/jedis/BinaryClient.java | 5 ----- src/main/java/redis/clients/jedis/BinaryJedis.java | 5 ----- src/main/java/redis/clients/jedis/Client.java | 5 ----- src/main/java/redis/clients/jedis/Jedis.java | 5 ----- src/main/java/redis/clients/jedis/PipelineBase.java | 10 ---------- 5 files changed, 30 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 10d980c..48dfdf1 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -1091,11 +1091,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)); } diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index a08cb09..f0787a0 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -3314,11 +3314,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/Client.java b/src/main/java/redis/clients/jedis/Client.java index 98b33b4..6b5f2bb 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -777,11 +777,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); } diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 43e0de9..9b935c2 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3060,11 +3060,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); diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index 9e237bd..b34d062 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -1080,16 +1080,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); From c0697cd6d7cb8579d6a476c9cfc1e40c61e58667 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Sun, 16 Mar 2014 22:58:26 +0900 Subject: [PATCH 09/52] Add "closeable" unit tests to JedisSentinelPool, ShardedJedisPoolTest --- .../jedis/tests/JedisSentinelPoolTest.java | 16 ++++++++++++++++ .../jedis/tests/ShardedJedisPoolTest.java | 13 +++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index c8df9c5..c88bd55 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -34,6 +34,22 @@ public class JedisSentinelPoolTest extends JedisTestBase { sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); } + + @Test + public void checkCloseableConnections() throws Exception { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + + Closer closer = new Closer(); + JedisSentinelPool pool = closer.register(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); + closer.close(); + assertTrue(pool.isClosed()); + } @Test public void ensureSafeTwiceFailover() throws InterruptedException { diff --git a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java index ee7951b..272656c 100644 --- a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java @@ -54,6 +54,19 @@ public class ShardedJedisPoolTest extends Assert { pool.destroy(); } + @Test + public void checkCloseableConnections() throws Exception { + Closer closer = new Closer(); + ShardedJedisPool pool = closer.register(new ShardedJedisPool( + new GenericObjectPoolConfig(), shards)); + ShardedJedis jedis = pool.getResource(); + jedis.set("foo", "bar"); + assertEquals("bar", jedis.get("foo")); + pool.returnResource(jedis); + closer.close(); + assertTrue(pool.isClosed()); + } + @Test public void checkConnectionWithDefaultPort() { ShardedJedisPool pool = new ShardedJedisPool( From 1fd5b575756fa2bb96c275fe379b9bf3e2f68adc Mon Sep 17 00:00:00 2001 From: UglyTroLL Date: Tue, 18 Mar 2014 18:29:03 -0700 Subject: [PATCH 10/52] Fixed #595: The byte version of pipeline.getrange should returns byte[] instead of Long. TESTED: export TEST=PipeliningTest make test --- .../java/redis/clients/jedis/BinaryRedisPipeline.java | 2 +- src/main/java/redis/clients/jedis/PipelineBase.java | 4 ++-- .../java/redis/clients/jedis/tests/PipeliningTest.java | 10 +++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java index 73037b7..009423b 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); diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index 3183ba1..0cabb86 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -159,9 +159,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) { diff --git a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java index d3cddd0..9d220e2 100755 --- a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java +++ b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java @@ -52,6 +52,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,7 +71,9 @@ public class PipeliningTest extends Assert { p.sadd("set", "foo"); Response> smembers = p.smembers("set"); Response> zrangeWithScores = p.zrangeWithScores("zset", 0, - -1); + -1); + Response getrange = p.getrange("setrange", 1, 3); + Response getrangeBytes = p.getrange("setrangebytes".getBytes(), 6, 8); p.sync(); assertEquals("foo", string.get()); @@ -83,6 +88,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 From 5d3600485fbdf9029579c799c104c9604f5d76d3 Mon Sep 17 00:00:00 2001 From: UglyTroLL Date: Tue, 18 Mar 2014 19:51:51 -0700 Subject: [PATCH 11/52] Indent fix --- .../redis/clients/jedis/tests/PipeliningTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java index 9d220e2..63bbd94 100755 --- a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java +++ b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java @@ -52,9 +52,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); + 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"); @@ -72,9 +72,9 @@ public class PipeliningTest extends Assert { Response> smembers = p.smembers("set"); Response> zrangeWithScores = p.zrangeWithScores("zset", 0, -1); - Response getrange = p.getrange("setrange", 1, 3); - Response getrangeBytes = p.getrange("setrangebytes".getBytes(), 6, 8); - p.sync(); + 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()); From 409740f06cd2375c9164f66c84b217546ef38aac Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Tue, 22 Apr 2014 23:39:37 +0900 Subject: [PATCH 12/52] Support Sorted Set with LEX commands * new commands : ZLEXCOUNT, ZRANGEBYLEX, ZREMRANGEBYLEX ** added commands to Jedis, ShardedJedis, JedisCluster, PipelineBase with Binary / Normal(String) ** description links *** http://redis.io/commands/zlexcount *** http://redis.io/commands/zrangebylex *** http://redis.io/commands/zremrangebylex ** Unit test included --- .../redis/clients/jedis/BinaryClient.java | 20 +++ .../java/redis/clients/jedis/BinaryJedis.java | 29 +++++ .../clients/jedis/BinaryJedisCommands.java | 9 ++ .../clients/jedis/BinaryRedisPipeline.java | 9 ++ .../clients/jedis/BinaryShardedJedis.java | 26 ++++ src/main/java/redis/clients/jedis/Client.java | 18 +++ src/main/java/redis/clients/jedis/Jedis.java | 30 +++++ .../redis/clients/jedis/JedisCluster.java | 46 +++++++ .../redis/clients/jedis/JedisCommands.java | 9 ++ .../redis/clients/jedis/PipelineBase.java | 50 ++++++++ .../java/redis/clients/jedis/Protocol.java | 2 +- .../redis/clients/jedis/RedisPipeline.java | 9 ++ .../redis/clients/jedis/ShardedJedis.java | 22 ++++ .../tests/commands/SortedSetCommandsTest.java | 119 +++++++++++++++++- 14 files changed, 396 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryClient.java b/src/main/java/redis/clients/jedis/BinaryClient.java index 2377665..a921b06 100644 --- a/src/main/java/redis/clients/jedis/BinaryClient.java +++ b/src/main/java/redis/clients/jedis/BinaryClient.java @@ -16,6 +16,7 @@ import static redis.clients.jedis.Protocol.Keyword.WITHSCORES; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.Map.Entry; import 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); diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index eba466f..d061389 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -2732,6 +2732,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. *

diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index b229f97..3920c67 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java +++ b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java @@ -190,6 +190,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 73037b7..799557d 100644 --- a/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java +++ b/src/main/java/redis/clients/jedis/BinaryRedisPipeline.java @@ -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 5895f20..b879d55 100644 --- a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java @@ -474,6 +474,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) { @@ -569,4 +594,5 @@ public class BinaryShardedJedis extends Sharded Jedis j = getShard(key); return j.bitcount(key, start, end); } + } \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 64f6f5c..f0d9f82 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)); diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 4961f42..ff5bd89 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -2561,6 +2561,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); @@ -3412,4 +3441,5 @@ public class Jedis extends BinaryJedis implements JedisCommands, return BuilderFactory.STRING_MAP .build(client.getBinaryMultiBulkReply()); } + } diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 121bde8..8f8b693 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -1063,6 +1063,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, @@ -1481,4 +1526,5 @@ public class JedisCluster implements JedisCommands, BasicCommands { } }.run(null); } + } diff --git a/src/main/java/redis/clients/jedis/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index 5952bdb..907b328 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -189,6 +189,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); diff --git a/src/main/java/redis/clients/jedis/PipelineBase.java b/src/main/java/redis/clients/jedis/PipelineBase.java index 3183ba1..db37b2e 100644 --- a/src/main/java/redis/clients/jedis/PipelineBase.java +++ b/src/main/java/redis/clients/jedis/PipelineBase.java @@ -1008,6 +1008,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); diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 681bc56..76e74ef 100644 --- a/src/main/java/redis/clients/jedis/Protocol.java +++ b/src/main/java/redis/clients/jedis/Protocol.java @@ -208,7 +208,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, 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; + 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, 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; public final byte[] raw; diff --git a/src/main/java/redis/clients/jedis/RedisPipeline.java b/src/main/java/redis/clients/jedis/RedisPipeline.java index bb5226c..2961a68 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/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 7235cfe..2211467 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -506,6 +506,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) { @@ -570,4 +591,5 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands { Jedis j = getShard(key); return j.zscan(key, cursor); } + } 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 90b4c20..3b046a2 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -3,6 +3,8 @@ package redis.clients.jedis.tests.commands; import java.util.LinkedHashSet; import java.util.Set; +import javax.swing.text.html.MinimalHTMLWriter; + import org.junit.Test; import redis.clients.jedis.ScanParams; @@ -19,6 +21,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 }; @Test public void zadd() { @@ -48,7 +54,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertEquals(0, bstatus); } - + @Test public void zrange() { jedis.zadd("foo", 1d, "a"); @@ -85,6 +91,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() { @@ -395,6 +443,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() { @@ -733,6 +815,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() { From 3917a50c033f0e640a0b1b4e67056188d670bb15 Mon Sep 17 00:00:00 2001 From: wjw Date: Fri, 23 May 2014 15:04:52 +0800 Subject: [PATCH 13/52] format code use STS --- .../clients/jedis/JedisSentinelPool.java | 474 +++++++++--------- 1 file changed, 237 insertions(+), 237 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 224ca99..72602ee 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -14,287 +14,287 @@ import redis.clients.util.Pool; public class JedisSentinelPool extends Pool { - protected GenericObjectPoolConfig poolConfig; + protected GenericObjectPoolConfig poolConfig; - protected int timeout = Protocol.DEFAULT_TIMEOUT; + protected int timeout = Protocol.DEFAULT_TIMEOUT; - protected String password; + protected String password; - protected int database = Protocol.DEFAULT_DATABASE; + protected int database = Protocol.DEFAULT_DATABASE; - protected Set masterListeners = new HashSet(); + protected Set masterListeners = new HashSet(); - protected Logger log = Logger.getLogger(getClass().getName()); + protected Logger log = Logger.getLogger(getClass().getName()); - public JedisSentinelPool(String masterName, Set sentinels, - final GenericObjectPoolConfig poolConfig) { - this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null, - Protocol.DEFAULT_DATABASE); - } - - public JedisSentinelPool(String masterName, Set sentinels) { - this(masterName, sentinels, new GenericObjectPoolConfig(), - Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE); - } - - public JedisSentinelPool(String masterName, Set sentinels, - String password) { - this(masterName, sentinels, new GenericObjectPoolConfig(), - Protocol.DEFAULT_TIMEOUT, password); - } - - public JedisSentinelPool(String masterName, Set sentinels, - final GenericObjectPoolConfig poolConfig, int timeout, - final String password) { - this(masterName, sentinels, poolConfig, timeout, password, - Protocol.DEFAULT_DATABASE); - } - - public JedisSentinelPool(String masterName, Set sentinels, - final GenericObjectPoolConfig poolConfig, final int timeout) { - this(masterName, sentinels, poolConfig, timeout, null, - Protocol.DEFAULT_DATABASE); - } - - public JedisSentinelPool(String masterName, Set sentinels, - final GenericObjectPoolConfig poolConfig, final String password) { - this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, - password); - } - - 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; - this.database = database; - - HostAndPort master = initSentinels(sentinels, masterName); - initPool(master); - } - - public void returnBrokenResource(final Jedis resource) { - if (resource != null) { - returnBrokenResourceObject(resource); - } - } - - public void returnResource(final Jedis resource) { - if (resource != null) { - resource.resetState(); - returnResourceObject(resource); - } - } - - private volatile HostAndPort currentHostMaster; - - public void destroy() { - for (MasterListener m : masterListeners) { - m.shutdown(); + public JedisSentinelPool(String masterName, Set sentinels, + final GenericObjectPoolConfig poolConfig) { + this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, null, + Protocol.DEFAULT_DATABASE); } - super.destroy(); - } - - public HostAndPort getCurrentHostMaster() { - return currentHostMaster; - } - - private void initPool(HostAndPort master) { - if (!master.equals(currentHostMaster)) { - currentHostMaster = master; - log.info("Created JedisPool to master at " + master); - initPool(poolConfig, - new JedisFactory(master.getHost(), master.getPort(), - timeout, password, database)); + public JedisSentinelPool(String masterName, Set sentinels) { + this(masterName, sentinels, new GenericObjectPoolConfig(), + Protocol.DEFAULT_TIMEOUT, null, Protocol.DEFAULT_DATABASE); } - } - private HostAndPort initSentinels(Set sentinels, - final String masterName) { + public JedisSentinelPool(String masterName, Set sentinels, + String password) { + this(masterName, sentinels, new GenericObjectPoolConfig(), + Protocol.DEFAULT_TIMEOUT, password); + } - HostAndPort master = null; - boolean running = true; + public JedisSentinelPool(String masterName, Set sentinels, + final GenericObjectPoolConfig poolConfig, int timeout, + final String password) { + this(masterName, sentinels, poolConfig, timeout, password, + Protocol.DEFAULT_DATABASE); + } - outer: while (running) { + public JedisSentinelPool(String masterName, Set sentinels, + final GenericObjectPoolConfig poolConfig, final int timeout) { + this(masterName, sentinels, poolConfig, timeout, null, + Protocol.DEFAULT_DATABASE); + } - log.info("Trying to find master from available Sentinels..."); + public JedisSentinelPool(String masterName, Set sentinels, + final GenericObjectPoolConfig poolConfig, final String password) { + this(masterName, sentinels, poolConfig, Protocol.DEFAULT_TIMEOUT, + password); + } - for (String sentinel : sentinels) { + 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; + this.database = database; - final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel - .split(":"))); + HostAndPort master = initSentinels(sentinels, masterName); + initPool(master); + } - log.fine("Connecting to Sentinel " + hap); - - try { - Jedis jedis = new Jedis(hap.getHost(), hap.getPort()); - - if (master == null) { - master = toHostAndPort(jedis - .sentinelGetMasterAddrByName(masterName)); - 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."); + public void returnBrokenResource(final Jedis resource) { + if (resource != null) { + returnBrokenResourceObject(resource); } - } - - try { - log.severe("All sentinels down, cannot determine where is " - + masterName + " master is running... sleeping 1000ms."); - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } } - log.info("Redis master running at " + master - + ", starting Sentinel listeners..."); - - for (String sentinel : sentinels) { - final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel - .split(":"))); - MasterListener masterListener = new MasterListener(masterName, - hap.getHost(), hap.getPort()); - masterListeners.add(masterListener); - masterListener.start(); + public void returnResource(final Jedis resource) { + if (resource != null) { + resource.resetState(); + returnResourceObject(resource); + } } - return master; - } + private volatile HostAndPort currentHostMaster; - private HostAndPort toHostAndPort(List getMasterAddrByNameResult) { - String host = getMasterAddrByNameResult.get(0); - int port = Integer.parseInt(getMasterAddrByNameResult.get(1)); + public void destroy() { + for (MasterListener m : masterListeners) { + m.shutdown(); + } - return new HostAndPort(host, port); - } - - protected class JedisPubSubAdapter extends JedisPubSub { - @Override - public void onMessage(String channel, String message) { + super.destroy(); } - @Override - public void onPMessage(String pattern, String channel, String message) { + public HostAndPort getCurrentHostMaster() { + return currentHostMaster; } - @Override - public void onPSubscribe(String pattern, int subscribedChannels) { + private void initPool(HostAndPort master) { + if (!master.equals(currentHostMaster)) { + currentHostMaster = master; + log.info("Created JedisPool to master at " + master); + initPool(poolConfig, + new JedisFactory(master.getHost(), master.getPort(), + timeout, password, database)); + } } - @Override - public void onPUnsubscribe(String pattern, int subscribedChannels) { - } + private HostAndPort initSentinels(Set sentinels, + final String masterName) { - @Override - public void onSubscribe(String channel, int subscribedChannels) { - } + HostAndPort master = null; + boolean running = true; - @Override - public void onUnsubscribe(String channel, int subscribedChannels) { - } - } + outer: while (running) { - protected class MasterListener extends Thread { + log.info("Trying to find master from available Sentinels..."); - protected String masterName; - protected String host; - protected int port; - protected long subscribeRetryWaitTimeMillis = 5000; - protected Jedis j; - protected AtomicBoolean running = new AtomicBoolean(false); + for (String sentinel : sentinels) { - protected MasterListener() { - } + final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel + .split(":"))); - public MasterListener(String masterName, String host, int port) { - this.masterName = masterName; - this.host = host; - this.port = port; - } + log.fine("Connecting to Sentinel " + hap); - public MasterListener(String masterName, String host, int port, - long subscribeRetryWaitTimeMillis) { - this(masterName, host, port); - this.subscribeRetryWaitTimeMillis = subscribeRetryWaitTimeMillis; - } + try { + Jedis jedis = new Jedis(hap.getHost(), hap.getPort()); - public void run() { - - running.set(true); - - while (running.get()) { - - j = new Jedis(host, port); - - try { - j.subscribe(new JedisPubSubAdapter() { - @Override - public void onMessage(String channel, String message) { - log.fine("Sentinel " + host + ":" + port - + " published: " + message + "."); - - String[] switchMasterMsg = message.split(" "); - - if (switchMasterMsg.length > 3) { - - if (masterName.equals(switchMasterMsg[0])) { - initPool(toHostAndPort(Arrays.asList( - switchMasterMsg[3], - switchMasterMsg[4]))); - } else { - log.fine("Ignoring message on +switch-master for master name " - + switchMasterMsg[0] - + ", our master name is " - + masterName); + if (master == null) { + master = toHostAndPort(jedis + .sentinelGetMasterAddrByName(masterName)); + 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."); } - - } else { - log.severe("Invalid message received on Sentinel " - + host - + ":" - + port - + " on channel +switch-master: " - + message); - } } - }, "+switch-master"); - } catch (JedisConnectionException e) { - - if (running.get()) { - log.severe("Lost connection to Sentinel at " + host - + ":" + port - + ". Sleeping 5000ms and retrying."); try { - Thread.sleep(subscribeRetryWaitTimeMillis); - } catch (InterruptedException e1) { - e1.printStackTrace(); + log.severe("All sentinels down, cannot determine where is " + + masterName + " master is running... sleeping 1000ms."); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); } - } else { - log.fine("Unsubscribing from Sentinel at " + host + ":" - + port); - } } - } + + log.info("Redis master running at " + master + + ", starting Sentinel listeners..."); + + for (String sentinel : sentinels) { + final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel + .split(":"))); + MasterListener masterListener = new MasterListener(masterName, + hap.getHost(), hap.getPort()); + masterListeners.add(masterListener); + masterListener.start(); + } + + return master; } - public void shutdown() { - try { - log.fine("Shutting down listener on " + host + ":" + port); - running.set(false); - // This isn't good, the Jedis object is not thread safe - j.disconnect(); - } catch (Exception e) { - log.severe("Caught exception while shutting down: " - + e.getMessage()); - } + private HostAndPort toHostAndPort(List getMasterAddrByNameResult) { + String host = getMasterAddrByNameResult.get(0); + int port = Integer.parseInt(getMasterAddrByNameResult.get(1)); + + return new HostAndPort(host, port); + } + + protected class JedisPubSubAdapter extends JedisPubSub { + @Override + public void onMessage(String channel, String message) { + } + + @Override + public void onPMessage(String pattern, String channel, String message) { + } + + @Override + public void onPSubscribe(String pattern, int subscribedChannels) { + } + + @Override + public void onPUnsubscribe(String pattern, int subscribedChannels) { + } + + @Override + public void onSubscribe(String channel, int subscribedChannels) { + } + + @Override + public void onUnsubscribe(String channel, int subscribedChannels) { + } + } + + protected class MasterListener extends Thread { + + protected String masterName; + protected String host; + protected int port; + protected long subscribeRetryWaitTimeMillis = 5000; + protected Jedis j; + protected AtomicBoolean running = new AtomicBoolean(false); + + protected MasterListener() { + } + + public MasterListener(String masterName, String host, int port) { + this.masterName = masterName; + this.host = host; + this.port = port; + } + + public MasterListener(String masterName, String host, int port, + long subscribeRetryWaitTimeMillis) { + this(masterName, host, port); + this.subscribeRetryWaitTimeMillis = subscribeRetryWaitTimeMillis; + } + + public void run() { + + running.set(true); + + while (running.get()) { + + j = new Jedis(host, port); + + try { + j.subscribe(new JedisPubSubAdapter() { + @Override + public void onMessage(String channel, String message) { + log.fine("Sentinel " + host + ":" + port + + " published: " + message + "."); + + String[] switchMasterMsg = message.split(" "); + + if (switchMasterMsg.length > 3) { + + if (masterName.equals(switchMasterMsg[0])) { + initPool(toHostAndPort(Arrays.asList( + switchMasterMsg[3], + switchMasterMsg[4]))); + } else { + log.fine("Ignoring message on +switch-master for master name " + + switchMasterMsg[0] + + ", our master name is " + + masterName); + } + + } else { + log.severe("Invalid message received on Sentinel " + + host + + ":" + + port + + " on channel +switch-master: " + + message); + } + } + }, "+switch-master"); + + } catch (JedisConnectionException e) { + + if (running.get()) { + log.severe("Lost connection to Sentinel at " + host + + ":" + port + + ". Sleeping 5000ms and retrying."); + try { + Thread.sleep(subscribeRetryWaitTimeMillis); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } else { + log.fine("Unsubscribing from Sentinel at " + host + ":" + + port); + } + } + } + } + + public void shutdown() { + try { + log.fine("Shutting down listener on " + host + ":" + port); + running.set(false); + // This isn't good, the Jedis object is not thread safe + j.disconnect(); + } catch (Exception e) { + log.severe("Caught exception while shutting down: " + + e.getMessage()); + } + } } - } } \ No newline at end of file From 268706b65c8084cda17fdc98d56b682b82438fff Mon Sep 17 00:00:00 2001 From: wjw Date: Fri, 23 May 2014 15:39:51 +0800 Subject: [PATCH 14/52] format test code --- .../jedis/tests/JedisSentinelPoolTest.java | 262 +++++++++--------- 1 file changed, 131 insertions(+), 131 deletions(-) diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index 1dd2896..437c80a 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -15,145 +15,145 @@ import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.tests.utils.JedisSentinelTestUtil; public class JedisSentinelPoolTest extends JedisTestBase { - private static final String MASTER_NAME = "mymaster"; + private static final String MASTER_NAME = "mymaster"; - protected static HostAndPort master = HostAndPortUtil.getRedisServers() - .get(2); - protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers() - .get(3); - protected static HostAndPort sentinel1 = HostAndPortUtil - .getSentinelServers().get(1); + protected static HostAndPort master = HostAndPortUtil.getRedisServers() + .get(2); + protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers() + .get(3); + protected static HostAndPort sentinel1 = HostAndPortUtil + .getSentinelServers().get(1); - protected static Jedis sentinelJedis1; + protected static Jedis sentinelJedis1; - protected Set sentinels = new HashSet(); + protected Set sentinels = new HashSet(); - @Before - public void setUp() throws Exception { - sentinels.add(sentinel1.toString()); + @Before + public void setUp() throws Exception { + sentinels.add(sentinel1.toString()); - sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); - } - - @Test - public void ensureSafeTwiceFailover() throws InterruptedException { - JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, - new GenericObjectPoolConfig(), 1000, "foobared", 2); - - forceFailover(pool); - forceFailover(pool); - - // you can test failover as much as possible - } - - @Test - public void returnResourceShouldResetState() { - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - config.setMaxTotal(1); - config.setBlockWhenExhausted(false); - JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, - config, 1000, "foobared", 2); - - Jedis jedis = pool.getResource(); - Jedis jedis2 = null; - - try { - jedis.set("hello", "jedis"); - Transaction t = jedis.multi(); - t.set("hello", "world"); - pool.returnResource(jedis); - - jedis2 = pool.getResource(); - - assertTrue(jedis == jedis2); - assertEquals("jedis", jedis2.get("hello")); - } catch (JedisConnectionException e) { - if (jedis2 != null) { - pool.returnBrokenResource(jedis2); - jedis2 = null; - } - } finally { - if (jedis2 != null) - pool.returnResource(jedis2); - - pool.destroy(); + sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); } - } - @Test - public void returnResourceWithNullResource() { - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - config.setMaxTotal(1); - config.setBlockWhenExhausted(false); - JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, - config, 1000, "foobared", 2); + @Test + public void ensureSafeTwiceFailover() throws InterruptedException { + JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, + new GenericObjectPoolConfig(), 1000, "foobared", 2); - Jedis nullJedis = null; - pool.returnResource(nullJedis); - pool.destroy(); - } + forceFailover(pool); + forceFailover(pool); - @Test - public void returnBrokenResourceWithNullResource() { - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - config.setMaxTotal(1); - config.setBlockWhenExhausted(false); - JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, - config, 1000, "foobared", 2); - - Jedis nullJedis = null; - pool.returnBrokenResource(nullJedis); - pool.destroy(); - } - - private void forceFailover(JedisSentinelPool pool) - throws InterruptedException { - HostAndPort oldMaster = pool.getCurrentHostMaster(); - - // jedis connection should be master - Jedis jedis = pool.getResource(); - assertEquals("PONG", jedis.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 = pool.getResource(); - assertEquals("PONG", jedis.ping()); - assertEquals("foobared", jedis.configGet("requirepass").get(1)); - assertEquals(2, jedis.getDB().intValue()); - } - - private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) - throws InterruptedException { - HostAndPort newMaster = JedisSentinelTestUtil - .waitForNewPromotedMaster(sentinelJedis1); - - waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster); - } - - private void waitForJedisSentinelPoolRecognizeNewMaster( - JedisSentinelPool pool, HostAndPort newMaster) - throws InterruptedException { - - while (true) { - String host = pool.getCurrentHostMaster().getHost(); - int port = pool.getCurrentHostMaster().getPort(); - - if (host.equals(newMaster.getHost()) && port == newMaster.getPort()) - break; - - System.out - .println("JedisSentinelPool's master is not yet changed, sleep..."); - - Thread.sleep(100); + // you can test failover as much as possible } - } - + + @Test + public void returnResourceShouldResetState() { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(1); + config.setBlockWhenExhausted(false); + JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, + config, 1000, "foobared", 2); + + Jedis jedis = pool.getResource(); + Jedis jedis2 = null; + + try { + jedis.set("hello", "jedis"); + Transaction t = jedis.multi(); + t.set("hello", "world"); + pool.returnResource(jedis); + + jedis2 = pool.getResource(); + + assertTrue(jedis == jedis2); + assertEquals("jedis", jedis2.get("hello")); + } catch (JedisConnectionException e) { + if (jedis2 != null) { + pool.returnBrokenResource(jedis2); + jedis2 = null; + } + } finally { + if (jedis2 != null) + pool.returnResource(jedis2); + + pool.destroy(); + } + } + + @Test + public void returnResourceWithNullResource() { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(1); + config.setBlockWhenExhausted(false); + JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, + config, 1000, "foobared", 2); + + Jedis nullJedis = null; + pool.returnResource(nullJedis); + pool.destroy(); + } + + @Test + public void returnBrokenResourceWithNullResource() { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(1); + config.setBlockWhenExhausted(false); + JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, + config, 1000, "foobared", 2); + + Jedis nullJedis = null; + pool.returnBrokenResource(nullJedis); + pool.destroy(); + } + + private void forceFailover(JedisSentinelPool pool) + throws InterruptedException { + HostAndPort oldMaster = pool.getCurrentHostMaster(); + + // jedis connection should be master + Jedis jedis = pool.getResource(); + assertEquals("PONG", jedis.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 = pool.getResource(); + assertEquals("PONG", jedis.ping()); + assertEquals("foobared", jedis.configGet("requirepass").get(1)); + assertEquals(2, jedis.getDB().intValue()); + } + + private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) + throws InterruptedException { + HostAndPort newMaster = JedisSentinelTestUtil + .waitForNewPromotedMaster(sentinelJedis1); + + waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster); + } + + private void waitForJedisSentinelPoolRecognizeNewMaster( + JedisSentinelPool pool, HostAndPort newMaster) + throws InterruptedException { + + while (true) { + String host = pool.getCurrentHostMaster().getHost(); + int port = pool.getCurrentHostMaster().getPort(); + + if (host.equals(newMaster.getHost()) && port == newMaster.getPort()) + break; + + System.out + .println("JedisSentinelPool's master is not yet changed, sleep..."); + + Thread.sleep(100); + } + } + } From ab2f43b8c0155f03c8b8f3932141630e1c825f65 Mon Sep 17 00:00:00 2001 From: wjw Date: Fri, 23 May 2014 16:18:07 +0800 Subject: [PATCH 15/52] fix issue #642 --- .../clients/jedis/JedisSentinelPool.java | 13 +++++++--- .../jedis/tests/JedisSentinelPoolTest.java | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 72602ee..6b07fc4 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -130,10 +130,17 @@ public class JedisSentinelPool extends Pool { try { Jedis 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 + "."); + jedis.disconnect(); + continue; + } + + master = toHostAndPort(masterAddr); log.fine("Found Redis master at " + master); jedis.disconnect(); break outer; diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index 437c80a..b1bd468 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; @@ -35,6 +36,29 @@ public class JedisSentinelPoolTest extends JedisTestBase { sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.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 ensureSafeTwiceFailover() throws InterruptedException { JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, From 1d29b759fe10b51dad245e0f46aa0b2518701fc0 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Sun, 15 Jun 2014 21:50:38 +0900 Subject: [PATCH 16/52] Make it better to use URI from Jedis / JedisPool * no need to provide password / DB index when user uses URI * can provide timeout when user users URI --- .../java/redis/clients/jedis/BinaryJedis.java | 32 +++++--- src/main/java/redis/clients/jedis/Jedis.java | 80 ++++++++++--------- .../java/redis/clients/jedis/JedisPool.java | 33 +++++--- .../redis/clients/util/JedisURIHelper.java | 21 +++++ .../clients/jedis/tests/JedisPoolTest.java | 6 ++ .../redis/clients/jedis/tests/JedisTest.java | 18 ++++- 6 files changed, 134 insertions(+), 56 deletions(-) create mode 100644 src/main/java/redis/clients/util/JedisURIHelper.java diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 781f17f..5f3d089 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -17,6 +17,7 @@ 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, @@ -27,11 +28,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, 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 +50,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 != null) { + client.select(dbIndex); + client.getStatusCodeReply(); + } } public String ping() { diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index fbf430c..cae04cd 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); } /** @@ -2707,12 +2713,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(); } @@ -3140,7 +3147,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, return client.getIntegerReply(); } - public String psetex(final String key, final int milliseconds, final String value) { checkIsInMulti(); @@ -3435,55 +3441,55 @@ 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(); @@ -3529,7 +3535,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 +3552,7 @@ public class Jedis extends BinaryJedis implements JedisCommands, @Override public long pfcount(String... keys) { - checkIsInMulti(); + checkIsInMulti(); client.pfcount(keys); return client.getIntegerReply(); } diff --git a/src/main/java/redis/clients/jedis/JedisPool.java b/src/main/java/redis/clients/jedis/JedisPool.java index 0fbfdfe..763d15d 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(); 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..027fa3a --- /dev/null +++ b/src/main/java/redis/clients/util/JedisURIHelper.java @@ -0,0 +1,21 @@ +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) { + return Integer.parseInt(pathSplit[1]); + } + return null; + } +} diff --git a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index 7d8e611..30aff37 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -144,6 +144,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(), diff --git a/src/test/java/redis/clients/jedis/tests/JedisTest.java b/src/test/java/redis/clients/jedis/tests/JedisTest.java index 3f5cdf1..abec911 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,15 @@ 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"); + assertEquals(jedis.getClient().getHost(), "localhost"); + assertEquals(jedis.getClient().getPort(), 6380); + assertEquals(jedis.getDB(), (Long) 0L); + } + @Test public void checkCloseable() { jedis.close(); From 4c4446a71f6f8a130e3ba2eccb82bafbb52f2033 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Tue, 24 Jun 2014 09:23:19 +0900 Subject: [PATCH 17/52] Remove unused (by accident?) import --- .../clients/jedis/tests/commands/SortedSetCommandsTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 3b046a2..98b55e7 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -3,8 +3,6 @@ package redis.clients.jedis.tests.commands; import java.util.LinkedHashSet; import java.util.Set; -import javax.swing.text.html.MinimalHTMLWriter; - import org.junit.Test; import redis.clients.jedis.ScanParams; @@ -1047,4 +1045,4 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { assertFalse(result.getResult().isEmpty()); } -} \ No newline at end of file +} From 18c4a987d5e5d515576176bdc1ccbaaf1944c73e Mon Sep 17 00:00:00 2001 From: Lars Strojny Date: Tue, 1 Jul 2014 15:10:07 +0200 Subject: [PATCH 18/52] Completing interface --- .../java/redis/clients/jedis/BinaryJedisCommands.java | 2 ++ .../java/redis/clients/jedis/BinaryShardedJedis.java | 6 ++++++ src/main/java/redis/clients/jedis/JedisCluster.java | 11 +++++++++++ src/main/java/redis/clients/jedis/JedisCommands.java | 2 ++ src/main/java/redis/clients/jedis/ShardedJedis.java | 6 ++++++ 5 files changed, 27 insertions(+) diff --git a/src/main/java/redis/clients/jedis/BinaryJedisCommands.java b/src/main/java/redis/clients/jedis/BinaryJedisCommands.java index ada68c2..ebd59fd 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); diff --git a/src/main/java/redis/clients/jedis/BinaryShardedJedis.java b/src/main/java/redis/clients/jedis/BinaryShardedJedis.java index 77695e7..7fbcb94 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); diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index f6cb6fd..029ea55 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -623,6 +623,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, diff --git a/src/main/java/redis/clients/jedis/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index d89f508..6d794cb 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); diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 9691448..35ac3e5 100644 --- a/src/main/java/redis/clients/jedis/ShardedJedis.java +++ b/src/main/java/redis/clients/jedis/ShardedJedis.java @@ -346,6 +346,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); From fd23f8b8f71fa1bdd5c0a5b2ce0c8af656ceb026 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 2 Jul 2014 06:46:58 +0900 Subject: [PATCH 19/52] Support CLUSTER SLOTS command * CLUSTER SLOTS returns a Redis-formatted mapping from slot ranges to IP/Port pairs serving that slot range * description link including output format ** https://github.com/antirez/redis/commit/e14829de3025ffb0d3294e5e5a1553afd9f10b60 * Unit test included --- src/main/java/redis/clients/jedis/Client.java | 4 +++ .../redis/clients/jedis/ClusterCommands.java | 2 ++ src/main/java/redis/clients/jedis/Jedis.java | 7 +++++ .../java/redis/clients/jedis/Protocol.java | 1 + .../tests/commands/ClusterCommandsTest.java | 31 +++++++++++++++++++ 5 files changed, 45 insertions(+) diff --git a/src/main/java/redis/clients/jedis/Client.java b/src/main/java/redis/clients/jedis/Client.java index 69054ef..3e7bbca 100644 --- a/src/main/java/redis/clients/jedis/Client.java +++ b/src/main/java/redis/clients/jedis/Client.java @@ -1011,4 +1011,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/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index fbf430c..83f414b 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3489,6 +3489,13 @@ public class Jedis extends BinaryJedis implements JedisCommands, client.clusterFailover(); return client.getStatusCodeReply(); } + + @Override + public List clusterSlots() { + checkIsInMulti(); + client.clusterSlots(); + return client.getObjectMultiBulkReply(); + } public String asking() { checkIsInMulti(); diff --git a/src/main/java/redis/clients/jedis/Protocol.java b/src/main/java/redis/clients/jedis/Protocol.java index 3f77b9a..83d0fba 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"; 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 From 0f472c97a27da62c86444a1c72e599fdb81edf83 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 2 Jul 2014 07:42:29 +0900 Subject: [PATCH 20/52] fix build after CLUSTER NODES output has been changed * https://github.com/antirez/redis/issues/1848 * we don't need to handle :0 by changes --- .../clients/util/ClusterNodeInformationParser.java | 11 +++++------ .../tests/JedisClusterNodeInformationParserTest.java | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) 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/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); From 94966e6163e414ae5dc326c084f404cf6cb1a5bf Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 2 Jul 2014 23:29:30 +0900 Subject: [PATCH 21/52] Renew slots when MOVED occured during request to Cluster * It's suggested by http://redis.io/topics/cluster-spec ** antirez/redis-rb-cluster implementation does it, too * Since Redis 3.0-beta 7 introduces CLUSTER SLOTS, it becomes easier * FIXME: It's fully synchronized, so it hurts performance (somewhat poor implementation) ** We can try Reader / Writer strategy to make lock waiting make shorter --- .../clients/jedis/JedisClusterCommand.java | 16 ++- .../jedis/JedisClusterConnectionHandler.java | 115 +++++----------- .../clients/jedis/JedisClusterInfoCache.java | 127 ++++++++++++++++++ .../JedisSlotBasedConnectionHandler.java | 9 +- 4 files changed, 174 insertions(+), 93 deletions(-) create mode 100644 src/main/java/redis/clients/jedis/JedisClusterInfoCache.java diff --git a/src/main/java/redis/clients/jedis/JedisClusterCommand.java b/src/main/java/redis/clients/jedis/JedisClusterCommand.java index 051d5cd..c4d80fa 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterCommand.java +++ b/src/main/java/redis/clients/jedis/JedisClusterCommand.java @@ -72,13 +72,15 @@ public abstract class JedisClusterCommand { } catch (JedisRedirectionException jre) { if (jre instanceof JedisAskDataException) { asking = true; - } else if (jre instanceof JedisMovedDataException) { - // TODO : In antirez's redis-rb-cluster implementation, - // it rebuilds cluster's slot and node cache - } - - this.connectionHandler.assignSlotToNode(jre.getSlot(), - jre.getTargetNode()); + this.connectionHandler.assignSlotToNode(jre.getSlot(), + jre.getTargetNode()); + } else if (jre instanceof JedisMovedDataException) { + // it rebuilds cluster's slot cache + // recommended by Redis cluster specification + this.connectionHandler.renewSlotCache(); + } else { + throw new JedisClusterException(jre); + } releaseConnection(connection, false); connection = null; diff --git a/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java b/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java index e6eb01f..102921e 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java +++ b/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java @@ -1,27 +1,26 @@ package redis.clients.jedis; -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(); + protected JedisClusterInfoCache cache = new JedisClusterInfoCache(); 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( - connection); + cache.getNode(getNodeKey(connection.getClient())) + .returnBrokenResource(connection); } abstract Jedis getConnectionFromSlot(int slot); @@ -31,7 +30,11 @@ public abstract class JedisClusterConnectionHandler { } public Map getNodes() { - return nodes; + return cache.getNodes(); + } + + public void assignSlotToNode(int slot, HostAndPort targetNode) { + cache.assignSlotToNode(slot, targetNode); } private void initializeSlotsCache(Set startNodes) { @@ -39,89 +42,43 @@ public abstract class JedisClusterConnectionHandler { JedisPool jp = new JedisPool(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); - } + if (jedis != null) { + 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(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..7c1f491 --- /dev/null +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -0,0 +1,127 @@ +package redis.clients.jedis; + +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; + +public class JedisClusterInfoCache { + public static final ClusterNodeInformationParser nodeInfoParser = new ClusterNodeInformationParser(); + + private Map nodes = new HashMap(); + private Map slots = new HashMap(); + + public synchronized void discoverClusterNodesAndSlots(Jedis jedis) { + 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); + } + } + + public synchronized void discoverClusterSlots(Jedis jedis) { + this.slots.clear(); + + List slots = jedis.clusterSlots(); + + for (Object slotInfoObj : slots) { + List slotInfo = (List) slotInfoObj; + + if (slotInfo.size() <= 2) { + continue; + } + + // assigned slots + List slotNums = new ArrayList(); + for (int slot = ((Long) slotInfo.get(0)).intValue() ; + slot <= ((Long) slotInfo.get(1)).intValue() ; + slot++) { + slotNums.add(slot); + } + + // hostInfos + List hostInfos = (List) slotInfo.get(2); + if (hostInfos.size() <= 0) { + continue; + } + + // at this time, we just use master, discard slave information + HostAndPort targetNode = new HostAndPort( + SafeEncoder.encode((byte[]) hostInfos.get(0)), + ((Long) hostInfos.get(1)).intValue()); + + setNodeIfNotExist(targetNode); + assignSlotsToNode(slotNums, targetNode); + } + } + + public synchronized void setNodeIfNotExist(HostAndPort node) { + String nodeKey = getNodeKey(node); + if (nodes.containsKey(nodeKey)) + return; + + JedisPool nodePool = new JedisPool(node.getHost(), node.getPort()); + nodes.put(nodeKey, nodePool); + } + + public synchronized 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 synchronized 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 synchronized JedisPool getNode(String nodeKey) { + return nodes.get(nodeKey); + } + + public synchronized JedisPool getSlotPool(int slot) { + return slots.get(slot); + } + + public synchronized Map getNodes() { + return new HashMap(nodes); + } + + 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()); + } + +} diff --git a/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java b/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java index 4cd4fc7..bc9c2d4 100644 --- a/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java +++ b/src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java @@ -46,14 +46,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(); @@ -64,7 +59,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; } From 4b72a4d25492ad4664e857006643e3bd8a361fff Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 2 Jul 2014 23:46:15 +0900 Subject: [PATCH 22/52] Replace synchronized keyword lock to ReaderWriterLock --- .../clients/jedis/JedisClusterInfoCache.java | 182 ++++++++++++------ 1 file changed, 119 insertions(+), 63 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java index 7c1f491..0906b5e 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -8,6 +8,8 @@ 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(); @@ -15,101 +17,145 @@ public class JedisClusterInfoCache { private Map nodes = new HashMap(); private Map slots = new HashMap(); - public synchronized void discoverClusterNodesAndSlots(Jedis jedis) { - this.nodes.clear(); - this.slots.clear(); + private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final Lock r = rwl.readLock(); + private final Lock w = rwl.writeLock(); - String localNodes = jedis.clusterNodes(); - for (String nodeInfo : localNodes.split("\n")) { - ClusterNodeInformation clusterNodeInfo = nodeInfoParser.parse( - nodeInfo, new HostAndPort(jedis.getClient().getHost(), - jedis.getClient().getPort())); + public void discoverClusterNodesAndSlots(Jedis jedis) { + w.lock(); - HostAndPort targetNode = clusterNodeInfo.getNode(); - setNodeIfNotExist(targetNode); - assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), targetNode); + 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 synchronized void discoverClusterSlots(Jedis jedis) { - this.slots.clear(); + public void discoverClusterSlots(Jedis jedis) { + w.lock(); - List slots = jedis.clusterSlots(); + try { + this.slots.clear(); - for (Object slotInfoObj : slots) { - List slotInfo = (List) slotInfoObj; + List slots = jedis.clusterSlots(); - if (slotInfo.size() <= 2) { - continue; + 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); } - - // assigned slots - List slotNums = new ArrayList(); - for (int slot = ((Long) slotInfo.get(0)).intValue() ; - slot <= ((Long) slotInfo.get(1)).intValue() ; - slot++) { - slotNums.add(slot); - } - - // hostInfos - List hostInfos = (List) slotInfo.get(2); - if (hostInfos.size() <= 0) { - continue; - } - - // at this time, we just use master, discard slave information - HostAndPort targetNode = new HostAndPort( - SafeEncoder.encode((byte[]) hostInfos.get(0)), - ((Long) hostInfos.get(1)).intValue()); - - setNodeIfNotExist(targetNode); - assignSlotsToNode(slotNums, targetNode); + } finally { + w.unlock(); } } - public synchronized void setNodeIfNotExist(HostAndPort node) { - String nodeKey = getNodeKey(node); - if (nodes.containsKey(nodeKey)) - return; - - JedisPool nodePool = new JedisPool(node.getHost(), node.getPort()); - nodes.put(nodeKey, nodePool); + private HostAndPort generateHostAndPort(List hostInfos) { + return new HostAndPort( + SafeEncoder.encode((byte[]) hostInfos.get(0)), + ((Long) hostInfos.get(1)).intValue()); } - public synchronized void assignSlotToNode(int slot, HostAndPort targetNode) { - JedisPool targetPool = nodes.get(getNodeKey(targetNode)); + public void setNodeIfNotExist(HostAndPort node) { + w.lock(); + try { + String nodeKey = getNodeKey(node); + if (nodes.containsKey(nodeKey)) + return; - if (targetPool == null) { - setNodeIfNotExist(targetNode); - targetPool = nodes.get(getNodeKey(targetNode)); + JedisPool nodePool = new JedisPool(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(); } - slots.put(slot, targetPool); } public synchronized void assignSlotsToNode(List targetSlots, HostAndPort targetNode) { - JedisPool targetPool = nodes.get(getNodeKey(targetNode)); + w.lock(); + try { + JedisPool targetPool = nodes.get(getNodeKey(targetNode)); - if (targetPool == null) { - setNodeIfNotExist(targetNode); - targetPool = nodes.get(getNodeKey(targetNode)); - } + if (targetPool == null) { + setNodeIfNotExist(targetNode); + targetPool = nodes.get(getNodeKey(targetNode)); + } - for (Integer slot : targetSlots) { - slots.put(slot, targetPool); + for (Integer slot : targetSlots) { + slots.put(slot, targetPool); + } + } finally { + w.unlock(); } } public synchronized JedisPool getNode(String nodeKey) { - return nodes.get(nodeKey); + r.lock(); + try { + return nodes.get(nodeKey); + } finally { + r.unlock(); + } } public synchronized JedisPool getSlotPool(int slot) { - return slots.get(slot); + r.lock(); + try { + return slots.get(slot); + } finally { + r.unlock(); + } } public synchronized Map getNodes() { - return new HashMap(nodes); + r.lock(); + try { + return new HashMap(nodes); + } finally { + r.unlock(); + } } public static String getNodeKey(HostAndPort hnp) { @@ -124,4 +170,14 @@ public class JedisClusterInfoCache { 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; + } + } From 15ab93494562b712248190b2da78446fd5d3f758 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 2 Jul 2014 23:52:42 +0900 Subject: [PATCH 23/52] Re-format source to respect Jedis convention --- .../clients/jedis/JedisClusterCommand.java | 26 +-- .../jedis/JedisClusterConnectionHandler.java | 42 ++-- .../clients/jedis/JedisClusterInfoCache.java | 209 +++++++++--------- 3 files changed, 138 insertions(+), 139 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisClusterCommand.java b/src/main/java/redis/clients/jedis/JedisClusterCommand.java index c4d80fa..604afca 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterCommand.java +++ b/src/main/java/redis/clients/jedis/JedisClusterCommand.java @@ -63,35 +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) { - // 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()); + } else if (jre instanceof JedisMovedDataException) { + // it rebuilds cluster's slot cache + // recommended by Redis cluster specification + this.connectionHandler.renewSlotCache(); + } else { + throw new JedisClusterException(jre); + } 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 102921e..5288e7c 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java +++ b/src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java @@ -14,13 +14,13 @@ public abstract class JedisClusterConnectionHandler { abstract Jedis getConnection(); public void returnConnection(Jedis connection) { - cache.getNode(getNodeKey(connection.getClient())) - .returnResource(connection); + cache.getNode(getNodeKey(connection.getClient())).returnResource( + connection); } public void returnBrokenConnection(Jedis connection) { - cache.getNode(getNodeKey(connection.getClient())) - .returnBrokenResource(connection); + cache.getNode(getNodeKey(connection.getClient())).returnBrokenResource( + connection); } abstract Jedis getConnectionFromSlot(int slot); @@ -34,7 +34,7 @@ public abstract class JedisClusterConnectionHandler { } public void assignSlotToNode(int slot, HostAndPort targetNode) { - cache.assignSlotToNode(slot, targetNode); + cache.assignSlotToNode(slot, targetNode); } private void initializeSlotsCache(Set startNodes) { @@ -45,14 +45,14 @@ public abstract class JedisClusterConnectionHandler { Jedis jedis = null; try { jedis = jp.getResource(); - cache.discoverClusterNodesAndSlots(jedis); + cache.discoverClusterNodesAndSlots(jedis); break; } catch (JedisConnectionException e) { // try next nodes } finally { - if (jedis != null) { - jedis.close(); - } + if (jedis != null) { + jedis.close(); + } } } @@ -62,18 +62,18 @@ public abstract class JedisClusterConnectionHandler { } 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(); - } - } - } + 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() { diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java index 0906b5e..c98cde2 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -22,162 +22,161 @@ public class JedisClusterInfoCache { private final Lock w = rwl.writeLock(); public void discoverClusterNodesAndSlots(Jedis jedis) { - w.lock(); + w.lock(); - try { - this.nodes.clear(); - this.slots.clear(); + 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())); + 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(); - } + HostAndPort targetNode = clusterNodeInfo.getNode(); + setNodeIfNotExist(targetNode); + assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), + targetNode); + } + } finally { + w.unlock(); + } } public void discoverClusterSlots(Jedis jedis) { - w.lock(); + w.lock(); - try { - this.slots.clear(); + try { + this.slots.clear(); - List slots = jedis.clusterSlots(); + List slots = jedis.clusterSlots(); - for (Object slotInfoObj : slots) { - List slotInfo = (List) slotInfoObj; + for (Object slotInfoObj : slots) { + List slotInfo = (List) slotInfoObj; - if (slotInfo.size() <= 2) { - continue; - } + if (slotInfo.size() <= 2) { + continue; + } - List slotNums = getAssignedSlotArray(slotInfo); + List slotNums = getAssignedSlotArray(slotInfo); - // hostInfos - List hostInfos = (List) slotInfo.get(2); - if (hostInfos.size() <= 0) { - continue; - } + // 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); + // at this time, we just use master, discard slave information + HostAndPort targetNode = generateHostAndPort(hostInfos); - setNodeIfNotExist(targetNode); - assignSlotsToNode(slotNums, targetNode); - } - } finally { - w.unlock(); - } + 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()); + 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; + w.lock(); + try { + String nodeKey = getNodeKey(node); + if (nodes.containsKey(nodeKey)) + return; - JedisPool nodePool = new JedisPool(node.getHost(), node.getPort()); - nodes.put(nodeKey, nodePool); - } finally { - w.unlock(); - } + JedisPool nodePool = new JedisPool(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)); + 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(); - } + 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)); + HostAndPort targetNode) { + w.lock(); + try { + JedisPool targetPool = nodes.get(getNodeKey(targetNode)); - if (targetPool == null) { - setNodeIfNotExist(targetNode); - 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(); - } + 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(); - } + 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(); - } + r.lock(); + try { + return slots.get(slot); + } finally { + r.unlock(); + } } public synchronized Map getNodes() { - r.lock(); - try { - return new HashMap(nodes); - } finally { - r.unlock(); - } + r.lock(); + try { + return new HashMap(nodes); + } finally { + r.unlock(); + } } public static String getNodeKey(HostAndPort hnp) { - return hnp.getHost() + ":" + hnp.getPort(); + return hnp.getHost() + ":" + hnp.getPort(); } public static String getNodeKey(Client client) { - return client.getHost() + ":" + client.getPort(); + return client.getHost() + ":" + client.getPort(); } public static String getNodeKey(Jedis jedis) { - return getNodeKey(jedis.getClient()); + 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; + List slotNums = new ArrayList(); + for (int slot = ((Long) slotInfo.get(0)).intValue(); slot <= ((Long) slotInfo + .get(1)).intValue(); slot++) { + slotNums.add(slot); + } + return slotNums; } } From 088d86a60fc7cfd3ba55156fc949059b5e9ecdc9 Mon Sep 17 00:00:00 2001 From: xuyifei Date: Thu, 17 Jul 2014 16:40:22 +0800 Subject: [PATCH 24/52] Update Jedis.java edit the rpop note (just makei it Specific --- src/main/java/redis/clients/jedis/Jedis.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index fbf430c..77cb245 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -1116,8 +1116,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. From c2624c6c932e3ed2fee1873fcb72d33f5816904c Mon Sep 17 00:00:00 2001 From: Greg Tam Date: Thu, 17 Jul 2014 15:11:02 -0600 Subject: [PATCH 25/52] fixed the name of archiveBaseName to archivesBaseName --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From 75d2ba751ba59c1cf5e13ddad84d4f0d3a82fb3e Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Fri, 25 Jul 2014 18:06:33 -0700 Subject: [PATCH 26/52] Race condition when switching masters in JedisSentinelPool Instead of recreating GenericObjectPool, we change the underlying factory destination host. When returning objects to the pool we make sure they are pointing at the correct master. --- .../redis/clients/jedis/JedisFactory.java | 23 ++++++++++++++----- .../clients/jedis/JedisSentinelPool.java | 12 +++++++--- 2 files changed, 26 insertions(+), 9 deletions(-) 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/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 0ff0dff..2e076b1 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -74,6 +74,7 @@ public class JedisSentinelPool extends Pool { initPool(master); } + private volatile JedisFactory factory; private volatile HostAndPort currentHostMaster; public void destroy() { @@ -91,10 +92,15 @@ 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); + } + log.info("Created JedisPool to master at " + master); - initPool(poolConfig, - new JedisFactory(master.getHost(), master.getPort(), - timeout, password, database)); } } From 9e128b4520dbdcbeb9207bd9e2b02cbe6b14402a Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 10:55:09 -0700 Subject: [PATCH 27/52] Add an extra sentinel server to tests Adds an extra sentinel server monitoring the mymaster failover cluster, makes the tests more interesting. --- Makefile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 From 9013078d408be26dce3977a96ceaf1970ab03002 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 10:56:21 -0700 Subject: [PATCH 28/52] Fix race condition in JedisSentinelPoolTest The test was issuing the failover command and only afterwards connecting to the pub-sub channel to receive failover notifications. If the failover occurred fast enought the pub-sub listener would never get the notification. Run the failover command on a separate Jedis connection after we're absolutely sure that we're subscribed to the pub-sub channel. --- .../redis/clients/jedis/tests/HostAndPortUtil.java | 1 + .../clients/jedis/tests/JedisSentinelPoolTest.java | 13 +++++++------ .../jedis/tests/utils/JedisSentinelTestUtil.java | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) 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/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index 205d90a..ea0e8a0 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -21,18 +21,24 @@ 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 @@ -137,11 +143,6 @@ public class JedisSentinelPoolTest extends JedisTestBase { Jedis jedis = pool.getResource(); assertEquals("PONG", jedis.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 @@ -156,7 +157,7 @@ public class JedisSentinelPoolTest extends JedisTestBase { private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) throws InterruptedException { HostAndPort newMaster = JedisSentinelTestUtil - .waitForNewPromotedMaster(sentinelJedis1); + .waitForNewPromotedMaster(MASTER_NAME, sentinelJedis1, sentinelJedis2); waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster); } 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); } }, "*"); From c02c663776cae170f2b72a3070d1d536ee427e53 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 11:34:00 -0700 Subject: [PATCH 29/52] Add check that JedisSentinelPool accepts closing connections before and after failover --- .../jedis/tests/JedisSentinelPoolTest.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index ea0e8a0..5a43b3f 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -47,6 +47,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 @@ -140,18 +142,19 @@ 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()); 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) @@ -167,10 +170,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 From fceb7198482bc428513ab02891e1c23d07708ac9 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 11:35:39 -0700 Subject: [PATCH 30/52] Proper master failover detection depends on testOnBorrow --- src/main/java/redis/clients/jedis/JedisSentinelPool.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 2e076b1..0aec8d5 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -65,6 +65,9 @@ public class JedisSentinelPool extends Pool { public JedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) { + // Proper master failover detection dependes on testOnBorrow, so force it here + poolConfig.setTestOnBorrow(true); + this.poolConfig = poolConfig; this.timeout = timeout; this.password = password; From d52cc06b72f14cb020a652cbbb770e32babb62e3 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 11:44:23 -0700 Subject: [PATCH 31/52] Let the user choose whether to testOnBorrow or testOnReturn Force testOnBorrow if neither is specified. --- src/main/java/redis/clients/jedis/JedisSentinelPool.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 0aec8d5..c80ae8e 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -65,8 +65,10 @@ public class JedisSentinelPool extends Pool { public JedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) { - // Proper master failover detection dependes on testOnBorrow, so force it here - poolConfig.setTestOnBorrow(true); + // Proper master failover detection dependes on testOnBorrow or testOnReturn, so force it here + if (!poolConfig.getTestOnBorrow() && !poolConfig.getTestOnReturn()) { + poolConfig.setTestOnBorrow(true); + } this.poolConfig = poolConfig; this.timeout = timeout; From c81bdc08491932caadee59fa8582b7703d5fced7 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 11:45:34 -0700 Subject: [PATCH 32/52] Properly close jedis connection in case of exceptions --- .../java/redis/clients/jedis/JedisSentinelPool.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index c80ae8e..9138cc0 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -126,20 +126,24 @@ 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)); 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(); + } + } } try { From dddc0d15f108637e8fd733359713e13bc1656fb4 Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Mon, 28 Jul 2014 11:51:41 -0700 Subject: [PATCH 33/52] Add second jedis connection to waitForNewPromotedMaster call --- .../java/redis/clients/jedis/tests/JedisSentinelTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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); From 056e6e9db2c3a3081e41092ea748332526cdaf4c Mon Sep 17 00:00:00 2001 From: Nelson Rodrigues Date: Sat, 2 Aug 2014 14:34:06 -0700 Subject: [PATCH 34/52] Do master failover detection in JedisSentielPool.getResource --- .../clients/jedis/JedisSentinelPool.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/redis/clients/jedis/JedisSentinelPool.java b/src/main/java/redis/clients/jedis/JedisSentinelPool.java index 9138cc0..84afe80 100644 --- a/src/main/java/redis/clients/jedis/JedisSentinelPool.java +++ b/src/main/java/redis/clients/jedis/JedisSentinelPool.java @@ -65,10 +65,6 @@ public class JedisSentinelPool extends Pool { public JedisSentinelPool(String masterName, Set sentinels, final GenericObjectPoolConfig poolConfig, int timeout, final String password, final int database) { - // Proper master failover detection dependes on testOnBorrow or testOnReturn, so force it here - if (!poolConfig.getTestOnBorrow() && !poolConfig.getTestOnReturn()) { - poolConfig.setTestOnBorrow(true); - } this.poolConfig = poolConfig; this.timeout = timeout; @@ -103,6 +99,9 @@ public class JedisSentinelPool extends Pool { 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); @@ -143,7 +142,7 @@ public class JedisSentinelPool extends Pool { if (jedis != null) { jedis.close(); } - } + } } try { @@ -179,9 +178,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) { @@ -319,4 +331,4 @@ public class JedisSentinelPool extends Pool { } } } -} \ No newline at end of file +} From d7cd3a0af671b0fcf30b7cd4819fa9026f8d92f8 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Mon, 4 Aug 2014 09:28:17 +0900 Subject: [PATCH 35/52] Fixed critical JedisCluster bug : hlen calls hdel --- src/main/java/redis/clients/jedis/JedisCluster.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index f6cb6fd..d39d43d 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -394,7 +394,7 @@ public class JedisCluster implements JedisCommands, BasicCommands { maxRedirections) { @Override public Long execute(Jedis connection) { - return connection.hdel(key); + return connection.hlen(key); } }.run(key); } From 2d93fa0e2b6df113d49b0e2790a3aa1e306d07fd Mon Sep 17 00:00:00 2001 From: Jonathan Leibiusky Date: Mon, 4 Aug 2014 11:20:52 -0400 Subject: [PATCH 36/52] version bump --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 514144d472135dbf5ece2677be2d28f4fa58ca31 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Fri, 8 Aug 2014 10:56:39 +0900 Subject: [PATCH 37/52] Fix indentation (code formatting...) --- .../java/redis/clients/jedis/BinaryJedis.java | 39 +++++++-------- .../java/redis/clients/jedis/Connection.java | 50 +++++++++---------- .../java/redis/clients/jedis/Pipeline.java | 10 ++-- .../redis/clients/jedis/PipelineBlock.java | 8 +-- .../java/redis/clients/jedis/Queable.java | 6 +-- .../java/redis/clients/jedis/Transaction.java | 12 ++--- .../redis/clients/jedis/TransactionBlock.java | 10 ++-- 7 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index f76a391..f2ca337 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -22,11 +22,10 @@ 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")) { @@ -1771,10 +1770,10 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, public List multi(final TransactionBlock jedisTransaction) { List results = null; jedisTransaction.setClient(client); - client.multi(); - client.getOne(); // expected OK - jedisTransaction.execute(); - results = jedisTransaction.exec(); + client.multi(); + client.getOne(); // expected OK + jedisTransaction.execute(); + results = jedisTransaction.exec(); return results; } @@ -1794,24 +1793,24 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, } public void resetState() { - if (client.isConnected()) { - if (transaction != null) { - transaction.clear(); - } + if (client.isConnected()) { + if (transaction != null) { + transaction.clear(); + } - if (pipeline != null) { - pipeline.clear(); - } + if (pipeline != null) { + pipeline.clear(); + } - if (client.isInWatch()) { - unwatch(); - } + if (client.isInWatch()) { + unwatch(); + } - client.resetState(); - } + client.resetState(); + } - transaction = null; - pipeline = null; + transaction = null; + pipeline = null; } public String watch(final byte[]... keys) { diff --git a/src/main/java/redis/clients/jedis/Connection.java b/src/main/java/redis/clients/jedis/Connection.java index cee0e3a..c57b170 100644 --- a/src/main/java/redis/clients/jedis/Connection.java +++ b/src/main/java/redis/clients/jedis/Connection.java @@ -231,42 +231,42 @@ public class Connection implements Closeable { } public Object getOne() { - flush(); - return readProtocolWithCheckingBroken(); + flush(); + return readProtocolWithCheckingBroken(); } public boolean isBroken() { - return broken; + return broken; } protected void flush() { - try { - outputStream.flush(); - } catch (IOException ex) { - broken = true; - throw new JedisConnectionException(ex); - } + try { + outputStream.flush(); + } catch (IOException ex) { + broken = true; + throw new JedisConnectionException(ex); + } } protected Object readProtocolWithCheckingBroken() { - try { - return Protocol.read(inputStream); - } catch (JedisConnectionException exc) { - broken = true; - throw exc; - } + try { + return Protocol.read(inputStream); + } catch (JedisConnectionException exc) { + broken = true; + 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; + 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/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index f837894..ba17387 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -70,15 +70,15 @@ public class Pipeline extends MultiKeyPipelineBase { } public void clear() { - if (isInMulti()) { - discard(); - } + if (isInMulti()) { + discard(); + } - sync(); + sync(); } public boolean isInMulti() { - return currentMulti != null; + return currentMulti != null; } /** diff --git a/src/main/java/redis/clients/jedis/PipelineBlock.java b/src/main/java/redis/clients/jedis/PipelineBlock.java index 76d84eb..24bae84 100644 --- a/src/main/java/redis/clients/jedis/PipelineBlock.java +++ b/src/main/java/redis/clients/jedis/PipelineBlock.java @@ -7,9 +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; - + // For shadowing + @SuppressWarnings("unused") + private Client client; + public abstract void execute(); } diff --git a/src/main/java/redis/clients/jedis/Queable.java b/src/main/java/redis/clients/jedis/Queable.java index 643abf9..2cd5265 100644 --- a/src/main/java/redis/clients/jedis/Queable.java +++ b/src/main/java/redis/clients/jedis/Queable.java @@ -25,10 +25,10 @@ public class Queable { } protected boolean hasPipelinedResponse() { - return pipelinedResponses.size() > 0; + return pipelinedResponses.size() > 0; } - + protected int getPipelinedResponseLength() { - return pipelinedResponses.size(); + return pipelinedResponses.size(); } } diff --git a/src/main/java/redis/clients/jedis/Transaction.java b/src/main/java/redis/clients/jedis/Transaction.java index 57238d6..e6088ff 100644 --- a/src/main/java/redis/clients/jedis/Transaction.java +++ b/src/main/java/redis/clients/jedis/Transaction.java @@ -32,9 +32,9 @@ public class Transaction extends MultiKeyPipelineBase { } public void clear() { - if (inTransaction) { - discard(); - } + if (inTransaction) { + discard(); + } } public List exec() { @@ -60,7 +60,7 @@ public class Transaction extends MultiKeyPipelineBase { public List> execGetResponse() { // Discard QUEUED or ERROR client.getMany(getPipelinedResponseLength()); - client.exec(); + client.exec(); List unformatted = client.getObjectMultiBulkReply(); if (unformatted == null) { @@ -81,8 +81,8 @@ public class Transaction extends MultiKeyPipelineBase { return client.getStatusCodeReply(); } - public void setClient(Client client) { + 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 3dfc8ab..c038ac2 100644 --- a/src/main/java/redis/clients/jedis/TransactionBlock.java +++ b/src/main/java/redis/clients/jedis/TransactionBlock.java @@ -9,10 +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; - + // For shadowing + @SuppressWarnings("unused") + private Client client; + public TransactionBlock(Client client) { super(client); } @@ -23,6 +23,6 @@ public abstract class TransactionBlock extends Transaction { public abstract void execute() throws JedisException; public void setClient(Client client) { - super.setClient(client); + super.setClient(client); } } From c62672e3a058bde24e37b0e49694505472ae904f Mon Sep 17 00:00:00 2001 From: Ming Date: Wed, 13 Aug 2014 14:44:17 +0800 Subject: [PATCH 38/52] add timeout parameter to blpop/brpop --- src/main/java/redis/clients/jedis/ShardedJedis.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/ShardedJedis.java b/src/main/java/redis/clients/jedis/ShardedJedis.java index 5d4c625..3f6c057 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); From a30598b7cbb24b133a35d472c8440395a65706cc Mon Sep 17 00:00:00 2001 From: Ming Date: Thu, 14 Aug 2014 10:37:28 +0800 Subject: [PATCH 39/52] add blpop/brpop with timeout parameter interface to JedisCommands --- src/main/java/redis/clients/jedis/Jedis.java | 27 +++++++++++++++++++ .../redis/clients/jedis/JedisCluster.java | 22 +++++++++++++++ .../redis/clients/jedis/JedisCommands.java | 4 +++ 3 files changed, 53 insertions(+) diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 49569e2..571ad82 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3433,4 +3433,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 8e1202b..902a096 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -1474,4 +1474,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/JedisCommands.java b/src/main/java/redis/clients/jedis/JedisCommands.java index b5263f4..b4b71e0 100644 --- a/src/main/java/redis/clients/jedis/JedisCommands.java +++ b/src/main/java/redis/clients/jedis/JedisCommands.java @@ -203,8 +203,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); From 52ac566dd3856eb19a8286d3eb4306da825880ef Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Sat, 23 Aug 2014 18:14:50 +0200 Subject: [PATCH 40/52] Changed weights from ints to doubles --- src/main/java/redis/clients/jedis/ZParams.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/ZParams.java b/src/main/java/redis/clients/jedis/ZParams.java index 7b585f3..ff2ef60 100644 --- a/src/main/java/redis/clients/jedis/ZParams.java +++ b/src/main/java/redis/clients/jedis/ZParams.java @@ -23,9 +23,9 @@ public class ZParams { private List params = new ArrayList(); - public ZParams weights(final int... 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)); } From ae73a99a17628d6e12ade3550b9a15967342696f Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Sat, 23 Aug 2014 19:39:19 +0200 Subject: [PATCH 41/52] Adopted test to use decimal weight values --- .../tests/commands/SortedSetCommandsTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 f055500..467fc7b 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -783,15 +783,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 +802,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 +810,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 +855,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 +872,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 +880,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)); From 9f4faf53ffdc87387d84bb9b4d1b1a9de393afed Mon Sep 17 00:00:00 2001 From: Ivan Dyedov Date: Tue, 26 Aug 2014 11:50:56 -0400 Subject: [PATCH 42/52] fix binary version of hgetAll(), fixes #711 --- .../redis/clients/jedis/BuilderFactory.java | 3 ++- .../tests/commands/HashesCommandsTest.java | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 76d013e..10bf457 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 { @@ -170,7 +171,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/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java b/src/test/java/redis/clients/jedis/tests/commands/HashesCommandsTest.java index 229b2ac..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"); From ad5412d8cfc24ab56f9da3d3159035630fd00d36 Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Wed, 27 Aug 2014 21:12:28 +0200 Subject: [PATCH 43/52] Restored old method for int weights for backwards compatibility --- .../java/redis/clients/jedis/ZParams.java | 25 ++++++++++++++++++- .../tests/commands/SortedSetCommandsTest.java | 8 +++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/redis/clients/jedis/ZParams.java b/src/main/java/redis/clients/jedis/ZParams.java index ff2ef60..ac1d1bd 100644 --- a/src/main/java/redis/clients/jedis/ZParams.java +++ b/src/main/java/redis/clients/jedis/ZParams.java @@ -23,7 +23,30 @@ public class ZParams { private List params = new ArrayList(); - public ZParams weights(final double... weights) { + /** + * Set weights. + * + * @param weights + * weights. + * @deprecated Use {@link #weightsByDouble(double...)} instead + */ + @Deprecated + public ZParams weights(final int... weights) { + params.add(WEIGHTS.raw); + for (final int weight : weights) { + params.add(Protocol.toByteArray(weight)); + } + + return this; + } + + /** + * Set weights. + * + * @param weights + * weights. + */ + public ZParams weightsByDouble(final double... weights) { params.add(WEIGHTS.raw); for (final double weight : weights) { params.add(Protocol.toByteArray(weight)); 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 467fc7b..f510ae3 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -783,7 +783,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "b"); ZParams params = new ZParams(); - params.weights(2, 2.5); + params.weightsByDouble(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zunionstore("dst", params, "foo", "bar"); @@ -802,7 +802,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, bb); ZParams bparams = new ZParams(); - bparams.weights(2, 2.5); + bparams.weightsByDouble(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zunionstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); @@ -855,7 +855,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "a"); ZParams params = new ZParams(); - params.weights(2, 2.5); + params.weightsByDouble(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zinterstore("dst", params, "foo", "bar"); @@ -872,7 +872,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, ba); ZParams bparams = new ZParams(); - bparams.weights(2, 2.5); + bparams.weightsByDouble(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zinterstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); From 2eda9cd8fb78745996fdc20d93000f9ab787a89f Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Wed, 27 Aug 2014 21:41:22 +0200 Subject: [PATCH 44/52] Removed deprecated int based weights --- .../java/redis/clients/jedis/ZParams.java | 19 +------------------ .../tests/commands/SortedSetCommandsTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/main/java/redis/clients/jedis/ZParams.java b/src/main/java/redis/clients/jedis/ZParams.java index ac1d1bd..6b42174 100644 --- a/src/main/java/redis/clients/jedis/ZParams.java +++ b/src/main/java/redis/clients/jedis/ZParams.java @@ -28,25 +28,8 @@ public class ZParams { * * @param weights * weights. - * @deprecated Use {@link #weightsByDouble(double...)} instead */ - @Deprecated - public ZParams weights(final int... weights) { - params.add(WEIGHTS.raw); - for (final int weight : weights) { - params.add(Protocol.toByteArray(weight)); - } - - return this; - } - - /** - * Set weights. - * - * @param weights - * weights. - */ - public ZParams weightsByDouble(final double... weights) { + public ZParams weights(final double... weights) { params.add(WEIGHTS.raw); for (final double weight : weights) { params.add(Protocol.toByteArray(weight)); 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 f510ae3..467fc7b 100644 --- a/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/tests/commands/SortedSetCommandsTest.java @@ -783,7 +783,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "b"); ZParams params = new ZParams(); - params.weightsByDouble(2, 2.5); + params.weights(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zunionstore("dst", params, "foo", "bar"); @@ -802,7 +802,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, bb); ZParams bparams = new ZParams(); - bparams.weightsByDouble(2, 2.5); + bparams.weights(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zunionstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); @@ -855,7 +855,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd("bar", 2, "a"); ZParams params = new ZParams(); - params.weightsByDouble(2, 2.5); + params.weights(2, 2.5); params.aggregate(ZParams.Aggregate.SUM); long result = jedis.zinterstore("dst", params, "foo", "bar"); @@ -872,7 +872,7 @@ public class SortedSetCommandsTest extends JedisCommandTestBase { jedis.zadd(bbar, 2, ba); ZParams bparams = new ZParams(); - bparams.weightsByDouble(2, 2.5); + bparams.weights(2, 2.5); bparams.aggregate(ZParams.Aggregate.SUM); long bresult = jedis.zinterstore(SafeEncoder.encode("dst"), bparams, bfoo, bbar); From 431ae79ff161f9f1e20f4b8713d370b0f561eb6d Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Thu, 28 Aug 2014 18:14:49 +0900 Subject: [PATCH 45/52] Follow up changes on "pubsub numsub" output * String, String to String, Long * We're avoiding to break backward compatibility ** convert Long to String so that return type is same to old type --- .../redis/clients/jedis/BuilderFactory.java | 20 +++++++++++++++++++ src/main/java/redis/clients/jedis/Jedis.java | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/BuilderFactory.java b/src/main/java/redis/clients/jedis/BuilderFactory.java index 10bf457..8c119b6 100755 --- a/src/main/java/redis/clients/jedis/BuilderFactory.java +++ b/src/main/java/redis/clients/jedis/BuilderFactory.java @@ -105,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) { diff --git a/src/main/java/redis/clients/jedis/Jedis.java b/src/main/java/redis/clients/jedis/Jedis.java index 49569e2..1f4fcde 100644 --- a/src/main/java/redis/clients/jedis/Jedis.java +++ b/src/main/java/redis/clients/jedis/Jedis.java @@ -3388,7 +3388,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()); } From 0a094ff0b4327f2fdffdc5fe051d7903ac084a92 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Thu, 28 Aug 2014 23:49:52 +0900 Subject: [PATCH 46/52] Implements #701, add close() to JedisCluster --- .../redis/clients/jedis/JedisCluster.java | 18 ++++++++++- .../clients/jedis/tests/JedisClusterTest.java | 30 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/main/java/redis/clients/jedis/JedisCluster.java b/src/main/java/redis/clients/jedis/JedisCluster.java index 8e1202b..d5ffd0b 100644 --- a/src/main/java/redis/clients/jedis/JedisCluster.java +++ b/src/main/java/redis/clients/jedis/JedisCluster.java @@ -2,12 +2,13 @@ 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; import java.util.Set; -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; @@ -32,6 +33,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) { diff --git a/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java b/src/test/java/redis/clients/jedis/tests/JedisClusterTest.java index 28af2a4..6dfac6d 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; @@ -14,9 +15,11 @@ import org.junit.Test; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; +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; @@ -321,6 +324,33 @@ public class JedisClusterTest extends Assert { assertEquals("foo", jc.get("51")); } + @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")) { From b2193457613cb76bfc107d038140071c8674905c Mon Sep 17 00:00:00 2001 From: Himanshu Verma Date: Sun, 31 Aug 2014 16:06:33 +0530 Subject: [PATCH 47/52] pipelined transaction response fix --- .../java/redis/clients/jedis/Pipeline.java | 12 ++- .../clients/jedis/tests/PipeliningTest.java | 93 ++++++++++++++++--- 2 files changed, 88 insertions(+), 17 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index ba17387..bf3309d 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; } diff --git a/src/test/java/redis/clients/jedis/tests/PipeliningTest.java b/src/test/java/redis/clients/jedis/tests/PipeliningTest.java index 94ccb13..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); @@ -381,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)); + } } From 9b824c3aadc94a9dcd3a3f0def24ffdab43ffb9f Mon Sep 17 00:00:00 2001 From: Himanshu Verma Date: Mon, 1 Sep 2014 11:12:26 +0530 Subject: [PATCH 48/52] pipelined transaction response fix : indentation fix --- src/main/java/redis/clients/jedis/Pipeline.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/redis/clients/jedis/Pipeline.java b/src/main/java/redis/clients/jedis/Pipeline.java index bf3309d..c79c969 100755 --- a/src/main/java/redis/clients/jedis/Pipeline.java +++ b/src/main/java/redis/clients/jedis/Pipeline.java @@ -26,13 +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)); - Object builtResponse; - try { - builtResponse = response.get(); - } catch (JedisDataException e) { - builtResponse = e; - } - values.add(builtResponse); + Object builtResponse; + try { + builtResponse = response.get(); + } catch (JedisDataException e) { + builtResponse = e; + } + values.add(builtResponse); } return values; } From a201e29d88ca8fccfe28d71e5e7c76cbe91d2a02 Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Tue, 2 Sep 2014 14:54:36 -0400 Subject: [PATCH 49/52] Closes #656. Add a getNumActive() method to JedisPool to provide access to the current state of the internal pool. --- .../java/redis/clients/jedis/JedisPool.java | 8 +++++ .../clients/jedis/tests/JedisPoolTest.java | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/main/java/redis/clients/jedis/JedisPool.java b/src/main/java/redis/clients/jedis/JedisPool.java index 0fbfdfe..c6d2cb3 100644 --- a/src/main/java/redis/clients/jedis/JedisPool.java +++ b/src/main/java/redis/clients/jedis/JedisPool.java @@ -98,4 +98,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/test/java/redis/clients/jedis/tests/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index 7d8e611..68c7c35 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -238,4 +238,35 @@ 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); + pool.returnResource(jedis2); + pool.destroy(); + } } From 36810dfcba45dbf8a200c893cc287adf101bd962 Mon Sep 17 00:00:00 2001 From: Ethan Urie Date: Wed, 3 Sep 2014 14:15:48 -0400 Subject: [PATCH 50/52] Closes #656. Added 2 more asserts to ensure the count decrements correctly. --- src/test/java/redis/clients/jedis/tests/JedisPoolTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index 68c7c35..9904c1e 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -266,7 +266,12 @@ public class JedisPoolTest extends Assert { assertEquals(2, pool.getNumActive()); pool.returnResource(jedis); + assertEquals(1, pool.getNumActive()); + pool.returnResource(jedis2); + + assertEquals(0, pool.getNumActive()); + pool.destroy(); } } From bfcecd73cb3b56a4f9ae99dac9bc068518f62224 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 10 Sep 2014 20:46:57 +0900 Subject: [PATCH 51/52] JedisURIHelper.getDBIndex() now returns 0 when db index is not provided --- src/main/java/redis/clients/jedis/BinaryJedis.java | 2 +- src/main/java/redis/clients/util/JedisURIHelper.java | 9 +++++++-- src/test/java/redis/clients/jedis/tests/JedisTest.java | 7 +++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/redis/clients/jedis/BinaryJedis.java b/src/main/java/redis/clients/jedis/BinaryJedis.java index 5f3d089..b89fcc0 100644 --- a/src/main/java/redis/clients/jedis/BinaryJedis.java +++ b/src/main/java/redis/clients/jedis/BinaryJedis.java @@ -68,7 +68,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, } Integer dbIndex = JedisURIHelper.getDBIndex(uri); - if (dbIndex != null) { + if (dbIndex > 0) { client.select(dbIndex); client.getStatusCodeReply(); } diff --git a/src/main/java/redis/clients/util/JedisURIHelper.java b/src/main/java/redis/clients/util/JedisURIHelper.java index 027fa3a..d2039a8 100644 --- a/src/main/java/redis/clients/util/JedisURIHelper.java +++ b/src/main/java/redis/clients/util/JedisURIHelper.java @@ -14,8 +14,13 @@ public class JedisURIHelper { public static Integer getDBIndex(URI uri) { String[] pathSplit = uri.getPath().split("/", 2); if (pathSplit.length > 1) { - return Integer.parseInt(pathSplit[1]); + String dbIndexStr = pathSplit[1]; + if (dbIndexStr.isEmpty()) { + return 0; + } + return Integer.parseInt(dbIndexStr); + } else { + return 0; } - return null; } } diff --git a/src/test/java/redis/clients/jedis/tests/JedisTest.java b/src/test/java/redis/clients/jedis/tests/JedisTest.java index abec911..3b7a87f 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisTest.java @@ -104,6 +104,13 @@ public class JedisTest extends JedisCommandTestBase { @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); From f931a4fc81871710a9ba4dc62ca62e035c9be5e7 Mon Sep 17 00:00:00 2001 From: Jungtaek Lim Date: Wed, 10 Sep 2014 21:15:02 +0900 Subject: [PATCH 52/52] Replace Closer class to use its close() method --- .../redis/clients/jedis/tests/Closer.java | 39 ------------------- .../jedis/tests/ConnectionCloseTest.java | 27 +++++-------- .../clients/jedis/tests/JedisPoolTest.java | 7 ++-- .../jedis/tests/JedisSentinelPoolTest.java | 7 ++-- .../jedis/tests/ShardedJedisPoolTest.java | 7 ++-- 5 files changed, 19 insertions(+), 68 deletions(-) delete mode 100644 src/test/java/redis/clients/jedis/tests/Closer.java diff --git a/src/test/java/redis/clients/jedis/tests/Closer.java b/src/test/java/redis/clients/jedis/tests/Closer.java deleted file mode 100644 index 5c7d801..0000000 --- a/src/test/java/redis/clients/jedis/tests/Closer.java +++ /dev/null @@ -1,39 +0,0 @@ -package redis.clients.jedis.tests; - -import java.io.Closeable; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -class Closer implements Closeable { - private final Set elements = new HashSet(); - - synchronized T register(T element) { - if (element != null) { - elements.add(element); - } - return element; - } - - public synchronized void close() throws IOException { - Throwable caught = null; - - for (Closeable element : elements) { - try { - element.close(); - } - catch (Throwable t) { - caught = t; - } - } - - elements.clear(); - - if (caught != null) { - if (caught instanceof IOException) { - throw (IOException) caught; - } - throw (RuntimeException) caught; - } - } -} diff --git a/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java b/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java index 77cb48d..5717641 100644 --- a/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java +++ b/src/test/java/redis/clients/jedis/tests/ConnectionCloseTest.java @@ -1,10 +1,5 @@ package redis.clients.jedis.tests; -import java.io.Closeable; -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -15,37 +10,35 @@ import redis.clients.jedis.exceptions.JedisConnectionException; public class ConnectionCloseTest extends Assert { - private final Closer closer = new Closer(); - private Connection client; @Before public void setUp() throws Exception { - client = closer.register(new Connection()); + client = new Connection(); } @After public void tearDown() throws Exception { - closer.close(); + client.close(); } @Test(expected = JedisConnectionException.class) public void checkUnkownHost() { - client.setHost("someunknownhost"); - client.connect(); + client.setHost("someunknownhost"); + client.connect(); } @Test(expected = JedisConnectionException.class) public void checkWrongPort() { - client.setHost("localhost"); - client.setPort(55665); - client.connect(); + client.setHost("localhost"); + client.setPort(55665); + client.connect(); } @Test public void connectIfNotConnectedWhenSettingTimeoutInfinite() { - client.setHost("localhost"); - client.setPort(6379); - client.setTimeoutInfinite(); + client.setHost("localhost"); + client.setPort(6379); + client.setTimeoutInfinite(); } } diff --git a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java index 58db11d..becf91f 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisPoolTest.java @@ -32,15 +32,14 @@ public class JedisPoolTest extends Assert { @Test public void checkCloseableConnections() throws Exception { - Closer closer = new Closer(); - JedisPool pool = closer.register(new JedisPool(new JedisPoolConfig(), hnp.getHost(), - hnp.getPort(), 2000)); + 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); - closer.close(); + pool.close(); assertTrue(pool.isClosed()); } diff --git a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java index c88bd55..87bc1b9 100644 --- a/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/JedisSentinelPoolTest.java @@ -39,15 +39,14 @@ public class JedisSentinelPoolTest extends JedisTestBase { public void checkCloseableConnections() throws Exception { GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - Closer closer = new Closer(); - JedisSentinelPool pool = closer.register(new JedisSentinelPool( - MASTER_NAME, sentinels, config, 1000, "foobared", 2)); + 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); - closer.close(); + pool.close(); assertTrue(pool.isClosed()); } diff --git a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java index 272656c..884361d 100644 --- a/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/tests/ShardedJedisPoolTest.java @@ -56,14 +56,13 @@ public class ShardedJedisPoolTest extends Assert { @Test public void checkCloseableConnections() throws Exception { - Closer closer = new Closer(); - ShardedJedisPool pool = closer.register(new ShardedJedisPool( - new GenericObjectPoolConfig(), shards)); + ShardedJedisPool pool = new ShardedJedisPool( + new GenericObjectPoolConfig(), shards); ShardedJedis jedis = pool.getResource(); jedis.set("foo", "bar"); assertEquals("bar", jedis.get("foo")); pool.returnResource(jedis); - closer.close(); + pool.close(); assertTrue(pool.isClosed()); }