Merge branch 'master' into pipeline-and-transaction-can-handle-responses-on-their-own-status

* it's broken with later features, resetState()
* fixed resetState() to make it work with this PR

Conflicts:
	src/main/java/redis/clients/jedis/BinaryJedis.java
	src/main/java/redis/clients/jedis/Connection.java
	src/main/java/redis/clients/jedis/Pipeline.java
	src/main/java/redis/clients/jedis/Transaction.java
	src/main/java/redis/clients/jedis/TransactionBlock.java
This commit is contained in:
Jungtaek Lim
2014-08-08 10:46:43 +09:00
124 changed files with 9710 additions and 6367 deletions

3
.gitignore vendored
View File

@@ -9,3 +9,6 @@ target/
build/
bin/
tags
.idea
*.aof
*.rdb

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: java
jdk:
- openjdk6
- openjdk7
- oraclejdk7
install: make travis-install
script: make test

116
Makefile
View File

@@ -1,3 +1,5 @@
PATH := ./redis-git/src:${PATH}
define REDIS1_CONF
daemonize yes
port 6379
@@ -23,6 +25,7 @@ define REDIS3_CONF
daemonize yes
port 6381
requirepass foobared
masterauth foobared
pidfile /tmp/redis3.pid
logfile /tmp/redis3.log
save ""
@@ -50,7 +53,7 @@ pidfile /tmp/redis5.pid
logfile /tmp/redis5.log
save ""
appendonly no
slaveof localhost 6381
slaveof localhost 6379
endef
define REDIS6_CONF
@@ -62,7 +65,18 @@ pidfile /tmp/redis6.pid
logfile /tmp/redis6.log
save ""
appendonly no
slaveof localhost 6379
endef
define REDIS7_CONF
daemonize yes
port 6385
requirepass foobared
masterauth foobared
pidfile /tmp/redis7.pid
logfile /tmp/redis7.log
save ""
appendonly no
slaveof localhost 6384
endef
# SENTINELS
@@ -71,8 +85,8 @@ port 26379
daemonize yes
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 3000
sentinel failover-timeout mymaster 900000
sentinel down-after-milliseconds mymaster 2000
sentinel failover-timeout mymaster 120000
sentinel parallel-syncs mymaster 1
pidfile /tmp/sentinel1.pid
logfile /tmp/sentinel1.log
@@ -81,11 +95,11 @@ endef
define REDIS_SENTINEL2
port 26380
daemonize yes
sentinel monitor mymaster 127.0.0.1 6381 2
sentinel monitor mymaster 127.0.0.1 6381 1
sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 3000
sentinel down-after-milliseconds mymaster 2000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 900000
sentinel failover-timeout mymaster 120000
pidfile /tmp/sentinel2.pid
logfile /tmp/sentinel2.log
endef
@@ -93,11 +107,11 @@ endef
define REDIS_SENTINEL3
port 26381
daemonize yes
sentinel monitor mymaster 127.0.0.1 6381 2
sentinel auth-pass mymaster foobared
sentinel down-after-milliseconds mymaster 3000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 900000
sentinel monitor mymasterfailover 127.0.0.1 6384 1
sentinel auth-pass mymasterfailover foobared
sentinel down-after-milliseconds mymasterfailover 2000
sentinel failover-timeout mymasterfailover 120000
sentinel parallel-syncs mymasterfailover 1
pidfile /tmp/sentinel3.pid
logfile /tmp/sentinel3.log
endef
@@ -106,6 +120,7 @@ endef
define REDIS_CLUSTER_NODE1_CONF
daemonize yes
port 7379
cluster-node-timeout 50
pidfile /tmp/redis_cluster_node1.pid
logfile /tmp/redis_cluster_node1.log
save ""
@@ -117,6 +132,7 @@ endef
define REDIS_CLUSTER_NODE2_CONF
daemonize yes
port 7380
cluster-node-timeout 50
pidfile /tmp/redis_cluster_node2.pid
logfile /tmp/redis_cluster_node2.log
save ""
@@ -128,6 +144,7 @@ endef
define REDIS_CLUSTER_NODE3_CONF
daemonize yes
port 7381
cluster-node-timeout 50
pidfile /tmp/redis_cluster_node3.pid
logfile /tmp/redis_cluster_node3.log
save ""
@@ -136,18 +153,58 @@ cluster-enabled yes
cluster-config-file /tmp/redis_cluster_node3.conf
endef
define REDIS_CLUSTER_NODE4_CONF
daemonize yes
port 7382
cluster-node-timeout 50
pidfile /tmp/redis_cluster_node4.pid
logfile /tmp/redis_cluster_node4.log
save ""
appendonly no
cluster-enabled yes
cluster-config-file /tmp/redis_cluster_node4.conf
endef
define REDIS_CLUSTER_NODE5_CONF
daemonize yes
port 7383
cluster-node-timeout 5000
pidfile /tmp/redis_cluster_node5.pid
logfile /tmp/redis_cluster_node5.log
save ""
appendonly no
cluster-enabled yes
cluster-config-file /tmp/redis_cluster_node5.conf
endef
define REDIS_CLUSTER_NODE6_CONF
daemonize yes
port 7384
cluster-node-timeout 5000
pidfile /tmp/redis_cluster_node6.pid
logfile /tmp/redis_cluster_node6.log
save ""
appendonly no
cluster-enabled yes
cluster-config-file /tmp/redis_cluster_node6.conf
endef
export REDIS1_CONF
export REDIS2_CONF
export REDIS3_CONF
export REDIS4_CONF
export REDIS5_CONF
export REDIS6_CONF
export REDIS7_CONF
export REDIS_SENTINEL1
export REDIS_SENTINEL2
export REDIS_SENTINEL3
export REDIS_CLUSTER_NODE1_CONF
export REDIS_CLUSTER_NODE2_CONF
export REDIS_CLUSTER_NODE3_CONF
export REDIS_CLUSTER_NODE4_CONF
export REDIS_CLUSTER_NODE5_CONF
export REDIS_CLUSTER_NODE6_CONF
start: cleanup
echo "$$REDIS1_CONF" | redis-server -
@@ -156,6 +213,7 @@ start: cleanup
echo "$$REDIS4_CONF" | redis-server -
echo "$$REDIS5_CONF" | redis-server -
echo "$$REDIS6_CONF" | redis-server -
echo "$$REDIS7_CONF" | redis-server -
echo "$$REDIS_SENTINEL1" > /tmp/sentinel1.conf && redis-server /tmp/sentinel1.conf --sentinel
@sleep 0.5
echo "$$REDIS_SENTINEL2" > /tmp/sentinel2.conf && redis-server /tmp/sentinel2.conf --sentinel
@@ -164,27 +222,40 @@ start: cleanup
echo "$$REDIS_CLUSTER_NODE1_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE2_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE3_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE4_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE5_CONF" | redis-server -
echo "$$REDIS_CLUSTER_NODE6_CONF" | redis-server -
cleanup:
rm -vf /tmp/redis_cluster_node*.conf
- rm -vf /tmp/redis_cluster_node*.conf 2>/dev/null
- rm dump.rdb appendonly.aof - 2>/dev/null
stop:
kill `cat /tmp/redis1.pid`
kill `cat /tmp/redis2.pid`
# this get's segfaulted by the tests
kill `cat /tmp/redis3.pid` || true
kill `cat /tmp/redis4.pid` || true
kill `cat /tmp/redis5.pid` || true
kill `cat /tmp/redis6.pid` || true
kill `cat /tmp/redis3.pid`
kill `cat /tmp/redis4.pid`
kill `cat /tmp/redis5.pid`
kill `cat /tmp/redis6.pid`
kill `cat /tmp/redis7.pid`
kill `cat /tmp/sentinel1.pid`
kill `cat /tmp/sentinel2.pid`
kill `cat /tmp/sentinel3.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
kill `cat /tmp/redis_cluster_node4.pid` || true
kill `cat /tmp/redis_cluster_node5.pid` || true
kill `cat /tmp/redis_cluster_node6.pid` || true
rm -f /tmp/sentinel1.conf
rm -f /tmp/sentinel2.conf
rm -f /tmp/sentinel3.conf
rm -f /tmp/redis_cluster_node1.conf
rm -f /tmp/redis_cluster_node2.conf
rm -f /tmp/redis_cluster_node3.conf
rm -f /tmp/redis_cluster_node4.conf
rm -f /tmp/redis_cluster_node5.conf
rm -f /tmp/redis_cluster_node6.conf
test:
make start
@@ -192,6 +263,11 @@ test:
mvn -Dtest=${TEST} clean compile test
make stop
package:
make start
mvn clean package
make stop
deploy:
make start
mvn clean deploy
@@ -204,4 +280,8 @@ release:
mvn release:perform
make stop
travis-install:
[ ! -e redis-git ] && git clone https://github.com/antirez/redis.git redis-git || true
make -C redis-git -j4
.PHONY: test

View File

@@ -1,10 +1,12 @@
[![Build Status](https://travis-ci.org/xetorthio/jedis.png?branch=master)](https://travis-ci.org/xetorthio/jedis)
# Jedis
Jedis is a blazingly small and sane [Redis](http://github.com/antirez/redis "Redis") java client.
Jedis was conceived to be EASY to use.
Jedis is fully compatible with redis 2.6.14.
Jedis is fully compatible with redis 2.8.5.
## Community
@@ -38,7 +40,7 @@ All of the following redis features are supported:
## How do I use it?
You can download the latest build at:
http://github.com/xetorthio/jedis/downloads
http://github.com/xetorthio/jedis/releases
Or use it as a maven dependency:
@@ -46,7 +48,7 @@ Or use it as a maven dependency:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.2.1</version>
<version>2.4.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
@@ -73,8 +75,8 @@ Redis cluster [specification](http://redis.io/topics/cluster-spec) (still under
```java
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNode);
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar");
String value = jc.get("foo");
```

View File

@@ -3,7 +3,7 @@ apply plugin: 'maven'
apply plugin: 'eclipse'
group = 'com.googlecode.jedis'
archiveBaseName = 'jedis'
archivesBaseName = 'jedis'
version = '1.5.0'
repositories {

View File

@@ -9,7 +9,7 @@
<packaging>jar</packaging>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.2.2-SNAPSHOT</version>
<version>2.5.2-SNAPSHOT</version>
<name>Jedis</name>
<description>Jedis is a blazingly small and sane Redis java client.</description>
<url>https://github.com/xetorthio/jedis</url>
@@ -45,9 +45,9 @@
</scm>
<properties>
<redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384</redis-hosts>
<redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384,localhost:6385</redis-hosts>
<sentinel-hosts>localhost:26379,localhost:26380,localhost:26381</sentinel-hosts>
<cluster-hosts>localhost:7379,localhost:7380,localhost:7381</cluster-hosts>
<cluster-hosts>localhost:7379,localhost:7380,localhost:7381,localhost:7382,localhost:7383,localhost:7384,localhost:7385</cluster-hosts>
<github.global.server>github</github.global.server>
</properties>

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis;
import java.util.List;
public interface AdvancedBinaryJedisCommands {

View File

@@ -1,9 +1,8 @@
package redis.clients.jedis;
import redis.clients.util.Slowlog;
import java.util.List;
import redis.clients.util.Slowlog;
public interface AdvancedJedisCommands {
List<String> configGet(String pattern);

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis;
import java.util.List;
/**
* Pipelined responses for all of the low level, non key related commands
@@ -26,6 +27,8 @@ public interface BasicRedisPipeline {
Response<String> info();
Response<List<String>> time();
Response<Long> dbSize();
Response<String> shutdown();

View File

@@ -34,10 +34,16 @@ public class BinaryClient extends Connection {
private long db;
private boolean isInWatch;
public boolean isInMulti() {
return isInMulti;
}
public boolean isInWatch() {
return isInWatch;
}
public BinaryClient(final String host) {
super(host);
}
@@ -82,11 +88,11 @@ public class BinaryClient extends Connection {
sendCommand(Command.SET, key, value);
}
public void set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx, final long time) {
public void set(final byte[] key, final byte[] value, final byte[] nxxx,
final byte[] expx, final long time) {
sendCommand(Command.SET, key, value, nxxx, expx, toByteArray(time));
}
public void get(final byte[] key) {
sendCommand(Command.GET, key);
}
@@ -193,6 +199,10 @@ public class BinaryClient extends Connection {
sendCommand(INCRBY, key, toByteArray(integer));
}
public void incrByFloat(final byte[] key, final double value) {
sendCommand(INCRBYFLOAT, key, toByteArray(value));
}
public void incr(final byte[] key) {
sendCommand(INCR, key);
}
@@ -377,15 +387,16 @@ public class BinaryClient extends Connection {
sendCommand(ZADD, key, toByteArray(score), member);
}
public void zaddBinary(final byte[] key, Map<Double, byte[]> scoreMembers) {
public void zaddBinary(final byte[] key,
final Map<byte[], Double> scoreMembers) {
ArrayList<byte[]> args = new ArrayList<byte[]>(
scoreMembers.size() * 2 + 1);
args.add(key);
for (Map.Entry<Double, byte[]> entry : scoreMembers.entrySet()) {
args.add(toByteArray(entry.getKey()));
args.add(entry.getValue());
for (Map.Entry<byte[], Double> entry : scoreMembers.entrySet()) {
args.add(toByteArray(entry.getValue()));
args.add(entry.getKey());
}
byte[][] argsArray = new byte[args.size()][];
@@ -447,19 +458,23 @@ public class BinaryClient extends Connection {
public void discard() {
sendCommand(DISCARD);
isInMulti = false;
isInWatch = false;
}
public void exec() {
sendCommand(EXEC);
isInMulti = false;
isInWatch = false;
}
public void watch(final byte[]... keys) {
sendCommand(WATCH, keys);
isInWatch = true;
}
public void unwatch() {
sendCommand(UNWATCH);
isInWatch = false;
}
public void sort(final byte[] key) {
@@ -546,10 +561,15 @@ public class BinaryClient extends Connection {
sendCommand(PUNSUBSCRIBE, patterns);
}
public void pubsub(final byte[]... args) {
sendCommand(PUBSUB, args);
}
public void zcount(final byte[] key, final double min, final double max) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZCOUNT, key, byteArrayMin, byteArrayMax);
}
@@ -565,8 +585,10 @@ public class BinaryClient extends Connection {
public void zrangeByScore(final byte[] key, final double min,
final double max) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax);
}
@@ -584,8 +606,10 @@ public class BinaryClient extends Connection {
public void zrevrangeByScore(final byte[] key, final double max,
final double min) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZREVRANGEBYSCORE, key, byteArrayMax, byteArrayMin);
}
@@ -603,11 +627,13 @@ public class BinaryClient extends Connection {
public void zrangeByScore(final byte[] key, final double min,
final double max, final int offset, int count) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax,
LIMIT.raw, toByteArray(offset), toByteArray(count));
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax, LIMIT.raw,
toByteArray(offset), toByteArray(count));
}
public void zrangeByScore(final byte[] key, final String min,
@@ -620,8 +646,10 @@ public class BinaryClient extends Connection {
public void zrevrangeByScore(final byte[] key, final double max,
final double min, final int offset, int count) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZREVRANGEBYSCORE, key, byteArrayMax, byteArrayMin,
LIMIT.raw, toByteArray(offset), toByteArray(count));
@@ -637,8 +665,10 @@ public class BinaryClient extends Connection {
public void zrangeByScoreWithScores(final byte[] key, final double min,
final double max) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax,
WITHSCORES.raw);
@@ -654,8 +684,10 @@ public class BinaryClient extends Connection {
public void zrevrangeByScoreWithScores(final byte[] key, final double max,
final double min) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZREVRANGEBYSCORE, key, byteArrayMax, byteArrayMin,
WITHSCORES.raw);
@@ -670,12 +702,13 @@ public class BinaryClient extends Connection {
public void zrangeByScoreWithScores(final byte[] key, final double min,
final double max, final int offset, final int count) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax,
LIMIT.raw, toByteArray(offset), toByteArray(count),
WITHSCORES.raw);
sendCommand(ZRANGEBYSCORE, key, byteArrayMin, byteArrayMax, LIMIT.raw,
toByteArray(offset), toByteArray(count), WITHSCORES.raw);
}
public void zrangeByScoreWithScores(final byte[] key, final String min,
@@ -688,8 +721,10 @@ public class BinaryClient extends Connection {
public void zrevrangeByScoreWithScores(final byte[] key, final double max,
final double min, final int offset, final int count) {
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf".getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf".getBytes() : toByteArray(max);
byte byteArrayMin[] = (min == Double.NEGATIVE_INFINITY) ? "-inf"
.getBytes() : toByteArray(min);
byte byteArrayMax[] = (max == Double.POSITIVE_INFINITY) ? "+inf"
.getBytes() : toByteArray(max);
sendCommand(ZREVRANGEBYSCORE, key, byteArrayMax, byteArrayMin,
LIMIT.raw, toByteArray(offset), toByteArray(count),
@@ -895,6 +930,14 @@ public class BinaryClient extends Connection {
sendCommand(GETBIT, key, toByteArray(offset));
}
public void bitpos(final byte[] key, final boolean value, final BitPosParams params) {
final List<byte[]> args = new ArrayList<byte[]>();
args.add(key);
args.add(toByteArray(value));
args.addAll(params.getParams());
sendCommand(BITPOS, args.toArray(new byte[args.size()][]));
}
public void setrange(byte[] key, long offset, byte[] value) {
sendCommand(SETRANGE, key, toByteArray(offset), value);
}
@@ -913,6 +956,17 @@ public class BinaryClient extends Connection {
super.disconnect();
}
@Override
public void close() {
db = 0;
super.close();
}
public void resetState() {
if (isInWatch())
unwatch();
}
private void sendEvalCommand(Command command, byte[] script,
byte[] keyCount, byte[][] params) {
@@ -1037,11 +1091,17 @@ public class BinaryClient extends Connection {
sendCommand(DUMP, key);
}
public void restore(final byte[] key, final int ttl, final byte[] serializedValue) {
public void restore(final byte[] key, final int ttl,
final byte[] serializedValue) {
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));
}
@@ -1053,11 +1113,8 @@ public class BinaryClient extends Connection {
sendCommand(PTTL, key);
}
public void incrByFloat(final byte[] key, final double increment) {
sendCommand(INCRBYFLOAT, key, toByteArray(increment));
}
public void psetex(final byte[] key, final int milliseconds, final byte[] value) {
public void psetex(final byte[] key, final int milliseconds,
final byte[] value) {
sendCommand(PSETEX, key, toByteArray(milliseconds), value);
}
@@ -1065,7 +1122,8 @@ public class BinaryClient extends Connection {
sendCommand(Command.SET, key, value, nxxx);
}
public void set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx, final int time) {
public void set(final byte[] key, final byte[] value, final byte[] nxxx,
final byte[] expx, final int time) {
sendCommand(Command.SET, key, value, nxxx, expx, toByteArray(time));
}
@@ -1093,14 +1151,23 @@ public class BinaryClient extends Connection {
sendCommand(TIME);
}
public void migrate(final byte[] host, final int port, final byte[] key, final int destinationDb, final int timeout) {
sendCommand(MIGRATE, host, toByteArray(port), key, toByteArray(destinationDb), toByteArray(timeout));
public void migrate(final byte[] host, final int port, final byte[] key,
final int destinationDb, final int timeout) {
sendCommand(MIGRATE, host, toByteArray(port), key,
toByteArray(destinationDb), toByteArray(timeout));
}
public void hincrByFloat(final byte[] key, final byte[] field, double increment) {
public void hincrByFloat(final byte[] key, final byte[] field,
double increment) {
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<byte[]> args = new ArrayList<byte[]>();
args.add(toByteArray(cursor));
@@ -1108,6 +1175,12 @@ public class BinaryClient extends Connection {
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<byte[]> args = new ArrayList<byte[]>();
args.add(key);
@@ -1116,6 +1189,12 @@ public class BinaryClient extends Connection {
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<byte[]> args = new ArrayList<byte[]>();
args.add(key);
@@ -1124,6 +1203,12 @@ public class BinaryClient extends Connection {
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<byte[]> args = new ArrayList<byte[]>();
args.add(key);
@@ -1132,6 +1217,37 @@ public class BinaryClient extends Connection {
sendCommand(ZSCAN, args.toArray(new byte[args.size()][]));
}
public void scan(final byte[] cursor, final ScanParams params) {
final List<byte[]> args = new ArrayList<byte[]>();
args.add(cursor);
args.addAll(params.getParams());
sendCommand(SCAN, args.toArray(new byte[args.size()][]));
}
public void hscan(final byte[] key, final byte[] cursor, final ScanParams params) {
final List<byte[]> args = new ArrayList<byte[]>();
args.add(key);
args.add(cursor);
args.addAll(params.getParams());
sendCommand(HSCAN, args.toArray(new byte[args.size()][]));
}
public void sscan(final byte[] key, final byte[] cursor, final ScanParams params) {
final List<byte[]> args = new ArrayList<byte[]>();
args.add(key);
args.add(cursor);
args.addAll(params.getParams());
sendCommand(SSCAN, args.toArray(new byte[args.size()][]));
}
public void zscan(final byte[] key, final byte[] cursor, final ScanParams params) {
final List<byte[]> args = new ArrayList<byte[]>();
args.add(key);
args.add(cursor);
args.addAll(params.getParams());
sendCommand(ZSCAN, args.toArray(new byte[args.size()][]));
}
public void waitReplicas(int replicas, long timeout) {
sendCommand(WAIT, toByteArray(replicas), toByteArray(timeout));
}
@@ -1139,7 +1255,24 @@ public class BinaryClient extends Connection {
public void cluster(final byte[]... args) {
sendCommand(CLUSTER, args);
}
public void asking() {
sendCommand(Command.ASKING);
}
public void pfadd(final byte[] key, final byte[]... elements) {
sendCommand(PFADD, joinParameters(key, elements));
}
public void pfcount(final byte[] key) {
sendCommand(PFCOUNT, key);
}
public void pfcount(final byte[]...keys) {
sendCommand(PFCOUNT, keys);
}
public void pfmerge(final byte[] destkey, final byte[]... sourcekeys) {
sendCommand(PFMERGE, joinParameters(destkey, sourcekeys));
}
}

View File

@@ -1,18 +1,31 @@
package redis.clients.jedis;
import static redis.clients.jedis.Protocol.toByteArray;
import java.io.Closeable;
import java.net.URI;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.SafeEncoder;
import java.net.URI;
import java.util.*;
public class BinaryJedis implements BasicCommands, BinaryJedisCommands,
MultiKeyBinaryCommands, AdvancedBinaryJedisCommands,
BinaryScriptingCommands, Closeable {
import static redis.clients.jedis.Protocol.toByteArray;
public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKeyBinaryCommands, AdvancedBinaryJedisCommands, BinaryScriptingCommands {
protected Client client = null;
protected Transaction transaction = null;
protected Pipeline pipeline = null;
public BinaryJedis(final String host) {
URI uri = URI.create(host);
@@ -75,15 +88,20 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
/**
* Set the string value as value of the key. The string can't be longer than
* 1073741824 bytes (1 GB).
*
* @param key
* @param value
* @param nxxx NX|XX, NX -- Only set the key if it does not already exist.
* XX -- Only set the key if it already exist.
* @param expx EX|PX, expire time units: EX = seconds; PX = milliseconds
* @param time expire time in the units of {@param #expx}
* @param nxxx
* NX|XX, NX -- Only set the key if it does not already exist. XX
* -- Only set the key if it already exist.
* @param expx
* EX|PX, expire time units: EX = seconds; PX = milliseconds
* @param time
* expire time in the units of {@param #expx}
* @return Status code reply
*/
public String set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx, final long time) {
public String set(final byte[] key, final byte[] value, final byte[] nxxx,
final byte[] expx, final long time) {
checkIsInMulti();
client.set(key, value, nxxx, expx, time);
return client.getStatusCodeReply();
@@ -619,6 +637,37 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply();
}
/**
* INCRBYFLOAT work just like {@link #incrBy(byte[]) INCRBY} but increments
* by floats instead of integers.
* <p>
* INCRBYFLOAT commands are limited to double precision floating point
* values.
* <p>
* 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
* negative value will work as expected.
* <p>
* Time complexity: O(1)
*
* @see #incr(byte[])
* @see #decr(byte[])
* @see #decrBy(byte[], long)
*
* @param key
* @param integer
* @return Integer reply, this commands will reply with the new value of key
* after the increment.
*/
public Double incrByFloat(final byte[] key, final double integer) {
checkIsInMulti();
client.incrByFloat(key, integer);
String dval = client.getBulkReply();
return (dval != null ? new Double(dval) : null);
}
/**
* Increment the number stored at key by one. If the key does not exist or
* contains a value of a wrong type, set the key to the value of "0" before
@@ -811,6 +860,33 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply();
}
/**
* 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.
* <p>
* The range of values supported by HINCRBYFLOAT is limited to double
* precision floating point values.
* <p>
* <b>Time complexity:</b> O(1)
*
* @param key
* @param field
* @param value
* @return Double precision floating point reply The new value at field
* after the increment operation.
*/
public Double hincrByFloat(final byte[] key, final byte[] field,
final double value) {
checkIsInMulti();
client.hincrByFloat(key, field, value);
final String dval = client.getBulkReply();
return (dval != null ? new Double(dval) : null);
}
/**
* Test for existence of a specified field in a hash.
*
@@ -1006,7 +1082,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
* @return Multi bulk reply, specifically a list of elements in the
* specified range.
*/
public List<byte[]> lrange(final byte[] key, final long start, final long end) {
public List<byte[]> lrange(final byte[] key, final long start,
final long end) {
checkIsInMulti();
client.lrange(key, start, end);
return client.getBinaryMultiBulkReply();
@@ -1502,7 +1579,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply();
}
public Long zadd(final byte[] key, final Map<Double, byte[]> scoreMembers) {
public Long zadd(final byte[] key, final Map<byte[], Double> scoreMembers) {
checkIsInMulti();
client.zaddBinary(key, scoreMembers);
return client.getIntegerReply();
@@ -1680,20 +1757,24 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
public Transaction multi() {
client.multi();
client.getOne(); // expected OK
return new Transaction(client);
transaction = new Transaction(client);
return transaction;
}
@Deprecated
/**
* This method is deprecated due to its error prone
* and will be removed on next major release
* You can use multi() instead
* @see https://github.com/xetorthio/jedis/pull/498
*/
public List<Object> multi(final TransactionBlock jedisTransaction) {
List<Object> results = null;
jedisTransaction.setClient(client);
try {
client.multi();
client.getOne(); // expected OK
jedisTransaction.execute();
results = jedisTransaction.exec();
} catch (Exception ex) {
jedisTransaction.discard();
}
return results;
}
@@ -1712,6 +1793,27 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
client.disconnect();
}
public void resetState() {
if (client.isConnected()) {
if (transaction != null) {
transaction.clear();
}
if (pipeline != null) {
pipeline.clear();
}
if (client.isInWatch()) {
unwatch();
}
client.resetState();
}
transaction = null;
pipeline = null;
}
public String watch(final byte[]... keys) {
client.watch(keys);
return client.getStatusCodeReply();
@@ -1722,6 +1824,11 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getStatusCodeReply();
}
@Override
public void close() {
client.close();
}
/**
* Sort a Set or a List.
* <p>
@@ -2106,14 +2213,12 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getStatusCodeReply();
}
@Deprecated
/**
* Starts a pipeline, which is a very efficient way to send lots of command
* and read all the responses when you finish sending them. Try to avoid
* this version and use pipelined() when possible as it will give better
* performance.
*
* @param jedisPipeline
* @return The results of the command in the same order you've run them.
* This method is deprecated due to its error prone with multi
* and will be removed on next major release
* You can use pipelined() instead
* @see https://github.com/xetorthio/jedis/pull/498
*/
public List<Object> pipelined(final PipelineBlock jedisPipeline) {
jedisPipeline.setClient(client);
@@ -2122,7 +2227,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
}
public Pipeline pipelined() {
Pipeline pipeline = new Pipeline();
pipeline = new Pipeline();
pipeline.setClient(client);
return pipeline;
}
@@ -2263,7 +2368,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
*/
public Set<byte[]> zrangeByScore(final byte[] key, final double min,
final double max, final int offset, final int count) {
return zrangeByScore(key, toByteArray(min),toByteArray(max),offset, count);
return zrangeByScore(key, toByteArray(min), toByteArray(max), offset,
count);
}
public Set<byte[]> zrangeByScore(final byte[] key, final byte[] min,
@@ -2401,7 +2507,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
public Set<Tuple> zrangeByScoreWithScores(final byte[] key,
final double min, final double max, final int offset,
final int count) {
return zrangeByScoreWithScores(key, toByteArray(min), toByteArray(max), offset, count);
return zrangeByScoreWithScores(key, toByteArray(min), toByteArray(max),
offset, count);
}
public Set<Tuple> zrangeByScoreWithScores(final byte[] key,
@@ -2439,7 +2546,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
public Set<byte[]> zrevrangeByScore(final byte[] key, final double max,
final double min, final int offset, final int count) {
return zrevrangeByScore(key, toByteArray(max), toByteArray(min), offset, count);
return zrevrangeByScore(key, toByteArray(max), toByteArray(min),
offset, count);
}
public Set<byte[]> zrevrangeByScore(final byte[] key, final byte[] max,
@@ -2451,13 +2559,15 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key,
final double max, final double min) {
return zrevrangeByScoreWithScores(key, toByteArray(max), toByteArray(min));
return zrevrangeByScoreWithScores(key, toByteArray(max),
toByteArray(min));
}
public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key,
final double max, final double min, final int offset,
final int count) {
return zrevrangeByScoreWithScores(key, toByteArray(max), toByteArray(min), offset, count);
return zrevrangeByScoreWithScores(key, toByteArray(max),
toByteArray(min), offset, count);
}
public Set<Tuple> zrevrangeByScoreWithScores(final byte[] key,
@@ -2490,7 +2600,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
* operation
*
*/
public Long zremrangeByRank(final byte[] key, final long start, final long end) {
public Long zremrangeByRank(final byte[] key, final long start,
final long end) {
checkIsInMulti();
client.zremrangeByRank(key, start, end);
return client.getIntegerReply();
@@ -3096,6 +3207,16 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply() == 1;
}
public Long bitpos(final byte[] key, final boolean value) {
return bitpos(key, value, new BitPosParams());
}
public Long bitpos(final byte[] key, final boolean value,
final BitPosParams params) {
client.bitpos(key, value, params);
return client.getIntegerReply();
}
public Long setrange(byte[] key, long offset, byte[] value) {
client.setrange(key, offset, value);
return client.getIntegerReply();
@@ -3142,12 +3263,13 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
private byte[][] getParams(List<byte[]> keys, List<byte[]> args) {
int keyCount = keys.size();
int argCount = args.size();
byte[][] params = new byte[keyCount + args.size()][];
for (int i = 0; i < keyCount; i++)
params[i] = keys.get(i);
for (int i = 0; i < keys.size(); i++)
for (int i = 0; i < argCount; i++)
params[keyCount + i] = args.get(i);
return params;
@@ -3161,7 +3283,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
public Object eval(byte[] script, int keyCount, byte[]... params) {
client.setTimeoutInfinite();
client.eval(script, SafeEncoder.encode(Integer.toString(keyCount)), params);
client.eval(script, SafeEncoder.encode(Integer.toString(keyCount)),
params);
return client.getOne();
}
@@ -3190,7 +3313,6 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
for (int i = 0; i < argCount; i++)
params[keyCount + i] = args.get(i);
return evalsha(sha1, keyCount, params);
}
@@ -3276,13 +3398,19 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getBinaryBulkReply();
}
public String restore(final byte[] key, final int ttl, final byte[] serializedValue) {
public String restore(final byte[] key, final int ttl,
final byte[] serializedValue) {
checkIsInMulti();
client.restore(key, ttl, serializedValue);
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);
return client.getIntegerReply();
@@ -3300,14 +3428,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply();
}
public Double incrByFloat(final byte[] key, final double increment) {
checkIsInMulti();
client.incrByFloat(key, increment);
String relpy = client.getBulkReply();
return (relpy != null ? new Double(relpy) : null);
}
public String psetex(final byte[] key, final int milliseconds, final byte[] value) {
public String psetex(final byte[] key, final int milliseconds,
final byte[] value) {
checkIsInMulti();
client.psetex(key, milliseconds, value);
return client.getStatusCodeReply();
@@ -3319,7 +3441,8 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getStatusCodeReply();
}
public String set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx, final int time) {
public String set(final byte[] key, final byte[] value, final byte[] nxxx,
final byte[] expx, final int time) {
checkIsInMulti();
client.set(key, value, nxxx, expx, time);
return client.getStatusCodeReply();
@@ -3355,19 +3478,13 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getMultiBulkReply();
}
public String migrate(final byte[] host, final int port, final byte[] key, final int destinationDb, final int timeout) {
public String migrate(final byte[] host, final int port, final byte[] key,
final int destinationDb, final int timeout) {
checkIsInMulti();
client.migrate(host, port, key, destinationDb, timeout);
return client.getStatusCodeReply();
}
public Double hincrByFloat(final byte[] key, final byte[] field, double increment) {
checkIsInMulti();
client.hincrByFloat(key, field, increment);
String relpy = client.getBulkReply();
return (relpy != null ? new Double(relpy) : null);
}
/**
* Syncrhonous replication of Redis as described here:
* http://antirez.com/news/66
@@ -3381,4 +3498,99 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKey
return client.getIntegerReply();
}
@Override
public Long pfadd(final byte[] key, final byte[]... elements) {
checkIsInMulti();
client.pfadd(key, elements);
return client.getIntegerReply();
}
@Override
public long pfcount(final byte[] key) {
checkIsInMulti();
client.pfcount(key);
return client.getIntegerReply();
}
@Override
public String pfmerge(final byte[] destkey, final byte[]... sourcekeys) {
checkIsInMulti();
client.pfmerge(destkey, sourcekeys);
return client.getStatusCodeReply();
}
@Override
public Long pfcount(byte[]... keys) {
checkIsInMulti();
client.pfcount(keys);
return client.getIntegerReply();
}
public ScanResult<byte[]> scan(final byte[] cursor) {
return scan(cursor, new ScanParams());
}
public ScanResult<byte[]> scan(final byte[] cursor, final ScanParams params) {
checkIsInMulti();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
return new ScanResult<byte[]>(newcursor, rawResults);
}
public ScanResult<Map.Entry<byte[], byte[]>> hscan(final byte[] key,
final byte[] cursor) {
return hscan(key, cursor, new ScanParams());
}
public ScanResult<Map.Entry<byte[], byte[]>> hscan(final byte[] key,
final byte[] cursor, final ScanParams params) {
checkIsInMulti();
client.hscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<Map.Entry<byte[], byte[]>> results = new ArrayList<Map.Entry<byte[], byte[]>>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while (iterator.hasNext()) {
results.add(new AbstractMap.SimpleEntry<byte[], byte[]>(iterator
.next(), iterator.next()));
}
return new ScanResult<Map.Entry<byte[], byte[]>>(newcursor, results);
}
public ScanResult<byte[]> sscan(final byte[] key, final byte[] cursor) {
return sscan(key, cursor, new ScanParams());
}
public ScanResult<byte[]> sscan(final byte[] key, final byte[] cursor,
final ScanParams params) {
checkIsInMulti();
client.sscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
return new ScanResult<byte[]>(newcursor, rawResults);
}
public ScanResult<Tuple> zscan(final byte[] key, final byte[] cursor) {
return zscan(key, cursor, new ScanParams());
}
public ScanResult<Tuple> zscan(final byte[] key, final byte[] cursor,
final ScanParams params) {
checkIsInMulti();
client.zscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
byte[] newcursor = (byte[]) result.get(0);
List<Tuple> results = new ArrayList<Tuple>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while (iterator.hasNext()) {
results.add(new Tuple(iterator.next(), Double.valueOf(SafeEncoder
.encode(iterator.next()))));
}
return new ScanResult<Tuple>(newcursor, results);
}
}

View File

@@ -47,6 +47,8 @@ public interface BinaryJedisCommands {
Long incrBy(byte[] key, long integer);
Double incrByFloat(byte[] key, double value);
Long incr(byte[] key);
Long append(byte[] key, byte[] value);
@@ -65,6 +67,8 @@ public interface BinaryJedisCommands {
Long hincrBy(byte[] key, byte[] field, long value);
Double hincrByFloat(byte[] key, byte[] field, double value);
Boolean hexists(byte[] key, byte[] field);
Long hdel(byte[] key, byte[]... field);
@@ -115,7 +119,7 @@ public interface BinaryJedisCommands {
Long zadd(byte[] key, double score, byte[] member);
Long zadd(byte[] key, Map<Double, byte[]> scoreMembers);
Long zadd(byte[] key, Map<byte[], Double> scoreMembers);
Set<byte[]> zrange(byte[] key, long start, long end);
@@ -211,4 +215,8 @@ public interface BinaryJedisCommands {
Long bitcount(final byte[] key);
Long bitcount(final byte[] key, long start, long end);
Long pfadd(final byte[] key, final byte[]... elements);
long pfcount(final byte[] key);
}

View File

@@ -117,8 +117,7 @@ public interface BinaryRedisPipeline {
Response<List<byte[]>> sort(byte[] key);
Response<List<byte[]>> sort(byte[] key,
SortingParams sortingParameters);
Response<List<byte[]>> sort(byte[] key, SortingParams sortingParameters);
Response<byte[]> spop(byte[] key);
@@ -144,17 +143,15 @@ public interface BinaryRedisPipeline {
Response<Set<byte[]>> zrange(byte[] key, long start, long end);
Response<Set<byte[]>> zrangeByScore(byte[] key, double min,
double max);
Response<Set<byte[]>> zrangeByScore(byte[] key, double min, double max);
Response<Set<byte[]>> zrangeByScore(byte[] key, byte[] min,
byte[] max);
Response<Set<byte[]>> zrangeByScore(byte[] key, byte[] min, byte[] max);
Response<Set<byte[]>> zrangeByScore(byte[] key, double min,
double max, int offset, int count);
Response<Set<byte[]>> zrangeByScore(byte[] key, double min, double max,
int offset, int count);
Response<Set<byte[]>> zrangeByScore(byte[] key, byte[] min,
byte[] max, int offset, int count);
Response<Set<byte[]>> zrangeByScore(byte[] key, byte[] min, byte[] max,
int offset, int count);
Response<Set<Tuple>> zrangeByScoreWithScores(byte[] key, double min,
double max);
@@ -168,30 +165,28 @@ public interface BinaryRedisPipeline {
Response<Set<Tuple>> zrangeByScoreWithScores(byte[] key, byte[] min,
byte[] max, int offset, int count);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max,
Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max, double min);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, byte[] max, byte[] min);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max, double min,
int offset, int count);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, byte[] max, byte[] min,
int offset, int count);
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key, double max,
double min);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, byte[] max,
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key, byte[] max,
byte[] min);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max,
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key, double max,
double min, int offset, int count);
Response<Set<byte[]>> zrevrangeByScore(byte[] key, byte[] max,
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key, byte[] max,
byte[] min, int offset, int count);
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
double max, double min);
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
byte[] max, byte[] min);
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
double max, double min, int offset, int count);
Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
byte[] max, byte[] min, int offset, int count);
Response<Set<Tuple>> zrangeWithScores(byte[] key, long start, long end);
Response<Long> zrank(byte[] key, byte[] member);
@@ -206,8 +201,7 @@ public interface BinaryRedisPipeline {
Response<Set<byte[]>> zrevrange(byte[] key, long start, long end);
Response<Set<Tuple>> zrevrangeWithScores(byte[] key, long start,
long end);
Response<Set<Tuple>> zrevrangeWithScores(byte[] key, long start, long end);
Response<Long> zrevrank(byte[] key, byte[] member);
@@ -216,4 +210,8 @@ public interface BinaryRedisPipeline {
Response<Long> bitcount(byte[] key);
Response<Long> bitcount(byte[] key, long start, long end);
Response<Long> pfadd(final byte[] key, final byte[]... elements);
Response<Long> pfcount(final byte[] key);
}

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis;
import java.util.List;
public interface BinaryScriptingCommands {

View File

@@ -110,6 +110,11 @@ public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo>
return j.incrBy(key, integer);
}
public Double incrByFloat(byte[] key, double integer) {
Jedis j = getShard(key);
return j.incrByFloat(key, integer);
}
public Long incr(byte[] key) {
Jedis j = getShard(key);
return j.incr(key);
@@ -155,6 +160,11 @@ public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo>
return j.hincrBy(key, field, value);
}
public Double hincrByFloat(byte[] key, byte[] field, double value) {
Jedis j = getShard(key);
return j.hincrByFloat(key, field, value);
}
public Boolean hexists(byte[] key, byte[] field) {
Jedis j = getShard(key);
return j.hexists(key, field);
@@ -295,7 +305,7 @@ public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo>
return j.zadd(key, score, member);
}
public Long zadd(byte[] key, Map<Double, byte[]> scoreMembers) {
public Long zadd(byte[] key, Map<byte[], Double> scoreMembers) {
Jedis j = getShard(key);
return j.zadd(key, scoreMembers);
}
@@ -482,6 +492,12 @@ public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo>
}
@Deprecated
/**
* This method is deprecated due to its error prone with multi
* and will be removed on next major release
* You can use pipelined() instead
* @see https://github.com/xetorthio/jedis/pull/498
*/
public List<Object> pipelined(ShardedJedisPipeline shardedJedisPipeline) {
shardedJedisPipeline.setShardedJedis(this);
shardedJedisPipeline.execute();
@@ -563,4 +579,17 @@ public class BinaryShardedJedis extends Sharded<Jedis, JedisShardInfo>
Jedis j = getShard(key);
return j.bitcount(key, start, end);
}
@Override
public Long pfadd(final byte[] key, final byte[]... elements) {
Jedis j = getShard(key);
return j.pfadd(key, elements);
}
@Override
public long pfcount(final byte[] key) {
Jedis j = getShard(key);
return j.pfcount(key);
}
}

View File

@@ -1,8 +1,5 @@
package redis.clients.jedis;
public enum BitOP {
AND,
OR,
XOR,
NOT;
AND, OR, XOR, NOT;
}

View File

@@ -0,0 +1,27 @@
package redis.clients.jedis;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class BitPosParams {
private List<byte[]> params = new ArrayList<byte[]>();
protected BitPosParams() {
}
public BitPosParams(long start) {
params.add(Protocol.toByteArray(start));
}
public BitPosParams(long start, long end) {
this(start);
params.add(Protocol.toByteArray(end));
}
public Collection<byte[]> getParams() {
return Collections.unmodifiableCollection(params);
}
}

View File

@@ -1,8 +1,15 @@
package redis.clients.jedis;
import redis.clients.util.SafeEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import redis.clients.util.SafeEncoder;
public class BuilderFactory {
public static final Builder<Double> DOUBLE = new Builder<Double>() {
@@ -84,8 +91,8 @@ public class BuilderFactory {
final Map<String, String> hash = new HashMap<String, String>();
final Iterator<byte[]> iterator = flatHash.iterator();
while (iterator.hasNext()) {
hash.put(SafeEncoder.encode(iterator.next()), SafeEncoder
.encode(iterator.next()));
hash.put(SafeEncoder.encode(iterator.next()),
SafeEncoder.encode(iterator.next()));
}
return hash;
@@ -96,6 +103,7 @@ public class BuilderFactory {
}
};
public static final Builder<Set<String>> STRING_SET = new Builder<Set<String>>() {
@SuppressWarnings("unchecked")
public Set<String> build(Object data) {

View File

@@ -1,6 +1,6 @@
package redis.clients.jedis;
import redis.clients.util.SafeEncoder;
import static redis.clients.jedis.Protocol.toByteArray;
import java.util.ArrayList;
import java.util.HashMap;
@@ -8,8 +8,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static redis.clients.jedis.Protocol.toByteArray;
import static redis.clients.jedis.Protocol.Command.HSCAN;
import redis.clients.util.SafeEncoder;
public class Client extends BinaryClient implements Commands {
public Client(final String host) {
@@ -24,8 +23,10 @@ public class Client extends BinaryClient implements Commands {
set(SafeEncoder.encode(key), SafeEncoder.encode(value));
}
public void set(final String key, final String value, final String nxxx, final String expx, final long time) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value), SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
public void set(final String key, final String value, final String nxxx,
final String expx, final long time) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value),
SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
}
public void get(final String key) {
@@ -628,6 +629,9 @@ public class Client extends BinaryClient implements Commands {
getbit(SafeEncoder.encode(key), offset);
}
public void bitpos(final String key, final boolean value, final BitPosParams params) {
bitpos(SafeEncoder.encode(key), value, params);
}
public void setrange(String key, long offset, String value) {
setrange(SafeEncoder.encode(key), offset, SafeEncoder.encode(value));
}
@@ -672,6 +676,18 @@ public class Client extends BinaryClient implements Commands {
subscribe(cs);
}
public void pubsubChannels(String pattern) {
pubsub(Protocol.PUBSUB_CHANNELS, pattern);
}
public void pubsubNumPat() {
pubsub(Protocol.PUBSUB_NUM_PAT);
}
public void pubsubNumSub(String... channels) {
pubsub(Protocol.PUBSUB_NUMSUB, channels);
}
public void configSet(String parameter, String value) {
configSet(SafeEncoder.encode(parameter), SafeEncoder.encode(value));
}
@@ -710,12 +726,14 @@ public class Client extends BinaryClient implements Commands {
scriptLoad(SafeEncoder.encode(script));
}
public void zadd(String key, Map<Double, String> scoreMembers) {
HashMap<Double, byte[]> binaryScoreMembers = new HashMap<Double, byte[]>();
public void zadd(String key, Map<String, Double> scoreMembers) {
for (Map.Entry<Double, String> entry : scoreMembers.entrySet()) {
binaryScoreMembers.put(entry.getKey(),
SafeEncoder.encode(entry.getValue()));
HashMap<byte[], Double> binaryScoreMembers = new HashMap<byte[], Double>();
for (Map.Entry<String, Double> entry : scoreMembers.entrySet()) {
binaryScoreMembers.put(SafeEncoder.encode(entry.getKey()),
entry.getValue());
}
zaddBinary(SafeEncoder.encode(key), binaryScoreMembers);
@@ -757,11 +775,17 @@ public class Client extends BinaryClient implements Commands {
dump(SafeEncoder.encode(key));
}
public void restore(final String key, final int ttl, final byte[] serializedValue) {
public void restore(final String key, final int ttl,
final byte[] serializedValue) {
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);
}
@@ -777,16 +801,20 @@ public class Client extends BinaryClient implements Commands {
incrByFloat(SafeEncoder.encode(key), increment);
}
public void psetex(final String key, final int milliseconds, final String value) {
public void psetex(final String key, final int milliseconds,
final String value) {
psetex(SafeEncoder.encode(key), milliseconds, SafeEncoder.encode(value));
}
public void set(final String key, final String value, final String nxxx) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value), SafeEncoder.encode(nxxx));
set(SafeEncoder.encode(key), SafeEncoder.encode(value),
SafeEncoder.encode(nxxx));
}
public void set(final String key, final String value, final String nxxx, final String expx, final int time) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value), SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
public void set(final String key, final String value, final String nxxx,
final String expx, final int time) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value),
SafeEncoder.encode(nxxx), SafeEncoder.encode(expx), time);
}
public void srandmember(final String key, final int count) {
@@ -801,41 +829,88 @@ public class Client extends BinaryClient implements Commands {
clientSetname(SafeEncoder.encode(name));
}
public void migrate(final String host, final int port, final String key, final int destinationDb, final int timeout) {
migrate(SafeEncoder.encode(host), port, SafeEncoder.encode(key), destinationDb, timeout);
public void migrate(final String host, final int port, final String key,
final int destinationDb, final int timeout) {
migrate(SafeEncoder.encode(host), port, SafeEncoder.encode(key),
destinationDb, timeout);
}
public void hincrByFloat(final String key, final String field, double increment) {
hincrByFloat(SafeEncoder.encode(key), SafeEncoder.encode(field), increment);
public void hincrByFloat(final String key, final String field,
double increment) {
hincrByFloat(SafeEncoder.encode(key), SafeEncoder.encode(field),
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);
}
public void hscan(final String key, final String cursor, final ScanParams params) {
hscan(SafeEncoder.encode(key), SafeEncoder.encode(cursor), params);
}
public void sscan(final String key, final String cursor, final ScanParams params) {
sscan(SafeEncoder.encode(key), SafeEncoder.encode(cursor), params);
}
public void zscan(final String key, final String cursor, final ScanParams params) {
zscan(SafeEncoder.encode(key), SafeEncoder.encode(cursor), params);
}
public void cluster(final String subcommand, final int... args) {
final byte[][] arg = new byte[args.length+1][];
final byte[][] arg = new byte[args.length + 1][];
for (int i = 1; i < arg.length; i++) {
arg[i] = toByteArray(args[i-1]);
arg[i] = toByteArray(args[i - 1]);
}
arg[0] = SafeEncoder.encode(subcommand);
cluster(arg);
}
public void cluster(final String subcommand, final String... args) {
public void pubsub(final String subcommand, final String... args) {
final byte[][] arg = new byte[args.length+1][];
for (int i = 1; i < arg.length; i++) {
arg[i] = SafeEncoder.encode(args[i-1]);
}
arg[0] = SafeEncoder.encode(subcommand);
pubsub(arg);
}
public void cluster(final String subcommand, final String... args) {
final byte[][] arg = new byte[args.length + 1][];
for (int i = 1; i < arg.length; i++) {
arg[i] = SafeEncoder.encode(args[i - 1]);
}
arg[0] = SafeEncoder.encode(subcommand);
cluster(arg);
}
@@ -853,11 +928,11 @@ public class Client extends BinaryClient implements Commands {
cluster(Protocol.CLUSTER_MEET, ip, String.valueOf(port));
}
public void clusterAddSlots(final int ...slots) {
public void clusterAddSlots(final int... slots) {
cluster(Protocol.CLUSTER_ADDSLOTS, slots);
}
public void clusterDelSlots(final int ...slots) {
public void clusterDelSlots(final int... slots) {
cluster(Protocol.CLUSTER_DELSLOTS, slots);
}
@@ -866,19 +941,74 @@ public class Client extends BinaryClient implements Commands {
}
public void clusterGetKeysInSlot(final int slot, final int count) {
final int[] args = new int[]{ slot, count };
final int[] args = new int[] { slot, count };
cluster(Protocol.CLUSTER_GETKEYSINSLOT, args);
}
public void clusterSetSlotNode(final int slot, final String nodeId) {
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot), Protocol.CLUSTER_SETSLOT_NODE, nodeId);
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot),
Protocol.CLUSTER_SETSLOT_NODE, nodeId);
}
public void clusterSetSlotMigrating(final int slot, final String nodeId) {
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot), Protocol.CLUSTER_SETSLOT_MIGRATING, nodeId);
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot),
Protocol.CLUSTER_SETSLOT_MIGRATING, nodeId);
}
public void clusterSetSlotImporting(final int slot, final String nodeId) {
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot), Protocol.CLUSTER_SETSLOT_IMPORTING, nodeId);
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot),
Protocol.CLUSTER_SETSLOT_IMPORTING, nodeId);
}
public void pfadd(String key, final String... elements) {
pfadd(SafeEncoder.encode(key), SafeEncoder.encodeMany(elements));
}
public void pfcount(final String key) {
pfcount(SafeEncoder.encode(key));
}
public void pfcount(final String...keys) {
pfcount(SafeEncoder.encodeMany(keys));
}
public void pfmerge(final String destkey, final String... sourcekeys) {
pfmerge(SafeEncoder.encode(destkey), SafeEncoder.encodeMany(sourcekeys));
}
public void clusterSetSlotStable(final int slot) {
cluster(Protocol.CLUSTER_SETSLOT, String.valueOf(slot),
Protocol.CLUSTER_SETSLOT_STABLE);
}
public void clusterForget(final String nodeId) {
cluster(Protocol.CLUSTER_FORGET, nodeId);
}
public void clusterFlushSlots() {
cluster(Protocol.CLUSTER_FLUSHSLOT);
}
public void clusterKeySlot(final String key) {
cluster(Protocol.CLUSTER_KEYSLOT, key);
}
public void clusterCountKeysInSlot(final int slot) {
cluster(Protocol.CLUSTER_COUNTKEYINSLOT, String.valueOf(slot));
}
public void clusterSaveConfig() {
cluster(Protocol.CLUSTER_SAVECONFIG);
}
public void clusterReplicate(final String nodeId) {
cluster(Protocol.CLUSTER_REPLICATE, nodeId);
}
public void clusterSlaves(final String nodeId) {
cluster(Protocol.CLUSTER_SLAVES, nodeId);
}
public void clusterFailover() {
cluster(Protocol.CLUSTER_FAILOVER);
}
}

View File

@@ -20,4 +20,22 @@ public interface ClusterCommands {
String clusterSetSlotMigrating(final int slot, final String nodeId);
String clusterSetSlotImporting(final int slot, final String nodeId);
String clusterSetSlotStable(final int slot);
String clusterForget(final String nodeId);
String clusterFlushSlots();
Long clusterKeySlot(final String key);
Long clusterCountKeysInSlot(final int slot);
String clusterSaveConfig();
String clusterReplicate(final String nodeId);
List<String> clusterSlaves(final String nodeId);
String clusterFailover();
}

View File

@@ -61,6 +61,8 @@ public interface Commands {
public void incrBy(final String key, final long integer);
public void incrByFloat(final String key, final double value);
public void incr(final String key);
public void append(final String key, final String value);
@@ -79,6 +81,8 @@ public interface Commands {
public void hincrBy(final String key, final String field, final long value);
public void hincrByFloat(final String key, final String field, final double value);
public void hexists(final String key, final String field);
public void hdel(final String key, final String... fields);
@@ -144,7 +148,7 @@ public interface Commands {
public void zadd(final String key, final double score, final String member);
public void zadd(final String key, final Map<Double, String> scoreMembers);
public void zadd(final String key, final Map<String, Double> scoreMembers);
public void zrange(final String key, final long start, final long end);
@@ -297,13 +301,45 @@ 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);
public void sscan(final String key, final String cursor, final ScanParams params);
public void zscan(final String key, final String cursor, final ScanParams params);
public void waitReplicas(int replicas, long timeout);
}

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -10,12 +11,11 @@ import java.util.List;
import redis.clients.jedis.Protocol.Command;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.util.RedisInputStream;
import redis.clients.util.RedisOutputStream;
import redis.clients.util.SafeEncoder;
public class Connection {
public class Connection implements Closeable {
private String host;
private int port = Protocol.DEFAULT_PORT;
private Socket socket;
@@ -23,6 +23,8 @@ public class Connection {
private RedisInputStream inputStream;
private int timeout = Protocol.DEFAULT_TIMEOUT;
private boolean broken = false;
public Socket getSocket() {
return socket;
}
@@ -37,13 +39,14 @@ public class Connection {
public void setTimeoutInfinite() {
try {
if(!isConnected()) {
if (!isConnected()) {
connect();
}
socket.setKeepAlive(true);
socket.setSoTimeout(0);
} catch (SocketException ex) {
throw new JedisException(ex);
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -52,7 +55,8 @@ public class Connection {
socket.setSoTimeout(timeout);
socket.setKeepAlive(false);
} catch (SocketException ex) {
throw new JedisException(ex);
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -61,14 +65,6 @@ public class Connection {
this.host = host;
}
protected void flush() {
try {
outputStream.flush();
} catch (IOException e) {
throw new JedisConnectionException(e);
}
}
protected Connection sendCommand(final Command cmd, final String... args) {
final byte[][] bargs = new byte[args.length][];
for (int i = 0; i < args.length; i++) {
@@ -78,15 +74,27 @@ public class Connection {
}
protected Connection sendCommand(final Command cmd, final byte[]... args) {
try {
connect();
Protocol.sendCommand(outputStream, cmd, args);
return this;
} catch (JedisConnectionException ex) {
// Any other exceptions related to connection?
broken = true;
throw ex;
}
}
protected Connection sendCommand(final Command cmd) {
try {
connect();
Protocol.sendCommand(outputStream, cmd, new byte[0][]);
return this;
} catch (JedisConnectionException ex) {
// Any other exceptions related to connection?
broken = true;
throw ex;
}
}
public Connection(final String host, final int port) {
@@ -119,23 +127,33 @@ public class Connection {
if (!isConnected()) {
try {
socket = new Socket();
//->@wjw_add
// ->@wjw_add
socket.setReuseAddress(true);
socket.setKeepAlive(true); //Will monitor the TCP connection is valid
socket.setTcpNoDelay(true); //Socket buffer Whetherclosed, to ensure timely delivery of data
socket.setSoLinger(true,0); //Control calls close () method, the underlying socket is closed immediately
//<-@wjw_add
socket.setKeepAlive(true); // Will monitor the TCP connection is
// valid
socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to
// ensure timely delivery of data
socket.setSoLinger(true, 0); // Control calls close () method,
// the underlying socket is closed
// immediately
// <-@wjw_add
socket.connect(new InetSocketAddress(host, port), timeout);
socket.setSoTimeout(timeout);
outputStream = new RedisOutputStream(socket.getOutputStream());
inputStream = new RedisInputStream(socket.getInputStream());
} catch (IOException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
}
}
@Override
public void close() {
disconnect();
}
public void disconnect() {
if (isConnected()) {
try {
@@ -145,6 +163,7 @@ public class Connection {
socket.close();
}
} catch (IOException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -158,7 +177,7 @@ public class Connection {
protected String getStatusCodeReply() {
flush();
final byte[] resp = (byte[]) Protocol.read(inputStream);
final byte[] resp = (byte[]) readProtocolWithCheckingBroken();
if (null == resp) {
return null;
} else {
@@ -177,12 +196,12 @@ public class Connection {
public byte[] getBinaryBulkReply() {
flush();
return (byte[]) Protocol.read(inputStream);
return (byte[]) readProtocolWithCheckingBroken();
}
public Long getIntegerReply() {
flush();
return (Long) Protocol.read(inputStream);
return (Long) readProtocolWithCheckingBroken();
}
public List<String> getMultiBulkReply() {
@@ -192,13 +211,17 @@ public class Connection {
@SuppressWarnings("unchecked")
public List<byte[]> getBinaryMultiBulkReply() {
flush();
return (List<byte[]>) Protocol.read(inputStream);
return (List<byte[]>) readProtocolWithCheckingBroken();
}
@SuppressWarnings("unchecked")
public List<Object> getRawObjectMultiBulkReply() {
return (List<Object>) readProtocolWithCheckingBroken();
}
public List<Object> getObjectMultiBulkReply() {
flush();
return (List<Object>) Protocol.read(inputStream);
return getRawObjectMultiBulkReply();
}
@SuppressWarnings("unchecked")
@@ -209,7 +232,29 @@ public class Connection {
public Object getOne() {
flush();
return readProtocolWithCheckingBroken();
}
public boolean isBroken() {
return broken;
}
protected void flush() {
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;
}
}
public List<Object> getMany(int count) {
@@ -217,7 +262,7 @@ public class Connection {
List<Object> responses = new ArrayList<Object>();
for (int i = 0 ; i < count ; i++) {
try {
responses.add(Protocol.read(inputStream));
responses.add(readProtocolWithCheckingBroken());
} catch (JedisDataException e) {
responses.add(e);
}

View File

@@ -26,8 +26,7 @@ public class HostAndPort {
String thisHost = convertHost(host);
String hpHost = convertHost(hp.host);
return port == hp.port &&
thisHost.equals(hpHost);
return port == hp.port && thisHost.equals(hpHost);
}

View File

@@ -1,22 +1,20 @@
package redis.clients.jedis;
import java.net.URI;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import redis.clients.util.Pool;
import redis.clients.util.SafeEncoder;
import redis.clients.util.Slowlog;
import java.net.URI;
import java.util.*;
import java.util.Map.Entry;
public class Jedis extends BinaryJedis implements JedisCommands,
MultiKeyCommands, AdvancedJedisCommands, ScriptingCommands,
BasicCommands, ClusterCommands {
protected Pool<Jedis> dataSource = null;
public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommands, AdvancedJedisCommands, ScriptingCommands, BasicCommands, ClusterCommands {
public Jedis(final String host) {
super(host);
}
@@ -56,24 +54,29 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
/**
* Set the string value as value of the key. The string can't be longer than
* 1073741824 bytes (1 GB).
*
* @param key
* @param value
* @param nxxx NX|XX, NX -- Only set the key if it does not already exist.
* XX -- Only set the key if it already exist.
* @param expx EX|PX, expire time units: EX = seconds; PX = milliseconds
* @param time expire time in the units of {@param #expx}
* @param nxxx
* NX|XX, NX -- Only set the key if it does not already exist. XX
* -- Only set the key if it already exist.
* @param expx
* EX|PX, expire time units: EX = seconds; PX = milliseconds
* @param time
* expire time in the units of {@param #expx}
* @return Status code reply
*/
public String set(final String key, final String value, final String nxxx, final String expx, final long time) {
public String set(final String key, final String value, final String nxxx,
final String expx, final long time) {
checkIsInMulti();
client.set(key, value, nxxx, expx, time);
return client.getStatusCodeReply();
}
/**
* Get the value of the specified key. If the key does not exist the special
* value 'nil' is returned. If the value stored at key is not a string an
* error is returned because GET can only handle string values.
* Get the value of the specified key. If the key does not exist null is
* returned. If the value stored at key is not a string an error is returned
* because GET can only handle string values.
* <p>
* Time complexity: O(1)
*
@@ -541,6 +544,31 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getIntegerReply();
}
/**
* INCRBYFLOAT
* <p>
* INCRBYFLOAT commands are limited to double precision floating point values.
* <p>
* 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
* negative value will work as expected.
* <p>
* 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);
}
/**
* Increment the number stored at key by one. If the key does not exist or
* contains a value of a wrong type, set the key to the value of "0" before
@@ -733,6 +761,32 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getIntegerReply();
}
/**
* 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.
* <p>
* The range of values supported by HINCRBYFLOAT is limited to
* double precision floating point values.
* <p>
* <b>Time complexity:</b> O(1)
*
* @param key
* @param field
* @param value
* @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);
}
/**
* Test for existence of a specified field in a hash.
*
@@ -1062,8 +1116,8 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
/**
* 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".
* <p>
* If the key does not exist or the list is already empty the special value
* 'nil' is returned.
@@ -1415,7 +1469,7 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getIntegerReply();
}
public Long zadd(final String key, final Map<Double, String> scoreMembers) {
public Long zadd(final String key, final Map<String, Double> scoreMembers) {
checkIsInMulti();
client.zadd(key, scoreMembers);
return client.getIntegerReply();
@@ -1954,8 +2008,6 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return multiBulkReply;
}
public Long zcount(final String key, final double min, final double max) {
checkIsInMulti();
client.zcount(key, min, max);
@@ -2020,8 +2072,10 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
* @see #zcount(String, double, double)
*
* @param key
* @param min a double or Double.MIN_VALUE for "-inf"
* @param max a double or Double.MAX_VALUE for "+inf"
* @param min
* a double or Double.MIN_VALUE for "-inf"
* @param max
* a double or Double.MAX_VALUE for "+inf"
* @return Multi bulk reply specifically a list of elements in the specified
* score range.
*/
@@ -2654,6 +2708,15 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
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) {
client.bitpos(key, value, params);
return client.getIntegerReply();
}
/**
* Retrieve the configuration of a running Redis server. Not all the
* configuration parameters are supported.
@@ -2792,17 +2855,18 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
}
private Object getEvalResult() {
Object result = client.getOne();
return evalResult(client.getOne());
}
private Object evalResult(Object result) {
if (result instanceof byte[])
return SafeEncoder.encode((byte[]) result);
if (result instanceof List<?>) {
List<?> list = (List<?>) result;
List<String> listResult = new ArrayList<String>(list.size());
List<Object> listResult = new ArrayList<Object>(list.size());
for (Object bin : list) {
listResult.add((bin == null ? null : SafeEncoder
.encode((byte[]) bin)));
listResult.add(evalResult(bin));
}
return listResult;
@@ -3006,19 +3070,59 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return slaves;
}
public String sentinelFailover(String masterName) {
client.sentinel(Protocol.SENTINEL_FAILOVER, masterName);
return client.getStatusCodeReply();
}
public String sentinelMonitor(String masterName, String ip, int port,
int quorum) {
client.sentinel(Protocol.SENTINEL_MONITOR, masterName, ip,
String.valueOf(port), String.valueOf(quorum));
return client.getStatusCodeReply();
}
public String sentinelRemove(String masterName) {
client.sentinel(Protocol.SENTINEL_REMOVE, masterName);
return client.getStatusCodeReply();
}
public String sentinelSet(String masterName,
Map<String, String> parameterMap) {
int index = 0;
int paramsLength = parameterMap.size() * 2 + 2;
String[] params = new String[paramsLength];
params[index++] = Protocol.SENTINEL_SET;
params[index++] = masterName;
for (Entry<String, String> entry : parameterMap.entrySet()) {
params[index++] = entry.getKey();
params[index++] = entry.getValue();
}
client.sentinel(params);
return client.getStatusCodeReply();
}
public byte[] dump(final String key) {
checkIsInMulti();
client.dump(key);
return client.getBinaryBulkReply();
}
public String restore(final String key, final int ttl, final byte[] serializedValue) {
public String restore(final String key, final int ttl,
final byte[] serializedValue) {
checkIsInMulti();
client.restore(key, ttl, serializedValue);
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);
return client.getIntegerReply();
@@ -3036,14 +3140,9 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getIntegerReply();
}
public Double incrByFloat(final String key, final double increment) {
checkIsInMulti();
client.incrByFloat(key, increment);
String relpy = client.getBulkReply();
return (relpy != null ? new Double(relpy) : null);
}
public String psetex(final String key, final int milliseconds, final String value) {
public String psetex(final String key, final int milliseconds,
final String value) {
checkIsInMulti();
client.psetex(key, milliseconds, value);
return client.getStatusCodeReply();
@@ -3055,7 +3154,8 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getStatusCodeReply();
}
public String set(final String key, final String value, final String nxxx, final String expx, final int time) {
public String set(final String key, final String value, final String nxxx,
final String expx, final int time) {
checkIsInMulti();
client.set(key, value, nxxx, expx, time);
return client.getStatusCodeReply();
@@ -3073,88 +3173,215 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getStatusCodeReply();
}
public String migrate(final String host, final int port, final String key, final int destinationDb, final int timeout) {
public String migrate(final String host, final int port, final String key,
final int destinationDb, final int timeout) {
checkIsInMulti();
client.migrate(host, port, key, destinationDb, timeout);
return client.getStatusCodeReply();
}
public Double hincrByFloat(final String key, final String field, double increment) {
checkIsInMulti();
client.hincrByFloat(key, field, increment);
String relpy = client.getBulkReply();
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<String> 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<String> scan(int cursor, final ScanParams params) {
checkIsInMulti();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
int newcursor = Integer.parseInt(new String((byte[])result.get(0)));
int newcursor = Integer.parseInt(new String((byte[]) result.get(0)));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>)result.get(1);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(newcursor, results);
}
public ScanResult<Map.Entry<String, String>> 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
*/
public ScanResult<Map.Entry<String, String>> hscan(final String key,
int cursor) {
return hscan(key, cursor, new ScanParams());
}
public ScanResult<Map.Entry<String, String>> 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 ScanResult<Map.Entry<String, String>> hscan(final String key,
int cursor, final ScanParams params) {
checkIsInMulti();
client.hscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
int newcursor = Integer.parseInt(new String((byte[])result.get(0)));
int newcursor = Integer.parseInt(new String((byte[]) result.get(0)));
List<Map.Entry<String, String>> results = new ArrayList<Map.Entry<String, String>>();
List<byte[]> rawResults = (List<byte[]>)result.get(1);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while(iterator.hasNext()) {
results.add(new AbstractMap.SimpleEntry<String, String>(SafeEncoder.encode(iterator.next()), SafeEncoder.encode(iterator.next())));
while (iterator.hasNext()) {
results.add(new AbstractMap.SimpleEntry<String, String>(SafeEncoder
.encode(iterator.next()), SafeEncoder.encode(iterator
.next())));
}
return new ScanResult<Map.Entry<String, String>>(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<String> sscan(final String key, int cursor) {
return sscan(key, cursor, new ScanParams());
}
public ScanResult<String> 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 ScanResult<String> sscan(final String key, int cursor,
final ScanParams params) {
checkIsInMulti();
client.sscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
int newcursor = Integer.parseInt(new String((byte[])result.get(0)));
int newcursor = Integer.parseInt(new String((byte[]) result.get(0)));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>)result.get(1);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(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<Tuple> zscan(final String key, int cursor) {
return zscan(key, cursor, new ScanParams());
}
public ScanResult<Tuple> zscan(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 ScanResult<Tuple> zscan(final String key, int cursor,
final ScanParams params) {
checkIsInMulti();
client.zscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
int newcursor = Integer.parseInt(new String((byte[])result.get(0)));
int newcursor = Integer.parseInt(new String((byte[]) result.get(0)));
List<Tuple> results = new ArrayList<Tuple>();
List<byte[]> rawResults = (List<byte[]>)result.get(1);
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while(iterator.hasNext()) {
results.add(new Tuple(SafeEncoder.encode(iterator.next()), Double.valueOf(SafeEncoder.encode(iterator.next()))));
while (iterator.hasNext()) {
results.add(new Tuple(SafeEncoder.encode(iterator.next()), Double
.valueOf(SafeEncoder.encode(iterator.next()))));
}
return new ScanResult<Tuple>(newcursor, results);
}
public ScanResult<String> scan(final String cursor) {
return scan(cursor, new ScanParams());
}
public ScanResult<String> scan(final String cursor, final ScanParams params) {
checkIsInMulti();
client.scan(cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(newcursor, results);
}
public ScanResult<Map.Entry<String, String>> hscan(final String key,
final String cursor) {
return hscan(key, cursor, new ScanParams());
}
public ScanResult<Map.Entry<String, String>> hscan(final String key,
final String cursor, final ScanParams params) {
checkIsInMulti();
client.hscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<Map.Entry<String, String>> results = new ArrayList<Map.Entry<String, String>>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while (iterator.hasNext()) {
results.add(new AbstractMap.SimpleEntry<String, String>(SafeEncoder
.encode(iterator.next()), SafeEncoder.encode(iterator
.next())));
}
return new ScanResult<Map.Entry<String, String>>(newcursor, results);
}
public ScanResult<String> sscan(final String key, final String cursor) {
return sscan(key, cursor, new ScanParams());
}
public ScanResult<String> sscan(final String key, final String cursor,
final ScanParams params) {
checkIsInMulti();
client.sscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<String> results = new ArrayList<String>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
for (byte[] bs : rawResults) {
results.add(SafeEncoder.encode(bs));
}
return new ScanResult<String>(newcursor, results);
}
public ScanResult<Tuple> zscan(final String key, final String cursor) {
return zscan(key, cursor, new ScanParams());
}
public ScanResult<Tuple> zscan(final String key, final String cursor,
final ScanParams params) {
checkIsInMulti();
client.zscan(key, cursor, params);
List<Object> result = client.getObjectMultiBulkReply();
String newcursor = new String((byte[]) result.get(0));
List<Tuple> results = new ArrayList<Tuple>();
List<byte[]> rawResults = (List<byte[]>) result.get(1);
Iterator<byte[]> iterator = rawResults.iterator();
while (iterator.hasNext()) {
results.add(new Tuple(SafeEncoder.encode(iterator.next()), Double
.valueOf(SafeEncoder.encode(iterator.next()))));
}
return new ScanResult<Tuple>(newcursor, results);
}
public String clusterNodes() {
checkIsInMulti();
client.clusterNodes();
@@ -3167,13 +3394,13 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
return client.getStatusCodeReply();
}
public String clusterAddSlots(final int ...slots) {
public String clusterAddSlots(final int... slots) {
checkIsInMulti();
client.clusterAddSlots(slots);
return client.getStatusCodeReply();
}
public String clusterDelSlots(final int ...slots) {
public String clusterDelSlots(final int... slots) {
checkIsInMulti();
client.clusterDelSlots(slots);
return client.getStatusCodeReply();
@@ -3209,9 +3436,124 @@ public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommand
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<String> clusterSlaves(final String nodeId) {
checkIsInMulti();
client.clusterSlaves(nodeId);
return client.getMultiBulkReply();
}
public String clusterFailover() {
checkIsInMulti();
client.clusterFailover();
return client.getStatusCodeReply();
}
public String asking() {
checkIsInMulti();
client.asking();
return client.getStatusCodeReply();
}
public List<String> pubsubChannels(String pattern) {
checkIsInMulti();
client.pubsubChannels(pattern);
return client.getMultiBulkReply();
}
public Long pubsubNumPat() {
checkIsInMulti();
client.pubsubNumPat();
return client.getIntegerReply();
}
public Map<String, String> pubsubNumSub(String... channels) {
checkIsInMulti();
client.pubsubNumSub(channels);
return BuilderFactory.STRING_MAP
.build(client.getBinaryMultiBulkReply());
}
@Override
public void close() {
if (dataSource != null) {
if (client.isBroken()) {
this.dataSource.returnBrokenResource(this);
} else {
this.dataSource.returnResource(this);
}
} else {
client.close();
}
}
public void setDataSource(Pool<Jedis> jedisPool) {
this.dataSource = jedisPool;
}
public Long pfadd(final String key, final String... elements) {
checkIsInMulti();
client.pfadd(key, elements);
return client.getIntegerReply();
}
public long pfcount(final String key) {
checkIsInMulti();
client.pfcount(key);
return client.getIntegerReply();
}
@Override
public long pfcount(String... keys) {
checkIsInMulti();
client.pfcount(keys);
return client.getIntegerReply();
}
public String pfmerge(final String destkey, final String... sourcekeys) {
checkIsInMulti();
client.pfmerge(destkey, sourcekeys);
return client.getStatusCodeReply();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,51 +3,101 @@ package redis.clients.jedis;
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.JedisMovedDataException;
import redis.clients.jedis.exceptions.JedisRedirectionException;
import redis.clients.util.JedisClusterCRC16;
public abstract class JedisClusterCommand<T> {
private boolean asking = false;
private JedisClusterConnectionHandler connectionHandler;
private int commandTimeout;
private int redirections;
// private boolean asking = false;
public JedisClusterCommand(JedisClusterConnectionHandler connectionHandler, int timeout, int maxRedirections) {
public JedisClusterCommand(JedisClusterConnectionHandler connectionHandler,
int timeout, int maxRedirections) {
this.connectionHandler = connectionHandler;
this.commandTimeout = timeout;
this.redirections = maxRedirections;
}
public abstract T execute();
public abstract T execute(Jedis connection);
public T run(String key) {
try {
if (key == null) {
throw new JedisClusterException("No way to dispatch this command to Redis Cluster.");
} else if (redirections == 0) {
throw new JedisClusterMaxRedirectionsException("Too many Cluster redirections?");
}
connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
if (asking) {
//TODO: Pipeline asking with the original command to make it faster....
connectionHandler.getConnection().asking();
}
return execute();
} catch (JedisRedirectionException jre) {
return handleRedirection(jre, key);
}
throw new JedisClusterException(
"No way to dispatch this command to Redis Cluster.");
}
private T handleRedirection(JedisRedirectionException jre, String key) {
return runWithRetries(key, this.redirections, false, false);
}
private T runWithRetries(String key, int redirections,
boolean tryRandomNode, boolean asking) {
if (redirections <= 0) {
throw new JedisClusterMaxRedirectionsException(
"Too many Cluster redirections?");
}
Jedis connection = null;
try {
if (tryRandomNode) {
connection = connectionHandler.getConnection();
} else {
connection = connectionHandler
.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
}
if (asking) {
// TODO: Pipeline asking with the original command to make it
// faster....
connection.asking();
// if asking success, reset asking flag
asking = false;
}
return execute(connection);
} catch (JedisConnectionException jce) {
if (tryRandomNode) {
// 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;
} else if (jre instanceof JedisMovedDataException) {
// TODO : In antirez's redis-rb-cluster implementation,
// it rebuilds cluster's slot and node cache
}
redirections--;
this.connectionHandler.assignSlotToNode(jre.getSlot(), jre.getTargetNode());
return run(key);
this.connectionHandler.assignSlotToNode(jre.getSlot(),
jre.getTargetNode());
releaseConnection(connection, false);
connection = null;
return runWithRetries(key, redirections - 1, false, asking);
} finally {
releaseConnection(connection, false);
}
}
private void releaseConnection(Jedis connection, boolean broken) {
if (connection != null) {
if (broken) {
connectionHandler.returnBrokenConnection(connection);
} else {
connectionHandler.returnConnection(connection);
}
}
}
}

View File

@@ -1,17 +1,29 @@
package redis.clients.jedis;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.*;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.util.ClusterNodeInformation;
import redis.clients.util.ClusterNodeInformationParser;
public abstract class JedisClusterConnectionHandler {
public static ClusterNodeInformationParser nodeInfoParser = new ClusterNodeInformationParser();
protected Map<String, JedisPool> nodes = new HashMap<String, JedisPool>();
protected Map<Integer, JedisPool> slots = new HashMap<Integer, JedisPool>();
abstract Jedis getConnection();
protected void returnConnection(Jedis connection) {
nodes.get(getNodeKey(connection.getClient()))
.returnResource(connection);
}
public void returnBrokenConnection(Jedis connection) {
nodes.get(getNodeKey(connection.getClient())).returnBrokenResource(
connection);
}
abstract Jedis getConnectionFromSlot(int slot);
public JedisClusterConnectionHandler(Set<HostAndPort> nodes) {
@@ -22,61 +34,94 @@ public abstract class JedisClusterConnectionHandler {
return nodes;
}
private void initializeSlotsCache(Set<HostAndPort> nodes) {
for (HostAndPort hostAndPort : nodes) {
JedisPool jp = new JedisPool(hostAndPort.getHost(), hostAndPort.getPort());
this.nodes.put(hostAndPort.getHost() + hostAndPort.getPort(), jp);
discoverClusterNodesAndSlots(jp);
private void initializeSlotsCache(Set<HostAndPort> startNodes) {
for (HostAndPort hostAndPort : startNodes) {
JedisPool jp = new JedisPool(hostAndPort.getHost(),
hostAndPort.getPort());
this.nodes.clear();
this.slots.clear();
Jedis jedis = null;
try {
jedis = jp.getResource();
discoverClusterNodesAndSlots(jedis);
break;
} catch (JedisConnectionException e) {
if (jedis != null) {
jp.returnBrokenResource(jedis);
jedis = null;
}
// try next nodes
} finally {
if (jedis != null) {
jp.returnResource(jedis);
}
}
}
private void discoverClusterNodesAndSlots(JedisPool jp) {
String localNodes = jp.getResource().clusterNodes();
for (HostAndPort node : startNodes) {
setNodeIfNotExist(node);
}
}
private void discoverClusterNodesAndSlots(Jedis jedis) {
String localNodes = jedis.clusterNodes();
for (String nodeInfo : localNodes.split("\n")) {
HostAndPort node = getHostAndPortFromNodeLine(nodeInfo);
JedisPool nodePool = new JedisPool(node.getHost(), node.getPort());
this.nodes.put(node.getHost() + node.getPort(), nodePool);
populateNodeSlots(nodeInfo, nodePool);
}
}
ClusterNodeInformation clusterNodeInfo = nodeInfoParser.parse(
nodeInfo, new HostAndPort(jedis.getClient().getHost(),
jedis.getClient().getPort()));
private void populateNodeSlots(String nodeInfo, JedisPool nodePool) {
String[] nodeInfoArray = nodeInfo.split(" ");
if (nodeInfoArray.length > 7) {
for (int i = 8; i < nodeInfoArray.length; i++) {
processSlot(nodeInfoArray[i], nodePool);
HostAndPort targetNode = clusterNodeInfo.getNode();
setNodeIfNotExist(targetNode);
assignSlotsToNode(clusterNodeInfo.getAvailableSlots(), targetNode);
}
}
}
private void processSlot(String slot, JedisPool nodePool) {
if (slot.contains("-")) {
String[] slotRange = slot.split("-");
for (int i = Integer.valueOf(slotRange[0]); i <= Integer.valueOf(slotRange[1]); i++) {
slots.put(i, nodePool);
}
} else {
slots.put(Integer.valueOf(slot), nodePool);
}
}
private HostAndPort getHostAndPortFromNodeLine(String nodeInfo) {
String stringHostAndPort = nodeInfo.split(" ",3)[1];
String[] arrayHostAndPort = stringHostAndPort.split(":");
return new HostAndPort(arrayHostAndPort[0], Integer.valueOf(arrayHostAndPort[1]));
}
public void assignSlotToNode(int slot, HostAndPort targetNode) {
JedisPool targetPool = nodes.get(targetNode.getHost() + targetNode.getPort());
JedisPool targetPool = nodes.get(getNodeKey(targetNode));
if (targetPool == null) {
setNodeIfNotExist(targetNode);
targetPool = nodes.get(getNodeKey(targetNode));
}
slots.put(slot, targetPool);
}
public void assignSlotsToNode(List<Integer> 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);
}
}
protected JedisPool getRandomConnection() {
Object[] nodeArray = nodes.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);
}
}

View File

@@ -7,10 +7,12 @@ import java.util.Set;
/**
* Common interface for sharded and non-sharded Jedis
*/
public interface
JedisCommands {
public interface JedisCommands {
String set(String key, String value);
String set(String key, String value, String nxxx,
String expx, long time);
String get(String key);
Boolean exists(String key);
@@ -115,7 +117,7 @@ public interface
Long zadd(String key, double score, String member);
Long zadd(String key, Map<Double, String> scoreMembers);
Long zadd(String key, Map<String, Double> scoreMembers);
Set<String> zrange(String key, long start, long end);
@@ -212,9 +214,38 @@ public interface
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<Map.Entry<String, String>> 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<String> 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<Tuple> zscan(final String key, int cursor);
ScanResult<Map.Entry<String, String>> hscan(final String key, final String cursor);
ScanResult<String> sscan(final String key, final String cursor);
ScanResult<Tuple> zscan(final String key, final String cursor);
Long pfadd(final String key, final String... elements);
long pfcount(final String key);
}

View File

@@ -79,11 +79,23 @@ public class JedisPool extends Pool<Jedis> {
database, clientName));
}
@Override
public Jedis getResource() {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
public void returnBrokenResource(final Jedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final Jedis resource) {
if (resource != null) {
resource.resetState();
returnResourceObject(resource);
}
}
}

View File

@@ -16,7 +16,7 @@ import redis.clients.util.SafeEncoder;
public abstract class JedisPubSub {
private int subscribedChannels = 0;
private Client client;
private volatile Client client;
public abstract void onMessage(String channel, String message);
@@ -41,26 +41,46 @@ public abstract class JedisPubSub {
}
public void unsubscribe(String... channels) {
if (client == null) {
throw new JedisConnectionException(
"JedisPubSub is not subscribed to a Jedis instance.");
}
client.unsubscribe(channels);
client.flush();
}
public void subscribe(String... channels) {
if (client == null) {
throw new JedisConnectionException(
"JedisPubSub is not subscribed to a Jedis instance.");
}
client.subscribe(channels);
client.flush();
}
public void psubscribe(String... patterns) {
if (client == null) {
throw new JedisConnectionException(
"JedisPubSub is not subscribed to a Jedis instance.");
}
client.psubscribe(patterns);
client.flush();
}
public void punsubscribe() {
if (client == null) {
throw new JedisConnectionException(
"JedisPubSub is not subscribed to a Jedis instance.");
}
client.punsubscribe();
client.flush();
}
public void punsubscribe(String... patterns) {
if (client == null) {
throw new JedisConnectionException(
"JedisPubSub is not subscribed to a Jedis instance.");
}
client.punsubscribe(patterns);
client.flush();
}
@@ -84,8 +104,9 @@ public abstract class JedisPubSub {
}
private void process(Client client) {
do {
List<Object> reply = client.getObjectMultiBulkReply();
List<Object> reply = client.getRawObjectMultiBulkReply();
final Object firstObj = reply.get(0);
if (!(firstObj instanceof byte[])) {
throw new JedisException("Unknown message type: " + firstObj);
@@ -138,6 +159,9 @@ public abstract class JedisPubSub {
throw new JedisException("Unknown message type: " + firstObj);
}
} while (isSubscribed());
/* Invalidate instance since this thread is no longer listening */
this.client = null;
}
public int getSubscribedChannels() {

View File

@@ -4,7 +4,6 @@ import java.util.Set;
public class JedisRandomConnectionHandler extends JedisClusterConnectionHandler {
public JedisRandomConnectionHandler(Set<HostAndPort> nodes) {
super(nodes);
}

View File

@@ -74,14 +74,6 @@ public class JedisSentinelPool extends Pool<Jedis> {
initPool(master);
}
public void returnBrokenResource(final Jedis resource) {
returnBrokenResourceObject(resource);
}
public void returnResource(final Jedis resource) {
returnResourceObject(resource);
}
private volatile HostAndPort currentHostMaster;
public void destroy() {
@@ -100,7 +92,8 @@ public class JedisSentinelPool extends Pool<Jedis> {
if (!master.equals(currentHostMaster)) {
currentHostMaster = master;
log.info("Created JedisPool to master at " + master);
initPool(poolConfig, new JedisFactory(master.getHost(), master.getPort(),
initPool(poolConfig,
new JedisFactory(master.getHost(), master.getPort(),
timeout, password, database));
}
}
@@ -169,6 +162,26 @@ public class JedisSentinelPool extends Pool<Jedis> {
return new HostAndPort(host, port);
}
@Override
public Jedis getResource() {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
public void returnBrokenResource(final Jedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final Jedis resource) {
if (resource != null) {
resource.resetState();
returnResourceObject(resource);
}
}
protected class JedisPubSubAdapter extends JedisPubSub {
@Override
public void onMessage(String channel, String message) {

View File

@@ -1,48 +1,72 @@
package redis.clients.jedis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class JedisSlotBasedConnectionHandler extends JedisClusterConnectionHandler {
import redis.clients.jedis.exceptions.JedisConnectionException;
private Jedis currentConnection;
public class JedisSlotBasedConnectionHandler extends
JedisClusterConnectionHandler {
public JedisSlotBasedConnectionHandler(Set<HostAndPort> nodes) {
super(nodes);
}
public Jedis getConnection() {
return currentConnection != null ? currentConnection : getRandomConnection().getResource();
// In antirez's redis-rb-cluster implementation,
// getRandomConnection always return valid connection (able to ping-pong)
// or exception if all connections are invalid
List<JedisPool> pools = getShuffledNodesPool();
for (JedisPool pool : pools) {
Jedis jedis = null;
try {
jedis = pool.getResource();
if (jedis == null) {
continue;
}
String result = jedis.ping();
if (result.equalsIgnoreCase("pong"))
return jedis;
private void returnCurrentConnection() {
if (currentConnection != null) {
nodes.get(currentConnection.getClient().getHost()+currentConnection.getClient().getPort()).returnResource(currentConnection);
pool.returnBrokenResource(jedis);
} catch (JedisConnectionException ex) {
if (jedis != null) {
pool.returnBrokenResource(jedis);
}
}
}
throw new JedisConnectionException("no reachable node in cluster");
}
@Override
public void assignSlotToNode(int slot, HostAndPort targetNode) {
super.assignSlotToNode(slot, targetNode);
getConnectionFromSlot(slot);
}
@Override
public Jedis getConnectionFromSlot(int slot) {
returnCurrentConnection();
JedisPool connectionPool = slots.get(slot);
if (connectionPool == null) {
connectionPool = getRandomConnection();
}
currentConnection = connectionPool.getResource();
if (connectionPool != null) {
// It can't guaranteed to get valid connection because of node assignment
return connectionPool.getResource();
} else {
return getConnection();
}
}
private List<JedisPool> getShuffledNodesPool() {
List<JedisPool> pools = new ArrayList<JedisPool>();
pools.addAll(nodes.values());
Collections.shuffle(pools);
return pools;
}
}

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Set;
@@ -70,4 +69,8 @@ public interface MultiKeyBinaryCommands {
byte[] randomBinaryKey();
Long bitop(BitOP op, final byte[] destKey, byte[]... srcKeys);
String pfmerge(final byte[] destkey, final byte[]... sourcekeys);
Long pfcount(byte[]... keys);
}

View File

@@ -1,11 +1,11 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Set;
/**
* Multikey related commands (these are split out because they are non-shardable)
* Multikey related commands (these are split out because they are
* non-shardable)
*/
public interface MultiKeyBinaryRedisPipeline {
@@ -39,7 +39,8 @@ public interface MultiKeyBinaryRedisPipeline {
Response<Long> smove(byte[] srckey, byte[] dstkey, byte[] member);
Response<Long> sort(byte[] key, SortingParams sortingParameters, byte[] dstkey);
Response<Long> sort(byte[] key, SortingParams sortingParameters,
byte[] dstkey);
Response<Long> sort(byte[] key, byte[] dstkey);
@@ -64,4 +65,8 @@ public interface MultiKeyBinaryRedisPipeline {
Response<byte[]> randomKeyBinary();
Response<Long> bitop(BitOP op, final byte[] destKey, byte[]... srcKeys);
Response<String> pfmerge(final byte[] destkey, final byte[]... sourcekeys);
Response<Long> pfcount(final byte[] ... keys);
}

View File

@@ -1,8 +1,6 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface MultiKeyCommands {
@@ -72,5 +70,17 @@ 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<String> scan(int cursor);
ScanResult<String> scan(final String cursor);
String pfmerge(final String destkey, final String... sourcekeys);
long pfcount(final String...keys);
}

View File

@@ -1,12 +1,11 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Set;
/**
* Multikey related commands (these are split out because they are non-shardable)
* Multikey related commands (these are split out because they are
* non-shardable)
*/
public interface MultiKeyCommandsPipeline {
Response<Long> del(String... keys);
@@ -39,7 +38,8 @@ public interface MultiKeyCommandsPipeline {
Response<Long> smove(String srckey, String dstkey, String member);
Response<Long> sort(String key, SortingParams sortingParameters, String dstkey);
Response<Long> sort(String key, SortingParams sortingParameters,
String dstkey);
Response<Long> sort(String key, String dstkey);
@@ -64,4 +64,8 @@ public interface MultiKeyCommandsPipeline {
Response<String> randomKey();
Response<Long> bitop(BitOP op, final String destKey, String... srcKeys);
Response<String> pfmerge(final String destkey, final String... sourcekeys);
Response<Long> pfcount(final String...keys);
}

View File

@@ -5,10 +5,8 @@ import java.util.Map;
import java.util.Set;
abstract class MultiKeyPipelineBase extends PipelineBase implements
BasicRedisPipeline,
MultiKeyBinaryRedisPipeline,
MultiKeyCommandsPipeline,
ClusterPipeline {
BasicRedisPipeline, MultiKeyBinaryRedisPipeline,
MultiKeyCommandsPipeline, ClusterPipeline {
protected Client client = null;
@@ -192,14 +190,14 @@ abstract class MultiKeyPipelineBase extends PipelineBase implements
return getResponse(BuilderFactory.LONG);
}
public Response<Long> sort(String key,
SortingParams sortingParameters, String dstkey) {
public Response<Long> sort(String key, SortingParams sortingParameters,
String dstkey) {
client.sort(key, sortingParameters, dstkey);
return getResponse(BuilderFactory.LONG);
}
public Response<Long> sort(byte[] key,
SortingParams sortingParameters, byte[] dstkey) {
public Response<Long> sort(byte[] key, SortingParams sortingParameters,
byte[] dstkey) {
client.sort(key, sortingParameters, dstkey);
return getResponse(BuilderFactory.LONG);
}
@@ -370,6 +368,11 @@ abstract class MultiKeyPipelineBase extends PipelineBase implements
return getResponse(BuilderFactory.STRING);
}
public Response<List<String>> time() {
client.time();
return getResponse(BuilderFactory.STRING_LIST);
}
public Response<Long> dbSize() {
client.dbSize();
return getResponse(BuilderFactory.LONG);
@@ -425,23 +428,51 @@ abstract class MultiKeyPipelineBase extends PipelineBase implements
return getResponse(BuilderFactory.STRING);
}
public Response<List<String>> clusterGetKeysInSlot(final int slot, final int count) {
public Response<List<String>> clusterGetKeysInSlot(final int slot,
final int count) {
client.clusterGetKeysInSlot(slot, count);
return getResponse(BuilderFactory.STRING_LIST);
}
public Response<String> clusterSetSlotNode(final int slot, final String nodeId) {
public Response<String> clusterSetSlotNode(final int slot,
final String nodeId) {
client.clusterSetSlotNode(slot, nodeId);
return getResponse(BuilderFactory.STRING);
}
public Response<String> clusterSetSlotMigrating(final int slot, final String nodeId) {
public Response<String> clusterSetSlotMigrating(final int slot,
final String nodeId) {
client.clusterSetSlotMigrating(slot, nodeId);
return getResponse(BuilderFactory.STRING);
}
public Response<String> clusterSetSlotImporting(final int slot, final String nodeId) {
public Response<String> clusterSetSlotImporting(final int slot,
final String nodeId) {
client.clusterSetSlotImporting(slot, nodeId);
return getResponse(BuilderFactory.STRING);
}
@Override
public Response<String> pfmerge(byte[] destkey, byte[]... sourcekeys) {
client.pfmerge(destkey, sourcekeys);
return getResponse(BuilderFactory.STRING);
}
@Override
public Response<String> pfmerge(String destkey, String... sourcekeys) {
client.pfmerge(destkey, sourcekeys);
return getResponse(BuilderFactory.STRING);
}
@Override
public Response<Long> pfcount(String...keys) {
client.pfcount(keys);
return getResponse(BuilderFactory.LONG);
}
@Override
public Response<Long> pfcount(final byte[] ... keys) {
client.pfcount(keys);
return getResponse(BuilderFactory.LONG);
}
}

View File

@@ -1,28 +1,29 @@
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;
private class MultiResponseBuilder extends Builder<List<Object>>{
private class MultiResponseBuilder extends Builder<List<Object>> {
private List<Response<?>> responses = new ArrayList<Response<?>>();
@Override
public List<Object> build(Object data) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)data;
List<Object> list = (List<Object>) data;
List<Object> values = new ArrayList<Object>();
if(list.size() != responses.size()){
throw new JedisDataException("Expected data size " + responses.size() + " but was " + list.size());
if (list.size() != responses.size()) {
throw new JedisDataException("Expected data size "
+ responses.size() + " but was " + list.size());
}
for(int i=0;i<list.size();i++){
for (int i = 0; i < list.size(); i++) {
Response<?> response = responses.get(i);
response.set(list.get(i));
values.add(response.get());
@@ -30,21 +31,26 @@ public class Pipeline extends MultiKeyPipelineBase {
return values;
}
public void addResponse(Response<?> response){
public void setResponseDependency(Response<?> dependency) {
for (Response<?> response : responses) {
response.setDependency(dependency);
}
}
public void addResponse(Response<?> response) {
responses.add(response);
}
}
@Override
protected <T> Response<T> getResponse(Builder<T> builder) {
if(currentMulti != null){
super.getResponse(BuilderFactory.STRING); //Expected QUEUED
if (currentMulti != null) {
super.getResponse(BuilderFactory.STRING); // Expected QUEUED
Response<T> lr = new Response<T>(builder);
currentMulti.addResponse(lr);
return lr;
}
else{
} else {
return super.getResponse(builder);
}
}
@@ -63,6 +69,18 @@ public class Pipeline extends MultiKeyPipelineBase {
return client;
}
public void clear() {
if (isInMulti()) {
discard();
}
sync();
}
public boolean isInMulti() {
return currentMulti != null;
}
/**
* Syncronize pipeline by reading all responses. This operation close the
* pipeline. In order to get return values from pipelined commands, capture
@@ -70,9 +88,9 @@ public class Pipeline extends MultiKeyPipelineBase {
*/
public void sync() {
List<Object> unformatted = client.getMany(getPipelinedResponseLength());
for (Object resp : unformatted)
generateResponse(resp);
for (Object o : unformatted) {
generateResponse(o);
}
}
/**
@@ -87,28 +105,42 @@ public class Pipeline extends MultiKeyPipelineBase {
List<Object> unformatted = client.getMany(getPipelinedResponseLength());
List<Object> formatted = new ArrayList<Object>();
for (Object resp : unformatted)
formatted.add(generateResponse(resp).get());
for (Object o : unformatted) {
try {
formatted.add(generateResponse(o).get());
} catch (JedisDataException e) {
formatted.add(e);
}
}
return formatted;
}
public Response<String> discard() {
if (currentMulti == null)
throw new JedisDataException("DISCARD without MULTI");
client.discard();
currentMulti = null;
return getResponse(BuilderFactory.STRING);
}
public Response<List<Object>> exec() {
if (currentMulti == null)
throw new JedisDataException("EXEC without MULTI");
client.exec();
Response<List<Object>> response = super.getResponse(currentMulti);
currentMulti.setResponseDependency(response);
currentMulti = null;
return response;
}
public Response<String> multi() {
if (currentMulti != null)
throw new JedisDataException("MULTI calls can not be nested");
client.multi();
Response<String> response = getResponse(BuilderFactory.STRING); //Expecting OK
Response<String> response = getResponse(BuilderFactory.STRING); // Expecting
// OK
currentMulti = new MultiResponseBuilder();
return response;
}

View File

@@ -1,15 +1,14 @@
package redis.clients.jedis;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import static redis.clients.jedis.Protocol.toByteArray;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static redis.clients.jedis.Protocol.toByteArray;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
abstract class PipelineBase extends Queable implements
BinaryRedisPipeline,
abstract class PipelineBase extends Queable implements BinaryRedisPipeline,
RedisPipeline {
protected abstract Client getClient(String key);
@@ -144,6 +143,24 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.BOOLEAN);
}
public Response<Long> bitpos(final String key, final boolean value) {
return bitpos(key, value, new BitPosParams());
}
public Response<Long> bitpos(final String key, final boolean value, final BitPosParams params) {
getClient(key).bitpos(key, value, params);
return getResponse(BuilderFactory.LONG);
}
public Response<Long> bitpos(final byte[] key, final boolean value) {
return bitpos(key, value, new BitPosParams());
}
public Response<Long> bitpos(final byte[] key, final boolean value, final BitPosParams params) {
getClient(key).bitpos(key, value, params);
return getResponse(BuilderFactory.LONG);
}
public Response<String> getrange(String key, long startOffset,
long endOffset) {
getClient(key).getrange(key, startOffset, endOffset);
@@ -654,7 +671,7 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.LONG);
}
public Response<Long> zadd(String key, Map<Double, String> scoreMembers) {
public Response<Long> zadd(String key, Map<String, Double> scoreMembers) {
getClient(key).zadd(key, scoreMembers);
return getResponse(BuilderFactory.LONG);
}
@@ -738,14 +755,16 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.STRING_ZSET);
}
public Response<Set<String>> zrangeByScore(String key, String min, String max, int offset, int count) {
public Response<Set<String>> zrangeByScore(String key, String min,
String max, int offset, int count) {
getClient(key).zrangeByScore(key, min, max, offset, count);
return getResponse(BuilderFactory.STRING_ZSET);
}
public Response<Set<byte[]>> zrangeByScore(byte[] key, double min,
double max, int offset, int count) {
return zrangeByScore(key, toByteArray(min), toByteArray(max), offset, count);
return zrangeByScore(key, toByteArray(min), toByteArray(max), offset,
count);
}
public Response<Set<byte[]>> zrangeByScore(byte[] key, byte[] min,
@@ -791,7 +810,8 @@ abstract class PipelineBase extends Queable implements
public Response<Set<Tuple>> zrangeByScoreWithScores(byte[] key, double min,
double max, int offset, int count) {
getClient(key).zrangeByScoreWithScores(key, toByteArray(min), toByteArray(max), offset, count);
getClient(key).zrangeByScoreWithScores(key, toByteArray(min),
toByteArray(max), offset, count);
return getResponse(BuilderFactory.TUPLE_ZSET_BINARY);
}
@@ -809,7 +829,8 @@ abstract class PipelineBase extends Queable implements
public Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max,
double min) {
getClient(key).zrevrangeByScore(key, toByteArray(max), toByteArray(min));
getClient(key)
.zrevrangeByScore(key, toByteArray(max), toByteArray(min));
return getResponse(BuilderFactory.BYTE_ARRAY_ZSET);
}
@@ -839,7 +860,8 @@ abstract class PipelineBase extends Queable implements
public Response<Set<byte[]>> zrevrangeByScore(byte[] key, double max,
double min, int offset, int count) {
getClient(key).zrevrangeByScore(key, toByteArray(max), toByteArray(min), offset, count);
getClient(key).zrevrangeByScore(key, toByteArray(max),
toByteArray(min), offset, count);
return getResponse(BuilderFactory.BYTE_ARRAY_ZSET);
}
@@ -863,7 +885,8 @@ abstract class PipelineBase extends Queable implements
public Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
double max, double min) {
getClient(key).zrevrangeByScoreWithScores(key, toByteArray(max), toByteArray(min));
getClient(key).zrevrangeByScoreWithScores(key, toByteArray(max),
toByteArray(min));
return getResponse(BuilderFactory.TUPLE_ZSET_BINARY);
}
@@ -887,7 +910,8 @@ abstract class PipelineBase extends Queable implements
public Response<Set<Tuple>> zrevrangeByScoreWithScores(byte[] key,
double max, double min, int offset, int count) {
getClient(key).zrevrangeByScoreWithScores(key, toByteArray(max), toByteArray(min), offset, count);
getClient(key).zrevrangeByScoreWithScores(key, toByteArray(max),
toByteArray(min), offset, count);
return getResponse(BuilderFactory.TUPLE_ZSET_BINARY);
}
@@ -897,12 +921,14 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.TUPLE_ZSET_BINARY);
}
public Response<Set<Tuple>> zrangeWithScores(String key, long start, long end) {
public Response<Set<Tuple>> zrangeWithScores(String key, long start,
long end) {
getClient(key).zrangeWithScores(key, start, end);
return getResponse(BuilderFactory.TUPLE_ZSET);
}
public Response<Set<Tuple>> zrangeWithScores(byte[] key, long start, long end) {
public Response<Set<Tuple>> zrangeWithScores(byte[] key, long start,
long end) {
getClient(key).zrangeWithScores(key, start, end);
return getResponse(BuilderFactory.TUPLE_ZSET_BINARY);
}
@@ -948,7 +974,8 @@ abstract class PipelineBase extends Queable implements
}
public Response<Long> zremrangeByScore(byte[] key, double start, double end) {
getClient(key).zremrangeByScore(key, toByteArray(start), toByteArray(end));
getClient(key).zremrangeByScore(key, toByteArray(start),
toByteArray(end));
return getResponse(BuilderFactory.LONG);
}
@@ -1029,12 +1056,14 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.BYTE_ARRAY);
}
public Response<String> migrate(String host, int port, String key, int destinationDb, int timeout) {
public Response<String> migrate(String host, int port, String key,
int destinationDb, int timeout) {
getClient(key).migrate(host, port, key, destinationDb, timeout);
return getResponse(BuilderFactory.STRING);
}
public Response<String> migrate(byte[] host, int port, byte[] key, int destinationDb, int timeout) {
public Response<String> migrate(byte[] host, int port, byte[] key,
int destinationDb, int timeout) {
getClient(key).migrate(host, port, key, destinationDb, timeout);
return getResponse(BuilderFactory.STRING);
}
@@ -1069,12 +1098,22 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.LONG);
}
@Deprecated
public Response<Long> pexpire(String key, int milliseconds) {
return pexpire(key, (long) milliseconds);
}
@Deprecated
public Response<Long> pexpire(byte[] key, int milliseconds) {
return pexpire(key, (long) milliseconds);
}
public Response<Long> pexpire(String key, long milliseconds) {
getClient(key).pexpire(key, milliseconds);
return getResponse(BuilderFactory.LONG);
}
public Response<Long> pexpire(byte[] key, int milliseconds) {
public Response<Long> pexpire(byte[] key, long milliseconds) {
getClient(key).pexpire(key, milliseconds);
return getResponse(BuilderFactory.LONG);
}
@@ -1139,22 +1178,26 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.STRING);
}
public Response<String> set(String key, String value, String nxxx, String expx, int time) {
public Response<String> set(String key, String value, String nxxx,
String expx, int time) {
getClient(key).set(key, value, nxxx, expx, time);
return getResponse(BuilderFactory.STRING);
}
public Response<String> set(byte[] key, byte[] value, byte[] nxxx, byte[] expx, int time) {
public Response<String> set(byte[] key, byte[] value, byte[] nxxx,
byte[] expx, int time) {
getClient(key).set(key, value, nxxx, expx, time);
return getResponse(BuilderFactory.STRING);
}
public Response<Double> hincrByFloat(String key, String field, double increment) {
public Response<Double> hincrByFloat(String key, String field,
double increment) {
getClient(key).hincrByFloat(key, field, increment);
return getResponse(BuilderFactory.DOUBLE);
}
public Response<Double> hincrByFloat(byte[] key, byte[] field, double increment) {
public Response<Double> hincrByFloat(byte[] key, byte[] field,
double increment) {
getClient(key).hincrByFloat(key, field, increment);
return getResponse(BuilderFactory.DOUBLE);
}
@@ -1163,7 +1206,8 @@ abstract class PipelineBase extends Queable implements
return this.eval(script, 0, new String[0]);
}
public Response<String> eval(String script, List<String> keys, List<String> args) {
public Response<String> eval(String script, List<String> keys,
List<String> args) {
String[] argv = Jedis.getParams(keys, args);
return this.eval(script, keys.size(), argv);
}
@@ -1177,7 +1221,8 @@ abstract class PipelineBase extends Queable implements
return this.evalsha(script, 0, new String[0]);
}
public Response<String> evalsha(String sha1, List<String> keys, List<String> args) {
public Response<String> evalsha(String sha1, List<String> keys,
List<String> args) {
String[] argv = Jedis.getParams(keys, args);
return this.evalsha(sha1, keys.size(), argv);
}
@@ -1187,5 +1232,28 @@ abstract class PipelineBase extends Queable implements
return getResponse(BuilderFactory.STRING);
}
@Override
public Response<Long> pfadd(byte[] key, byte[]... elements) {
getClient(key).pfadd(key, elements);
return getResponse(BuilderFactory.LONG);
}
@Override
public Response<Long> pfcount(byte[] key) {
getClient(key).pfcount(key);
return getResponse(BuilderFactory.LONG);
}
@Override
public Response<Long> pfadd(String key, String... elements) {
getClient(key).pfadd(key, elements);
return getResponse(BuilderFactory.LONG);
}
@Override
public Response<Long> pfcount(String key) {
getClient(key).pfcount(key);
return getResponse(BuilderFactory.LONG);
}
}

View File

@@ -1,6 +1,11 @@
package redis.clients.jedis;
@Deprecated
/**
* This method is deprecated due to its error prone with multi
* and will be removed on next major release
* @see https://github.com/xetorthio/jedis/pull/498
*/
public abstract class PipelineBlock extends Pipeline {
// For shadowing
@SuppressWarnings("unused")

View File

@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.List;
import redis.clients.jedis.exceptions.JedisAskDataException;
import redis.clients.jedis.exceptions.JedisClusterException;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisMovedDataException;
@@ -16,6 +17,7 @@ public final class Protocol {
private static final String ASK_RESPONSE = "ASK";
private static final String MOVED_RESPONSE = "MOVED";
private static final String CLUSTERDOWN_RESPONSE = "CLUSTERDOWN";
public static final int DEFAULT_PORT = 6379;
public static final int DEFAULT_SENTINEL_PORT = 26379;
public static final int DEFAULT_TIMEOUT = 2000;
@@ -33,6 +35,10 @@ public final class Protocol {
public static final String SENTINEL_GET_MASTER_ADDR_BY_NAME = "get-master-addr-by-name";
public static final String SENTINEL_RESET = "reset";
public static final String SENTINEL_SLAVES = "slaves";
public static final String SENTINEL_FAILOVER = "failover";
public static final String SENTINEL_MONITOR = "monitor";
public static final String SENTINEL_REMOVE = "remove";
public static final String SENTINEL_SET = "set";
public static final String CLUSTER_NODES = "nodes";
public static final String CLUSTER_MEET = "meet";
@@ -44,6 +50,18 @@ public final class Protocol {
public static final String CLUSTER_SETSLOT_NODE = "node";
public static final String CLUSTER_SETSLOT_MIGRATING = "migrating";
public static final String CLUSTER_SETSLOT_IMPORTING = "importing";
public static final String CLUSTER_SETSLOT_STABLE = "stable";
public static final String CLUSTER_FORGET = "forget";
public static final String CLUSTER_FLUSHSLOT = "flushslots";
public static final String CLUSTER_KEYSLOT = "keyslot";
public static final String CLUSTER_COUNTKEYINSLOT = "countkeysinslot";
public static final String CLUSTER_SAVECONFIG = "saveconfig";
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 PUBSUB_CHANNELS= "channels";
public static final String PUBSUB_NUMSUB = "numsub";
public static final String PUBSUB_NUM_PAT = "numpat";
private Protocol() {
// this prevent the class from instantiation
@@ -77,19 +95,26 @@ public final class Protocol {
private static void processError(final RedisInputStream is) {
String message = is.readLine();
//TODO: I'm not sure if this is the best way to do this.
//Maybe Read only first 5 bytes instead?
// TODO: I'm not sure if this is the best way to do this.
// Maybe Read only first 5 bytes instead?
if (message.startsWith(MOVED_RESPONSE)) {
String[] movedInfo = parseTargetHostAndSlot(message);
throw new JedisMovedDataException(message, new HostAndPort(movedInfo[1], Integer.valueOf(movedInfo[2])), Integer.valueOf(movedInfo[0]));
throw new JedisMovedDataException(message, new HostAndPort(
movedInfo[1], Integer.valueOf(movedInfo[2])),
Integer.valueOf(movedInfo[0]));
} else if (message.startsWith(ASK_RESPONSE)) {
String[] askInfo = parseTargetHostAndSlot(message);
throw new JedisAskDataException(message, new HostAndPort(askInfo[1], Integer.valueOf(askInfo[2])), Integer.valueOf(askInfo[0]));
throw new JedisAskDataException(message, new HostAndPort(
askInfo[1], Integer.valueOf(askInfo[2])),
Integer.valueOf(askInfo[0]));
} else if (message.startsWith(CLUSTERDOWN_RESPONSE)) {
throw new JedisClusterException(message);
}
throw new JedisDataException(message);
}
private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) {
private static String[] parseTargetHostAndSlot(
String clusterRedirectResponse) {
String[] response = new String[3];
String[] messageInfo = clusterRedirectResponse.split(" ");
String[] targetHostAndPort = messageInfo[2].split(":");
@@ -136,7 +161,8 @@ public final class Protocol {
while (offset < len) {
int size = is.read(read, offset, (len - offset));
if (size == -1)
throw new JedisConnectionException("It seems like server has closed the connection.");
throw new JedisConnectionException(
"It seems like server has closed the connection.");
offset += size;
}
// read 2 more bytes for the command delimiter
@@ -191,7 +217,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, 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, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, BITPOS, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT, BITCOUNT, BITOP, SENTINEL, DUMP, RESTORE, PEXPIRE, PEXPIREAT, PTTL, INCRBYFLOAT, PSETEX, CLIENT, TIME, MIGRATE, HINCRBYFLOAT, SCAN, HSCAN, SSCAN, ZSCAN, WAIT, CLUSTER, ASKING, PFADD, PFCOUNT, PFMERGE;
public final byte[] raw;
@@ -201,8 +227,7 @@ public final class Protocol {
}
public static enum Keyword {
AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME, AND, OR, XOR, NOT,
GETNAME, SETNAME,LIST, MATCH, COUNT;
AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME, AND, OR, XOR, NOT, GETNAME, SETNAME, LIST, MATCH, COUNT;
public final byte[] raw;
Keyword() {

View File

@@ -32,10 +32,7 @@ public interface RedisPipeline {
Response<Boolean> getbit(String key, long offset);
Response<String> getrange(String key, long startOffset,
long endOffset);
Response<String> getrange(String key, long startOffset, long endOffset);
Response<String> getSet(String key, String value);
@@ -118,8 +115,7 @@ public interface RedisPipeline {
Response<List<String>> sort(String key);
Response<List<String>> sort(String key,
SortingParams sortingParameters);
Response<List<String>> sort(String key, SortingParams sortingParameters);
Response<String> spop(String key);
@@ -145,14 +141,12 @@ public interface RedisPipeline {
Response<Set<String>> zrange(String key, long start, long end);
Response<Set<String>> zrangeByScore(String key, double min,
double max);
Response<Set<String>> zrangeByScore(String key, double min, double max);
Response<Set<String>> zrangeByScore(String key, String min,
String max);
Response<Set<String>> zrangeByScore(String key, String min, String max);
Response<Set<String>> zrangeByScore(String key, double min,
double max, int offset, int count);
Response<Set<String>> zrangeByScore(String key, double min, double max,
int offset, int count);
Response<Set<Tuple>> zrangeByScoreWithScores(String key, double min,
double max);
@@ -160,21 +154,19 @@ public interface RedisPipeline {
Response<Set<Tuple>> zrangeByScoreWithScores(String key, double min,
double max, int offset, int count);
Response<Set<String>> zrevrangeByScore(String key, double max,
Response<Set<String>> zrevrangeByScore(String key, double max, double min);
Response<Set<String>> zrevrangeByScore(String key, String max, String min);
Response<Set<String>> zrevrangeByScore(String key, double max, double min,
int offset, int count);
Response<Set<Tuple>> zrevrangeByScoreWithScores(String key, double max,
double min);
Response<Set<String>> zrevrangeByScore(String key, String max,
String min);
Response<Set<String>> zrevrangeByScore(String key, double max,
Response<Set<Tuple>> zrevrangeByScoreWithScores(String key, double max,
double min, int offset, int count);
Response<Set<Tuple>> zrevrangeByScoreWithScores(String key,
double max, double min);
Response<Set<Tuple>> zrevrangeByScoreWithScores(String key,
double max, double min, int offset, int count);
Response<Set<Tuple>> zrangeWithScores(String key, long start, long end);
Response<Long> zrank(String key, String member);
@@ -187,8 +179,7 @@ public interface RedisPipeline {
Response<Set<String>> zrevrange(String key, long start, long end);
Response<Set<Tuple>> zrevrangeWithScores(String key, long start,
long end);
Response<Set<Tuple>> zrevrangeWithScores(String key, long start, long end);
Response<Long> zrevrank(String key, String member);
@@ -197,4 +188,8 @@ public interface RedisPipeline {
Response<Long> bitcount(String key);
Response<Long> bitcount(String key, long start, long end);
Response<Long> pfadd(final String key, final String... elements);
Response<Long> pfcount(final String key);
}

View File

@@ -8,6 +8,8 @@ public class Response<T> {
private boolean set = false;
private Builder<T> builder;
private Object data;
private Response<?> dependency = null;
private boolean requestDependencyBuild = false;
public Response(Builder<T> b) {
this.builder = b;
@@ -19,22 +21,38 @@ public class Response<T> {
}
public T get() {
// if response has dependency response and dependency is not built,
// build it first and no more!!
if (!requestDependencyBuild && dependency != null && dependency.set
&& !dependency.built) {
requestDependencyBuild = true;
dependency.build();
}
if (!set) {
throw new JedisDataException(
"Please close pipeline or multi block before calling this method.");
}
if (!built) {
if(data != null ){
if (data instanceof JedisDataException){
throw new JedisDataException((JedisDataException)data);
build();
}
return response;
}
public void setDependency(Response<?> dependency) {
this.dependency = dependency;
this.requestDependencyBuild = false;
}
private void build() {
if (data != null) {
if (data instanceof JedisDataException) {
throw new JedisDataException((JedisDataException) data);
}
response = builder.build(data);
}
this.data = null;
data = null;
built = true;
}
return response;
}
public String toString() {
return "Response " + builder.toString();

View File

@@ -12,15 +12,25 @@ import redis.clients.util.SafeEncoder;
public class ScanParams {
private List<byte[]> params = new ArrayList<byte[]>();
public final static String SCAN_POINTER_START = String.valueOf(0);
public final static byte[] SCAN_POINTER_START_BINARY = SafeEncoder.encode(SCAN_POINTER_START);
public void match(final String pattern) {
public ScanParams match(final byte[] pattern) {
params.add(MATCH.raw);
params.add(SafeEncoder.encode(pattern));
params.add(pattern);
return this;
}
public void count(final int count) {
public ScanParams match(final String pattern) {
params.add(MATCH.raw);
params.add(SafeEncoder.encode(pattern));
return this;
}
public ScanParams count(final int count) {
params.add(COUNT.raw);
params.add(Protocol.toByteArray(count));
return this;
}
public Collection<byte[]> getParams() {

View File

@@ -2,16 +2,50 @@ package redis.clients.jedis;
import java.util.List;
import redis.clients.util.SafeEncoder;
public class ScanResult<T> {
private int cursor;
private byte[] cursor;
private List<T> 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<T> results) {
this(Protocol.toByteArray(cursor), results);
}
public ScanResult(String cursor, List<T> results) {
this(SafeEncoder.encode(cursor), results);
}
public ScanResult(byte[] cursor, List<T> 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(getStringCursor());
}
/**
* FIXME: This method should be changed to getCursor() on next major release
*/
public String getStringCursor() {
return SafeEncoder.encode(cursor);
}
public byte[] getCursorAsBytes() {
return cursor;
}

View File

@@ -0,0 +1,22 @@
package redis.clients.jedis;
import java.util.List;
import java.util.Map;
public interface SentinelCommands {
public List<Map<String, String>> sentinelMasters();
public List<String> sentinelGetMasterAddrByName(String masterName);
public Long sentinelReset(String pattern);
public List<Map<String, String>> sentinelSlaves(String masterName);
public String sentinelFailover(String masterName);
public String sentinelMonitor(String masterName, String ip, int port, int quorum);
public String sentinelRemove(String masterName);
public String sentinelSet(String masterName, Map<String, String> parameterMap);
}

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis;
import java.io.Closeable;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import redis.clients.util.Hashing;
@@ -9,7 +10,13 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
import redis.clients.util.Pool;
public class ShardedJedis extends BinaryShardedJedis implements JedisCommands,
Closeable {
protected Pool<ShardedJedis> dataSource = null;
public ShardedJedis(List<JedisShardInfo> shards) {
super(shards);
}
@@ -32,6 +39,13 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
return j.set(key, value);
}
@Override
public String set(String key, String value, String nxxx, String expx,
long time) {
Jedis j = getShard(key);
return j.set(key, value, nxxx, expx, time);
}
public String get(String key) {
Jedis j = getShard(key);
return j.get(key);
@@ -132,6 +146,11 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
return j.incrBy(key, integer);
}
public Double incrByFloat(String key, double integer) {
Jedis j = getShard(key);
return j.incrByFloat(key, integer);
}
public Long incr(String key) {
Jedis j = getShard(key);
return j.incr(key);
@@ -177,6 +196,11 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
return j.hincrBy(key, field, value);
}
public Double hincrByFloat(String key, String field, double value) {
Jedis j = getShard(key);
return j.hincrByFloat(key, field, value);
}
public Boolean hexists(String key, String field) {
Jedis j = getShard(key);
return j.hexists(key, field);
@@ -327,7 +351,7 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
return j.zadd(key, score, member);
}
public Long zadd(String key, Map<Double, String> scoreMembers) {
public Long zadd(String key, Map<String, Double> scoreMembers) {
Jedis j = getShard(key);
return j.zadd(key, scoreMembers);
}
@@ -523,18 +547,96 @@ 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<Entry<String, String>> 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<String> 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<Tuple> zscan(String key, int cursor) {
Jedis j = getShard(key);
return j.zscan(key, cursor);
}
public ScanResult<Entry<String, String>> hscan(String key,
final String cursor) {
Jedis j = getShard(key);
return j.hscan(key, cursor);
}
public ScanResult<String> sscan(String key, final String cursor) {
Jedis j = getShard(key);
return j.sscan(key, cursor);
}
public ScanResult<Tuple> zscan(String key, final String cursor) {
Jedis j = getShard(key);
return j.zscan(key, cursor);
}
@Override
public void close() {
if (dataSource != null) {
boolean broken = false;
for (Jedis jedis : getAllShards()) {
if (jedis.getClient().isBroken()) {
broken = true;
}
}
if (broken) {
dataSource.returnBrokenResource(this);
} else {
this.resetState();
dataSource.returnResource(this);
}
} else {
disconnect();
}
}
public void setDataSource(Pool<ShardedJedis> shardedJedisPool) {
this.dataSource = shardedJedisPool;
}
public void resetState() {
for (Jedis jedis : getAllShards()) {
jedis.resetState();
}
}
public Long pfadd(String key, String... elements) {
Jedis j = getShard(key);
return j.pfadd(key, elements);
}
@Override
public long pfcount(String key) {
Jedis j = getShard(key);
return j.pfcount(key);
}
}

View File

@@ -48,8 +48,8 @@ public class ShardedJedisPipeline extends PipelineBase {
/**
* Syncronize pipeline by reading all responses. This operation closes the
* pipeline. Whenever possible try to avoid using this version and use
* ShardedJedisPipeline.sync() as it won't go through all the responses and generate the
* right response type (usually it is a waste of time).
* ShardedJedisPipeline.sync() as it won't go through all the responses and
* generate the right response type (usually it is a waste of time).
*
* @return A list of all the responses in the order you executed them.
*/
@@ -62,8 +62,8 @@ public class ShardedJedisPipeline extends PipelineBase {
}
/**
* This method will be removed in Jedis 3.0. Use the methods that return Response's and call
* sync().
* This method will be removed in Jedis 3.0. Use the methods that return
* Response's and call sync().
*/
@Deprecated
public void execute() {

View File

@@ -32,6 +32,28 @@ public class ShardedJedisPool extends Pool<ShardedJedis> {
super(poolConfig, new ShardedJedisFactory(shards, algo, keyTagPattern));
}
@Override
public ShardedJedis getResource() {
ShardedJedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
@Override
public void returnBrokenResource(final ShardedJedis resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
@Override
public void returnResource(final ShardedJedis resource) {
if (resource != null) {
resource.resetState();
returnResourceObject(resource);
}
}
/**
* PoolableObjectFactory custom impl.
*/

View File

@@ -6,13 +6,14 @@ import java.util.List;
import redis.clients.jedis.exceptions.JedisDataException;
/**
* Transaction is nearly identical to Pipeline, only differences are the multi/discard behaviors
* Transaction is nearly identical to Pipeline, only differences are the
* multi/discard behaviors
*/
public class Transaction extends MultiKeyPipelineBase {
protected boolean inTransaction = true;
protected Transaction(){
protected Transaction() {
// client will be set later in transaction block
}
@@ -30,10 +31,15 @@ public class Transaction extends MultiKeyPipelineBase {
return client;
}
public void clear() {
if (inTransaction) {
discard();
}
}
public List<Object> exec() {
// Discard QUEUED or ERROR
client.getMany(getPipelinedResponseLength());
client.exec();
List<Object> unformatted = client.getObjectMultiBulkReply();
@@ -54,7 +60,6 @@ public class Transaction extends MultiKeyPipelineBase {
public List<Response<?>> execGetResponse() {
// Discard QUEUED or ERROR
client.getMany(getPipelinedResponseLength());
client.exec();
List<Object> unformatted = client.getObjectMultiBulkReply();

View File

@@ -2,6 +2,12 @@ package redis.clients.jedis;
import redis.clients.jedis.exceptions.JedisException;
@Deprecated
/**
* This class is deprecated due to its error prone
* and will be removed on next major release
* @see https://github.com/xetorthio/jedis/pull/498
*/
public abstract class TransactionBlock extends Transaction {
// For shadowing
@SuppressWarnings("unused")

View File

@@ -5,15 +5,18 @@ import redis.clients.jedis.HostAndPort;
public class JedisAskDataException extends JedisRedirectionException {
private static final long serialVersionUID = 3878126572474819403L;
public JedisAskDataException(Throwable cause, HostAndPort targetHost, int slot) {
public JedisAskDataException(Throwable cause, HostAndPort targetHost,
int slot) {
super(cause, targetHost, slot);
}
public JedisAskDataException(String message, Throwable cause, HostAndPort targetHost, int slot) {
public JedisAskDataException(String message, Throwable cause,
HostAndPort targetHost, int slot) {
super(message, cause, targetHost, slot);
}
public JedisAskDataException(String message, HostAndPort targetHost, int slot) {
public JedisAskDataException(String message, HostAndPort targetHost,
int slot) {
super(message, targetHost, slot);
}

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis.exceptions;
public class JedisClusterException extends JedisDataException {
private static final long serialVersionUID = 3878126572474819403L;

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis.exceptions;
public class JedisClusterMaxRedirectionsException extends JedisDataException {
private static final long serialVersionUID = 3878126572474819403L;

View File

@@ -1,6 +1,5 @@
package redis.clients.jedis.exceptions;
public class JedisException extends RuntimeException {
private static final long serialVersionUID = -2946266495682282677L;

View File

@@ -2,20 +2,21 @@ package redis.clients.jedis.exceptions;
import redis.clients.jedis.HostAndPort;
public class JedisMovedDataException extends JedisRedirectionException {
private static final long serialVersionUID = 3878126572474819403L;
public JedisMovedDataException(String message, HostAndPort targetNode, int slot) {
public JedisMovedDataException(String message, HostAndPort targetNode,
int slot) {
super(message, targetNode, slot);
}
public JedisMovedDataException(Throwable cause, HostAndPort targetNode, int slot) {
public JedisMovedDataException(Throwable cause, HostAndPort targetNode,
int slot) {
super(cause, targetNode, slot);
}
public JedisMovedDataException(String message, Throwable cause, HostAndPort targetNode, int slot) {
public JedisMovedDataException(String message, Throwable cause,
HostAndPort targetNode, int slot) {
super(message, cause, targetNode, slot);
}
}

View File

@@ -2,26 +2,28 @@ package redis.clients.jedis.exceptions;
import redis.clients.jedis.HostAndPort;
public class JedisRedirectionException extends JedisDataException {
private static final long serialVersionUID = 3878126572474819403L;
private HostAndPort targetNode;
private int slot;
public JedisRedirectionException(String message, HostAndPort targetNode, int slot) {
public JedisRedirectionException(String message, HostAndPort targetNode,
int slot) {
super(message);
this.targetNode = targetNode;
this.slot = slot;
}
public JedisRedirectionException(Throwable cause, HostAndPort targetNode, int slot) {
public JedisRedirectionException(Throwable cause, HostAndPort targetNode,
int slot) {
super(cause);
this.targetNode = targetNode;
this.slot = slot;
}
public JedisRedirectionException(String message, Throwable cause, HostAndPort targetNode, int slot) {
public JedisRedirectionException(String message, Throwable cause,
HostAndPort targetNode, int slot) {
super(message, cause);
this.targetNode = targetNode;
this.slot = slot;

View File

@@ -0,0 +1,48 @@
package redis.clients.util;
import redis.clients.jedis.HostAndPort;
import java.util.ArrayList;
import java.util.List;
public class ClusterNodeInformation {
private HostAndPort node;
private List<Integer> availableSlots;
private List<Integer> slotsBeingImported;
private List<Integer> slotsBeingMigrated;
public ClusterNodeInformation(HostAndPort node) {
this.node = node;
this.availableSlots = new ArrayList<Integer>();
this.slotsBeingImported = new ArrayList<Integer>();
this.slotsBeingMigrated = new ArrayList<Integer>();
}
public void addAvailableSlot(int slot) {
availableSlots.add(slot);
}
public void addSlotBeingImported(int slot) {
slotsBeingImported.add(slot);
}
public void addSlotBeingMigrated(int slot) {
slotsBeingMigrated.add(slot);
}
public HostAndPort getNode() {
return node;
}
public List<Integer> getAvailableSlots() {
return availableSlots;
}
public List<Integer> getSlotsBeingImported() {
return slotsBeingImported;
}
public List<Integer> getSlotsBeingMigrated() {
return slotsBeingMigrated;
}
}

View File

@@ -0,0 +1,80 @@
package redis.clients.util;
import redis.clients.jedis.HostAndPort;
public class ClusterNodeInformationParser {
private static final String SLOT_IMPORT_IDENTIFIER = "-<-";
private static final String SLOT_IN_TRANSITION_IDENTIFIER = "[";
public static final int SLOT_INFORMATIONS_START_INDEX = 8;
public static final int HOST_AND_PORT_INDEX = 1;
public ClusterNodeInformation parse(String nodeInfo, HostAndPort current) {
String[] nodeInfoPartArray = nodeInfo.split(" ");
HostAndPort node = getHostAndPortFromNodeLine(nodeInfoPartArray,
current);
ClusterNodeInformation info = new ClusterNodeInformation(node);
if (nodeInfoPartArray.length >= SLOT_INFORMATIONS_START_INDEX) {
String[] slotInfoPartArray = extractSlotParts(nodeInfoPartArray);
fillSlotInformation(slotInfoPartArray, info);
}
return info;
}
private String[] extractSlotParts(String[] nodeInfoPartArray) {
String[] slotInfoPartArray = new String[nodeInfoPartArray.length
- SLOT_INFORMATIONS_START_INDEX];
for (int i = SLOT_INFORMATIONS_START_INDEX; i < nodeInfoPartArray.length; i++) {
slotInfoPartArray[i - SLOT_INFORMATIONS_START_INDEX] = nodeInfoPartArray[i];
}
return slotInfoPartArray;
}
public HostAndPort getHostAndPortFromNodeLine(String[] nodeInfoPartArray,
HostAndPort current) {
String stringHostAndPort = nodeInfoPartArray[HOST_AND_PORT_INDEX];
String[] arrayHostAndPort = stringHostAndPort.split(":");
return new HostAndPort(
arrayHostAndPort[0].isEmpty() ? current.getHost()
: arrayHostAndPort[0],
arrayHostAndPort[1].isEmpty() ? current.getPort() : Integer
.valueOf(arrayHostAndPort[1]));
}
private void fillSlotInformation(String[] slotInfoPartArray,
ClusterNodeInformation info) {
for (String slotRange : slotInfoPartArray) {
fillSlotInformationFromSlotRange(slotRange, info);
}
}
private void fillSlotInformationFromSlotRange(String slotRange,
ClusterNodeInformation info) {
if (slotRange.startsWith(SLOT_IN_TRANSITION_IDENTIFIER)) {
// slot is in transition
int slot = Integer.parseInt(slotRange.substring(1).split("-")[0]);
if (slotRange.contains(SLOT_IMPORT_IDENTIFIER)) {
// import
info.addSlotBeingImported(slot);
} else {
// migrate (->-)
info.addSlotBeingMigrated(slot);
}
} else if (slotRange.contains("-")) {
// slot range
String[] slotRangePart = slotRange.split("-");
for (int slot = Integer.valueOf(slotRangePart[0]); slot <= Integer
.valueOf(slotRangePart[1]); slot++) {
info.addAvailableSlot(slot);
}
} else {
// single slot
info.addAvailableSlot(Integer.valueOf(slotRange));
}
}
}

View File

@@ -69,8 +69,8 @@ public class JedisByteHashMap implements Map<byte[], byte[]>, Cloneable,
while (iterator.hasNext()) {
Entry<? extends byte[], ? extends byte[]> next = (Entry<? extends byte[], ? extends byte[]>) iterator
.next();
internalMap.put(new ByteArrayWrapper(next.getKey()), next
.getValue());
internalMap.put(new ByteArrayWrapper(next.getKey()),
next.getValue());
}
}

View File

@@ -2,20 +2,33 @@ package redis.clients.util;
public class JedisClusterCRC16 {
public final static int polynomial = 0x1021; // Represents x^16+x^12+x^5+1
static int crc;
public static int getSlot(String key) {
crc = 0x0000;
int s = key.indexOf("{");
if (s > -1) {
int e = key.indexOf("}", s+1);
if (e > -1 && e != s+1) {
key = key.substring(s+1, e);
}
}
return getCRC16(key) % 16384;
}
private static int getCRC16(String key) {
int crc = 0x0000;
for (byte b : key.getBytes()) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7-i) & 1) == 1);
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((crc >> 15 & 1) == 1);
crc <<= 1;
// If coefficient of bit and remainder polynomial = 1 xor crc with polynomial
if (c15 ^ bit) crc ^= polynomial;
// If coefficient of bit and remainder polynomial = 1 xor crc
// with polynomial
if (c15 ^ bit)
crc ^= polynomial;
}
}
return crc &= 0xffff % 16384;
return crc &= 0xffff ;
}
}

View File

@@ -45,6 +45,9 @@ public abstract class Pool<T> {
}
public void returnResourceObject(final T resource) {
if (resource == null) {
return;
}
try {
internalPool.returnObject(resource);
} catch (Exception e) {
@@ -54,12 +57,16 @@ public abstract class Pool<T> {
}
public void returnBrokenResource(final T resource) {
if (resource != null) {
returnBrokenResourceObject(resource);
}
}
public void returnResource(final T resource) {
if (resource != null) {
returnResourceObject(resource);
}
}
public void destroy() {
closeInternalPool();

View File

@@ -1,11 +1,13 @@
package redis.clients.util;
import java.io.*;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* The class implements a buffered output stream without synchronization
* There are also special operations like in-place string encoding.
* This stream fully ignore mark/reset and should not be used outside Jedis
* The class implements a buffered output stream without synchronization There
* are also special operations like in-place string encoding. This stream fully
* ignore mark/reset and should not be used outside Jedis
*/
public final class RedisOutputStream extends FilterOutputStream {
protected final byte buf[];
@@ -32,17 +34,18 @@ public final class RedisOutputStream extends FilterOutputStream {
}
public void write(final byte b) throws IOException {
buf[count++] = b;
if (count == buf.length) {
flushBuffer();
}
buf[count++] = b;
}
public void write(final byte[] b) throws IOException {
write(b, 0, b.length);
}
public void write(final byte b[], final int off, final int len) throws IOException {
public void write(final byte b[], final int off, final int len)
throws IOException {
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
@@ -60,10 +63,10 @@ public final class RedisOutputStream extends FilterOutputStream {
final int size = in.length();
for (int i = 0; i != size; ++i) {
buf[count++] = (byte) in.charAt(i);
if (count == buf.length) {
flushBuffer();
}
buf[count++] = (byte) in.charAt(i);
}
writeCrLf();
@@ -73,9 +76,9 @@ public final class RedisOutputStream extends FilterOutputStream {
return ch >= Character.MIN_SURROGATE && ch <= Character.MAX_SURROGATE;
}
public static int utf8Length (final String str) {
public static int utf8Length(final String str) {
int strLen = str.length(), utfLen = 0;
for(int i = 0; i != strLen; ++i) {
for (int i = 0; i != strLen; ++i) {
char c = str.charAt(i);
if (c < 0x80) {
utfLen++;
@@ -106,88 +109,80 @@ public final class RedisOutputStream extends FilterOutputStream {
int i;
for (i = 0; i < strLen; i++) {
char c = str.charAt(i);
if (!(c < 0x80)) break;
buf[count++] = (byte) c;
if(count == buf.length) {
if (!(c < 0x80))
break;
if (count == buf.length) {
flushBuffer();
}
buf[count++] = (byte) c;
}
for (; i < strLen; i++) {
char c = str.charAt(i);
if (c < 0x80) {
if (count == buf.length) {
flushBuffer();
}
buf[count++] = (byte) c;
if(count == buf.length) {
flushBuffer();
}
} else if (c < 0x800) {
if(2 >= buf.length - count) {
if (2 >= buf.length - count) {
flushBuffer();
}
buf[count++] = (byte)(0xc0 | (c >> 6));
buf[count++] = (byte)(0x80 | (c & 0x3f));
buf[count++] = (byte) (0xc0 | (c >> 6));
buf[count++] = (byte) (0x80 | (c & 0x3f));
} else if (isSurrogate(c)) {
if(4 >= buf.length - count) {
if (4 >= buf.length - count) {
flushBuffer();
}
int uc = Character.toCodePoint(c, str.charAt(i++));
buf[count++] = ((byte)(0xf0 | ((uc >> 18))));
buf[count++] = ((byte)(0x80 | ((uc >> 12) & 0x3f)));
buf[count++] = ((byte)(0x80 | ((uc >> 6) & 0x3f)));
buf[count++] = ((byte)(0x80 | (uc & 0x3f)));
buf[count++] = ((byte) (0xf0 | ((uc >> 18))));
buf[count++] = ((byte) (0x80 | ((uc >> 12) & 0x3f)));
buf[count++] = ((byte) (0x80 | ((uc >> 6) & 0x3f)));
buf[count++] = ((byte) (0x80 | (uc & 0x3f)));
} else {
if(3 >= buf.length - count) {
if (3 >= buf.length - count) {
flushBuffer();
}
buf[count++] =((byte)(0xe0 | ((c >> 12))));
buf[count++] =((byte)(0x80 | ((c >> 6) & 0x3f)));
buf[count++] =((byte)(0x80 | (c & 0x3f)));
buf[count++] = ((byte) (0xe0 | ((c >> 12))));
buf[count++] = ((byte) (0x80 | ((c >> 6) & 0x3f)));
buf[count++] = ((byte) (0x80 | (c & 0x3f)));
}
}
writeCrLf();
}
private final static int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE};
private final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999,
9999999, 99999999, 999999999, Integer.MAX_VALUE };
private final static byte[] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
};
private final static byte[] DigitTens = { '0', '0', '0', '0', '0', '0',
'0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3',
'3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4',
'4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5',
'5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8',
'8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9',
'9', '9', '9', };
private final static byte[] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
};
private final static byte[] DigitOnes = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1',
'2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', };
private final static byte[] digits = {
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
};
private final static byte[] digits = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z' };
public void writeIntCrLf(int value) throws IOException {
if (value < 0) {
write('-');
write((byte) '-');
value = -value;
}
@@ -211,12 +206,13 @@ public final class RedisOutputStream extends FilterOutputStream {
buf[--charPos] = DigitTens[r];
}
for (; ;) {
for (;;) {
q = (value * 52429) >>> (16 + 3);
r = value - ((q << 3) + (q << 1));
buf[--charPos] = digits[r];
value = q;
if (value == 0) break;
if (value == 0)
break;
}
count += size;

View File

@@ -11,9 +11,9 @@ import redis.clients.jedis.exceptions.JedisException;
*
*/
public class SafeEncoder {
public static byte[][] encodeMany(final String... strs){
public static byte[][] encodeMany(final String... strs) {
byte[][] many = new byte[strs.length][];
for(int i=0;i<strs.length;i++){
for (int i = 0; i < strs.length; i++) {
many[i] = encode(strs[i]);
}
return many;

View File

@@ -57,11 +57,14 @@ public class Sharded<R, S extends ShardInfo<R>> {
final S shardInfo = shards.get(i);
if (shardInfo.getName() == null)
for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n),
shardInfo);
}
else
for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash(shardInfo.getName() + "*" + shardInfo.getWeight() + n), shardInfo);
nodes.put(
this.algo.hash(shardInfo.getName() + "*"
+ shardInfo.getWeight() + n), shardInfo);
}
resources.put(shardInfo, shardInfo.createResource());
}
@@ -113,4 +116,3 @@ public class Sharded<R, S extends ShardInfo<R>> {
return Collections.unmodifiableCollection(resources.values());
}
}

View File

@@ -10,10 +10,10 @@ public class Slowlog {
private final List<String> args;
@SuppressWarnings("unchecked")
public static List<Slowlog> from(List<Object> nestedMultiBulkReply){
public static List<Slowlog> from(List<Object> nestedMultiBulkReply) {
List<Slowlog> logs = new ArrayList<Slowlog>(nestedMultiBulkReply.size());
for(Object obj : nestedMultiBulkReply){
List<Object> properties = (List<Object>)obj;
for (Object obj : nestedMultiBulkReply) {
List<Object> properties = (List<Object>) obj;
logs.add(new Slowlog(properties));
}
@@ -23,14 +23,14 @@ public class Slowlog {
@SuppressWarnings("unchecked")
private Slowlog(List<Object> properties) {
super();
this.id = (Long)properties.get(0);
this.timeStamp = (Long)properties.get(1);
this.executionTime = (Long)properties.get(2);
this.id = (Long) properties.get(0);
this.timeStamp = (Long) properties.get(1);
this.executionTime = (Long) properties.get(2);
List<byte[]> bargs = (List<byte[]>)properties.get(3);
List<byte[]> bargs = (List<byte[]>) properties.get(3);
this.args = new ArrayList<String>(bargs.size());
for(byte[] barg:bargs){
for (byte[] barg : bargs) {
this.args.add(SafeEncoder.encode(barg));
}
}

View File

@@ -41,4 +41,11 @@ public class ConnectionTest extends Assert {
client.setTimeoutInfinite();
}
@Test
public void checkCloseable() {
client.setHost("localhost");
client.setPort(6379);
client.connect();
client.close();
}
}

View File

@@ -12,46 +12,25 @@ public class HostAndPortUtil {
private static List<HostAndPort> clusterHostAndPortList = new ArrayList<HostAndPort>();
static {
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 1));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 2));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 3));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 4));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 5));
redisHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_PORT + 6));
HostAndPort defaulthnp1 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT);
redisHostAndPortList.add(defaulthnp1);
HostAndPort defaulthnp2 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 1);
redisHostAndPortList.add(defaulthnp2);
HostAndPort defaulthnp3 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 2);
redisHostAndPortList.add(defaulthnp3);
HostAndPort defaulthnp4 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 3);
redisHostAndPortList.add(defaulthnp4);
HostAndPort defaulthnp5 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 4);
redisHostAndPortList.add(defaulthnp5);
HostAndPort defaulthnp6 = new HostAndPort("localhost",
Protocol.DEFAULT_PORT + 5);
redisHostAndPortList.add(defaulthnp6);
HostAndPort defaulthnp7 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT);
sentinelHostAndPortList.add(defaulthnp7);
HostAndPort defaulthnp8 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT + 1);
sentinelHostAndPortList.add(defaulthnp8);
HostAndPort defaulthnp9 = new HostAndPort("localhost",
Protocol.DEFAULT_SENTINEL_PORT + 2);
sentinelHostAndPortList.add(defaulthnp9);
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));
clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
clusterHostAndPortList.add(new HostAndPort("localhost", 7380));
clusterHostAndPortList.add(new HostAndPort("localhost", 7381));
clusterHostAndPortList.add(new HostAndPort("localhost", 7382));
clusterHostAndPortList.add(new HostAndPort("localhost", 7383));
clusterHostAndPortList.add(new HostAndPort("localhost", 7384));
clusterHostAndPortList.add(new HostAndPort("localhost", 7385));
String envRedisHosts = System.getProperty("redis-hosts");
String envSentinelHosts = System.getProperty("sentinel-hosts");

View File

@@ -0,0 +1,63 @@
package redis.clients.jedis.tests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.util.ClusterNodeInformation;
import redis.clients.util.ClusterNodeInformationParser;
public class JedisClusterNodeInformationParserTest extends Assert {
private ClusterNodeInformationParser parser;
@Before
public void setUp() {
parser = new ClusterNodeInformationParser();
}
@Test
public void testParseNodeMyself() {
String nodeInfo = "9b0d2ab38ee31482c95fdb2c7847a0d40e88d518 :7379 myself,master - 0 0 1 connected 0-5460";
HostAndPort current = new HostAndPort("localhost", 7379);
ClusterNodeInformation clusterNodeInfo = parser
.parse(nodeInfo, current);
assertEquals(clusterNodeInfo.getNode(), current);
}
@Test
public void testParseNormalState() {
String nodeInfo = "5f4a2236d00008fba7ac0dd24b95762b446767bd 192.168.0.3:7380 master - 0 1400598804016 2 connected 5461-10922";
HostAndPort current = new HostAndPort("localhost", 7379);
ClusterNodeInformation clusterNodeInfo = parser
.parse(nodeInfo, current);
assertNotEquals(clusterNodeInfo.getNode(), current);
assertEquals(clusterNodeInfo.getNode(), new HostAndPort("192.168.0.3",
7380));
for (int slot = 5461; slot <= 10922; slot++) {
assertTrue(clusterNodeInfo.getAvailableSlots().contains(slot));
}
assertTrue(clusterNodeInfo.getSlotsBeingImported().isEmpty());
assertTrue(clusterNodeInfo.getSlotsBeingMigrated().isEmpty());
}
@Test
public void testParseSlotBeingMigrated() {
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);
assertEquals(clusterNodeInfo.getNode(), current);
for (int slot = 0; slot <= 5459; slot++) {
assertTrue(clusterNodeInfo.getAvailableSlots().contains(slot));
}
assertEquals(1, clusterNodeInfo.getSlotsBeingMigrated().size());
assertTrue(clusterNodeInfo.getSlotsBeingMigrated().contains(5460));
assertEquals(1, clusterNodeInfo.getSlotsBeingImported().size());
assertTrue(clusterNodeInfo.getSlotsBeingImported().contains(5461));
}
}

View File

@@ -0,0 +1,167 @@
package redis.clients.jedis.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.tests.utils.JedisClusterTestUtil;
public class JedisClusterReplicateTest {
private static Jedis node5;
private static Jedis node6;
private HostAndPort nodeInfo5 = HostAndPortUtil.getClusterServers().get(4);
private HostAndPort nodeInfo6 = HostAndPortUtil.getClusterServers().get(5);
private static int TIMEOUT = 15000; // cluster-node-timeout * 3
@Before
public void setUp() throws InterruptedException {
node5 = new Jedis(nodeInfo5.getHost(), nodeInfo5.getPort(), TIMEOUT);
node5.connect();
node5.flushAll();
node6 = new Jedis(nodeInfo6.getHost(), nodeInfo6.getPort(), TIMEOUT);
node6.connect();
// cannot flushall - it will be slave
// ---- configure cluster
// add nodes to cluster
node5.clusterMeet("127.0.0.1", nodeInfo6.getPort());
JedisClusterTestUtil.assertNodeIsKnown(node5, JedisClusterTestUtil.getNodeId(node6.clusterNodes()), 1000);
JedisClusterTestUtil.assertNodeIsKnown(node6, JedisClusterTestUtil.getNodeId(node5.clusterNodes()), 1000);
// split available slots across the three nodes
int[] node5Slots = new int[JedisCluster.HASHSLOTS];
for (int i = 0 ; i < JedisCluster.HASHSLOTS; i++) {
node5Slots[i] = i;
}
node5.clusterAddSlots(node5Slots);
JedisClusterTestUtil.waitForClusterReady(node5);
// replicate full 1on1
node6.clusterReplicate(JedisClusterTestUtil.getNodeId(node5
.clusterNodes()));
Map<Jedis, Jedis> replMap = new HashMap<Jedis, Jedis>();
replMap.put(node5, node6);
waitForReplicateReady(replMap, TIMEOUT);
JedisClusterTestUtil.waitForClusterReady(node5, node6);
}
private void waitForReplicateReady(Map<Jedis, Jedis> replMap, int timeoutMs) {
int interval = 100;
for (int timeout = 0; timeout <= timeoutMs; timeout += interval) {
for (Entry<Jedis, Jedis> entry : replMap.entrySet()) {
Jedis master = entry.getKey();
Jedis slave = entry.getValue();
String masterNodeId = JedisClusterTestUtil.getNodeId(master
.clusterNodes());
String slaveNodeId = JedisClusterTestUtil.getNodeId(slave
.clusterNodes());
try {
List<String> slaves = master.clusterSlaves(masterNodeId);
if (slaves.size() > 0 && slaves.get(0).contains(slaveNodeId)) {
return;
}
} catch (JedisDataException e) {
if (!e.getMessage().startsWith("ERR The specified node is not a master"))
throw e;
// retry...
}
}
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
throw new JedisException("there seems to replication error");
}
@After
public void tearDown() throws InterruptedException {
// clear all slots
int[] slotsToDelete = new int[JedisCluster.HASHSLOTS];
for (int i = 0; i < JedisCluster.HASHSLOTS; i++) {
slotsToDelete[i] = i;
}
node5.clusterDelSlots(slotsToDelete);
}
@Test
public void testClusterReplicate() {
// we're already replicate 1on1
List<String> slaveInfos = node5.clusterSlaves(JedisClusterTestUtil
.getNodeId(node5.clusterNodes()));
assertEquals(1, slaveInfos.size());
assertTrue(slaveInfos.get(0).contains(
JedisClusterTestUtil.getNodeId(node6.clusterNodes())));
}
@Test
public void testClusterFailover() throws InterruptedException {
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort(nodeInfo5.getHost(), nodeInfo5.getPort()));
JedisCluster jc = new JedisCluster(jedisClusterNode);
jc.set("51", "foo");
// node5 is responsible of taking care of slot for key "51" (7186)
node6.clusterFailover();
try {
// wait for failover
Map<Jedis, Jedis> replMap = new HashMap<Jedis, Jedis>();
replMap.put(node6, node5);
waitForReplicateReady(replMap, TIMEOUT);
JedisClusterTestUtil.waitForClusterReady(node5, node6);
List<String> slaveInfos = node6.clusterSlaves(JedisClusterTestUtil
.getNodeId(node6.clusterNodes()));
assertEquals(1, slaveInfos.size());
assertTrue(slaveInfos.get(0).contains(
JedisClusterTestUtil.getNodeId(node5.clusterNodes())));
} finally {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// rollback
node5.clusterFailover();
Map<Jedis, Jedis> replMap = new HashMap<Jedis, Jedis>();
replMap.put(node5, node6);
waitForReplicateReady(replMap, TIMEOUT);
JedisClusterTestUtil.waitForClusterReady(node5, node6);
}
}
}

View File

@@ -1,9 +1,12 @@
package redis.clients.jedis.tests;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -11,21 +14,24 @@ import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.exceptions.JedisAskDataException;
import redis.clients.jedis.exceptions.JedisClusterException;
import redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.jedis.exceptions.JedisMovedDataException;
import redis.clients.jedis.tests.utils.JedisClusterTestUtil;
import redis.clients.util.JedisClusterCRC16;
public class JedisClusterTest extends Assert {
private Jedis node1;
private Jedis node2;
private Jedis node3;
private static Jedis node1;
private static Jedis node2;
private static Jedis node3;
private static Jedis node4;
private HostAndPort nodeInfo1 = HostAndPortUtil.getClusterServers().get(0);
private HostAndPort nodeInfo2 = HostAndPortUtil.getClusterServers().get(1);
private HostAndPort nodeInfo3 = HostAndPortUtil.getClusterServers().get(2);
private HostAndPort nodeInfo4 = HostAndPortUtil.getClusterServers().get(3);
@Before
public void setUp() throws InterruptedException {
@@ -41,44 +47,82 @@ public class JedisClusterTest extends Assert {
node3.connect();
node3.flushAll();
node4 = new Jedis(nodeInfo4.getHost(), nodeInfo4.getPort());
node4.connect();
node4.flushAll();
// ---- configure cluster
// add nodes to cluster
node1.clusterMeet("127.0.0.1", nodeInfo1.getPort());
node1.clusterMeet("127.0.0.1", nodeInfo2.getPort());
node1.clusterMeet("127.0.0.1", nodeInfo3.getPort());
// split available slots across the three nodes
int slotsPerNode = JedisCluster.HASHSLOTS / 3;
Pipeline pipeline1 = node1.pipelined();
Pipeline pipeline2 = node2.pipelined();
Pipeline pipeline3 = node3.pipelined();
for (int i = 0; i < JedisCluster.HASHSLOTS; i++) {
int[] node1Slots = new int[slotsPerNode];
int[] node2Slots = new int[slotsPerNode+1];
int[] node3Slots = new int[slotsPerNode];
for (int i = 0, slot1 = 0, slot2 = 0, slot3 = 0 ; i < JedisCluster.HASHSLOTS; i++) {
if (i < slotsPerNode) {
pipeline1.clusterAddSlots(i);
node1Slots[slot1++] = i;
} else if (i > slotsPerNode * 2) {
pipeline3.clusterAddSlots(i);
node3Slots[slot3++] = i;
} else {
pipeline2.clusterAddSlots(i);
node2Slots[slot2++] = i;
}
}
pipeline1.sync();
pipeline2.sync();
pipeline3.sync();
waitForClusterReady();
node1.clusterAddSlots(node1Slots);
node2.clusterAddSlots(node2Slots);
node3.clusterAddSlots(node3Slots);
JedisClusterTestUtil.waitForClusterReady(node1, node2, node3);
}
@AfterClass
public static void cleanUp() {
int slotTest = JedisClusterCRC16.getSlot("test");
int slot51 = JedisClusterCRC16.getSlot("51");
String node1Id = JedisClusterTestUtil.getNodeId(node1.clusterNodes());
String node2Id = JedisClusterTestUtil.getNodeId(node2.clusterNodes());
String node3Id = JedisClusterTestUtil.getNodeId(node3.clusterNodes());
node2.clusterSetSlotNode(slotTest, node3Id);
node2.clusterSetSlotNode(slot51, node3Id);
node2.clusterDelSlots(slotTest, slot51);
// forget about all nodes
node1.clusterForget(node2Id);
node1.clusterForget(node3Id);
node2.clusterForget(node1Id);
node2.clusterForget(node3Id);
node3.clusterForget(node1Id);
node3.clusterForget(node2Id);
}
@After
public void tearDown() {
public void tearDown() throws InterruptedException {
// clear all slots
int[] slotsToDelete = new int[JedisCluster.HASHSLOTS];
for (int i = 0; i < JedisCluster.HASHSLOTS; i++) {
slotsToDelete[i] = i;
}
node1.clusterDelSlots(slotsToDelete);
node2.clusterDelSlots(slotsToDelete);
node3.clusterDelSlots(slotsToDelete);
clearAnyInconsistentMigration(node1);
clearAnyInconsistentMigration(node2);
clearAnyInconsistentMigration(node3);
}
private void clearAnyInconsistentMigration(Jedis node) {
// FIXME: it's too slow... apply pipeline if possible
List<Integer> slots = getInconsistentSlots(node.clusterNodes());
for (Integer slot : slots) {
node.clusterSetSlotStable(slot);
}
}
@Test(expected = JedisMovedDataException.class)
@@ -102,7 +146,7 @@ public class JedisClusterTest extends Assert {
@Test(expected = JedisAskDataException.class)
public void testThrowAskException() {
int keySlot = JedisClusterCRC16.getSlot("test");
String node3Id = getNodeId(node3.clusterNodes());
String node3Id = JedisClusterTestUtil.getNodeId(node3.clusterNodes());
node2.clusterSetSlotMigrating(keySlot, node3Id);
node2.get("test");
}
@@ -112,7 +156,7 @@ public class JedisClusterTest extends Assert {
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNode);
assertEquals(jc.getClusterNodes().size(), 3);
assertEquals(3, jc.getClusterNodes().size());
}
@Test
@@ -136,7 +180,7 @@ public class JedisClusterTest extends Assert {
node3.clusterDelSlots(slot51);
node3.clusterAddSlots(slot51);
waitForClusterReady();
JedisClusterTestUtil.waitForClusterReady(node1, node2, node3);
jc.set("51", "foo");
assertEquals("foo", jc.get("51"));
}
@@ -147,8 +191,8 @@ public class JedisClusterTest extends Assert {
jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379));
JedisCluster jc = new JedisCluster(jedisClusterNode);
int slot51 = JedisClusterCRC16.getSlot("51");
node3.clusterSetSlotImporting(slot51, getNodeId(node2.clusterNodes()));
node2.clusterSetSlotMigrating(slot51, getNodeId(node3.clusterNodes()));
node3.clusterSetSlotImporting(slot51, JedisClusterTestUtil.getNodeId(node2.clusterNodes()));
node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes()));
jc.set("51", "foo");
assertEquals("foo", jc.get("51"));
}
@@ -168,29 +212,193 @@ public class JedisClusterTest extends Assert {
JedisCluster jc = new JedisCluster(jedisClusterNode);
int slot51 = JedisClusterCRC16.getSlot("51");
// This will cause an infinite redirection loop
node2.clusterSetSlotMigrating(slot51, getNodeId(node3.clusterNodes()));
node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes()));
jc.set("51", "foo");
}
private String getNodeId(String infoOutput) {
for (String infoLine : infoOutput.split("\n")) {
if (infoLine.contains("myself")) {
return infoLine.split(" ")[0];
}
}
return "";
@Test
public void testRedisHashtag() {
assertEquals(JedisClusterCRC16.getSlot("{bar"), JedisClusterCRC16.getSlot("foo{{bar}}zap"));
assertEquals(JedisClusterCRC16.getSlot("{user1000}.following"), JedisClusterCRC16.getSlot("{user1000}.followers"));
assertNotEquals(JedisClusterCRC16.getSlot("foo{}{bar}"), JedisClusterCRC16.getSlot("bar"));
assertEquals(JedisClusterCRC16.getSlot("foo{bar}{zap}"), JedisClusterCRC16.getSlot("bar"));
}
private void waitForClusterReady() throws InterruptedException {
boolean clusterOk = false;
while (!clusterOk) {
if (node1.clusterInfo().split("\n")[0].contains("ok")
&& node2.clusterInfo().split("\n")[0].contains("ok")
&& node3.clusterInfo().split("\n")[0].contains("ok")) {
clusterOk = true;
@Test
public void testClusterForgetNode() throws InterruptedException {
// at first, join node4 to cluster
node1.clusterMeet("127.0.0.1", nodeInfo4.getPort());
String node7Id = JedisClusterTestUtil.getNodeId(node4.clusterNodes());
JedisClusterTestUtil.assertNodeIsKnown(node3, node7Id, 1000);
JedisClusterTestUtil.assertNodeIsKnown(node2, node7Id, 1000);
JedisClusterTestUtil.assertNodeIsKnown(node1, node7Id, 1000);
assertNodeHandshakeEnded(node3, 1000);
assertNodeHandshakeEnded(node2, 1000);
assertNodeHandshakeEnded(node1, 1000);
assertEquals(4, node1.clusterNodes().split("\n").length);
assertEquals(4, node2.clusterNodes().split("\n").length);
assertEquals(4, node3.clusterNodes().split("\n").length);
// do cluster forget
node1.clusterForget(node7Id);
node2.clusterForget(node7Id);
node3.clusterForget(node7Id);
JedisClusterTestUtil.assertNodeIsUnknown(node1, node7Id, 1000);
JedisClusterTestUtil.assertNodeIsUnknown(node2, node7Id, 1000);
JedisClusterTestUtil.assertNodeIsUnknown(node3, node7Id, 1000);
assertEquals(3, node1.clusterNodes().split("\n").length);
assertEquals(3, node2.clusterNodes().split("\n").length);
assertEquals(3, node3.clusterNodes().split("\n").length);
}
Thread.sleep(50);
@Test
public void testClusterFlushSlots() {
String slotRange = getNodeServingSlotRange(node1.clusterNodes());
assertNotNull(slotRange);
try {
node1.clusterFlushSlots();
assertNull(getNodeServingSlotRange(node1.clusterNodes()));
} finally {
// rollback
String[] rangeInfo = slotRange.split("-");
int lower = Integer.parseInt(rangeInfo[0]);
int upper = Integer.parseInt(rangeInfo[1]);
int[] node1Slots = new int[upper - lower + 1];
for (int i = 0 ; lower <= upper ; ) {
node1Slots[i++] = lower++;
}
node1.clusterAddSlots(node1Slots);
}
}
@Test
public void testClusterKeySlot() {
// It assumes JedisClusterCRC16 is correctly implemented
assertEquals(node1.clusterKeySlot("foo{bar}zap}").intValue(), JedisClusterCRC16.getSlot("foo{bar}zap"));
assertEquals(node1.clusterKeySlot("{user1000}.following").intValue(), JedisClusterCRC16.getSlot("{user1000}.following"));
}
@Test
public void testClusterCountKeysInSlot() {
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort()));
JedisCluster jc = new JedisCluster(jedisClusterNode);
for (int index = 0 ; index < 5 ; index++) {
jc.set("foo{bar}" + index, "hello");
}
int slot = JedisClusterCRC16.getSlot("foo{bar}");
assertEquals(5, node1.clusterCountKeysInSlot(slot).intValue());
}
@Test
public void testStableSlotWhenMigratingNodeOrImportingNodeIsNotSpecified() throws InterruptedException {
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort(nodeInfo1.getHost(), nodeInfo1.getPort()));
JedisCluster jc = new JedisCluster(jedisClusterNode);
int slot51 = JedisClusterCRC16.getSlot("51");
jc.set("51", "foo");
// node2 is responsible of taking care of slot51 (7186)
node3.clusterSetSlotImporting(slot51, JedisClusterTestUtil.getNodeId(node2.clusterNodes()));
assertEquals("foo", jc.get("51"));
node3.clusterSetSlotStable(slot51);
assertEquals("foo", jc.get("51"));
node2.clusterSetSlotMigrating(slot51, JedisClusterTestUtil.getNodeId(node3.clusterNodes()));
//assertEquals("foo", jc.get("51")); // it leads Max Redirections
node2.clusterSetSlotStable(slot51);
assertEquals("foo", jc.get("51"));
}
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")) {
if (infoLine.contains("myself")) {
try {
return infoLine.split(" ")[8];
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
}
}
return null;
}
private List<Integer> getInconsistentSlots(String infoOuput) {
for (String infoLine : infoOuput.split("\n")) {
if (infoLine.contains("myself")) {
return getSlotsBeingMigrated(infoLine);
}
}
return null;
}
private List<Integer> getSlotsBeingMigrated(String infoLine) {
List<Integer> inconsistentSlots = new ArrayList<Integer>();
String[] splitted = infoLine.split(" ");
if (splitted.length > 8) {
for (int index = 8 ; index < splitted.length ; index++) {
String info = splitted[index];
Integer slot = getSlotFromMigrationInfo(info);
if (slot != null) {
inconsistentSlots.add(slot);
}
}
}
return inconsistentSlots;
}
private Integer getSlotFromMigrationInfo(String info) {
if (info.startsWith("[")) {
if (info.contains("-<-")) {
return Integer.parseInt(info.split("-<-")[0].substring(1));
} else if (info.contains("->-")) {
return Integer.parseInt(info.split("->-")[0].substring(1));
}
}
return null;
}
private void assertNodeHandshakeEnded(Jedis node, int timeoutMs) {
int sleepInterval = 100;
for (int sleepTime = 0 ; sleepTime <= timeoutMs ; sleepTime += sleepInterval) {
boolean isHandshaking = isAnyNodeHandshaking(node);
if (!isHandshaking)
return;
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
}
}
throw new JedisException("Node handshaking is not ended");
}
private boolean isAnyNodeHandshaking(Jedis node) {
String infoOutput = node.clusterNodes();
for (String infoLine : infoOutput.split("\n")) {
if (infoLine.contains("handshake")) {
return true;
}
}
return false;
}
}

View File

@@ -11,6 +11,7 @@ import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;
public class JedisPoolTest extends Assert {
@@ -92,8 +93,8 @@ public class JedisPoolTest extends Assert {
public void securePool() {
JedisPoolConfig config = new JedisPoolConfig();
config.setTestOnBorrow(true);
JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(), 2000,
"foobared");
JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(),
2000, "foobared");
Jedis jedis = pool.getResource();
jedis.set("foo", "bar");
pool.returnResource(jedis);
@@ -176,4 +177,65 @@ public class JedisPoolTest extends Assert {
pool0.returnResource(jedis);
pool0.destroy();
}
@Test
public void returnResourceShouldResetState() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(),
2000, "foobared");
Jedis jedis = pool.getResource();
try {
jedis.set("hello", "jedis");
Transaction t = jedis.multi();
t.set("hello", "world");
} finally {
jedis.close();
}
Jedis jedis2 = pool.getResource();
try {
assertTrue(jedis == jedis2);
assertEquals("jedis", jedis2.get("hello"));
} finally {
jedis2.close();
}
pool.destroy();
}
@Test
public void checkResourceIsCloseable() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
JedisPool pool = new JedisPool(config, hnp.getHost(), hnp.getPort(),
2000, "foobared");
Jedis jedis = pool.getResource();
try {
jedis.set("hello", "jedis");
} finally {
jedis.close();
}
Jedis jedis2 = pool.getResource();
try {
assertEquals(jedis, jedis2);
} finally {
jedis2.close();
}
}
@Test
public void returnNullObjectShouldNotFail() {
JedisPool pool = new JedisPool(new JedisPoolConfig(), hnp.getHost(),
hnp.getPort(), 2000, "foobared", 0, "my_shiny_client_name");
pool.returnBrokenResource(null);
pool.returnResource(null);
pool.returnResourceObject(null);
}
}

View File

@@ -2,17 +2,17 @@ package redis.clients.jedis.tests;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.DebugParams;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Transaction;
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";
@@ -21,12 +21,8 @@ public class JedisSentinelPoolTest extends JedisTestBase {
.get(2);
protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers()
.get(3);
protected static HostAndPort slave2 = HostAndPortUtil.getRedisServers()
.get(4);
protected static HostAndPort sentinel1 = HostAndPortUtil
.getSentinelServers().get(1);
protected static HostAndPort sentinel2 = HostAndPortUtil
.getSentinelServers().get(2);
protected static Jedis sentinelJedis1;
@@ -35,7 +31,6 @@ public class JedisSentinelPoolTest extends JedisTestBase {
@Before
public void setUp() throws Exception {
sentinels.add(sentinel1.toString());
sentinels.add(sentinel2.toString());
sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort());
}
@@ -45,17 +40,96 @@ public class JedisSentinelPoolTest extends JedisTestBase {
JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels,
new GenericObjectPoolConfig(), 1000, "foobared", 2);
// perform failover
doSegFaultMaster(pool);
// perform failover once again
doSegFaultMaster(pool);
forceFailover(pool);
forceFailover(pool);
// you can test failover as much as possible
// but you need to prepare additional slave per failover
}
private void doSegFaultMaster(JedisSentinelPool pool)
@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 checkResourceIsCloseable() {
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();
try {
jedis.set("hello", "jedis");
} finally {
jedis.close();
}
Jedis jedis2 = pool.getResource();
try {
assertEquals(jedis, jedis2);
} finally {
jedis2.close();
}
}
@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();
@@ -63,12 +137,14 @@ public class JedisSentinelPoolTest extends JedisTestBase {
Jedis jedis = pool.getResource();
assertEquals("PONG", jedis.ping());
try {
jedis.debug(DebugParams.SEGFAULT());
} catch (Exception e) {
}
// 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();
@@ -79,62 +155,15 @@ public class JedisSentinelPoolTest extends JedisTestBase {
private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster)
throws InterruptedException {
waitForJedisSentinelPoolRecognizeNewMaster(pool);
HostAndPort newMaster = JedisSentinelTestUtil
.waitForNewPromotedMaster(sentinelJedis1);
waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster);
}
private void waitForJedisSentinelPoolRecognizeNewMaster(
JedisSentinelPool pool) throws InterruptedException {
final AtomicReference<String> newmaster = new AtomicReference<String>(
"");
sentinelJedis1.psubscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// TODO Auto-generated method stub
}
@Override
public void onPMessage(String pattern, String channel,
String message) {
if (channel.equals("+switch-master")) {
newmaster.set(message);
punsubscribe();
}
// TODO Auto-generated method stub
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
}, "*");
String[] chunks = newmaster.get().split(" ");
HostAndPort newMaster = new HostAndPort(chunks[3],
Integer.parseInt(chunks[4]));
JedisSentinelPool pool, HostAndPort newMaster)
throws InterruptedException {
while (true) {
String host = pool.getCurrentHostMaster().getHost();

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis.tests;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -9,24 +10,30 @@ import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.jedis.tests.utils.JedisSentinelTestUtil;
public class JedisSentinelTest extends JedisTestBase {
private static final String MASTER_NAME = "mymaster";
private static final String MONITOR_MASTER_NAME = "mymastermonitor";
private static final String REMOVE_MASTER_NAME = "mymasterremove";
private static final String FAILOVER_MASTER_NAME = "mymasterfailover";
private static final String MASTER_IP = "127.0.0.1";
protected static HostAndPort master = HostAndPortUtil.getRedisServers()
.get(0);
protected static HostAndPort slave = HostAndPortUtil.getRedisServers().get(
5);
protected static HostAndPort slave = HostAndPortUtil.getRedisServers()
.get(4);
protected static HostAndPort sentinel = HostAndPortUtil
.getSentinelServers().get(0);
protected static Jedis masterJedis;
protected static Jedis slaveJedis;
protected static Jedis sentinelJedis;
protected static HostAndPort sentinelForFailover = HostAndPortUtil
.getSentinelServers().get(2);
protected static HostAndPort masterForFailover = HostAndPortUtil
.getRedisServers().get(5);
@Before
public void setup() throws InterruptedException {
}
@After
@@ -36,30 +43,166 @@ public class JedisSentinelTest extends JedisTestBase {
// to restore it (demote)
// so, promote(slaveof) slave to master has no effect, not same to old
// Sentinel's behavior
ensureRemoved(MONITOR_MASTER_NAME);
ensureRemoved(REMOVE_MASTER_NAME);
}
@Test
public void sentinel() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
List<Map<String, String>> masters = j.sentinelMasters();
final String masterName = masters.get(0).get("name");
assertEquals(MASTER_NAME, masterName);
try {
List<Map<String, String>> masters = j.sentinelMasters();
boolean inMasters = false;
for (Map<String, String> master : masters)
if (MASTER_NAME.equals(master.get("name")))
inMasters = true;
assertTrue(inMasters);
List<String> masterHostAndPort = j
.sentinelGetMasterAddrByName(masterName);
.sentinelGetMasterAddrByName(MASTER_NAME);
HostAndPort masterFromSentinel = new HostAndPort(
masterHostAndPort.get(0), Integer.parseInt(masterHostAndPort
.get(1)));
masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
assertEquals(master, masterFromSentinel);
List<Map<String, String>> slaves = j.sentinelSlaves(masterName);
List<Map<String, String>> slaves = j.sentinelSlaves(MASTER_NAME);
assertTrue(slaves.size() > 0);
assertEquals(master.getPort(),
Integer.parseInt(slaves.get(0).get("master-port")));
// DO NOT RE-RUN TEST TOO FAST, RESET TAKES SOME TIME TO... RESET
assertEquals(Long.valueOf(1), j.sentinelReset(masterName));
assertEquals(Long.valueOf(0), j.sentinelReset("woof" + masterName));
assertEquals(Long.valueOf(1), j.sentinelReset(MASTER_NAME));
assertEquals(Long.valueOf(0), j.sentinelReset("woof" + MASTER_NAME));
} finally {
j.close();
}
}
@Test
public void sentinelFailover() throws InterruptedException {
Jedis j = new Jedis(sentinelForFailover.getHost(),
sentinelForFailover.getPort());
try {
List<String> 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);
masterHostAndPort = j
.sentinelGetMasterAddrByName(FAILOVER_MASTER_NAME);
HostAndPort newMaster = new HostAndPort(masterHostAndPort.get(0),
Integer.parseInt(masterHostAndPort.get(1)));
assertNotEquals(newMaster, currentMaster);
} finally {
j.close();
}
}
@Test
public void sentinelMonitor() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
// monitor new master
String result = j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
assertEquals("OK", result);
// already monitored
try {
j.sentinelMonitor(MONITOR_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
fail();
} catch (JedisDataException e) {
// pass
}
} finally {
j.close();
}
}
@Test
public void sentinelRemove() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
ensureMonitored(sentinel, REMOVE_MASTER_NAME, MASTER_IP,
master.getPort(), 1);
String result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertEquals("OK", result);
// not exist
try {
result = j.sentinelRemove(REMOVE_MASTER_NAME);
assertNotEquals("OK", result);
fail();
} catch (JedisDataException e) {
// pass
}
} finally {
j.close();
}
}
@Test
public void sentinelSet() {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
Map<String, String> parameterMap = new HashMap<String, String>();
parameterMap.put("down-after-milliseconds", String.valueOf(1234));
parameterMap.put("parallel-syncs", String.valueOf(3));
parameterMap.put("quorum", String.valueOf(2));
j.sentinelSet(MASTER_NAME, parameterMap);
List<Map<String, String>> masters = j.sentinelMasters();
for (Map<String, String> master : masters) {
if (master.get("name").equals(MASTER_NAME)) {
assertEquals(1234, Integer.parseInt(master
.get("down-after-milliseconds")));
assertEquals(3,
Integer.parseInt(master.get("parallel-syncs")));
assertEquals(2, Integer.parseInt(master.get("quorum")));
}
}
parameterMap.put("quorum", String.valueOf(1));
j.sentinelSet(MASTER_NAME, parameterMap);
} finally {
j.close();
}
}
private void ensureMonitored(HostAndPort sentinel, String masterName,
String ip, int port, int quorum) {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
j.sentinelMonitor(masterName, ip, port, quorum);
} catch (JedisDataException e) {
} finally {
j.close();
}
}
private void ensureRemoved(String masterName) {
Jedis j = new Jedis(sentinel.getHost(), sentinel.getPort());
try {
j.sentinelRemove(masterName);
} catch (JedisDataException e) {
} finally {
j.close();
}
}
}

View File

@@ -8,6 +8,7 @@ import java.util.Map;
import org.junit.Test;
import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Protocol;
@@ -91,4 +92,12 @@ public class JedisTest extends JedisCommandTestBase {
assertEquals("PONG", jedis.ping());
assertEquals("bar", jedis.get("foo"));
}
@Test
public void checkCloseable() {
jedis.close();
BinaryJedis bj = new BinaryJedis("localhost");
bj.connect();
bj.close();
}
}

View File

@@ -15,7 +15,6 @@ import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.PipelineBlock;
import redis.clients.jedis.Response;
import redis.clients.jedis.Tuple;
import redis.clients.jedis.exceptions.JedisDataException;
@@ -35,21 +34,10 @@ public class PipeliningTest extends Assert {
@Test
public void pipeline() throws UnsupportedEncodingException {
List<Object> results = jedis.pipelined(new PipelineBlock() {
public void execute() {
set("foo", "bar");
get("foo");
}
});
assertEquals(2, results.size());
assertEquals("OK", results.get(0));
assertEquals("bar", results.get(1));
Pipeline p = jedis.pipelined();
p.set("foo", "bar");
p.get("foo");
results = p.syncAndReturnAll();
List<Object> results = p.syncAndReturnAll();
assertEquals(2, results.size());
assertEquals("OK", results.get(0));
@@ -114,34 +102,41 @@ public class PipeliningTest extends Assert {
jedis.hset("key".getBytes(), "f22".getBytes(), "v2222".getBytes());
Pipeline p = jedis.pipelined();
Response<Map<byte[],byte[]>> fmap = p.hgetAll("key".getBytes());
Response<Map<byte[], byte[]>> fmap = p.hgetAll("key".getBytes());
Response<Set<byte[]>> fkeys = p.hkeys("key".getBytes());
Response<List<byte[]>> fordered = p.hmget("key".getBytes(), "f22".getBytes(), "f1".getBytes());
Response<List<byte[]>> fordered = p.hmget("key".getBytes(),
"f22".getBytes(), "f1".getBytes());
Response<List<byte[]>> fvals = p.hvals("key".getBytes());
p.sync();
assertNotNull(fmap.get());
// we have to do these strange contortions because byte[] is not a very good key
// for a java Map. It only works with equality (you need the exact key object to retrieve
// the value) I recommend we switch to using ByteBuffer or something similar:
// we have to do these strange contortions because byte[] is not a very
// good key
// for a java Map. It only works with equality (you need the exact key
// object to retrieve
// the value) I recommend we switch to using ByteBuffer or something
// similar:
// http://stackoverflow.com/questions/1058149/using-a-byte-array-as-hashmap-key-java
Map<byte[],byte[]> map = fmap.get();
Map<byte[], byte[]> map = fmap.get();
Set<byte[]> mapKeys = map.keySet();
Iterator<byte[]> iterMap = mapKeys.iterator();
byte[] firstMapKey = iterMap.next();
byte[] secondMapKey = iterMap.next();
assertFalse(iterMap.hasNext());
verifyHasBothValues(firstMapKey, secondMapKey, "f1".getBytes(), "f22".getBytes());
verifyHasBothValues(firstMapKey, secondMapKey, "f1".getBytes(),
"f22".getBytes());
byte[] firstMapValue = map.get(firstMapKey);
byte[] secondMapValue = map.get(secondMapKey);
verifyHasBothValues(firstMapValue, secondMapValue, "v111".getBytes(), "v2222".getBytes());
verifyHasBothValues(firstMapValue, secondMapValue, "v111".getBytes(),
"v2222".getBytes());
assertNotNull(fkeys.get());
Iterator<byte[]> iter = fkeys.get().iterator();
byte[] firstKey = iter.next();
byte[] secondKey = iter.next();
assertFalse(iter.hasNext());
verifyHasBothValues(firstKey, secondKey, "f1".getBytes(), "f22".getBytes());
verifyHasBothValues(firstKey, secondKey, "f1".getBytes(),
"f22".getBytes());
assertNotNull(fordered.get());
assertArrayEquals("v2222".getBytes(), fordered.get().get(0));
@@ -151,13 +146,17 @@ public class PipeliningTest extends Assert {
assertEquals(2, fvals.get().size());
byte[] firstValue = fvals.get().get(0);
byte[] secondValue = fvals.get().get(1);
verifyHasBothValues(firstValue, secondValue, "v111".getBytes(), "v2222".getBytes());
verifyHasBothValues(firstValue, secondValue, "v111".getBytes(),
"v2222".getBytes());
}
private void verifyHasBothValues(byte[] firstKey, byte[] secondKey, byte[] value1, byte[] value2) {
private void verifyHasBothValues(byte[] firstKey, byte[] secondKey,
byte[] value1, byte[] value2) {
assertFalse(Arrays.equals(firstKey, secondKey));
assertTrue(Arrays.equals(firstKey, value1) || Arrays.equals(firstKey, value2));
assertTrue(Arrays.equals(secondKey, value1) || Arrays.equals(secondKey, value2));
assertTrue(Arrays.equals(firstKey, value1)
|| Arrays.equals(firstKey, value2));
assertTrue(Arrays.equals(secondKey, value1)
|| Arrays.equals(secondKey, value2));
}
@Test
@@ -178,7 +177,6 @@ public class PipeliningTest extends Assert {
assertNull(score.get());
}
@Test(expected = JedisDataException.class)
public void pipelineResponseWithinPipeline() {
jedis.set("string", "foo");
@@ -193,8 +191,8 @@ public class PipeliningTest extends Assert {
public void pipelineWithPubSub() {
Pipeline pipelined = jedis.pipelined();
Response<Long> p1 = pipelined.publish("foo", "bar");
Response<Long> p2 = pipelined.publish("foo".getBytes(), "bar"
.getBytes());
Response<Long> p2 = pipelined.publish("foo".getBytes(),
"bar".getBytes());
pipelined.sync();
assertEquals(0, p1.get().longValue());
assertEquals(0, p2.get().longValue());
@@ -209,23 +207,23 @@ public class PipeliningTest extends Assert {
}
@Test
public void piplineWithError(){
public void piplineWithError() {
Pipeline p = jedis.pipelined();
p.set("foo", "bar");
Response<Set<String>> error = p.smembers("foo");
Response<String> r = p.get("foo");
p.sync();
try{
try {
error.get();
fail();
}catch(JedisDataException e){
//that is fine we should be here
} catch (JedisDataException e) {
// that is fine we should be here
}
assertEquals(r.get(), "bar");
}
@Test
public void multi(){
public void multi() {
Pipeline p = jedis.pipelined();
p.multi();
Response<Long> r1 = p.hincrBy("a", "f1", -1);
@@ -242,7 +240,7 @@ public class PipeliningTest extends Assert {
assertEquals("QUEUED", result.get(1));
assertEquals("QUEUED", result.get(2));
//4th result is a list with the results from the multi
// 4th result is a list with the results from the multi
@SuppressWarnings("unchecked")
List<Object> multiResult = (List<Object>) result.get(3);
assertEquals(new Long(-1), multiResult.get(0));
@@ -253,6 +251,47 @@ public class PipeliningTest extends Assert {
}
@Test
public void multiWithSync() {
jedis.set("foo", "314");
jedis.set("bar", "foo");
jedis.set("hello", "world");
Pipeline p = jedis.pipelined();
Response<String> r1 = p.get("bar");
p.multi();
Response<String> r2 = p.get("foo");
p.exec();
Response<String> r3 = p.get("hello");
p.sync();
// before multi
assertEquals("foo", r1.get());
// It should be readable whether exec's response was built or not
assertEquals("314", r2.get());
// after multi
assertEquals("world", r3.get());
}
@Test(expected = JedisDataException.class)
public void pipelineExecShoudThrowJedisDataExceptionWhenNotInMulti() {
Pipeline pipeline = jedis.pipelined();
pipeline.exec();
}
@Test(expected = JedisDataException.class)
public void pipelineDiscardShoudThrowJedisDataExceptionWhenNotInMulti() {
Pipeline pipeline = jedis.pipelined();
pipeline.discard();
}
@Test(expected = JedisDataException.class)
public void pipelineMultiShoudThrowJedisDataExceptionWhenAlreadyInMulti() {
Pipeline pipeline = jedis.pipelined();
pipeline.multi();
pipeline.set("foo", "3");
pipeline.multi();
}
@Test
public void testDiscardInPipeline() {
Pipeline pipeline = jedis.pipelined();
@@ -284,9 +323,11 @@ public class PipeliningTest extends Assert {
Pipeline p = jedis.pipelined();
p.set(key, "0");
Response<String> result0 = p.eval(script, Arrays.asList(key), Arrays.asList(arg));
Response<String> result0 = p.eval(script, Arrays.asList(key),
Arrays.asList(arg));
p.incr(key);
Response<String> result1 = p.eval(script, Arrays.asList(key), Arrays.asList(arg));
Response<String> result1 = p.eval(script, Arrays.asList(key),
Arrays.asList(arg));
Response<String> result2 = p.get(key);
p.sync();
@@ -320,9 +361,11 @@ public class PipeliningTest extends Assert {
Pipeline p = jedis.pipelined();
p.set(key, "0");
Response<String> result0 = p.evalsha(sha1, Arrays.asList(key), Arrays.asList(arg));
Response<String> result0 = p.evalsha(sha1, Arrays.asList(key),
Arrays.asList(arg));
p.incr(key);
Response<String> result1 = p.evalsha(sha1, Arrays.asList(key), Arrays.asList(arg));
Response<String> result1 = p.evalsha(sha1, Arrays.asList(key),
Arrays.asList(arg));
Response<String> result2 = p.get(key);
p.sync();

View File

@@ -4,6 +4,7 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.ArrayList;
@@ -39,6 +40,28 @@ public class ProtocolTest extends JedisTestBase {
assertEquals(expectedCommand, sb.toString());
}
@Test(expected=IOException.class)
public void writeOverflow() throws IOException {
RedisOutputStream ros = new RedisOutputStream(new OutputStream() {
@Override
public void write(int b) throws IOException {
throw new IOException("thrown exception");
}
});
ros.write(new byte[8191]);
try {
ros.write((byte)'*');
} catch (IOException ioe) {}
ros.write((byte)'*');
}
@Test
public void bulkReply() {
InputStream is = new ByteArrayInputStream("$6\r\nfoobar\r\n".getBytes());

View File

@@ -14,6 +14,7 @@ import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
@@ -155,7 +156,7 @@ public class ShardedJedisPoolTest extends Assert {
// items on one shard
// alter shard 1 and recreate pool
pool.destroy();
shards.set(1, new JedisShardInfo("nohost", 1234));
shards.set(1, new JedisShardInfo("localhost", 1234));
pool = new ShardedJedisPool(redisConfig, shards);
jedis = pool.getResource();
Long actual = Long.valueOf(0);
@@ -233,4 +234,69 @@ public class ShardedJedisPoolTest extends Assert {
assertEquals("PONG", jedis.ping());
assertEquals("bar", jedis.get("foo"));
}
@Test
public void returnResourceShouldResetState() throws URISyntaxException {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
shards.add(new JedisShardInfo(new URI(
"redis://:foobared@localhost:6380")));
shards.add(new JedisShardInfo(new URI(
"redis://:foobared@localhost:6379")));
ShardedJedisPool pool = new ShardedJedisPool(config, shards);
ShardedJedis jedis = pool.getResource();
jedis.set("pipelined", String.valueOf(0));
jedis.set("pipelined2", String.valueOf(0));
ShardedJedisPipeline pipeline = jedis.pipelined();
pipeline.incr("pipelined");
pipeline.incr("pipelined2");
jedis.resetState();
pipeline = jedis.pipelined();
pipeline.incr("pipelined");
pipeline.incr("pipelined2");
List<Object> results = pipeline.syncAndReturnAll();
assertEquals(2, results.size());
pool.returnResource(jedis);
pool.destroy();
}
@Test
public void checkResourceIsCloseable() throws URISyntaxException {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(1);
config.setBlockWhenExhausted(false);
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
shards.add(new JedisShardInfo(new URI(
"redis://:foobared@localhost:6380")));
shards.add(new JedisShardInfo(new URI(
"redis://:foobared@localhost:6379")));
ShardedJedisPool pool = new ShardedJedisPool(config, shards);
ShardedJedis jedis = pool.getResource();
try {
jedis.set("hello", "jedis");
} finally {
jedis.close();
}
ShardedJedis jedis2 = pool.getResource();
try {
assertEquals(jedis, jedis2);
} finally {
jedis2.close();
}
}
}

View File

@@ -53,7 +53,8 @@ public class ShardedJedisTest extends Assert {
@Test
public void trySharding() {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
JedisShardInfo si = new JedisShardInfo(redis1.getHost(), redis1.getPort());
JedisShardInfo si = new JedisShardInfo(redis1.getHost(),
redis1.getPort());
si.setPassword("foobared");
shards.add(si);
si = new JedisShardInfo(redis2.getHost(), redis2.getPort());
@@ -80,7 +81,8 @@ public class ShardedJedisTest extends Assert {
@Test
public void tryShardingWithMurmure() {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
JedisShardInfo si = new JedisShardInfo(redis1.getHost(), redis1.getPort());
JedisShardInfo si = new JedisShardInfo(redis1.getHost(),
redis1.getPort());
si.setPassword("foobared");
shards.add(si);
si = new JedisShardInfo(redis2.getHost(), redis2.getPort());
@@ -264,8 +266,8 @@ public class ShardedJedisTest extends Assert {
.toString(i));
JedisShardInfo jedisShardInfo2 = sharded2.getShardInfo(Integer
.toString(i));
assertEquals(shards.indexOf(jedisShardInfo), otherShards
.indexOf(jedisShardInfo2));
assertEquals(shards.indexOf(jedisShardInfo),
otherShards.indexOf(jedisShardInfo2));
}
}
@@ -300,4 +302,25 @@ public class ShardedJedisTest extends Assert {
assertEquals(jedisShardInfo.getName(), jedisShardInfo2.getName());
}
}
@Test
public void checkCloseable() {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
shards.add(new JedisShardInfo(redis1.getHost(), redis1.getPort()));
shards.add(new JedisShardInfo(redis2.getHost(), redis2.getPort()));
shards.get(0).setPassword("foobared");
shards.get(1).setPassword("foobared");
ShardedJedis jedisShard = new ShardedJedis(shards);
try {
jedisShard.set("shard_closeable", "true");
} finally {
jedisShard.close();
}
for (Jedis jedis : jedisShard.getAllShards()) {
assertTrue(!jedis.isConnected());
}
}
}

View File

@@ -21,7 +21,8 @@ public class HashingBenchmark {
public static void main(String[] args) throws UnknownHostException,
IOException {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
JedisShardInfo shard = new JedisShardInfo(hnp1.getHost(), hnp1.getPort());
JedisShardInfo shard = new JedisShardInfo(hnp1.getHost(),
hnp1.getPort());
shard.setPassword("foobared");
shards.add(shard);
shard = new JedisShardInfo(hnp2.getHost(), hnp2.getPort());

View File

@@ -10,6 +10,8 @@ import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.util.SafeEncoder;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
@@ -473,9 +475,16 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
long status = jedis.pexpire("foo", 10000);
assertEquals(0, status);
jedis.set("foo", "bar");
status = jedis.pexpire("foo", 10000);
jedis.set("foo1", "bar1");
status = jedis.pexpire("foo1", 10000);
assertEquals(1, status);
jedis.set("foo2", "bar2");
status = jedis.pexpire("foo2", 200000000000L);
assertEquals(1, status);
long pttl = jedis.pttl("foo2");
assertTrue(pttl > 100000000000L);
}
@Test
@@ -510,10 +519,16 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
jedis.set("b", "b");
jedis.set("a", "a");
ScanResult<String> result = jedis.scan(0);
ScanResult<String> result = jedis.scan(SCAN_POINTER_START);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
ScanResult<byte[]> bResult = jedis.scan(SCAN_POINTER_START_BINARY);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -524,10 +539,23 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
jedis.set("b", "b");
jedis.set("a", "a");
jedis.set("aa", "aa");
ScanResult<String> result = jedis.scan(0, params);
ScanResult<String> result = jedis.scan(SCAN_POINTER_START, params);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.match(bfoostar);
jedis.set(bfoo1, bbar);
jedis.set(bfoo2, bbar);
jedis.set(bfoo3, bbar);
ScanResult<byte[]> bResult = jedis.scan(SCAN_POINTER_START_BINARY, params);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -539,8 +567,20 @@ public class AllKindOfValuesCommandsTest extends JedisCommandTestBase {
jedis.set("a" + i, "a" + i);
}
ScanResult<String> result = jedis.scan(0, params);
ScanResult<String> result = jedis.scan(SCAN_POINTER_START, params);
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.count(2);
jedis.set(bfoo1, bbar);
jedis.set(bfoo2, bbar);
jedis.set(bfoo3, bbar);
ScanResult<byte[]> bResult = jedis.scan(SCAN_POINTER_START_BINARY, params);
assertFalse(bResult.getResult().isEmpty());
}
}

View File

@@ -1,14 +1,15 @@
package redis.clients.jedis.tests.commands;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Protocol.Keyword;
import redis.clients.jedis.exceptions.JedisDataException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Protocol.Keyword;
import redis.clients.jedis.exceptions.JedisDataException;
public class BinaryValuesCommandsTest extends JedisCommandTestBase {
byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
byte[] bbar = { 0x05, 0x06, 0x07, 0x08 };
@@ -54,10 +55,11 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
@Test
public void setIfNotExistAndGet() {
String status= jedis.set(bfoo, binaryValue);
String status = jedis.set(bfoo, binaryValue);
assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
// nx should fail if value exists
String statusFail = jedis.set(bfoo, binaryValue, bnx, bex, expireSeconds);
String statusFail = jedis.set(bfoo, binaryValue, bnx, bex,
expireSeconds);
assertNull(statusFail);
byte[] value = jedis.get(bfoo);
@@ -68,10 +70,11 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
@Test
public void setIfExistAndGet() {
String status= jedis.set(bfoo, binaryValue);
String status = jedis.set(bfoo, binaryValue);
assertTrue(Keyword.OK.name().equalsIgnoreCase(status));
// nx should fail if value exists
String statusSuccess = jedis.set(bfoo, binaryValue, bxx, bex, expireSeconds);
String statusSuccess = jedis.set(bfoo, binaryValue, bxx, bex,
expireSeconds);
assertTrue(Keyword.OK.name().equalsIgnoreCase(statusSuccess));
byte[] value = jedis.get(bfoo);
@@ -83,7 +86,8 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
@Test
public void setFailIfNotExistAndGet() {
// xx should fail if value does NOT exists
String statusFail = jedis.set(bfoo, binaryValue, bxx, bex, expireSeconds);
String statusFail = jedis.set(bfoo, binaryValue, bxx, bex,
expireSeconds);
assertNull(statusFail);
}
@@ -95,7 +99,6 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
assertTrue(ttl > 0 && ttl <= expireSeconds);
}
@Test
public void setAndExpire() {
String status = jedis.set(bfoo, binaryValue, bnx, bex, expireSeconds);
@@ -104,7 +107,6 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
assertTrue(ttl > 0 && ttl <= expireSeconds);
}
@Test
public void getSet() {
byte[] value = jedis.getSet(bfoo, binaryValue);
@@ -263,15 +265,13 @@ public class BinaryValuesCommandsTest extends JedisCommandTestBase {
assertTrue(Arrays.equals(first512, rfirst512));
byte[] last512 = new byte[512];
System
.arraycopy(binaryValue, binaryValue.length - 512, last512, 0,
512);
System.arraycopy(binaryValue, binaryValue.length - 512, last512, 0, 512);
assertTrue(Arrays.equals(last512, jedis.substr(bfoo, -512, -1)));
assertTrue(Arrays.equals(binaryValue, jedis.substr(bfoo, 0, -1)));
assertTrue(Arrays.equals(last512, jedis.substr(bfoo,
binaryValue.length - 512, 100000)));
assertTrue(Arrays.equals(last512,
jedis.substr(bfoo, binaryValue.length - 512, 100000)));
}
@Test

View File

@@ -3,6 +3,8 @@ package redis.clients.jedis.tests.commands;
import org.junit.Test;
import redis.clients.jedis.BitOP;
import redis.clients.jedis.BitPosParams;
import redis.clients.jedis.Protocol;
public class BitCommandsTest extends JedisCommandTestBase {
@Test
@@ -20,6 +22,111 @@ public class BitCommandsTest extends JedisCommandTestBase {
assertTrue(bbit);
}
@Test
public void bitpos() {
String foo = "foo";
jedis.set(foo, String.valueOf(0));
jedis.setbit(foo, 3, true);
jedis.setbit(foo, 7, true);
jedis.setbit(foo, 13, true);
jedis.setbit(foo, 39, true);
/*
* byte: 0 1 2 3 4
* bit: 00010001 / 00000100 / 00000000 / 00000000 / 00000001
*/
long offset = jedis.bitpos(foo, true);
assertEquals(2, offset);
offset = jedis.bitpos(foo, false);
assertEquals(0, offset);
offset = jedis.bitpos(foo, true, new BitPosParams(1));
assertEquals(13, offset);
offset = jedis.bitpos(foo, false, new BitPosParams(1));
assertEquals(8, offset);
offset = jedis.bitpos(foo, true, new BitPosParams(2, 3));
assertEquals(-1, offset);
offset = jedis.bitpos(foo, false, new BitPosParams(2, 3));
assertEquals(16, offset);
offset = jedis.bitpos(foo, true, new BitPosParams(3, 4));
assertEquals(39, offset);
}
@Test
public void bitposBinary() {
// binary
byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
jedis.set(bfoo, Protocol.toByteArray(0));
jedis.setbit(bfoo, 3, true);
jedis.setbit(bfoo, 7, true);
jedis.setbit(bfoo, 13, true);
jedis.setbit(bfoo, 39, true);
/*
* byte: 0 1 2 3 4
* bit: 00010001 / 00000100 / 00000000 / 00000000 / 00000001
*/
long offset = jedis.bitpos(bfoo, true);
assertEquals(2, offset);
offset = jedis.bitpos(bfoo, false);
assertEquals(0, offset);
offset = jedis.bitpos(bfoo, true, new BitPosParams(1));
assertEquals(13, offset);
offset = jedis.bitpos(bfoo, false, new BitPosParams(1));
assertEquals(8, offset);
offset = jedis.bitpos(bfoo, true, new BitPosParams(2, 3));
assertEquals(-1, offset);
offset = jedis.bitpos(bfoo, false, new BitPosParams(2, 3));
assertEquals(16, offset);
offset = jedis.bitpos(bfoo, true, new BitPosParams(3, 4));
assertEquals(39, offset);
}
@Test
public void bitposWithNoMatchingBitExist() {
String foo = "foo";
jedis.set(foo, String.valueOf(0));
for (int idx = 0; idx < 8; idx++) {
jedis.setbit(foo, idx, true);
}
/*
* byte: 0
* bit: 11111111
*/
long offset = jedis.bitpos(foo, false);
// offset should be last index + 1
assertEquals(8, offset);
}
@Test
public void bitposWithNoMatchingBitExistWithinRange() {
String foo = "foo";
jedis.set(foo, String.valueOf(0));
for (int idx = 0; idx < 8 * 5; idx++) {
jedis.setbit(foo, idx, true);
}
/*
* byte: 0 1 2 3 4
* bit: 11111111 / 11111111 / 11111111 / 11111111 / 11111111
*/
long offset = jedis.bitpos(foo, false, new BitPosParams(2, 3));
// offset should be -1
assertEquals(-1, offset);
}
@Test
public void setAndgetrange() {
jedis.set("key1", "Hello World");
@@ -51,8 +158,7 @@ public class BitCommandsTest extends JedisCommandTestBase {
}
@Test
public void bitOp()
{
public void bitOp() {
jedis.set("key1", "\u0060");
jedis.set("key2", "\u0044");
@@ -76,8 +182,7 @@ public class BitCommandsTest extends JedisCommandTestBase {
}
@Test
public void bitOpNot()
{
public void bitOpNot() {
jedis.del("key");
jedis.setbit("key", 0, true);
jedis.setbit("key", 4, true);

View File

@@ -40,31 +40,30 @@ public class ClusterCommandsTest extends JedisTestBase {
@AfterClass
public static void removeSlots() throws InterruptedException {
//This is to wait for gossip to replicate data.
waitForEqualClusterSize();
String[] nodes = node1.clusterNodes().split("\n");
String node1Id = nodes[0].split(" ")[0];
node1.clusterDelSlots(1,2,3,4,5,500);
node1.clusterDelSlots(1, 2, 3, 4, 5, 500);
node1.clusterSetSlotNode(5000, node1Id);
node1.clusterDelSlots(5000, 10000);
node1.clusterAddSlots(6000);
node1.clusterDelSlots(6000);
node2.clusterDelSlots(6000,1,2,3,4,5,500,5000);
try {
node2.clusterDelSlots(10000);
} catch (JedisDataException jde) {
//Do nothing, slot may or may not be assigned depending on gossip
waitForGossip();
node2.clusterDelSlots(6000);
node1.clusterDelSlots(6000);
}
private static void waitForGossip() {
boolean notReady = true;
while (notReady) {
if (node1.clusterNodes().contains("6000")) {
notReady = false;
}
}
}
private static void waitForEqualClusterSize() throws InterruptedException {
boolean notEqualSize = true;
while (notEqualSize) {
notEqualSize = getClusterAttribute(node1.clusterInfo(), "cluster_known_nodes") == getClusterAttribute(node2.clusterInfo(), "cluster_size") ? false : true;
}
}
private static int getClusterAttribute(String clusterInfo, String attributeName) {
for (String infoElement: clusterInfo.split("\n")) {
private static int getClusterAttribute(String clusterInfo,
String attributeName) {
for (String infoElement : clusterInfo.split("\n")) {
if (infoElement.contains(attributeName)) {
return Integer.valueOf(infoElement.split(":")[1].trim());
}
@@ -72,6 +71,15 @@ public class ClusterCommandsTest extends JedisTestBase {
return 0;
}
@Test
public void clusterSetSlotImporting() {
node2.clusterAddSlots(6000);
String[] nodes = node1.clusterNodes().split("\n");
String nodeId = nodes[0].split(" ")[0];
String status = node1.clusterSetSlotImporting(6000, nodeId);
assertEquals("OK", status);
}
@Test
public void clusterNodes() {
String nodes = node1.clusterNodes();
@@ -127,12 +135,4 @@ public class ClusterCommandsTest extends JedisTestBase {
assertEquals("OK", status);
}
@Test
public void clusterSetSlotImporting() {
node2.clusterAddSlots(6000);
String[] nodes = node1.clusterNodes().split("\n");
String nodeId = nodes[0].split(" ")[0];
String status = node1.clusterSetSlotImporting(6000, nodeId);
assertEquals("OK", status);
}
}

View File

@@ -61,6 +61,11 @@ public class ControlCommandsTest extends JedisCommandTestBase {
public void monitor() {
new Thread(new Runnable() {
public void run() {
try {
// sleep 100ms to make sure that monitor thread runs first
Thread.sleep(100);
} catch (InterruptedException e) {
}
Jedis j = new Jedis("localhost");
j.auth("foobared");
for (int i = 0; i < 5; i++) {

View File

@@ -12,12 +12,19 @@ import org.junit.Test;
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;
public class HashesCommandsTest extends JedisCommandTestBase {
final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
final byte[] bbar = { 0x05, 0x06, 0x07, 0x08 };
final byte[] bcar = { 0x09, 0x0A, 0x0B, 0x0C };
final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A };
final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B };
final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C };
final byte[] bbarstar = { 0x05, 0x06, 0x07, 0x08, '*' };
@Test
public void hset() {
long status = jedis.hset("foo", "bar", "car");
@@ -146,6 +153,25 @@ public class HashesCommandsTest extends JedisCommandTestBase {
}
@Test
public void hincrByFloat() {
Double value = jedis.hincrByFloat("foo", "bar", 1.5d);
assertEquals((Double) 1.5d, value);
value = jedis.hincrByFloat("foo", "bar", -1.5d);
assertEquals((Double) 0d, value);
value = jedis.hincrByFloat("foo", "bar", -10.7d);
assertEquals(Double.compare(-10.7d, value), 0);
// Binary
double bvalue = jedis.hincrByFloat(bfoo, bbar, 1.5d);
assertEquals(Double.compare(1.5d, bvalue), 0);
bvalue = jedis.hincrByFloat(bfoo, bbar, -1.5d);
assertEquals(Double.compare(0d, bvalue), 0);
bvalue = jedis.hincrByFloat(bfoo, bbar, -10.7d);
assertEquals(Double.compare(-10.7d, value), 0);
}
@Test
public void hexists() {
Map<String, String> hash = new HashMap<String, String>();
@@ -295,10 +321,18 @@ public class HashesCommandsTest extends JedisCommandTestBase {
jedis.hset("foo", "b", "b");
jedis.hset("foo", "a", "a");
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo", 0);
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo", SCAN_POINTER_START);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
jedis.hset(bfoo, bbar, bcar);
ScanResult<Map.Entry<byte[], byte[]>> bResult = jedis.hscan(bfoo, SCAN_POINTER_START_BINARY);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -309,10 +343,25 @@ public class HashesCommandsTest extends JedisCommandTestBase {
jedis.hset("foo", "b", "b");
jedis.hset("foo", "a", "a");
jedis.hset("foo", "aa", "aa");
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo", 0, params);
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo",
SCAN_POINTER_START, params);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.match(bbarstar);
jedis.hset(bfoo, bbar, bcar);
jedis.hset(bfoo, bbar1, bcar);
jedis.hset(bfoo, bbar2, bcar);
jedis.hset(bfoo, bbar3, bcar);
ScanResult<Map.Entry<byte[], byte[]>> bResult = jedis.hscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -324,8 +373,22 @@ public class HashesCommandsTest extends JedisCommandTestBase {
jedis.hset("foo", "a" + i, "a" + i);
}
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo", 0, params);
ScanResult<Map.Entry<String, String>> result = jedis.hscan("foo",
SCAN_POINTER_START, params);
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.count(2);
jedis.hset(bfoo, bbar, bcar);
jedis.hset(bfoo, bbar1, bcar);
jedis.hset(bfoo, bbar2, bcar);
jedis.hset(bfoo, bbar3, bcar);
ScanResult<Map.Entry<byte[], byte[]>> bResult = jedis.hscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertFalse(bResult.getResult().isEmpty());
}
}

View File

@@ -0,0 +1,130 @@
package redis.clients.jedis.tests.commands;
import org.junit.Test;
import redis.clients.util.SafeEncoder;
public class HyperLogLogCommandsTest extends JedisCommandTestBase {
@Test
public void pfadd() {
long status = jedis.pfadd("foo", "a");
assertEquals(1, status);
status = jedis.pfadd("foo", "a");
assertEquals(0, status);
}
@Test
public void pfaddBinary() {
byte[] bFoo = SafeEncoder.encode("foo");
byte[] bBar = SafeEncoder.encode("bar");
byte[] bBar2 = SafeEncoder.encode("bar2");
long status = jedis.pfadd(bFoo, bBar, bBar2);
assertEquals(1, status);
status = jedis.pfadd(bFoo, bBar, bBar2);
assertEquals(0, status);
}
@Test
public void pfcount() {
long status = jedis.pfadd("hll", "foo", "bar", "zap");
assertEquals(1, status);
status = jedis.pfadd("hll", "zap", "zap", "zap");
assertEquals(0, status);
status = jedis.pfadd("hll", "foo", "bar");
assertEquals(0, status);
status = jedis.pfcount("hll");
assertEquals(3, status);
}
@Test
public void pfcounts() {
long status = jedis.pfadd("hll_1", "foo", "bar", "zap");
assertEquals(1, status);
status = jedis.pfadd("hll_2", "foo", "bar", "zap");
assertEquals(1, status);
status = jedis.pfadd("hll_3", "foo", "bar", "baz");
assertEquals(1, status);
status = jedis.pfcount("hll_1");
assertEquals(3, status);
status = jedis.pfcount("hll_2");
assertEquals(3, status);
status = jedis.pfcount("hll_3");
assertEquals(3, status);
status = jedis.pfcount("hll_1", "hll_2");
assertEquals(3, status);
status = jedis.pfcount("hll_1", "hll_2", "hll_3");
assertEquals(4, status);
}
@Test
public void pfcountBinary() {
byte[] bHll = SafeEncoder.encode("hll");
byte[] bFoo = SafeEncoder.encode("foo");
byte[] bBar = SafeEncoder.encode("bar");
byte[] bZap = SafeEncoder.encode("zap");
long status = jedis.pfadd(bHll, bFoo, bBar, bZap);
assertEquals(1, status);
status = jedis.pfadd(bHll, bZap, bZap, bZap);
assertEquals(0, status);
status = jedis.pfadd(bHll, bFoo, bBar);
assertEquals(0, status);
status = jedis.pfcount(bHll);
assertEquals(3, status);
}
@Test
public void pfmerge() {
long status = jedis.pfadd("hll1", "foo", "bar", "zap", "a");
assertEquals(1, status);
status = jedis.pfadd("hll2", "a", "b", "c", "foo");
assertEquals(1, status);
String mergeStatus = jedis.pfmerge("hll3", "hll1", "hll2");
assertEquals("OK", mergeStatus);
status = jedis.pfcount("hll3");
assertEquals(6, status);
}
@Test
public void pfmergeBinary() {
byte[] bHll1 = SafeEncoder.encode("hll1");
byte[] bHll2 = SafeEncoder.encode("hll2");
byte[] bHll3 = SafeEncoder.encode("hll3");
byte[] bFoo = SafeEncoder.encode("foo");
byte[] bBar = SafeEncoder.encode("bar");
byte[] bZap = SafeEncoder.encode("zap");
byte[] bA = SafeEncoder.encode("a");
byte[] bB = SafeEncoder.encode("b");
byte[] bC = SafeEncoder.encode("c");
long status = jedis.pfadd(bHll1, bFoo, bBar, bZap, bA);
assertEquals(1, status);
status = jedis.pfadd(bHll2, bA, bB, bC, bFoo);
assertEquals(1, status);
String mergeStatus = jedis.pfmerge(bHll3, bHll1, bHll2);
assertEquals("OK", mergeStatus);
status = jedis.pfcount("hll3");
assertEquals(6, status);
}
}

View File

@@ -33,7 +33,6 @@ public class ListCommandsTest extends JedisCommandTestBase {
size = jedis.rpush("foo", "bar", "foo");
assertEquals(4, size);
// Binary
long bsize = jedis.rpush(bfoo, bbar);
assertEquals(1, bsize);
@@ -445,7 +444,6 @@ public class ListCommandsTest extends JedisCommandTestBase {
List<String> result = jedis.brpop(1, "foo");
assertNull(result);
jedis.lpush("foo", "bar");
result = jedis.brpop(1, "foo");
assertNotNull(result);

View File

@@ -3,16 +3,17 @@ package redis.clients.jedis.tests.commands;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Ignore;
import org.junit.Test;
import redis.clients.jedis.BinaryJedisPubSub;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.util.SafeEncoder;
public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
@@ -43,7 +44,7 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
assertEquals("foo", channel);
assertEquals(1, subscribedChannels);
//now that I'm subscribed... publish
// now that I'm subscribed... publish
publishOne("foo", "exit");
}
@@ -64,6 +65,124 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
}, "foo");
}
@Test
public void pubSubChannels(){
final List<String> expectedActiveChannels = Arrays.asList("testchan1", "testchan2", "testchan3");
jedis.subscribe(new JedisPubSub() {
private int count = 0;
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
count++;
//All channels are subscribed
if (count == 3) {
Jedis otherJedis = createJedis();
List<String> activeChannels = otherJedis.pubsubChannels("test*");
assertTrue(expectedActiveChannels.containsAll(activeChannels));
unsubscribe();
}
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPMessage(String pattern, String channel, String message) {
}
@Override
public void onMessage(String channel, String message) {
}
}, "testchan1", "testchan2", "testchan3");
}
@Test
public void pubSubNumPat(){
jedis.psubscribe(new JedisPubSub() {
private int count=0;
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
count++;
if (count == 3) {
Jedis otherJedis = createJedis();
Long numPatterns = otherJedis.pubsubNumPat();
assertEquals(new Long(2l), numPatterns);
punsubscribe();
}
}
@Override
public void onPMessage(String pattern, String channel, String message) {
}
@Override
public void onMessage(String channel, String message) {
}
}, "test*", "test*", "chan*");
}
@Test
public void pubSubNumSub(){
final Map<String, String> expectedNumSub = new HashMap<String, String>();
expectedNumSub.put("testchannel2", "1");
expectedNumSub.put("testchannel1", "1");
jedis.subscribe(new JedisPubSub() {
private int count=0;
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
count++;
if (count == 2) {
Jedis otherJedis = createJedis();
Map<String, String> numSub = otherJedis.pubsubNumSub("testchannel1", "testchannel2");
assertEquals(expectedNumSub, numSub);
unsubscribe();
}
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPMessage(String pattern, String channel, String message) {
}
@Override
public void onMessage(String channel, String message) {
}
}, "testchannel1", "testchannel2");
}
@Test
public void subscribeMany() throws UnknownHostException, IOException,
InterruptedException {
@@ -264,7 +383,8 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
public void onPSubscribe(byte[] pattern, int subscribedChannels) {
assertTrue(Arrays.equals(SafeEncoder.encode("foo.*"), pattern));
assertEquals(1, subscribedChannels);
publishOne(SafeEncoder.encode(pattern).replace("*", "bar"), "exit");
publishOne(SafeEncoder.encode(pattern).replace("*", "bar"),
"exit");
}
public void onPUnsubscribe(byte[] pattern, int subscribedChannels) {
@@ -297,7 +417,8 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
}
public void onPSubscribe(byte[] pattern, int subscribedChannels) {
publishOne(SafeEncoder.encode(pattern).replace("*", "123"), "exit");
publishOne(SafeEncoder.encode(pattern).replace("*", "123"),
"exit");
}
public void onPUnsubscribe(byte[] pattern, int subscribedChannels) {
@@ -321,7 +442,7 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
public void onSubscribe(byte[] channel, int subscribedChannels) {
publishOne(SafeEncoder.encode(channel), "exit");
if(!SafeEncoder.encode(channel).equals("bar")) {
if (!SafeEncoder.encode(channel).equals("bar")) {
this.subscribe(SafeEncoder.encode("bar"));
this.psubscribe(SafeEncoder.encode("bar.*"));
}
@@ -331,7 +452,8 @@ public class PublishSubscribeCommandsTest extends JedisCommandTestBase {
}
public void onPSubscribe(byte[] pattern, int subscribedChannels) {
publishOne(SafeEncoder.encode(pattern).replace("*", "123"), "exit");
publishOne(SafeEncoder.encode(pattern).replace("*", "123"),
"exit");
}
public void onPUnsubscribe(byte[] pattern, int subscribedChannels) {

View File

@@ -1,19 +1,23 @@
package redis.clients.jedis.tests.commands;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher;
import org.junit.Test;
import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.util.SafeEncoder;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import redis.clients.jedis.exceptions.JedisDataException;
import redis.clients.util.SafeEncoder;
import static org.hamcrest.CoreMatchers.equalTo;
public class ScriptingCommandsTest extends JedisCommandTestBase {
@SuppressWarnings("unchecked")
@Test
public void evalMultiBulk() {
String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}";
String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2],ARGV[3]}";
List<String> keys = new ArrayList<String>();
keys.add("key1");
keys.add("key2");
@@ -21,14 +25,44 @@ public class ScriptingCommandsTest extends JedisCommandTestBase {
List<String> args = new ArrayList<String>();
args.add("first");
args.add("second");
args.add("third");
List<String> response = (List<String>) jedis.eval(script, keys, args);
assertEquals(4, response.size());
assertEquals(5, response.size());
assertEquals("key1", response.get(0));
assertEquals("key2", response.get(1));
assertEquals("first", response.get(2));
assertEquals("second", response.get(3));
assertEquals("third", response.get(4));
}
@SuppressWarnings("unchecked")
@Test
public void evalMultiBulkWithBinaryJedis() {
String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2],ARGV[3]}";
List<byte[]> keys = new ArrayList<byte[]>();
keys.add("key1".getBytes());
keys.add("key2".getBytes());
List<byte[]> args = new ArrayList<byte[]>();
args.add("first".getBytes());
args.add("second".getBytes());
args.add("third".getBytes());
BinaryJedis binaryJedis = new BinaryJedis(hnp.getHost(), hnp.getPort(),
500);
binaryJedis.connect();
binaryJedis.auth("foobared");
List<byte[]> responses = (List<byte[]>) binaryJedis.eval(
script.getBytes(), keys, args);
assertEquals(5, responses.size());
assertEquals("key1", new String(responses.get(0)));
assertEquals("key2", new String(responses.get(1)));
assertEquals("first", new String(responses.get(2)));
assertEquals("second", new String(responses.get(3)));
assertEquals("third", new String(responses.get(4)));
}
@Test
@@ -57,6 +91,15 @@ public class ScriptingCommandsTest extends JedisCommandTestBase {
assertEquals(new Long(2), response);
}
@Test
public void evalNestedLists() {
String script = "return { {KEYS[1]} , {2} }";
List<?> results = (List<?>) jedis.eval(script, 1, "key1");
assertThat((List<String>) results.get(0), listWithItem("key1"));
assertThat((List<Long>) results.get(1), listWithItem(2L));
}
@Test
public void evalNoArgs() {
String script = "return KEYS[1]";
@@ -141,10 +184,10 @@ public class ScriptingCommandsTest extends JedisCommandTestBase {
public void scriptEvalReturnNullValues() {
String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}";
List<String> results = (List<String>) jedis.eval(script, 2, "key1", "key2", "1", "2");
assertEquals(results.get(0), "key1");
assertEquals(results.get(1), "key2");
assertEquals(results.get(2), "1");
assertEquals(results.get(3), "2");
assertEquals("key1", results.get(0));
assertEquals("key2", results.get(1));
assertEquals("1", results.get(2));
assertEquals("2", results.get(3));
}
@Test
@@ -152,11 +195,13 @@ public class ScriptingCommandsTest extends JedisCommandTestBase {
String script = "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}";
String sha = jedis.scriptLoad(script);
List<String> results = (List<String>) jedis.evalsha(sha, 2, "key1", "key2", "1", "2");
assertEquals(results.get(0), "key1");
assertEquals(results.get(1), "key2");
assertEquals(results.get(2), "1");
assertEquals(results.get(3), "2");
assertEquals("key1", results.get(0));
assertEquals("key2", results.get(1));
assertEquals("1", results.get(2));
assertEquals("2", results.get(3));
}
private <T> Matcher<Iterable<? super T>> listWithItem(T expected) {
return CoreMatchers.<T>hasItem(equalTo(expected));
}
}

View File

@@ -2,13 +2,14 @@ package redis.clients.jedis.tests.commands;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
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;
public class SetCommandsTest extends JedisCommandTestBase {
final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
@@ -20,6 +21,11 @@ public class SetCommandsTest extends JedisCommandTestBase {
final byte[] bd = { 0x0D };
final byte[] bx = { 0x42 };
final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A };
final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B };
final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C };
final byte[] bbarstar = { 0x05, 0x06, 0x07, 0x08, '*' };
@Test
public void sadd() {
long status = jedis.sadd("foo", "a");
@@ -454,15 +460,22 @@ public class SetCommandsTest extends JedisCommandTestBase {
assertNull(bmember);
}
@Test
public void sscan() {
jedis.sadd("foo", "a", "b");
ScanResult<String> result = jedis.sscan("foo", 0);
ScanResult<String> result = jedis.sscan("foo", SCAN_POINTER_START);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
jedis.sadd(bfoo, ba, bb);
ScanResult<byte[]> bResult = jedis.sscan(bfoo, SCAN_POINTER_START_BINARY);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -471,10 +484,20 @@ public class SetCommandsTest extends JedisCommandTestBase {
params.match("a*");
jedis.sadd("foo", "b", "a", "aa");
ScanResult<String> result = jedis.sscan("foo", 0, params);
ScanResult<String> result = jedis.sscan("foo", SCAN_POINTER_START, params);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.match(bbarstar);
jedis.sadd(bfoo, bbar1, bbar2, bbar3);
ScanResult<byte[]> bResult = jedis.sscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -484,8 +507,17 @@ public class SetCommandsTest extends JedisCommandTestBase {
jedis.sadd("foo", "a1", "a2", "a3", "a4", "a5");
ScanResult<String> result = jedis.sscan("foo", 0, params);
ScanResult<String> result = jedis.sscan("foo", SCAN_POINTER_START, params);
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.count(2);
jedis.sadd(bfoo, bbar1, bbar2, bbar3);
ScanResult<byte[]> bResult = jedis.sscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertFalse(bResult.getResult().isEmpty());
}
}

View File

@@ -10,7 +10,7 @@ public class SlowlogCommandsTest extends JedisCommandTestBase {
@Test
public void slowlog() {
//do something
// do something
jedis.configSet("slowlog-log-slower-than", "0");
jedis.set("foo", "bar");
jedis.set("foo2", "bar2");

View File

@@ -10,6 +10,8 @@ import redis.clients.jedis.ScanResult;
import redis.clients.jedis.Tuple;
import redis.clients.jedis.ZParams;
import redis.clients.util.SafeEncoder;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START;
import static redis.clients.jedis.ScanParams.SCAN_POINTER_START_BINARY;
public class SortedSetCommandsTest extends JedisCommandTestBase {
final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 };
@@ -19,6 +21,11 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
final byte[] bb = { 0x0B };
final byte[] bc = { 0x0C };
final byte[] bbar1 = { 0x05, 0x06, 0x07, 0x08, 0x0A };
final byte[] bbar2 = { 0x05, 0x06, 0x07, 0x08, 0x0B };
final byte[] bbar3 = { 0x05, 0x06, 0x07, 0x08, 0x0C };
final byte[] bbarstar = { 0x05, 0x06, 0x07, 0x08, '*' };
@Test
public void zadd() {
long status = jedis.zadd("foo", 1d, "a");
@@ -389,7 +396,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
assertEquals(2, bresult);
bresult = jedis.zcount(bfoo, SafeEncoder.encode("(0.01"), SafeEncoder.encode("+inf"));
bresult = jedis.zcount(bfoo, SafeEncoder.encode("(0.01"),
SafeEncoder.encode("+inf"));
assertEquals(3, bresult);
}
@@ -447,8 +455,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
assertEquals(bexpected, brange);
brange = jedis.zrangeByScore(bfoo, 0d, 2d, 1, 1);
Set<byte[]> brange2 = jedis.zrangeByScore(bfoo, SafeEncoder
.encode("-inf"), SafeEncoder.encode("(2"));
Set<byte[]> brange2 = jedis.zrangeByScore(bfoo,
SafeEncoder.encode("-inf"), SafeEncoder.encode("(2"));
assertEquals(bexpected, brange2);
bexpected = new LinkedHashSet<byte[]>();
@@ -523,8 +531,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
assertEquals(bexpected, brange);
Set<byte[]> brange2 = jedis.zrevrangeByScore(bfoo, SafeEncoder
.encode("+inf"), SafeEncoder.encode("(2"));
Set<byte[]> brange2 = jedis.zrevrangeByScore(bfoo,
SafeEncoder.encode("+inf"), SafeEncoder.encode("(2"));
bexpected = new LinkedHashSet<byte[]>();
bexpected.add(bb);
@@ -763,8 +771,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
bexpected.add(new Tuple(bb, new Double(4)));
bexpected.add(new Tuple(ba, new Double(3)));
assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder
.encode("dst"), 0, 100));
assertEquals(bexpected,
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
}
@Test
@@ -805,8 +813,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
bexpected.add(new Tuple(bb, new Double(8)));
bexpected.add(new Tuple(ba, new Double(6)));
assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder
.encode("dst"), 0, 100));
assertEquals(bexpected,
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
}
@Test
@@ -836,8 +844,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
Set<Tuple> bexpected = new LinkedHashSet<Tuple>();
bexpected.add(new Tuple(ba, new Double(3)));
assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder
.encode("dst"), 0, 100));
assertEquals(bexpected,
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
}
@Test
@@ -874,8 +882,8 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
Set<Tuple> bexpected = new LinkedHashSet<Tuple>();
bexpected.add(new Tuple(ba, new Double(6)));
assertEquals(bexpected, jedis.zrangeWithScores(SafeEncoder
.encode("dst"), 0, 100));
assertEquals(bexpected,
jedis.zrangeWithScores(SafeEncoder.encode("dst"), 0, 100));
}
@Test
@@ -888,16 +896,24 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
assertEquals(0, t2.compareTo(t2));
}
@Test
public void zscan() {
jedis.zadd("foo", 1, "a");
jedis.zadd("foo", 2, "b");
ScanResult<Tuple> result = jedis.zscan("foo", 0);
ScanResult<Tuple> result = jedis.zscan("foo", SCAN_POINTER_START);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
jedis.zadd(bfoo, 1, ba);
jedis.zadd(bfoo, 1, bb);
ScanResult<Tuple> bResult = jedis.zscan(bfoo, SCAN_POINTER_START_BINARY);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -908,10 +924,23 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
jedis.zadd("foo", 2, "b");
jedis.zadd("foo", 1, "a");
jedis.zadd("foo", 11, "aa");
ScanResult<Tuple> result = jedis.zscan("foo", 0, params);
ScanResult<Tuple> result = jedis.zscan("foo", SCAN_POINTER_START, params);
assertEquals(0, result.getCursor());
assertEquals(SCAN_POINTER_START, result.getStringCursor());
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.match(bbarstar);
jedis.zadd(bfoo, 2, bbar1);
jedis.zadd(bfoo, 1, bbar2);
jedis.zadd(bfoo, 11, bbar3);
ScanResult<Tuple> bResult = jedis.zscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertArrayEquals(SCAN_POINTER_START_BINARY, bResult.getCursorAsBytes());
assertFalse(bResult.getResult().isEmpty());
}
@Test
@@ -925,8 +954,20 @@ public class SortedSetCommandsTest extends JedisCommandTestBase {
jedis.zadd("foo", 4, "a4");
jedis.zadd("foo", 5, "a5");
ScanResult<Tuple> result = jedis.zscan("foo", 0, params);
ScanResult<Tuple> result = jedis.zscan("foo", SCAN_POINTER_START, params);
assertFalse(result.getResult().isEmpty());
// binary
params = new ScanParams();
params.count(2);
jedis.zadd(bfoo, 2, bbar1);
jedis.zadd(bfoo, 1, bbar2);
jedis.zadd(bfoo, 11, bbar3);
ScanResult<Tuple> bResult = jedis.zscan(bfoo, SCAN_POINTER_START_BINARY, params);
assertFalse(bResult.getResult().isEmpty());
}
}

View File

@@ -123,6 +123,12 @@ public class StringValuesCommandsTest extends JedisCommandTestBase {
assertEquals(4, value);
}
@Test(expected = JedisDataException.class)
public void incrByFloatWrongValue() {
jedis.set("foo", "bar");
jedis.incrByFloat("foo", 2d);
}
@Test(expected = JedisDataException.class)
public void decrWrongValue() {
jedis.set("foo", "bar");
@@ -180,8 +186,8 @@ public class StringValuesCommandsTest extends JedisCommandTestBase {
public void incrLargeNumbers() {
long value = jedis.incr("foo");
assertEquals(1, value);
assertEquals(1L + Integer.MAX_VALUE, (long) jedis.incrBy("foo",
Integer.MAX_VALUE));
assertEquals(1L + Integer.MAX_VALUE,
(long) jedis.incrBy("foo", Integer.MAX_VALUE));
}
@Test(expected = JedisDataException.class)

View File

@@ -4,6 +4,7 @@ import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
@@ -11,10 +12,10 @@ import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Protocol.Keyword;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.TransactionBlock;
import redis.clients.jedis.exceptions.JedisDataException;
public class TransactionCommandsTest extends JedisCommandTestBase {
@@ -70,41 +71,6 @@ public class TransactionCommandsTest extends JedisCommandTestBase {
}
@Test
public void multiBlock() {
List<Object> response = jedis.multi(new TransactionBlock() {
@Override
public void execute() {
sadd("foo", "a");
sadd("foo", "b");
scard("foo");
}
});
List<Object> expected = new ArrayList<Object>();
expected.add(1L);
expected.add(1L);
expected.add(2L);
assertEquals(expected, response);
// Binary
response = jedis.multi(new TransactionBlock() {
@Override
public void execute() {
sadd(bfoo, ba);
sadd(bfoo, bb);
scard(bfoo);
}
});
expected = new ArrayList<Object>();
expected.add(1L);
expected.add(1L);
expected.add(2L);
assertEquals(expected, response);
}
@Test
public void watch() throws UnknownHostException, IOException {
jedis.watch("mykey", "somekey");
@@ -294,4 +260,48 @@ public class TransactionCommandsTest extends JedisCommandTestBase {
assertNull(results);
}
@Test
public void testResetStateWhenInMulti() {
jedis.auth("foobared");
Transaction t = jedis.multi();
t.set("foooo", "barrr");
jedis.resetState();
assertEquals(null, jedis.get("foooo"));
}
@Test
public void testResetStateWhenInMultiWithinPipeline() {
jedis.auth("foobared");
Pipeline p = jedis.pipelined();
p.multi();
p.set("foooo", "barrr");
jedis.resetState();
assertEquals(null, jedis.get("foooo"));
}
@Test
public void testResetStateWhenInWatch() {
jedis.watch("mykey", "somekey");
// state reset : unwatch
jedis.resetState();
Transaction t = jedis.multi();
nj.connect();
nj.auth("foobared");
nj.set("mykey", "bar");
nj.disconnect();
t.set("mykey", "foo");
List<Object> resp = t.exec();
assertNotNull(resp);
assertEquals(1, resp.size());
assertEquals("foo", jedis.get("mykey"));
}
}

View File

@@ -52,7 +52,7 @@ public class VariadicCommandsTest extends JedisCommandTestBase {
expected.add("bar");
expected.add("foo");
List<String> values = jedis.lrange("foo",0,-1);
List<String> values = jedis.lrange("foo", 0, -1);
assertEquals(expected, values);
// Binary
@@ -77,7 +77,7 @@ public class VariadicCommandsTest extends JedisCommandTestBase {
expected.add("foo");
expected.add("bar");
List<String> values = jedis.lrange("foo",0,-1);
List<String> values = jedis.lrange("foo", 0, -1);
assertEquals(expected, values);
// Binary
@@ -117,30 +117,30 @@ public class VariadicCommandsTest extends JedisCommandTestBase {
@Test
public void zadd() {
Map<Double, String> scoreMembers = new HashMap<Double, String>();
scoreMembers.put(1d, "bar");
scoreMembers.put(10d, "foo");
Map<String, Double> scoreMembers = new HashMap<String, Double>();
scoreMembers.put("bar", 1d);
scoreMembers.put("foo", 10d);
long status = jedis.zadd("foo", scoreMembers);
assertEquals(2, status);
scoreMembers.clear();
scoreMembers.put(0.1d, "car");
scoreMembers.put(2d, "bar");
scoreMembers.put("car", 0.1d);
scoreMembers.put("bar", 2d);
status = jedis.zadd("foo", scoreMembers);
assertEquals(1, status);
Map<Double, byte[]> bscoreMembers = new HashMap<Double, byte[]>();
bscoreMembers.put(1d, bbar);
bscoreMembers.put(10d, bfoo);
Map<byte[], Double> bscoreMembers = new HashMap<byte[], Double>();
bscoreMembers.put(bbar, 1d);
bscoreMembers.put(bfoo, 10d);
status = jedis.zadd(bfoo, bscoreMembers);
assertEquals(2, status);
bscoreMembers.clear();
bscoreMembers.put(0.1d, bcar);
bscoreMembers.put(2d, bbar);
bscoreMembers.put(bcar, 0.1d);
bscoreMembers.put(bbar, 2d);
status = jedis.zadd(bfoo, bscoreMembers);
assertEquals(1, status);
@@ -167,7 +167,7 @@ public class VariadicCommandsTest extends JedisCommandTestBase {
status = jedis.zrem("foo", "bar", "foo1");
assertEquals(1, status);
//Binary
// Binary
jedis.zadd(bfoo, 1d, bbar);
jedis.zadd(bfoo, 2d, bcar);
jedis.zadd(bfoo, 3d, bfoo1);

View File

@@ -0,0 +1,17 @@
package redis.clients.jedis.tests.utils;
public class FailoverAbortedException extends RuntimeException {
private static final long serialVersionUID = 1925110762858409954L;
public FailoverAbortedException(String message) {
super(message);
}
public FailoverAbortedException(Throwable cause) {
super(cause);
}
public FailoverAbortedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,70 @@
package redis.clients.jedis.tests.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisException;
public class JedisClusterTestUtil {
public static void waitForClusterReady(Jedis...nodes) throws InterruptedException {
boolean clusterOk = false;
while (!clusterOk) {
boolean isOk = true;
for (Jedis node : nodes) {
if (!node.clusterInfo().split("\n")[0].contains("ok")) {
isOk = false;
break;
}
}
if (isOk) {
clusterOk = true;
}
Thread.sleep(50);
}
}
public static String getNodeId(String infoOutput) {
for (String infoLine : infoOutput.split("\n")) {
if (infoLine.contains("myself")) {
return infoLine.split(" ")[0];
}
}
return "";
}
public static void assertNodeIsKnown(Jedis node, String targetNodeId, int timeoutMs) {
assertNodeRecognizedStatus(node, targetNodeId, true, timeoutMs);
}
public static void assertNodeIsUnknown(Jedis node, String targetNodeId, int timeoutMs) {
assertNodeRecognizedStatus(node, targetNodeId, false, timeoutMs);
}
private static void assertNodeRecognizedStatus(Jedis node, String targetNodeId, boolean shouldRecognized, int timeoutMs) {
int sleepInterval = 100;
for (int sleepTime = 0 ; sleepTime <= timeoutMs ; sleepTime += sleepInterval) {
boolean known = isKnownNode(node, targetNodeId);
if (shouldRecognized == known)
return;
try {
Thread.sleep(sleepInterval);
} catch (InterruptedException e) {
}
}
throw new JedisException("Node recognize check error");
}
private static boolean isKnownNode(Jedis node, String nodeId) {
String infoOutput = node.clusterNodes();
for (String infoLine : infoOutput.split("\n")) {
if (infoLine.contains(nodeId)) {
return true;
}
}
return false;
}
}

View File

@@ -1,128 +1,60 @@
package redis.clients.jedis.tests.utils;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.tests.utils.FailoverAbortedException;
public class JedisSentinelTestUtil {
public static void waitForSentinelRecognizeRedisReplication(
HostAndPort sentinel, String masterName, HostAndPort master,
List<HostAndPort> slaves) throws InterruptedException {
Jedis sentinelJedis = new Jedis(sentinel.getHost(), sentinel.getPort());
while (true) {
Thread.sleep(1000);
if (!isMasterRecognized(sentinelJedis, masterName, master)) {
System.out.println("Master not recognized by Sentinel "
+ sentinel.getHost() + ":" + sentinel.getPort()
+ ", sleep...");
continue;
}
if (!isSlavesRecognized(sentinelJedis, masterName, slaves)) {
System.out.println("Slaves not recognized by Sentinel "
+ sentinel.getHost() + ":" + sentinel.getPort()
+ ", sleep...");
continue;
}
// all recognized
break;
}
}
public static HostAndPort waitForNewPromotedMaster(HostAndPort sentinel,
String masterName, HostAndPort oldMaster)
public static HostAndPort waitForNewPromotedMaster(Jedis sentinelJedis)
throws InterruptedException {
Jedis sentinelJedis = new Jedis(sentinel.getHost(), sentinel.getPort());
HostAndPort newMaster = null;
while (true) {
Thread.sleep(1000);
final AtomicReference<String> newmaster = new AtomicReference<String>(
"");
List<String> sentinelMasterInfos = sentinelJedis
.sentinelGetMasterAddrByName(masterName);
if (sentinelMasterInfos == null)
continue;
sentinelJedis.psubscribe(new JedisPubSub() {
newMaster = new HostAndPort(sentinelMasterInfos.get(0),
Integer.parseInt(sentinelMasterInfos.get(1)));
if (!newMaster.equals(oldMaster))
break;
System.out
.println("Sentinel's master is not yet changed, sleep...");
@Override
public void onMessage(String channel, String message) {
}
@Override
public void onPMessage(String pattern, String channel,
String message) {
if (channel.equals("+switch-master")) {
newmaster.set(message);
punsubscribe();
} else if (channel.startsWith("-failover-abort")) {
punsubscribe();
throw new FailoverAbortedException("Unfortunately sentinel cannot failover... reason(channel) : " +
channel + " / message : " + message);
}
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
}
}, "*");
String[] chunks = newmaster.get().split(" ");
HostAndPort newMaster = new HostAndPort(chunks[3],
Integer.parseInt(chunks[4]));
return newMaster;
}
public static void waitForSentinelsRecognizeEachOthers()
throws InterruptedException {
// During failover, master has been changed
// It means that sentinels need to recognize other sentinels from new
// master's hello channel
// Without recognizing, Sentinels cannot run failover
// Sentinels need to take some time to recognize each other...
// http://redis.io/topics/sentinel
// Sentinel Rule #8: Every Sentinel publishes a message to every
// monitored master
// Pub/Sub channel __sentinel__:hello, every five seconds, blabla...
// FIXME There're no command for sentinel to list recognized sentinels
// so sleep wisely (channel's hello message interval + margin)
Thread.sleep(5000 + 500);
}
private static boolean isMasterRecognized(Jedis sentinelJedis,
String masterName, HostAndPort master) {
List<String> sentinelMasterInfos = sentinelJedis
.sentinelGetMasterAddrByName(masterName);
if (sentinelMasterInfos == null)
return false;
HostAndPort sentinelMaster = new HostAndPort(
sentinelMasterInfos.get(0),
Integer.parseInt(sentinelMasterInfos.get(1)));
return sentinelMaster.equals(master);
}
private static boolean isSlavesRecognized(Jedis sentinelJedis,
String masterName, List<HostAndPort> slaves) {
List<Map<String, String>> slavesMap = sentinelJedis
.sentinelSlaves(masterName);
if (slavesMap.size() != slaves.size())
return false;
int slavesRecognized = 0;
for (HostAndPort slave : slaves) {
if (isSlaveFoundInSlavesMap(slavesMap, slave))
slavesRecognized++;
}
return slavesRecognized == slaves.size();
}
private static boolean isSlaveFoundInSlavesMap(
List<Map<String, String>> slavesMap, HostAndPort slave) {
for (Map<String, String> slaveMap : slavesMap) {
HostAndPort sentinelSlave = new HostAndPort(slaveMap.get("ip"),
Integer.parseInt(slaveMap.get("port")));
if (sentinelSlave.equals(slave))
return true;
}
return false;
}
}