public abstract class JedisClusterConnectionHandler {
protected final JedisClusterInfoCache cache;
public JedisClusterConnectionHandler(Set nodes,
final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout) {
this.cache = new JedisClusterInfoCache(poolConfig, connectionTimeout, soTimeout);
//通过slot 初始化集群信息
initializeSlotsCache(nodes, poolConfig);
}
abstract Jedis getConnection();
abstract Jedis getConnectionFromSlot(int slot);
public Jedis getConnectionFromNode(HostAndPort node) {
cache.setNodeIfNotExist(node);
return cache.getNode(JedisClusterInfoCache.getNodeKey(node)).getResource();
}
public class JedisClusterInfoCache {
private Map nodes = new HashMap();
private Map slots = new HashMap();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
private final GenericObjectPoolConfig poolConfig;
private int connectionTimeout;
private int soTimeout;
private static final int MASTER_NODE_INDEX = 2;
public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig, int timeout) {
this(poolConfig, timeout, timeout);
}
public JedisClusterInfoCache(final GenericObjectPoolConfig poolConfig,
final int connectionTimeout, final int soTimeout) {
this.poolConfig = poolConfig;
this.connectionTimeout = connectionTimeout;
this.soTimeout = soTimeout;
}
public void discoverClusterNodesAndSlots(Jedis jedis) {
w.lock();
try {
this.nodes.clear();
this.slots.clear();
List slots = jedis.clusterSlots();
for (Object slotInfoObj : slots) {
List slotInfo = (List) slotInfoObj;
if (slotInfo.size() <= MASTER_NODE_INDEX) {
continue;
}
List slotNums = getAssignedSlotArray(slotInfo);
// hostInfos
int size = slotInfo.size();
for (int i = MASTER_NODE_INDEX; i
List hostInfos = (List) slotInfo.get(i);
if (hostInfos.size() <= 0) {
continue;
}
HostAndPort targetNode = generateHostAndPort(hostInfos);
setNodeIfNotExist(targetNode);
if (i == MASTER_NODE_INDEX) {
assignSlotsToNode(slotNums, targetNode);
}
}
}
} finally {
w.unlock();
}
}
//初始化集群信息
public void discoverClusterSlots(Jedis jedis) {
w.lock();
try {
this.slots.clear();
//通过 slots 命令获取集群信息
List slots = jedis.clusterSlots();
for (Object slotInfoObj : slots) {
List slotInfo = (List) slotInfoObj;
if (slotInfo.size() <= 2) {
continue;
}
List slotNums = getAssignedSlotArray(slotInfo);
// hostInfos
List hostInfos = (List) slotInfo.get(2);
if (hostInfos.size() <= 0) {
continue;
}
// at this time, we just use master, discard slave information
HostAndPort targetNode = generateHostAndPort(hostInfos);
setNodeIfNotExist(targetNode);
assignSlotsToNode(slotNums, targetNode);
}
} finally {
w.unlock();
}
}
private HostAndPort generateHostAndPort(List hostInfos) {
return new HostAndPort(SafeEncoder.encode((byte[]) hostInfos.get(0)),
((Long) hostInfos.get(1)).intValue());
}
public void setNodeIfNotExist(HostAndPort node) {
w.lock();
try {
String nodeKey = getNodeKey(node);
if (nodes.containsKey(nodeKey)) return;
JedisPool nodePool = new JedisPool(poolConfig, node.getHost(), node.getPort(),
connectionTimeout, soTimeout, null, 0, null);
nodes.put(nodeKey, nodePool);
} finally {
w.unlock();
}
}
public void assignSlotToNode(int slot, HostAndPort targetNode) {
w.lock();
try {
JedisPool targetPool = nodes.get(getNodeKey(targetNode));
if (targetPool == null) {
setNodeIfNotExist(targetNode);
targetPool = nodes.get(getNodeKey(targetNode));
}
slots.put(slot, targetPool);
} finally {
w.unlock();
}
}
public void assignSlotsToNode(List targetSlots, HostAndPort targetNode) {
w.lock();
try {
JedisPool targetPool = nodes.get(getNodeKey(targetNode));
if (targetPool == null) {
setNodeIfNotExist(targetNode);
targetPool = nodes.get(getNodeKey(targetNode));
}
for (Integer slot : targetSlots) {
slots.put(slot, targetPool);
}
} finally {
w.unlock();
}
}
public JedisPool getNode(String nodeKey) {
r.lock();
try {
return nodes.get(nodeKey);
} finally {
r.unlock();
}
}
public JedisPool getSlotPool(int slot) {
r.lock();
try {
return slots.get(slot);
} finally {
r.unlock();
}
}
public Map getNodes() {
r.lock();
try {
return new HashMap(nodes);
} finally {
r.unlock();
}
}
public static String getNodeKey(HostAndPort hnp) {
return hnp.getHost() + ":" + hnp.getPort();
}
public static String getNodeKey(Client client) {
return client.getHost() + ":" + client.getPort();
}
public static String getNodeKey(Jedis jedis) {
return getNodeKey(jedis.getClient());
}
private List getAssignedSlotArray(List slotInfo) {
List slotNums = new ArrayList();
for (int slot = ((Long) slotInfo.get(0)).intValue(); slot <= ((Long) slotInfo.get(1))
.intValue(); slot++) {
slotNums.add(slot);
}
return slotNums;
}
}
public Map getNodes() {
return cache.getNodes();
}
private void initializeSlotsCache(Set startNodes, GenericObjectPoolConfig poolConfig) {
for (HostAndPort hostAndPort : startNodes) {
Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort());
try {
cache.discoverClusterNodesAndSlots(jedis);
break;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if (jedis != null) {
jedis.close();
}
}
}
for (HostAndPort node : startNodes) {
cache.setNodeIfNotExist(node);
}
}
public void renewSlotCache() {
for (JedisPool jp : getShuffledNodesPool()) {
Jedis jedis = null;
try {
jedis = jp.getResource();
cache.discoverClusterSlots(jedis);
break;
} catch (JedisConnectionException e) {
// try next nodes
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
public void renewSlotCache(Jedis jedis) {
try {
cache.discoverClusterSlots(jedis);
} catch (JedisConnectionException e) {
renewSlotCache();
}
}
protected List getShuffledNodesPool() {
List pools = new ArrayList();
pools.addAll(cache.getNodes().values());
Collections.shuffle(pools);
return pools;
}
}