Handle host id conflicts properly. Patch by brandonwilliams, reviewed by Tyler Hobbs for CASSANDRA-6615
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/6c4333e3 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/6c4333e3 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/6c4333e3 Branch: refs/heads/trunk Commit: 6c4333e3d47dfe3fad9781e3c36a5c84476af1d3 Parents: 1d81765 Author: Brandon Williams <brandonwilli...@apache.org> Authored: Wed Jan 29 17:30:42 2014 -0600 Committer: Brandon Williams <brandonwilli...@apache.org> Committed: Wed Jan 29 17:31:45 2014 -0600 ---------------------------------------------------------------------- CHANGES.txt | 1 + src/java/org/apache/cassandra/gms/Gossiper.java | 2 +- .../cassandra/service/StorageService.java | 40 +++++++++++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c4333e3/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 2920c15..d88bb26 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -19,6 +19,7 @@ * Add properties to adjust FD initial value and max interval (CASSANDRA-4375) * Fix preparing with batch and delete from collection (CASSANDRA-6607) * Fix ABSC reverse iterator's remove() method (CASSANDRA-6629) + * Handle host ID conflicts properly (CASSANDRA-6615) 1.2.13 http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c4333e3/src/java/org/apache/cassandra/gms/Gossiper.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/gms/Gossiper.java b/src/java/org/apache/cassandra/gms/Gossiper.java index 3ed6cba..b51bbd3 100644 --- a/src/java/org/apache/cassandra/gms/Gossiper.java +++ b/src/java/org/apache/cassandra/gms/Gossiper.java @@ -596,7 +596,7 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean { return false; } - return !isDeadState(epState) && !epState.isAlive() && !StorageService.instance.getTokenMetadata().isMember(endpoint); + return !isDeadState(epState) && !StorageService.instance.getTokenMetadata().isMember(endpoint); } private void doStatusCheck() http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c4333e3/src/java/org/apache/cassandra/service/StorageService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index ab266d8..c93ea5b 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -1453,6 +1453,12 @@ public class StorageService extends NotificationBroadcasterSupport implements IE tokens = getTokensFor(endpoint, pieces[1]); + Set<Token> tokensToUpdateInMetadata = new HashSet<Token>(); + Set<Token> tokensToUpdateInSystemTable = new HashSet<Token>(); + Set<Token> localTokensToRemove = new HashSet<Token>(); + Set<InetAddress> endpointsToRemove = new HashSet<InetAddress>(); + + if (logger.isDebugEnabled()) logger.debug("Node " + endpoint + " state normal, token " + tokens); @@ -1463,16 +1469,38 @@ public class StorageService extends NotificationBroadcasterSupport implements IE if (Gossiper.instance.usesHostId(endpoint)) { UUID hostId = Gossiper.instance.getHostId(endpoint); + InetAddress existing = tokenMetadata.getEndpointForHostId(hostId); if (DatabaseDescriptor.isReplacing() && Gossiper.instance.getEndpointStateForEndpoint(DatabaseDescriptor.getReplaceAddress()) != null && (hostId.equals(Gossiper.instance.getHostId(DatabaseDescriptor.getReplaceAddress())))) logger.warn("Not updating token metadata for {} because I am replacing it", endpoint); else - tokenMetadata.updateHostId(hostId, endpoint); - } + { + if (existing != null && !existing.equals(endpoint)) + { + if (existing.equals(FBUtilities.getBroadcastAddress())) + { + logger.warn("Not updating host ID {} for {} because it's mine", hostId, endpoint); + tokenMetadata.removeEndpoint(endpoint); + endpointsToRemove.add(endpoint); + } + else if (Gossiper.instance.compareEndpointStartup(endpoint, existing) > 0) + { + logger.warn("Host ID collision for {} between {} and {}; {} is the new owner", hostId, existing, endpoint, endpoint); + tokenMetadata.removeEndpoint(existing); + endpointsToRemove.add(existing); + tokenMetadata.updateHostId(hostId, endpoint); + } + else + { + logger.warn("Host ID Collision for {} between {} and {}; ignored {}", hostId, existing, endpoint, endpoint); + tokenMetadata.removeEndpoint(endpoint); + endpointsToRemove.add(endpoint); + } + } + else + tokenMetadata.updateHostId(hostId, endpoint); + } - Set<Token> tokensToUpdateInMetadata = new HashSet<Token>(); - Set<Token> tokensToUpdateInSystemTable = new HashSet<Token>(); - Set<Token> localTokensToRemove = new HashSet<Token>(); - Set<InetAddress> endpointsToRemove = new HashSet<InetAddress>(); + } for (final Token token : tokens) {