diff --git a/CHANGES.txt b/CHANGES.txt index d16ddac707..80e194d327 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -30,6 +30,8 @@ dev * include secondary indexes in cleanup (CASSANDRA-1916) * CFS.scrubDataDirectories should also cleanup invalid secondary indexes (CASSANDRA-1904) + * ability to disable/enable gossip on nodes to force them down + (CASSANDRA-1108) 0.7.0-rc3 diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index b4eb27c2bc..ff0dceeccc 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -246,6 +246,28 @@ public class StorageService implements IEndpointStateChangeSubscriber, StorageSe throw new RuntimeException("Streaming service is unavailable."); } + // should only be called via JMX + public void stopGossiping() + { + if (initialized) + { + logger_.warn("Stopping gossip by operator request"); + Gossiper.instance.stop(); + initialized = false; + } + } + + // should only be called via JMX + public void startGossiping() + { + if (!initialized) + { + logger_.warn("Starting gossip by operator request"); + Gossiper.instance.start(FBUtilities.getLocalAddress(), (int)(System.currentTimeMillis() / 1000)); + initialized = true; + } + } + public void stopClient() { Gossiper.instance.unregister(migrationManager); diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index acce2b72c4..5d2a4fd56b 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -270,4 +270,13 @@ public interface StorageServiceMBean * @throws ConfigurationException classname not found on classpath */ public void updateSnitch(String epSnitchClassName, Boolean dynamic, Integer dynamicUpdateInterval, Integer dynamicResetInterval, Double dynamicBadnessThreshold) throws ConfigurationException; + + // allows a user to forcibly 'kill' a sick node + public void stopGossiping(); + + // allows a user to recover a forcibly 'killed' node + public void startGossiping(); + + // to determine if gossip is disabled + public boolean isInitialized(); } diff --git a/src/java/org/apache/cassandra/tools/NodeCmd.java b/src/java/org/apache/cassandra/tools/NodeCmd.java index 47f5139365..e29e9fe45f 100644 --- a/src/java/org/apache/cassandra/tools/NodeCmd.java +++ b/src/java/org/apache/cassandra/tools/NodeCmd.java @@ -74,7 +74,7 @@ public class NodeCmd { RING, INFO, CFSTATS, SNAPSHOT, CLEARSNAPSHOT, VERSION, TPSTATS, FLUSH, DRAIN, DECOMMISSION, MOVE, LOADBALANCE, REMOVETOKEN, REPAIR, CLEANUP, COMPACT, SETCACHECAPACITY, GETCOMPACTIONTHRESHOLD, SETCOMPACTIONTHRESHOLD, NETSTATS, CFHISTOGRAMS, - COMPACTIONSTATS + COMPACTIONSTATS, DISABLEGOSSIP, ENABLEGOSSIP } @@ -96,6 +96,8 @@ public class NodeCmd { + "decommission\n" + "loadbalance\n" + "compactionstats\n" + + "disablegossip\n" + + "enablegossip\n" // One arg + "snapshot [snapshotname]\n" @@ -189,6 +191,7 @@ public class NodeCmd { public void printInfo(PrintStream outs) { outs.println(probe.getToken()); + outs.printf("%-17s: %s%n", "Gossip active", probe.isInitialized()); outs.printf("%-17s: %s%n", "Load", probe.getLoadString()); outs.printf("%-17s: %s%n", "Generation No", probe.getCurrentGenerationNumber()); @@ -519,6 +522,8 @@ public class NodeCmd { case TPSTATS : nodeCmd.printThreadPoolStats(System.out); break; case VERSION : nodeCmd.printReleaseVersion(System.out); break; case COMPACTIONSTATS : nodeCmd.printCompactionStats(System.out); break; + case DISABLEGOSSIP : probe.stopGossiping(); break; + case ENABLEGOSSIP : probe.startGossiping(); break; case DRAIN : try { probe.drain(); } diff --git a/src/java/org/apache/cassandra/tools/NodeProbe.java b/src/java/org/apache/cassandra/tools/NodeProbe.java index 8177a2988a..a618e5a9f1 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -503,6 +503,21 @@ public class NodeProbe { return ssProxy.getKeyspaces(); } + + public void stopGossiping() + { + ssProxy.stopGossiping(); + } + + public void startGossiping() + { + ssProxy.startGossiping(); + } + + public boolean isInitialized() + { + return ssProxy.isInitialized(); + } } class ColumnFamilyStoreMBeanIterator implements Iterator>