Implements Closeable to Pooled Jedis & ShardedJedis

* Implement Closeable from Jedis, ShardedJedis with Pooled
** resources from JedisPool, JedisSentinelPool, ShardedJedis, ShardedJedisPool
* Connection class : check whether Jedis Connection is broken
** when it's time to throw JedisConnectionException, mark Connection to broken
This commit is contained in:
Jungtaek Lim
2014-02-23 23:50:40 +09:00
parent e9cf469200
commit 670e019a89
11 changed files with 338 additions and 69 deletions

View File

@@ -1707,9 +1707,9 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands,
public List<Object> multi(final TransactionBlock jedisTransaction) {
List<Object> results = null;
jedisTransaction.setClient(client);
client.multi();
jedisTransaction.execute();
results = jedisTransaction.exec();
client.multi();
jedisTransaction.execute();
results = jedisTransaction.exec();
return results;
}
@@ -1729,8 +1729,10 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands,
}
public void resetState() {
client.resetState();
client.getAll();
if (client.isConnected()) {
client.resetState();
client.getAll();
}
}
public String watch(final byte[]... keys) {
@@ -1744,7 +1746,7 @@ public class BinaryJedis implements BasicCommands, BinaryJedisCommands,
}
@Override
public void close() {
public void close() {
client.close();
}

View File

@@ -11,7 +11,6 @@ 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;
@@ -25,6 +24,8 @@ public class Connection implements Closeable {
private int pipelinedCommands = 0;
private int timeout = Protocol.DEFAULT_TIMEOUT;
private boolean broken = false;
public Socket getSocket() {
return socket;
}
@@ -45,7 +46,8 @@ public class Connection implements Closeable {
socket.setKeepAlive(true);
socket.setSoTimeout(0);
} catch (SocketException ex) {
throw new JedisException(ex);
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -54,7 +56,8 @@ public class Connection implements Closeable {
socket.setSoTimeout(timeout);
socket.setKeepAlive(false);
} catch (SocketException ex) {
throw new JedisException(ex);
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -63,14 +66,6 @@ public class Connection implements Closeable {
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++) {
@@ -80,17 +75,29 @@ public class Connection implements Closeable {
}
protected Connection sendCommand(final Command cmd, final byte[]... args) {
connect();
Protocol.sendCommand(outputStream, cmd, args);
pipelinedCommands++;
return this;
try {
connect();
Protocol.sendCommand(outputStream, cmd, args);
pipelinedCommands++;
return this;
} catch (JedisConnectionException ex) {
// Any other exceptions related to connection?
broken = true;
throw ex;
}
}
protected Connection sendCommand(final Command cmd) {
connect();
Protocol.sendCommand(outputStream, cmd, new byte[0][]);
pipelinedCommands++;
return this;
try {
connect();
Protocol.sendCommand(outputStream, cmd, new byte[0][]);
pipelinedCommands++;
return this;
} catch (JedisConnectionException ex) {
// Any other exceptions related to connection?
broken = true;
throw ex;
}
}
public Connection(final String host, final int port) {
@@ -139,6 +146,7 @@ public class Connection implements Closeable {
outputStream = new RedisOutputStream(socket.getOutputStream());
inputStream = new RedisInputStream(socket.getInputStream());
} catch (IOException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -147,7 +155,7 @@ public class Connection implements Closeable {
@Override
public void close() {
disconnect();
}
}
public void disconnect() {
if (isConnected()) {
@@ -158,6 +166,7 @@ public class Connection implements Closeable {
socket.close();
}
} catch (IOException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
}
@@ -172,7 +181,7 @@ public class Connection implements Closeable {
protected String getStatusCodeReply() {
flush();
pipelinedCommands--;
final byte[] resp = (byte[]) Protocol.read(inputStream);
final byte[] resp = (byte[]) readProtocolWithCheckingBroken();
if (null == resp) {
return null;
} else {
@@ -192,13 +201,13 @@ public class Connection implements Closeable {
public byte[] getBinaryBulkReply() {
flush();
pipelinedCommands--;
return (byte[]) Protocol.read(inputStream);
return (byte[]) readProtocolWithCheckingBroken();
}
public Long getIntegerReply() {
flush();
pipelinedCommands--;
return (Long) Protocol.read(inputStream);
return (Long) readProtocolWithCheckingBroken();
}
public List<String> getMultiBulkReply() {
@@ -209,29 +218,29 @@ public class Connection implements Closeable {
public List<byte[]> getBinaryMultiBulkReply() {
flush();
pipelinedCommands--;
return (List<byte[]>) Protocol.read(inputStream);
return (List<byte[]>) readProtocolWithCheckingBroken();
}
public void resetPipelinedCount() {
pipelinedCommands = 0;
pipelinedCommands = 0;
}
@SuppressWarnings("unchecked")
public List<Object> getRawObjectMultiBulkReply() {
return (List<Object>) Protocol.read(inputStream);
return (List<Object>) readProtocolWithCheckingBroken();
}
public List<Object> getObjectMultiBulkReply() {
flush();
pipelinedCommands--;
return getRawObjectMultiBulkReply();
flush();
pipelinedCommands--;
return getRawObjectMultiBulkReply();
}
@SuppressWarnings("unchecked")
public List<Long> getIntegerMultiBulkReply() {
flush();
pipelinedCommands--;
return (List<Long>) Protocol.read(inputStream);
return (List<Long>) readProtocolWithCheckingBroken();
}
public List<Object> getAll() {
@@ -243,7 +252,7 @@ public class Connection implements Closeable {
flush();
while (pipelinedCommands > except) {
try {
all.add(Protocol.read(inputStream));
all.add(readProtocolWithCheckingBroken());
} catch (JedisDataException e) {
all.add(e);
}
@@ -255,6 +264,28 @@ public class Connection implements Closeable {
public Object getOne() {
flush();
pipelinedCommands--;
return Protocol.read(inputStream);
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;
}
}
}

View File

@@ -12,12 +12,16 @@ import java.util.Map.Entry;
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;
public class Jedis extends BinaryJedis implements JedisCommands,
MultiKeyCommands, AdvancedJedisCommands, ScriptingCommands,
BasicCommands, ClusterCommands {
protected Pool<Jedis> dataSource = null;
public Jedis(final String host) {
super(host);
}
@@ -3256,11 +3260,11 @@ public class Jedis extends BinaryJedis implements JedisCommands,
}
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);
@@ -3273,12 +3277,12 @@ public class Jedis extends BinaryJedis implements JedisCommands,
}
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();
@@ -3291,15 +3295,15 @@ public class Jedis extends BinaryJedis implements JedisCommands,
while (iterator.hasNext()) {
results.add(new AbstractMap.SimpleEntry<String, String>(SafeEncoder
.encode(iterator.next()), SafeEncoder.encode(iterator
.next())));
.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();
@@ -3313,11 +3317,11 @@ public class Jedis extends BinaryJedis implements JedisCommands,
}
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();
@@ -3412,4 +3416,21 @@ public class Jedis extends BinaryJedis implements JedisCommands,
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;
}
}

View File

@@ -79,6 +79,13 @@ 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) {
returnBrokenResourceObject(resource);
}

View File

@@ -74,15 +74,6 @@ public class JedisSentinelPool extends Pool<Jedis> {
initPool(master);
}
public void returnBrokenResource(final Jedis resource) {
returnBrokenResourceObject(resource);
}
public void returnResource(final Jedis resource) {
resource.resetState();
returnResourceObject(resource);
}
private volatile HostAndPort currentHostMaster;
public void destroy() {
@@ -171,6 +162,24 @@ public class JedisSentinelPool extends Pool<Jedis> {
return new HostAndPort(host, port);
}
@Override
public Jedis getResource() {
Jedis jedis = super.getResource();
jedis.setDataSource(this);
return jedis;
}
@Override
public void returnBrokenResource(final Jedis resource) {
returnBrokenResourceObject(resource);
}
@Override
public void returnResource(final Jedis resource) {
resource.resetState();
returnResourceObject(resource);
}
protected class JedisPubSubAdapter extends JedisPubSub {
@Override
public void onMessage(String channel, String message) {

View File

@@ -1,5 +1,6 @@
package redis.clients.jedis;
import java.io.Closeable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -8,8 +9,13 @@ import java.util.regex.Pattern;
import redis.clients.jedis.BinaryClient.LIST_POSITION;
import redis.clients.util.Hashing;
import redis.clients.util.Pool;
public class ShardedJedis extends BinaryShardedJedis implements JedisCommands,
Closeable {
protected Pool<ShardedJedis> dataSource = null;
public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
public ShardedJedis(List<JedisShardInfo> shards) {
super(shards);
}
@@ -555,19 +561,53 @@ public class ShardedJedis extends BinaryShardedJedis implements JedisCommands {
Jedis j = getShard(key);
return j.zscan(key, cursor);
}
public ScanResult<Entry<String, String>> hscan(String key, final String 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();
}
}
}

View File

@@ -31,6 +31,25 @@ public class ShardedJedisPool extends Pool<ShardedJedis> {
List<JedisShardInfo> shards, Hashing algo, Pattern keyTagPattern) {
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) {
returnBrokenResourceObject(resource);
}
@Override
public void returnResource(final ShardedJedis resource) {
resource.resetState();
returnResourceObject(resource);
}
/**
* PoolableObjectFactory custom impl.