You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by br...@apache.org on 2014/09/18 00:26:07 UTC

git commit: Make assassinate a first class command.

Repository: cassandra
Updated Branches:
  refs/heads/trunk a07977900 -> a33733601


Make assassinate a first class command.

Patch by brandonwilliams, reviewed by thobbs for CASSANDRA-7935


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/a3373360
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/a3373360
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/a3373360

Branch: refs/heads/trunk
Commit: a337336013eb1efabe709844f1a7755d54b746a8
Parents: a079779
Author: Brandon Williams <br...@apache.org>
Authored: Wed Sep 17 15:25:01 2014 +0000
Committer: Brandon Williams <br...@apache.org>
Committed: Wed Sep 17 15:25:01 2014 +0000

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 src/java/org/apache/cassandra/gms/Gossiper.java | 16 ++++++++++++----
 .../org/apache/cassandra/gms/GossiperMBean.java |  2 ++
 .../org/apache/cassandra/tools/NodeProbe.java   | 10 ++++++++++
 .../org/apache/cassandra/tools/NodeTool.java    | 20 ++++++++++++++++++++
 5 files changed, 45 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3373360/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 5b80e07..6f9e681 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0
+ * Make assassinate a first class command (CASSANDRA-7935)
  * Support IN clause on any clustering column (CASSANDRA-4762)
  * Improve compaction logging (CASSANDRA-7818)
  * Remove YamlFileNetworkTopologySnitch (CASSANDRA-7917)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3373360/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 01af8cd..b9576f0 100644
--- a/src/java/org/apache/cassandra/gms/Gossiper.java
+++ b/src/java/org/apache/cassandra/gms/Gossiper.java
@@ -63,7 +63,7 @@ import com.google.common.collect.ImmutableList;
 
 public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
 {
-    private static final String MBEAN_NAME = "org.apache.cassandra.net:type=Gossiper";
+    public static final String MBEAN_NAME = "org.apache.cassandra.net:type=Gossiper";
 
     private static final DebuggableScheduledThreadPoolExecutor executor = new DebuggableScheduledThreadPoolExecutor("GossipTasks");
 
@@ -474,16 +474,21 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
         Uninterruptibles.sleepUninterruptibly(intervalInMillis * 2, TimeUnit.MILLISECONDS);
     }
 
+    public void unsafeAssassinateEndpoint(String address) throws UnknownHostException
+    {
+        logger.warn("Gossiper.unsafeAssassinateEndpoint is deprecated and will be removed in the next release; use assassinateEndpoint instead");
+        assassinateEndpoint(address);
+    }
+
     /**
      * Do not call this method unless you know what you are doing.
      * It will try extremely hard to obliterate any endpoint from the ring,
      * even if it does not know about it.
-     * This should only ever be called by human via JMX.
      *
      * @param address
      * @throws UnknownHostException
      */
-    public void unsafeAssassinateEndpoint(String address) throws UnknownHostException
+    public void assassinateEndpoint(String address) throws UnknownHostException
     {
         InetAddress endpoint = InetAddress.getByName(address);
         EndpointState epState = endpointStateMap.get(endpoint);
@@ -507,6 +512,7 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
                 tokens = Collections.singletonList(StorageService.getPartitioner().getRandomToken());
             }
             int generation = epState.getHeartBeatState().getGeneration();
+            int heartbeat = epState.getHeartBeatState().getHeartBeatVersion();
             logger.info("Sleeping for {}ms to ensure {} does not change", StorageService.RING_DELAY, endpoint);
             Uninterruptibles.sleepUninterruptibly(StorageService.RING_DELAY, TimeUnit.MILLISECONDS);
             // make sure it did not change
@@ -514,7 +520,9 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean
             if (newState == null)
                 logger.warn("Endpoint {} disappeared while trying to assassinate, continuing anyway", endpoint);
             else if (newState.getHeartBeatState().getGeneration() != generation)
-                throw new RuntimeException("Endpoint " + endpoint + " generation changed while trying to remove it");
+                throw new RuntimeException("Endpoint still alive: " + endpoint + " generation changed while trying to assassinate it");
+            else if (newState.getHeartBeatState().getHeartBeatVersion() != heartbeat)
+                throw new RuntimeException("Endpoint still alive: " + endpoint + " heartbeat changed while trying to assassinate it");
             epState.updateTimestamp(); // make sure we don't evict it too soon
             epState.getHeartBeatState().forceNewerGenerationUnsafe();
         }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3373360/src/java/org/apache/cassandra/gms/GossiperMBean.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/gms/GossiperMBean.java b/src/java/org/apache/cassandra/gms/GossiperMBean.java
index 521fd21..c4b244c 100644
--- a/src/java/org/apache/cassandra/gms/GossiperMBean.java
+++ b/src/java/org/apache/cassandra/gms/GossiperMBean.java
@@ -27,4 +27,6 @@ public interface GossiperMBean
 
     public void unsafeAssassinateEndpoint(String address) throws UnknownHostException;
 
+    public void assassinateEndpoint(String address) throws UnknownHostException;
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3373360/src/java/org/apache/cassandra/tools/NodeProbe.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java
index 0ad1186..b2ade5a 100644
--- a/src/java/org/apache/cassandra/tools/NodeProbe.java
+++ b/src/java/org/apache/cassandra/tools/NodeProbe.java
@@ -52,6 +52,8 @@ import org.apache.cassandra.db.compaction.CompactionManager;
 import org.apache.cassandra.db.compaction.CompactionManagerMBean;
 import org.apache.cassandra.gms.FailureDetector;
 import org.apache.cassandra.gms.FailureDetectorMBean;
+import org.apache.cassandra.gms.Gossiper;
+import org.apache.cassandra.gms.GossiperMBean;
 import org.apache.cassandra.locator.EndpointSnitchInfoMBean;
 import org.apache.cassandra.net.MessagingService;
 import org.apache.cassandra.net.MessagingServiceMBean;
@@ -78,6 +80,7 @@ public class NodeProbe implements AutoCloseable
     private MBeanServerConnection mbeanServerConn;
     private CompactionManagerMBean compactionProxy;
     private StorageServiceMBean ssProxy;
+    private GossiperMBean gossProxy;
     private MemoryMXBean memProxy;
     private GCInspectorMXBean gcProxy;
     private RuntimeMXBean runtimeProxy;
@@ -172,6 +175,8 @@ public class NodeProbe implements AutoCloseable
             hhProxy = JMX.newMBeanProxy(mbeanServerConn, name, HintedHandOffManagerMBean.class);
             name = new ObjectName(GCInspector.MBEAN_NAME);
             gcProxy = JMX.newMBeanProxy(mbeanServerConn, name, GCInspectorMXBean.class);
+            name = new ObjectName(Gossiper.MBEAN_NAME);
+            gossProxy = JMX.newMBeanProxy(mbeanServerConn, name, GossiperMBean.class);
         }
         catch (MalformedObjectNameException e)
         {
@@ -530,6 +535,11 @@ public class NodeProbe implements AutoCloseable
         ssProxy.forceRemoveCompletion();
     }
 
+    public void assassinateEndpoint(String address) throws UnknownHostException
+    {
+        gossProxy.assassinateEndpoint(address);
+    }
+
     public Iterator<Map.Entry<String, JMXEnabledThreadPoolExecutorMBean>> getThreadPoolMBeanProxies()
     {
         try

http://git-wip-us.apache.org/repos/asf/cassandra/blob/a3373360/src/java/org/apache/cassandra/tools/NodeTool.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/tools/NodeTool.java b/src/java/org/apache/cassandra/tools/NodeTool.java
index f7baa8b..db75305 100644
--- a/src/java/org/apache/cassandra/tools/NodeTool.java
+++ b/src/java/org/apache/cassandra/tools/NodeTool.java
@@ -114,6 +114,7 @@ public class NodeTool
                 Rebuild.class,
                 Refresh.class,
                 RemoveNode.class,
+                Assassinate.class,
                 Repair.class,
                 SetCacheCapacity.class,
                 SetHintedHandoffThrottleInKB.class,
@@ -1626,6 +1627,25 @@ public class NodeTool
         }
     }
 
+    @Command(name = "assassinate", description = "Forcefully remove a dead node without re-replicating any data.  Use as a last resort if you cannot removenode")
+    public static class Assassinate extends NodeToolCmd
+    {
+        @Arguments(title = "ip address", usage = "<ip_address>", description = "IP address of the endpoint to assassinate", required = true)
+        private String endpoint = EMPTY;
+
+        @Override
+        public void execute(NodeProbe probe)
+        {
+            try {
+                probe.assassinateEndpoint(endpoint);
+            }
+            catch (UnknownHostException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
     @Command(name = "repair", description = "Repair one or more tables")
     public static class Repair extends NodeToolCmd
     {