Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #1248: Avoid queueing multiple cluster discovers of the same type #1249

Merged
merged 1 commit into from Apr 4, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 27 additions & 21 deletions src/main/java/redis/clients/jedis/JedisClusterInfoCache.java
Expand Up @@ -22,6 +22,7 @@ public class JedisClusterInfoCache {
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
private volatile boolean rediscovering;
private final GenericObjectPoolConfig poolConfig;

private int connectionTimeout;
Expand Down Expand Up @@ -79,36 +80,41 @@ public void discoverClusterNodesAndSlots(Jedis jedis) {
}

public void discoverClusterSlots(Jedis jedis) {
w.lock();
//If rediscovering is already in process - no need to start one more same rediscovering, just return
if (!rediscovering) {
w.lock();
rediscovering = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Late to the party, but a possible perf enhancement here might be to check rediscovering again:

if (!rediscovering) {
  w.lock();
  if (rediscovering) {
    return;
  }

That way, if multiple threads make it past the initial check when under high load and block at lock acquisition, only the first one will do the work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't help. We set it to true only after lock and to false before releasing lock, so if thread got write lock - it's always false in this var.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right. This looks like a candidate for a double-checked locking pattern, but because we're resetting rediscovering it won't work. Darn. It'd be nice to be able to get rid of those extra rediscovers.

(And this, friends, is why I shouldn't read PRs before coffee.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


try {
this.slots.clear();
try {
this.slots.clear();

List<Object> slots = jedis.clusterSlots();
List<Object> slots = jedis.clusterSlots();

for (Object slotInfoObj : slots) {
List<Object> slotInfo = (List<Object>) slotInfoObj;
for (Object slotInfoObj : slots) {
List<Object> slotInfo = (List<Object>) slotInfoObj;

if (slotInfo.size() <= 2) {
continue;
}
if (slotInfo.size() <= 2) {
continue;
}

List<Integer> slotNums = getAssignedSlotArray(slotInfo);
List<Integer> slotNums = getAssignedSlotArray(slotInfo);

// hostInfos
List<Object> hostInfos = (List<Object>) slotInfo.get(2);
if (hostInfos.isEmpty()) {
continue;
}
// hostInfos
List<Object> hostInfos = (List<Object>) slotInfo.get(2);
if (hostInfos.isEmpty()) {
continue;
}

// at this time, we just use master, discard slave information
HostAndPort targetNode = generateHostAndPort(hostInfos);
// at this time, we just use master, discard slave information
HostAndPort targetNode = generateHostAndPort(hostInfos);

setNodeIfNotExist(targetNode);
assignSlotsToNode(slotNums, targetNode);
setNodeIfNotExist(targetNode);
assignSlotsToNode(slotNums, targetNode);
}
} finally {
rediscovering = false;
w.unlock();
}
} finally {
w.unlock();
}
}

Expand Down