package redis.clients.jedis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.exceptions.*;
import redis.clients.util.JedisClusterCRC16;
/**
* Created by yijunzhang on 14-7-19.
*/
public class SubPubClusterCommand {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
protected final PipelineCluster pipelineCluster;
private final JedisClusterConnectionHandler connectionHandler;
private final int redirections;
private ThreadLocal<Jedis> askConnection = new ThreadLocal<Jedis>();
public SubPubClusterCommand(PipelineCluster pipelineCluster, JedisClusterConnectionHandler connectionHandler,
int redirections) {
this.pipelineCluster = pipelineCluster;
this.connectionHandler = connectionHandler;
this.redirections = redirections;
}
private Jedis returnRetriesJedis(String key, int redirections,
boolean tryRandomNode, boolean asking) {
if (redirections <= 0) {
throw new JedisClusterMaxRedirectionsException(
"Too many Cluster redirections? key=" + key);
}
Jedis jedis = null;
try {
if (asking) {
// TODO: Pipeline asking with the original command to make it
// faster....
jedis = askConnection.get();
jedis.asking();
// if asking success, reset asking flag
asking = false;
} else if (tryRandomNode) {
jedis = connectionHandler.getConnection();
} else {
jedis = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));
}
return jedis;
} catch (JedisConnectionException jce) {
if (tryRandomNode) {
// maybe all connection is down
throw jce;
}
releaseConnection(jedis);
// retry with random connection
return returnRetriesJedis(key, redirections--, true, asking);
} catch (JedisRedirectionException jre) {
// if MOVED redirection occurred,
if (jre instanceof JedisMovedDataException) {
// it rebuilds cluster's slot cache
// recommended by Redis cluster specification
this.connectionHandler.renewSlotCache(jedis);
}
// release current connection before recursion or renewing
releaseConnection(jedis);
jedis = null;
if (jre instanceof JedisAskDataException) {
asking = true;
askConnection.set(this.connectionHandler.getConnectionFromNode(jre.getTargetNode()));
} else if (jre instanceof JedisMovedDataException) {
} else {
throw new JedisClusterException(jre);
}
return returnRetriesJedis(key, redirections - 1, false, asking);
}
}
public Jedis getJedis(String channel) {
return returnRetriesJedis(channel, this.redirections, false, false);
}
public Jedis getNewJedis(String channel, int timeout) {
Jedis jedis = getJedis(channel);
try {
String host = jedis.getClient().getHost();
int port = jedis.getClient().getPort();
Jedis newJedis = new Jedis(host, port, timeout);
String pong = newJedis.ping();
if (pong == null || !pong.equals("PONG")) {
throw new JedisException("SubPubCluster:jedis is not ping !");
}
return newJedis;
} finally {
releaseConnection(jedis);
}
}
public void releaseConnection(Jedis connection) {
if (connection != null) {
connection.close();
}
}
}