Unverified Commit 5b48d900 authored by KinWaiYuen's avatar KinWaiYuen Committed by GitHub
Browse files

Optimize CLUSTER SLOTS reply by reducing unneeded loops (#8541)

This commit more efficiently computes the cluster bulk slots response 
by looping over the entire slot space once, instead of for each node.
parent 3c09ce26
...@@ -4313,60 +4313,11 @@ int getSlotOrReply(client *c, robj *o) { ...@@ -4313,60 +4313,11 @@ int getSlotOrReply(client *c, robj *o) {
return (int) slot; return (int) slot;
} }
void clusterReplyMultiBulkSlots(client *c) { void addNodeReplyForClusterSlot(client *c, clusterNode *node, int start_slot, int end_slot) {
/* Format: 1) 1) start slot int i, nested_elements = 3; /* slots (2) + master addr (1) */
* 2) end slot void *nested_replylen = addReplyDeferredLen(c);
* 3) 1) master IP addReplyLongLong(c, start_slot);
* 2) master port addReplyLongLong(c, end_slot);
* 3) node ID
* 4) 1) replica IP
* 2) replica port
* 3) node ID
* ... continued until done
*/
int num_masters = 0;
void *slot_replylen = addReplyDeferredLen(c);
dictEntry *de;
dictIterator *di = dictGetSafeIterator(server.cluster->nodes);
while((de = dictNext(di)) != NULL) {
clusterNode *node = dictGetVal(de);
int j = 0, start = -1;
int i, nested_elements = 0;
/* Skip slaves (that are iterated when producing the output of their
* master) and masters not serving any slot. */
if (!nodeIsMaster(node) || node->numslots == 0) continue;
for(i = 0; i < node->numslaves; i++) {
if (nodeFailed(node->slaves[i])) continue;
nested_elements++;
}
for (j = 0; j < CLUSTER_SLOTS; j++) {
int bit, i;
if ((bit = clusterNodeGetSlotBit(node,j)) != 0) {
if (start == -1) start = j;
}
if (start != -1 && (!bit || j == CLUSTER_SLOTS-1)) {
addReplyArrayLen(c, nested_elements + 3); /* slots (2) + master addr (1). */
if (bit && j == CLUSTER_SLOTS-1) j++;
/* If slot exists in output map, add to it's list.
* else, create a new output map for this slot */
if (start == j-1) {
addReplyLongLong(c, start); /* only one slot; low==high */
addReplyLongLong(c, start);
} else {
addReplyLongLong(c, start); /* low */
addReplyLongLong(c, j-1); /* high */
}
start = -1;
/* First node reply position is always the master */
addReplyArrayLen(c, 3); addReplyArrayLen(c, 3);
addReplyBulkCString(c, node->ip); addReplyBulkCString(c, node->ip);
addReplyLongLong(c, node->port); addReplyLongLong(c, node->port);
...@@ -4375,18 +4326,51 @@ void clusterReplyMultiBulkSlots(client *c) { ...@@ -4375,18 +4326,51 @@ void clusterReplyMultiBulkSlots(client *c) {
/* Remaining nodes in reply are replicas for slot range */ /* Remaining nodes in reply are replicas for slot range */
for (i = 0; i < node->numslaves; i++) { for (i = 0; i < node->numslaves; i++) {
/* This loop is copy/pasted from clusterGenNodeDescription() /* This loop is copy/pasted from clusterGenNodeDescription()
* with modifications for per-slot node aggregation */ * with modifications for per-slot node aggregation. */
if (nodeFailed(node->slaves[i])) continue; if (nodeFailed(node->slaves[i])) continue;
addReplyArrayLen(c, 3); addReplyArrayLen(c, 3);
addReplyBulkCString(c, node->slaves[i]->ip); addReplyBulkCString(c, node->slaves[i]->ip);
addReplyLongLong(c, node->slaves[i]->port); addReplyLongLong(c, node->slaves[i]->port);
addReplyBulkCBuffer(c, node->slaves[i]->name, CLUSTER_NAMELEN); addReplyBulkCBuffer(c, node->slaves[i]->name, CLUSTER_NAMELEN);
nested_elements++;
} }
num_masters++; setDeferredArrayLen(c, nested_replylen, nested_elements);
}
void clusterReplyMultiBulkSlots(client * c) {
/* Format: 1) 1) start slot
* 2) end slot
* 3) 1) master IP
* 2) master port
* 3) node ID
* 4) 1) replica IP
* 2) replica port
* 3) node ID
* ... continued until done
*/
clusterNode *n = NULL;
int num_masters = 0, start = -1;
void *slot_replylen = addReplyDeferredLen(c);
for (int i = 0; i <= CLUSTER_SLOTS; i++) {
/* Find start node and slot id. */
if (n == NULL) {
if (i == CLUSTER_SLOTS) break;
n = server.cluster->slots[i];
start = i;
continue;
} }
/* Add cluster slots info when occur different node with start
* or end of slot. */
if (i == CLUSTER_SLOTS || n != server.cluster->slots[i]) {
addNodeReplyForClusterSlot(c, n, start, i-1);
num_masters++;
if (i == CLUSTER_SLOTS) break;
n = server.cluster->slots[i];
start = i;
} }
} }
dictReleaseIterator(di);
setDeferredArrayLen(c, slot_replylen, num_masters); setDeferredArrayLen(c, slot_replylen, num_masters);
} }
......
...@@ -37,26 +37,35 @@ set master2 [Rn 1] ...@@ -37,26 +37,35 @@ set master2 [Rn 1]
test "Continuous slots distribution" { test "Continuous slots distribution" {
assert_match "* 0-8191*" [$master1 CLUSTER NODES] assert_match "* 0-8191*" [$master1 CLUSTER NODES]
assert_match "* 8192-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-16383*" [$master2 CLUSTER NODES]
assert_match "*0 8191*" [$master1 CLUSTER SLOTS]
assert_match "*8192 16383*" [$master2 CLUSTER SLOTS]
$master1 CLUSTER DELSLOTS 4096 $master1 CLUSTER DELSLOTS 4096
assert_match "* 0-4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 0-4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*0 4095*4097 8191*" [$master1 CLUSTER SLOTS]
$master2 CLUSTER DELSLOTS 12288 $master2 CLUSTER DELSLOTS 12288
assert_match "* 8192-12287 12289-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-12287 12289-16383*" [$master2 CLUSTER NODES]
assert_match "*8192 12287*12289 16383*" [$master2 CLUSTER SLOTS]
} }
test "Discontinuous slots distribution" { test "Discontinuous slots distribution" {
# Remove middle slots # Remove middle slots
$master1 CLUSTER DELSLOTS 4092 4094 $master1 CLUSTER DELSLOTS 4092 4094
assert_match "* 0-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 0-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*0 4091*4093 4093*4095 4095*4097 8191*" [$master1 CLUSTER SLOTS]
$master2 CLUSTER DELSLOTS 12284 12286 $master2 CLUSTER DELSLOTS 12284 12286
assert_match "* 8192-12283 12285 12287 12289-16383*" [$master2 CLUSTER NODES] assert_match "* 8192-12283 12285 12287 12289-16383*" [$master2 CLUSTER NODES]
assert_match "*8192 12283*12285 12285*12287 12287*12289 16383*" [$master2 CLUSTER SLOTS]
# Remove head slots # Remove head slots
$master1 CLUSTER DELSLOTS 0 2 $master1 CLUSTER DELSLOTS 0 2
assert_match "* 1 3-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES] assert_match "* 1 3-4091 4093 4095 4097-8191*" [$master1 CLUSTER NODES]
assert_match "*1 1*3 4091*4093 4093*4095 4095*4097 8191*" [$master1 CLUSTER SLOTS]
# Remove tail slots # Remove tail slots
$master2 CLUSTER DELSLOTS 16380 16382 16383 $master2 CLUSTER DELSLOTS 16380 16382 16383
assert_match "* 8192-12283 12285 12287 12289-16379 16381*" [$master2 CLUSTER NODES] assert_match "* 8192-12283 12285 12287 12289-16379 16381*" [$master2 CLUSTER NODES]
assert_match "*8192 12283*12285 12285*12287 12287*12289 16379*16381 16381*" [$master2 CLUSTER SLOTS]
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment