mirror of https://github.com/apache/cassandra
checkForEndpointCollision fails for legitimate collisions
patch by stefania; reviewed by jasobrown for CASSANDRA-9765
This commit is contained in:
commit
046ff1e5d3
|
|
@ -678,6 +678,12 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A fat client is a node that has not joined the ring, therefore acting as a coordinator only.
|
||||
*
|
||||
* @param endpoint - the endpoint to check
|
||||
* @return true if it is a fat client
|
||||
*/
|
||||
public boolean isFatClient(InetAddress endpoint)
|
||||
{
|
||||
EndpointState epState = endpointStateMap.get(endpoint);
|
||||
|
|
@ -688,6 +694,30 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
|
|||
return !isDeadState(epState) && !StorageService.instance.getTokenMetadata().isMember(endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this endpoint can safely bootstrap into the cluster.
|
||||
*
|
||||
* @param endpoint - the endpoint to check
|
||||
* @return true if the endpoint can join the cluster
|
||||
*/
|
||||
public boolean isSafeForBootstrap(InetAddress endpoint)
|
||||
{
|
||||
EndpointState epState = endpointStateMap.get(endpoint);
|
||||
|
||||
// if there's no previous state, or the node was previously removed from the cluster, we're good
|
||||
if (epState == null || isDeadState(epState))
|
||||
return true;
|
||||
|
||||
String status = getGossipStatus(epState);
|
||||
|
||||
// these states are not allowed to join the cluster as it would not be safe
|
||||
final List<String> unsafeStatuses = new ArrayList<String>() {{
|
||||
add(""); // failed bootstrap but we did start gossiping
|
||||
add(VersionedValue.STATUS_NORMAL); // node is legit in the cluster or it was stopped with kill -9
|
||||
add(VersionedValue.SHUTDOWN); }}; // node was shutdown
|
||||
return !unsafeStatuses.contains(status);
|
||||
}
|
||||
|
||||
private void doStatusCheck()
|
||||
{
|
||||
if (logger.isTraceEnabled())
|
||||
|
|
@ -1008,34 +1038,31 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
|
|||
|
||||
public boolean isDeadState(EndpointState epState)
|
||||
{
|
||||
if (epState.getApplicationState(ApplicationState.STATUS) == null)
|
||||
String status = getGossipStatus(epState);
|
||||
if (status.isEmpty())
|
||||
return false;
|
||||
String value = epState.getApplicationState(ApplicationState.STATUS).value;
|
||||
String[] pieces = value.split(VersionedValue.DELIMITER_STR, -1);
|
||||
assert (pieces.length > 0);
|
||||
String state = pieces[0];
|
||||
for (String deadstate : DEAD_STATES)
|
||||
{
|
||||
if (state.equals(deadstate))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return DEAD_STATES.contains(status);
|
||||
}
|
||||
|
||||
public boolean isSilentShutdownState(EndpointState epState)
|
||||
{
|
||||
if (epState.getApplicationState(ApplicationState.STATUS) == null)
|
||||
String status = getGossipStatus(epState);
|
||||
if (status.isEmpty())
|
||||
return false;
|
||||
|
||||
return SILENT_SHUTDOWN_STATES.contains(status);
|
||||
}
|
||||
|
||||
private static String getGossipStatus(EndpointState epState)
|
||||
{
|
||||
if (epState == null || epState.getApplicationState(ApplicationState.STATUS) == null)
|
||||
return "";
|
||||
|
||||
String value = epState.getApplicationState(ApplicationState.STATUS).value;
|
||||
String[] pieces = value.split(VersionedValue.DELIMITER_STR, -1);
|
||||
assert (pieces.length > 0);
|
||||
String state = pieces[0];
|
||||
for (String deadstate : SILENT_SHUTDOWN_STATES)
|
||||
{
|
||||
if (state.equals(deadstate))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return pieces[0];
|
||||
}
|
||||
|
||||
void applyStateLocally(Map<InetAddress, EndpointState> epStateMap)
|
||||
|
|
|
|||
|
|
@ -455,8 +455,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
if (!MessagingService.instance().isListening())
|
||||
MessagingService.instance().listen(FBUtilities.getLocalAddress());
|
||||
Gossiper.instance.doShadowRound();
|
||||
EndpointState epState = Gossiper.instance.getEndpointStateForEndpoint(FBUtilities.getBroadcastAddress());
|
||||
if (epState != null && !Gossiper.instance.isDeadState(epState) && !Gossiper.instance.isFatClient(FBUtilities.getBroadcastAddress()))
|
||||
if (!Gossiper.instance.isSafeForBootstrap(FBUtilities.getBroadcastAddress()))
|
||||
{
|
||||
throw new RuntimeException(String.format("A node with address %s already exists, cancelling join. " +
|
||||
"Use cassandra.replace_address if you want to replace this node.",
|
||||
|
|
|
|||
Loading…
Reference in New Issue