From f4a6721dfd4d8e8a2aa7ce86304d0182070d8a64 Mon Sep 17 00:00:00 2001 From: "debing.sun" Date: Fri, 2 Aug 2024 07:22:13 +0800 Subject: [PATCH] Fix CLUSTER SHARDS command returns empty array (#13422) Close https://github.com/redis/redis/issues/13414 When the cluster's master node fails and is switched to another node, the first node in the shard node list (the old master) is no longer valid. Add a new method clusterGetMasterFromShard() to obtain the current master. --- src/cluster.c | 23 +++++++++++++++++++---- tests/cluster/tests/28-cluster-shards.tcl | 4 ++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/cluster.c b/src/cluster.c index 661b4e184..9aa5d9549 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -1722,6 +1722,22 @@ void clusterRemoveNodeFromShard(clusterNode *node) { sdsfree(s); } +static clusterNode *clusterGetMasterFromShard(list *nodes) { + clusterNode *n = NULL; + listIter li; + listNode *ln; + listRewind(nodes,&li); + while ((ln = listNext(&li)) != NULL) { + clusterNode *node = listNodeValue(ln); + if (!nodeFailed(node)) { + n = node; + break; + } + } + if (!n) return NULL; + return clusterNodeGetMaster(n); +} + /* ----------------------------------------------------------------------------- * CLUSTER config epoch handling * -------------------------------------------------------------------------- */ @@ -5727,14 +5743,13 @@ void addNodeDetailsToShardReply(client *c, clusterNode *node) { /* Add the shard reply of a single shard based off the given primary node. */ void addShardReplyForClusterShards(client *c, list *nodes) { serverAssert(listLength(nodes) > 0); - clusterNode *n = listNodeValue(listFirst(nodes)); + addReplyMapLen(c, 2); addReplyBulkCString(c, "slots"); /* Use slot_info_pairs from the primary only */ - n = clusterNodeGetMaster(n); - - if (n->slot_info_pairs != NULL) { + clusterNode *n = clusterGetMasterFromShard(nodes); + if (n && n->slot_info_pairs != NULL) { serverAssert((n->slot_info_pairs_count % 2) == 0); addReplyArrayLen(c, n->slot_info_pairs_count); for (int i = 0; i < n->slot_info_pairs_count; i++) diff --git a/tests/cluster/tests/28-cluster-shards.tcl b/tests/cluster/tests/28-cluster-shards.tcl index f24b91729..cbdae001f 100644 --- a/tests/cluster/tests/28-cluster-shards.tcl +++ b/tests/cluster/tests/28-cluster-shards.tcl @@ -124,6 +124,10 @@ test "Verify health as fail for killed node" { } } +test "Verify that other nodes can correctly output the new master's slots" { + assert_not_equal {} [dict get [get_node_info_from_shard [R 4 CLUSTER MYID] 8 "shard"] slots] +} + set primary_id 4 set replica_id 0