Avoid NPE during cms initialization abort

Patch by marcuse; reviewed by David Capwell and Caleb Rackliffe for CASSANDRA-20527
This commit is contained in:
Marcus Eriksson 2025-04-03 15:01:55 +02:00
parent b31d15b9b5
commit 95aca49915
4 changed files with 16 additions and 13 deletions

View File

@ -1,4 +1,5 @@
5.1 5.1
* Avoid NPE during cms initialization abort (CASSANDRA-20527)
* Avoid failing queries when epoch changes and replica goes up/down (CASSANDRA-20489) * Avoid failing queries when epoch changes and replica goes up/down (CASSANDRA-20489)
* Split out truncation record lock (CASSANDRA-20480) * Split out truncation record lock (CASSANDRA-20480)
* Throw new IndexBuildInProgressException when queries fail during index build, instead of IndexNotAvailableException (CASSANDRA-20402) * Throw new IndexBuildInProgressException when queries fail during index build, instead of IndexNotAvailableException (CASSANDRA-20402)

View File

@ -246,7 +246,7 @@ import static org.apache.cassandra.utils.FBUtilities.getBroadcastAddressAndPort;
else else
{ {
CMSInitializationRequest.Initiator initiator = Election.instance.initiator(); CMSInitializationRequest.Initiator initiator = Election.instance.initiator();
candidates = Discovery.instance.discoverOnce(initiator == null ? null : initiator.initiator); candidates = Discovery.instance.discoverOnce(initiator == null ? null : initiator.endpoint);
} }
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
} }

View File

@ -109,12 +109,12 @@ public class CMSInitializationRequest
public static class Initiator public static class Initiator
{ {
public static final Serializer serializer = new Serializer(); public static final Serializer serializer = new Serializer();
public final InetAddressAndPort initiator; public final InetAddressAndPort endpoint;
public final UUID initToken; public final UUID initToken;
public Initiator(InetAddressAndPort initiator, UUID initToken) public Initiator(InetAddressAndPort initiator, UUID initToken)
{ {
this.initiator = initiator; this.endpoint = initiator;
this.initToken = initToken; this.initToken = initToken;
} }
@ -124,20 +124,20 @@ public class CMSInitializationRequest
if (this == o) return true; if (this == o) return true;
if (!(o instanceof Initiator)) return false; if (!(o instanceof Initiator)) return false;
Initiator other = (Initiator) o; Initiator other = (Initiator) o;
return Objects.equals(initiator, other.initiator) && Objects.equals(initToken, other.initToken); return Objects.equals(endpoint, other.endpoint) && Objects.equals(initToken, other.initToken);
} }
@Override @Override
public int hashCode() public int hashCode()
{ {
return Objects.hash(initiator, initToken); return Objects.hash(endpoint, initToken);
} }
@Override @Override
public String toString() public String toString()
{ {
return "Initiator{" + return "Initiator{" +
"initiator=" + initiator + "initiator=" + endpoint +
", initToken=" + initToken + ", initToken=" + initToken +
'}'; '}';
} }
@ -147,7 +147,7 @@ public class CMSInitializationRequest
@Override @Override
public void serialize(Initiator t, DataOutputPlus out, int version) throws IOException public void serialize(Initiator t, DataOutputPlus out, int version) throws IOException
{ {
InetAddressAndPort.Serializer.inetAddressAndPortSerializer.serialize(t.initiator, out, version); InetAddressAndPort.Serializer.inetAddressAndPortSerializer.serialize(t.endpoint, out, version);
UUIDSerializer.serializer.serialize(t.initToken, out, version); UUIDSerializer.serializer.serialize(t.initToken, out, version);
} }
@ -161,7 +161,7 @@ public class CMSInitializationRequest
@Override @Override
public long serializedSize(Initiator t, int version) public long serializedSize(Initiator t, int version)
{ {
return InetAddressAndPort.Serializer.inetAddressAndPortSerializer.serializedSize(t.initiator, version) + return InetAddressAndPort.Serializer.inetAddressAndPortSerializer.serializedSize(t.endpoint, version) +
UUIDSerializer.serializer.serializedSize(t.initToken, version); UUIDSerializer.serializer.serializedSize(t.initToken, version);
} }
} }

View File

@ -134,7 +134,7 @@ public class Election
{ {
CMSInitializationRequest.Initiator currentInitiator = initiator.get(); CMSInitializationRequest.Initiator currentInitiator = initiator.get();
if (currentInitiator != null && if (currentInitiator != null &&
Objects.equals(currentInitiator.initiator, FBUtilities.getBroadcastAddressAndPort()) && Objects.equals(currentInitiator.endpoint, FBUtilities.getBroadcastAddressAndPort()) &&
initiator.compareAndSet(currentInitiator, MIGRATING)) initiator.compareAndSet(currentInitiator, MIGRATING))
{ {
Startup.initializeAsFirstCMSNode(); Startup.initializeAsFirstCMSNode();
@ -183,7 +183,7 @@ public class Election
{ {
InetAddressAndPort expectedInitiator = InetAddressAndPort.getByNameUnchecked(initiatorEp); InetAddressAndPort expectedInitiator = InetAddressAndPort.getByNameUnchecked(initiatorEp);
CMSInitializationRequest.Initiator currentInitiator = initiator.get(); CMSInitializationRequest.Initiator currentInitiator = initiator.get();
if (currentInitiator != null && Objects.equals(currentInitiator.initiator, expectedInitiator) && initiator.compareAndSet(currentInitiator, null)) if (currentInitiator != null && Objects.equals(currentInitiator.endpoint, expectedInitiator) && initiator.compareAndSet(currentInitiator, null))
{ {
ClusterMetadata metadata = ClusterMetadata.current(); ClusterMetadata metadata = ClusterMetadata.current();
for (Map.Entry<NodeId, NodeState> entry : metadata.directory.states.entrySet()) for (Map.Entry<NodeId, NodeState> entry : metadata.directory.states.entrySet())
@ -243,9 +243,11 @@ public class Election
public void doVerb(Message<CMSInitializationRequest.Initiator> message) throws IOException public void doVerb(Message<CMSInitializationRequest.Initiator> message) throws IOException
{ {
logger.info("Received election abort message {} from {}", message.payload, message.from()); logger.info("Received election abort message {} from {}", message.payload, message.from());
CMSInitializationRequest.Initiator initiator = message.payload; CMSInitializationRequest.Initiator remoteInitiator = message.payload;
if (!initiator.initiator.equals(initiator().initiator) || !updateInitiator(message.payload, null)) if (initiator() == null)
logger.error("Could not clear initiator - initiator is set to {}, abort message received from {}", initiator(), message.payload); logger.info("Initiator already cleared, ignoring abort message from {}: {}", message.from(), remoteInitiator);
else if (!remoteInitiator.endpoint.equals(initiator().endpoint) || !updateInitiator(remoteInitiator, null))
logger.error("Could not clear initiator - initiator is set to {}, abort message received from {}: {}", initiator(), message.from(), remoteInitiator);
} }
} }
} }