
redis.clients.jedis.providers.ClusterConnectionProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jedis Show documentation
Show all versions of jedis Show documentation
Jedis is a blazingly small and sane Redis java client.
package redis.clients.jedis.providers;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.ClusterCommandArguments;
import redis.clients.jedis.CommandArguments;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisClientConfig;
import redis.clients.jedis.Connection;
import redis.clients.jedis.ConnectionPool;
import redis.clients.jedis.JedisClusterInfoCache;
import redis.clients.jedis.annots.Experimental;
import redis.clients.jedis.csc.Cache;
import redis.clients.jedis.exceptions.JedisClusterOperationException;
import redis.clients.jedis.exceptions.JedisException;
import static redis.clients.jedis.JedisCluster.INIT_NO_ERROR_PROPERTY;
public class ClusterConnectionProvider implements ConnectionProvider {
protected final JedisClusterInfoCache cache;
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig) {
this.cache = new JedisClusterInfoCache(clientConfig, clusterNodes);
initializeSlotsCache(clusterNodes, clientConfig);
}
@Experimental
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache) {
this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, clusterNodes);
initializeSlotsCache(clusterNodes, clientConfig);
}
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig,
GenericObjectPoolConfig poolConfig) {
this.cache = new JedisClusterInfoCache(clientConfig, poolConfig, clusterNodes);
initializeSlotsCache(clusterNodes, clientConfig);
}
@Experimental
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache,
GenericObjectPoolConfig poolConfig) {
this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, poolConfig, clusterNodes);
initializeSlotsCache(clusterNodes, clientConfig);
}
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig,
GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod) {
this.cache = new JedisClusterInfoCache(clientConfig, poolConfig, clusterNodes, topologyRefreshPeriod);
initializeSlotsCache(clusterNodes, clientConfig);
}
@Experimental
public ClusterConnectionProvider(Set clusterNodes, JedisClientConfig clientConfig, Cache clientSideCache,
GenericObjectPoolConfig poolConfig, Duration topologyRefreshPeriod) {
this.cache = new JedisClusterInfoCache(clientConfig, clientSideCache, poolConfig, clusterNodes, topologyRefreshPeriod);
initializeSlotsCache(clusterNodes, clientConfig);
}
private void initializeSlotsCache(Set startNodes, JedisClientConfig clientConfig) {
if (startNodes.isEmpty()) {
throw new JedisClusterOperationException("No nodes to initialize cluster slots cache.");
}
ArrayList startNodeList = new ArrayList<>(startNodes);
Collections.shuffle(startNodeList);
JedisException firstException = null;
for (HostAndPort hostAndPort : startNodeList) {
try (Connection jedis = new Connection(hostAndPort, clientConfig)) {
cache.discoverClusterNodesAndSlots(jedis);
return;
} catch (JedisException e) {
if (firstException == null) {
firstException = e;
}
// try next nodes
}
}
if (System.getProperty(INIT_NO_ERROR_PROPERTY) != null) {
return;
}
JedisClusterOperationException uninitializedException
= new JedisClusterOperationException("Could not initialize cluster slots cache.");
uninitializedException.addSuppressed(firstException);
throw uninitializedException;
}
@Override
public void close() {
cache.close();
}
public void renewSlotCache() {
cache.renewClusterSlots(null);
}
public void renewSlotCache(Connection jedis) {
cache.renewClusterSlots(jedis);
}
public Map getNodes() {
return cache.getNodes();
}
public HostAndPort getNode(int slot) {
return slot >= 0 ? cache.getSlotNode(slot) : null;
}
public Connection getConnection(HostAndPort node) {
return node != null ? cache.setupNodeIfNotExist(node).getResource() : getConnection();
}
@Override
public Connection getConnection(CommandArguments args) {
final int slot = ((ClusterCommandArguments) args).getCommandHashSlot();
return slot >= 0 ? getConnectionFromSlot(slot) : getConnection();
}
public Connection getReplicaConnection(CommandArguments args) {
final int slot = ((ClusterCommandArguments) args).getCommandHashSlot();
return slot >= 0 ? getReplicaConnectionFromSlot(slot) : getConnection();
}
@Override
public Connection getConnection() {
// In antirez's redis-rb-cluster implementation, getRandomConnection always return
// valid connection (able to ping-pong) or exception if all connections are invalid
List pools = cache.getShuffledNodesPool();
JedisException suppressed = null;
for (ConnectionPool pool : pools) {
Connection jedis = null;
try {
jedis = pool.getResource();
if (jedis == null) {
continue;
}
jedis.ping();
return jedis;
} catch (JedisException ex) {
if (suppressed == null) { // remembering first suppressed exception
suppressed = ex;
}
if (jedis != null) {
jedis.close();
}
}
}
JedisClusterOperationException noReachableNode = new JedisClusterOperationException("No reachable node in cluster.");
if (suppressed != null) {
noReachableNode.addSuppressed(suppressed);
}
throw noReachableNode;
}
public Connection getConnectionFromSlot(int slot) {
ConnectionPool connectionPool = cache.getSlotPool(slot);
if (connectionPool != null) {
// It can't guaranteed to get valid connection because of node assignment
return connectionPool.getResource();
} else {
// It's abnormal situation for cluster mode that we have just nothing for slot.
// Try to rediscover state
renewSlotCache();
connectionPool = cache.getSlotPool(slot);
if (connectionPool != null) {
return connectionPool.getResource();
} else {
// no choice, fallback to new connection to random node
return getConnection();
}
}
}
public Connection getReplicaConnectionFromSlot(int slot) {
List connectionPools = cache.getSlotReplicaPools(slot);
ThreadLocalRandom random = ThreadLocalRandom.current();
if (connectionPools != null && !connectionPools.isEmpty()) {
// pick up randomly a connection
int idx = random.nextInt(connectionPools.size());
return connectionPools.get(idx).getResource();
}
renewSlotCache();
connectionPools = cache.getSlotReplicaPools(slot);
if (connectionPools != null && !connectionPools.isEmpty()) {
int idx = random.nextInt(connectionPools.size());
return connectionPools.get(idx).getResource();
}
return getConnectionFromSlot(slot);
}
@Override
public Map getConnectionMap() {
return Collections.unmodifiableMap(getNodes());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy