Pass extensions to node if extension processing is handled by it (#52)
Ref: https://github.com/redis/redis/pull/12760 ### Description #### Fixes compatibilty of PlaceholderKV cluster (7.2 - extensions enabled by default) with older Redis cluster (< 7.0 - extensions not handled) . With some of the extensions enabled by default in 7.2 version, new nodes running 7.2 and above start sending out larger clusterbus message payload including the ping extensions. This caused an incompatibility with node running engine versions < 7.0. Old nodes (< 7.0) would receive the payload from new nodes (> 7.2) would observe a payload length (totlen) > (estlen) and would perform an early exit and won't process the message. This fix introduces a flag `extensions_supported` on the clusterMsg indicating the sender node can handle extensions parsing. Once, a receiver nodes receives a message with this flag set to 1, it would update clusterNode new field extensions_supported and start sending out extensions if it has any. This PR also introduces a DEBUG sub command to enable/disable cluster message extensions `process-clustermsg-extensions` feature. Note: A successful `PING`/`PONG` is required as a sender for a given node to be marked as `extensions_supported` and then extensions message will be sent to it. This could cause a slight delay in receiving the extensions message(s). ### Testing TCL test verifying the cluster state is healthy irrespective of enabling/disabling cluster message extensions feature. --------- Signed-off-by: Harkrishn Patro <harkrisp@amazon.com>
This commit is contained in:
parent
d92dc78cb8
commit
ebfb440629
@ -2598,9 +2598,7 @@ uint32_t writePingExt(clusterMsg *hdr, int gossipcount) {
|
||||
extensions++;
|
||||
|
||||
if (hdr != NULL) {
|
||||
if (extensions != 0) {
|
||||
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
|
||||
}
|
||||
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
|
||||
hdr->extensions = htons(extensions);
|
||||
}
|
||||
|
||||
@ -2791,6 +2789,10 @@ int clusterProcessPacket(clusterLink *link) {
|
||||
|
||||
sender = getNodeFromLinkAndMsg(link, hdr);
|
||||
|
||||
if (sender && (hdr->mflags[0] & CLUSTERMSG_FLAG0_EXT_DATA)) {
|
||||
sender->flags |= CLUSTER_NODE_EXTENSIONS_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Update the last time we saw any data from this node. We
|
||||
* use this in order to avoid detecting a timeout from a node that
|
||||
* is just sending a lot of data in the cluster bus, for instance
|
||||
@ -3633,7 +3635,9 @@ void clusterSendPing(clusterLink *link, int type) {
|
||||
* to put inside the packet. */
|
||||
estlen = sizeof(clusterMsg) - sizeof(union clusterMsgData);
|
||||
estlen += (sizeof(clusterMsgDataGossip)*(wanted + pfail_wanted));
|
||||
estlen += writePingExt(NULL, 0);
|
||||
if (link->node && nodeSupportsExtensions(link->node)) {
|
||||
estlen += writePingExt(NULL, 0);
|
||||
}
|
||||
/* Note: clusterBuildMessageHdr() expects the buffer to be always at least
|
||||
* sizeof(clusterMsg) or more. */
|
||||
if (estlen < (int)sizeof(clusterMsg)) estlen = sizeof(clusterMsg);
|
||||
@ -3703,7 +3707,13 @@ void clusterSendPing(clusterLink *link, int type) {
|
||||
|
||||
/* Compute the actual total length and send! */
|
||||
uint32_t totlen = 0;
|
||||
totlen += writePingExt(hdr, gossipcount);
|
||||
|
||||
if (link->node && nodeSupportsExtensions(link->node)) {
|
||||
totlen += writePingExt(hdr, gossipcount);
|
||||
} else {
|
||||
serverLog(LL_DEBUG, "Unable to send extensions data, however setting ext data flag to true");
|
||||
hdr->mflags[0] |= CLUSTERMSG_FLAG0_EXT_DATA;
|
||||
}
|
||||
totlen += sizeof(clusterMsg)-sizeof(union clusterMsgData);
|
||||
totlen += (sizeof(clusterMsgDataGossip)*gossipcount);
|
||||
serverAssert(gossipcount < USHRT_MAX);
|
||||
|
@ -51,6 +51,7 @@ typedef struct clusterLink {
|
||||
#define CLUSTER_NODE_MEET 128 /* Send a MEET message to this node */
|
||||
#define CLUSTER_NODE_MIGRATE_TO 256 /* Master eligible for replica migration. */
|
||||
#define CLUSTER_NODE_NOFAILOVER 512 /* Slave will not try to failover. */
|
||||
#define CLUSTER_NODE_EXTENSIONS_SUPPORTED 1024 /* This node supports extensions. */
|
||||
#define CLUSTER_NODE_NULL_NAME "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
|
||||
|
||||
#define nodeIsSlave(n) ((n)->flags & CLUSTER_NODE_SLAVE)
|
||||
@ -59,6 +60,7 @@ typedef struct clusterLink {
|
||||
#define nodeTimedOut(n) ((n)->flags & CLUSTER_NODE_PFAIL)
|
||||
#define nodeFailed(n) ((n)->flags & CLUSTER_NODE_FAIL)
|
||||
#define nodeCantFailover(n) ((n)->flags & CLUSTER_NODE_NOFAILOVER)
|
||||
#define nodeSupportsExtensions(n) ((n)->flags & CLUSTER_NODE_EXTENSIONS_SUPPORTED)
|
||||
|
||||
/* This structure represent elements of node->fail_reports. */
|
||||
typedef struct clusterNodeFailReport {
|
||||
|
@ -116,10 +116,11 @@ test "Verify the nodes configured with prefer hostname only show hostname for ne
|
||||
# Have everyone forget node 6 and isolate it from the cluster.
|
||||
isolate_node 6
|
||||
|
||||
# Set hostnames for the masters, now that the node is isolated
|
||||
R 0 config set cluster-announce-hostname "shard-1.com"
|
||||
R 1 config set cluster-announce-hostname "shard-2.com"
|
||||
R 2 config set cluster-announce-hostname "shard-3.com"
|
||||
set primaries 3
|
||||
for {set j 0} {$j < $primaries} {incr j} {
|
||||
# Set hostnames for the masters, now that the node is isolated
|
||||
R $j config set cluster-announce-hostname "shard-$j.com"
|
||||
}
|
||||
|
||||
# Prevent Node 0 and Node 6 from properly meeting,
|
||||
# they'll hang in the handshake phase. This allows us to
|
||||
@ -149,9 +150,17 @@ test "Verify the nodes configured with prefer hostname only show hostname for ne
|
||||
} else {
|
||||
fail "Node did not learn about the 2 shards it can talk to"
|
||||
}
|
||||
set slot_result [R 6 CLUSTER SLOTS]
|
||||
assert_equal [lindex [get_slot_field $slot_result 0 2 3] 1] "shard-2.com"
|
||||
assert_equal [lindex [get_slot_field $slot_result 1 2 3] 1] "shard-3.com"
|
||||
wait_for_condition 50 100 {
|
||||
[lindex [get_slot_field [R 6 CLUSTER SLOTS] 0 2 3] 1] eq "shard-1.com"
|
||||
} else {
|
||||
fail "hostname for shard-1 didn't reach node 6"
|
||||
}
|
||||
|
||||
wait_for_condition 50 100 {
|
||||
[lindex [get_slot_field [R 6 CLUSTER SLOTS] 1 2 3] 1] eq "shard-2.com"
|
||||
} else {
|
||||
fail "hostname for shard-2 didn't reach node 6"
|
||||
}
|
||||
|
||||
# Also make sure we know about the isolated master, we
|
||||
# just can't reach it.
|
||||
@ -170,10 +179,14 @@ test "Verify the nodes configured with prefer hostname only show hostname for ne
|
||||
} else {
|
||||
fail "Node did not learn about the 2 shards it can talk to"
|
||||
}
|
||||
set slot_result [R 6 CLUSTER SLOTS]
|
||||
assert_equal [lindex [get_slot_field $slot_result 0 2 3] 1] "shard-1.com"
|
||||
assert_equal [lindex [get_slot_field $slot_result 1 2 3] 1] "shard-2.com"
|
||||
assert_equal [lindex [get_slot_field $slot_result 2 2 3] 1] "shard-3.com"
|
||||
|
||||
for {set j 0} {$j < $primaries} {incr j} {
|
||||
wait_for_condition 50 100 {
|
||||
[lindex [get_slot_field [R 6 CLUSTER SLOTS] $j 2 3] 1] eq "shard-$j.com"
|
||||
} else {
|
||||
fail "hostname information for shard-$j didn't reach node 6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "Test restart will keep hostname information" {
|
||||
|
Loading…
x
Reference in New Issue
Block a user