Skip to content

Commit ec87a52

Browse files
committed
Issue #1252: Acquire one long lock for trying all nodes when rediscover cluster
1 parent a5961d0 commit ec87a52

File tree

3 files changed

+64
-58
lines changed

3 files changed

+64
-58
lines changed

src/main/java/redis/clients/jedis/JedisClusterConnectionHandler.java

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package redis.clients.jedis;
22

33
import java.io.Closeable;
4-
import java.util.ArrayList;
5-
import java.util.Collections;
6-
import java.util.List;
74
import java.util.Map;
85
import java.util.Set;
96

@@ -49,39 +46,15 @@ private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPool
4946
}
5047

5148
public void renewSlotCache() {
52-
for (JedisPool jp : getShuffledNodesPool()) {
53-
Jedis jedis = null;
54-
try {
55-
jedis = jp.getResource();
56-
cache.discoverClusterSlots(jedis);
57-
break;
58-
} catch (JedisConnectionException e) {
59-
// try next nodes
60-
} finally {
61-
if (jedis != null) {
62-
jedis.close();
63-
}
64-
}
65-
}
49+
cache.renewClusterSlots(null);
6650
}
6751

6852
public void renewSlotCache(Jedis jedis) {
69-
try {
70-
cache.discoverClusterSlots(jedis);
71-
} catch (JedisConnectionException e) {
72-
renewSlotCache();
73-
}
53+
cache.renewClusterSlots(jedis);
7454
}
7555

7656
@Override
7757
public void close() {
7858
cache.reset();
7959
}
80-
81-
protected List<JedisPool> getShuffledNodesPool() {
82-
List<JedisPool> pools = new ArrayList<JedisPool>();
83-
pools.addAll(cache.getNodes().values());
84-
Collections.shuffle(pools);
85-
return pools;
86-
}
8760
}

src/main/java/redis/clients/jedis/JedisClusterInfoCache.java

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package redis.clients.jedis;
22

33
import java.util.ArrayList;
4+
import java.util.Collections;
45
import java.util.HashMap;
56
import java.util.List;
67
import java.util.Map;
@@ -13,6 +14,8 @@
1314

1415
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
1516

17+
import redis.clients.jedis.exceptions.JedisConnectionException;
18+
import redis.clients.jedis.exceptions.JedisException;
1619
import redis.clients.util.SafeEncoder;
1720

1821
public class JedisClusterInfoCache {
@@ -77,39 +80,34 @@ public void discoverClusterNodesAndSlots(Jedis jedis) {
7780
}
7881
}
7982

80-
public void discoverClusterSlots(Jedis jedis) {
83+
public void renewClusterSlots(Jedis jedis) {
8184
//If rediscovering is already in process - no need to start one more same rediscovering, just return
8285
if (!rediscovering) {
83-
w.lock();
84-
rediscovering = true;
85-
8686
try {
87-
List<Object> slots = jedis.clusterSlots();
88-
89-
// We should clear slots after getting result about cluster slots, because if we got exception or timeout in
90-
// getting new slots state, which is possible, because it's an external operation - we could got empty slots collection
91-
// and ton of new Jedis instances for random nodes, see JedisSlotBasedConnectionHandler#getConnectionFromSlot
92-
this.slots.clear();
93-
94-
for (Object slotInfoObj : slots) {
95-
List<Object> slotInfo = (List<Object>) slotInfoObj;
96-
97-
if (slotInfo.size() <= MASTER_NODE_INDEX) {
98-
continue;
87+
w.lock();
88+
rediscovering = true;
89+
90+
if (jedis != null) {
91+
try {
92+
discoverClusterSlots(jedis);
93+
return;
94+
} catch (JedisException e) {
95+
//try nodes from all pools
9996
}
97+
}
10098

101-
List<Integer> slotNums = getAssignedSlotArray(slotInfo);
102-
103-
// hostInfos
104-
List<Object> hostInfos = (List<Object>) slotInfo.get(MASTER_NODE_INDEX);
105-
if (hostInfos.isEmpty()) {
106-
continue;
99+
for (JedisPool jp : getShuffledNodesPool()) {
100+
try {
101+
jedis = jp.getResource();
102+
discoverClusterSlots(jedis);
103+
return;
104+
} catch (JedisConnectionException e) {
105+
// try next nodes
106+
} finally {
107+
if (jedis != null) {
108+
jedis.close();
109+
}
107110
}
108-
109-
// at this time, we just use master, discard slave information
110-
HostAndPort targetNode = generateHostAndPort(hostInfos);
111-
112-
assignSlotsToNode(slotNums, targetNode);
113111
}
114112
} finally {
115113
rediscovering = false;
@@ -118,6 +116,31 @@ public void discoverClusterSlots(Jedis jedis) {
118116
}
119117
}
120118

119+
private void discoverClusterSlots(Jedis jedis) {
120+
List<Object> slots = jedis.clusterSlots();
121+
this.slots.clear();
122+
123+
for (Object slotInfoObj : slots) {
124+
List<Object> slotInfo = (List<Object>) slotInfoObj;
125+
126+
if (slotInfo.size() <= MASTER_NODE_INDEX) {
127+
continue;
128+
}
129+
130+
List<Integer> slotNums = getAssignedSlotArray(slotInfo);
131+
132+
// hostInfos
133+
List<Object> hostInfos = (List<Object>) slotInfo.get(MASTER_NODE_INDEX);
134+
if (hostInfos.isEmpty()) {
135+
continue;
136+
}
137+
138+
// at this time, we just use master, discard slave information
139+
HostAndPort targetNode = generateHostAndPort(hostInfos);
140+
assignSlotsToNode(slotNums, targetNode);
141+
}
142+
}
143+
121144
private HostAndPort generateHostAndPort(List<Object> hostInfos) {
122145
return new HostAndPort(SafeEncoder.encode((byte[]) hostInfos.get(0)),
123146
((Long) hostInfos.get(1)).intValue());
@@ -222,6 +245,17 @@ public Map<String, JedisPool> getNodes() {
222245
}
223246
}
224247

248+
public List<JedisPool> getShuffledNodesPool() {
249+
r.lock();
250+
try {
251+
List<JedisPool> pools = new ArrayList<JedisPool>(nodes.values());
252+
Collections.shuffle(pools);
253+
return pools;
254+
} finally {
255+
r.unlock();
256+
}
257+
}
258+
225259
/**
226260
* Clear discovered nodes collections and gently release allocated resources
227261
*/
@@ -264,5 +298,4 @@ private List<Integer> getAssignedSlotArray(List<Object> slotInfo) {
264298
}
265299
return slotNums;
266300
}
267-
268301
}

src/main/java/redis/clients/jedis/JedisSlotBasedConnectionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public Jedis getConnection() {
2727
// ping-pong)
2828
// or exception if all connections are invalid
2929

30-
List<JedisPool> pools = getShuffledNodesPool();
30+
List<JedisPool> pools = cache.getShuffledNodesPool();
3131

3232
for (JedisPool pool : pools) {
3333
Jedis jedis = null;

0 commit comments

Comments
 (0)