From ee9e41878258914a5546e65dfd862e122be5d09c Mon Sep 17 00:00:00 2001 From: Runtian Liu Date: Wed, 10 Jan 2024 14:55:22 +0100 Subject: [PATCH] Skip version check if an endpoint is dead state in Gossiper#upgradeFromVersionSupplier patch by Runtian Liu; reviewed by Stefan Miklosovic and Brandon Williams for CASSANDRA-19187 --- CHANGES.txt | 1 + .../org/apache/cassandra/gms/Gossiper.java | 7 ++++-- .../utils/ExpiringMemoizingSupplier.java | 2 +- .../apache/cassandra/gms/GossiperTest.java | 22 +++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d944415f76..4c0db9b86b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0.12 + * Skip version check if an endpoint is dead state in Gossiper#upgradeFromVersionSupplier (CASSANDRA-19187) * Fix Gossiper::hasMajorVersion3Nodes to return false during minor upgrade (CASSANDRA-18999) * Revert unnecessary read lock acquisition when reading ring version in TokenMetadata introduced in CASSANDRA-16286 (CASSANDRA-19107) * Support max SSTable size in sorted CQLSSTableWriter (CASSANDRA-18941) diff --git a/src/java/org/apache/cassandra/gms/Gossiper.java b/src/java/org/apache/cassandra/gms/Gossiper.java index 22595b299a..63ff5150a7 100644 --- a/src/java/org/apache/cassandra/gms/Gossiper.java +++ b/src/java/org/apache/cassandra/gms/Gossiper.java @@ -208,10 +208,13 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean // Check the release version of all the peers it heard of. Not necessary the peer that it has/had contacted with. hasNodeWithUnknownVersion = false; - for (InetAddressAndPort host : endpointStateMap.keySet()) + for (Entry entry : endpointStateMap.entrySet()) { - CassandraVersion version = getReleaseVersion(host); + CassandraVersion version = getReleaseVersion(entry.getKey()); + // if it is dead state, we skip the version check + if (isDeadState(entry.getValue())) + continue; //Raced with changes to gossip state, wait until next iteration if (version == null) hasNodeWithUnknownVersion = true; diff --git a/src/java/org/apache/cassandra/utils/ExpiringMemoizingSupplier.java b/src/java/org/apache/cassandra/utils/ExpiringMemoizingSupplier.java index 1736ae251e..c7eab76f31 100644 --- a/src/java/org/apache/cassandra/utils/ExpiringMemoizingSupplier.java +++ b/src/java/org/apache/cassandra/utils/ExpiringMemoizingSupplier.java @@ -101,7 +101,7 @@ public class ExpiringMemoizingSupplier implements Supplier this.value = value; } - abstract boolean canMemoize(); + public abstract boolean canMemoize(); public T value() { diff --git a/test/unit/org/apache/cassandra/gms/GossiperTest.java b/test/unit/org/apache/cassandra/gms/GossiperTest.java index c0a2d453b3..96730baa19 100644 --- a/test/unit/org/apache/cassandra/gms/GossiperTest.java +++ b/test/unit/org/apache/cassandra/gms/GossiperTest.java @@ -195,6 +195,28 @@ public class GossiperTest Gossiper.instance.liveEndpoints.remove(InetAddressAndPort.getByName("127.0.0.2")); } + @Test + public void testAssassinatedNodeWillNotContributeToVersionCalculation() throws Exception + { + int initialNodeCount = 3; + Util.createInitialRing(ss, partitioner, endpointTokens, keyTokens, hosts, hostIds, initialNodeCount); + for (int i = 0; i < initialNodeCount; i++) + { + Gossiper.instance.injectApplicationState(hosts.get(i), ApplicationState.RELEASE_VERSION, new VersionedValue.VersionedValueFactory(null).releaseVersion(SystemKeyspace.CURRENT_VERSION.toString())); + } + Gossiper.instance.start(1); + Gossiper.instance.expireUpgradeFromVersion(); + + // assassinate a non-existing node + Gossiper.instance.assassinateEndpoint("127.0.0.4"); + + assertTrue(Gossiper.instance.endpointStateMap.containsKey(InetAddressAndPort.getByName("127.0.0.4"))); + assertNull(Gossiper.instance.upgradeFromVersionSupplier.get().value()); + assertTrue(Gossiper.instance.upgradeFromVersionSupplier.get().canMemoize()); + assertFalse(Gossiper.instance.hasMajorVersion3OrUnknownNodes()); + assertFalse(Gossiper.instance.isUpgradingFromVersionLowerThan(CassandraVersion.CASSANDRA_3_4)); + } + @Test public void testLargeGenerationJump() throws UnknownHostException, InterruptedException {