package redis.clients.jedis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.Map;
import java.util.Random;
import java.util.Set;

import static redis.clients.jedis.JedisClusterInfoCache.getNodeKey;

public abstract class JedisClusterConnectionHandler {
    protected final JedisClusterInfoCache cache;

    abstract Jedis getConnection();

    public void returnConnection(Jedis connection) {
	cache.getNode(getNodeKey(connection.getClient())).returnResource(
		connection);
    }

    public void returnBrokenConnection(Jedis connection) {
	cache.getNode(getNodeKey(connection.getClient())).returnBrokenResource(
		connection);
    }

    abstract Jedis getConnectionFromSlot(int slot);

    public JedisClusterConnectionHandler(Set<HostAndPort> nodes, final GenericObjectPoolConfig poolConfig) {
    this.cache = new JedisClusterInfoCache(poolConfig);
	initializeSlotsCache(nodes, poolConfig);
    }

    public Map<String, JedisPool> getNodes() {
	return cache.getNodes();
    }

    public void assignSlotToNode(int slot, HostAndPort targetNode) {
	cache.assignSlotToNode(slot, targetNode);
    }

    private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig) {
	for (HostAndPort hostAndPort : startNodes) {
	    JedisPool jp = new JedisPool(poolConfig, hostAndPort.getHost(),
		    hostAndPort.getPort());

	    Jedis jedis = null;
	    try {
		jedis = jp.getResource();
		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 : cache.getNodes().values()) {
	    Jedis jedis = null;
	    try {
		jedis = jp.getResource();
		cache.discoverClusterSlots(jedis);
		break;
	    } finally {
		if (jedis != null) {
		    jedis.close();
		}
	    }
	}
    }

    protected JedisPool getRandomConnection() {
	Object[] nodeArray = cache.getNodes().values().toArray();
	return (JedisPool) (nodeArray[new Random().nextInt(nodeArray.length)]);
    }

}

@@ -391,16 +391,84 @@
 e cache;
+%0A    private ThreadLocal%3CRandom%3E random = new ThreadLocal%3CRandom%3E();
 %0A%0A    ab
@@ -956,20 +956,17 @@
 nfig) %7B%0A
-    
+%09
 this.cac
@@ -1009,16 +1009,48 @@
 onfig);%0A
+%09this.random.set(new Random());%0A
 %09initial
@@ -2298,26 +2298,31 @@
 deArray%5B
-new R
+this.r
 andom
+.get
 ().nextI

use ThreadLocal<Random> instead of creating Random each time