Repository: cassandra Updated Branches: refs/heads/trunk 42efbddd3 -> 40aeaf0c1 (forced update)
nodetool describecluster should be more informative Patch by Preetika Tyagi, Reviewed by Ariel Weisberg for CASSANDRA-13853 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/40aeaf0c Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/40aeaf0c Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/40aeaf0c Branch: refs/heads/trunk Commit: 40aeaf0c12b24dbc0f554fbd00a42fe739767ac7 Parents: 3747a6c Author: Preetika Tyagi <preetika.ty...@intel.com> Authored: Wed Apr 11 15:18:17 2018 -0400 Committer: Ariel Weisberg <aweisb...@apple.com> Committed: Thu Apr 12 16:11:18 2018 -0400 ---------------------------------------------------------------------- CHANGES.txt | 1 + src/java/org/apache/cassandra/gms/Gossiper.java | 22 +++++ .../org/apache/cassandra/gms/GossiperMBean.java | 4 + .../cassandra/service/StorageService.java | 11 +++ .../cassandra/service/StorageServiceMBean.java | 5 ++ .../org/apache/cassandra/tools/NodeProbe.java | 10 +++ .../tools/nodetool/DescribeCluster.java | 94 +++++++++++++++++++- 7 files changed, 144 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 754b9f3..0935434 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0 + * nodetool describecluster should be more informative (CASSANDRA-13853) * Compaction performance improvements (CASSANDRA-14261) * Refactor Pair usage to avoid boxing ints/longs (CASSANDRA-14260) * Add options to nodetool tablestats to sort and limit output (CASSANDRA-13889) http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/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 24b659b..0f3a5cd 100644 --- a/src/java/org/apache/cassandra/gms/Gossiper.java +++ b/src/java/org/apache/cassandra/gms/Gossiper.java @@ -32,6 +32,7 @@ import javax.management.ObjectName; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; import com.google.common.util.concurrent.Uninterruptibles; import org.apache.cassandra.locator.InetAddressAndPort; @@ -1732,6 +1733,27 @@ public class Gossiper implements IFailureDetectionEventListener, GossiperMBean return state != null ? state.getReleaseVersion() : null; } + public Map<String, List<String>> getReleaseVersionsWithPort() + { + Map<String, List<String>> results = new HashMap<String, List<String>>(); + Iterable<InetAddressAndPort> allHosts = Iterables.concat(Gossiper.instance.getLiveMembers(), Gossiper.instance.getUnreachableMembers()); + + for (InetAddressAndPort host : allHosts) + { + CassandraVersion version = getReleaseVersion(host); + String stringVersion = version == null ? "" : version.toString(); + List<String> hosts = results.get(stringVersion); + if (hosts == null) + { + hosts = new ArrayList<>(); + results.put(stringVersion, hosts); + } + hosts.add(host.getHostAddress(true)); + } + + return results; + } + @Nullable public UUID getSchemaVersion(InetAddressAndPort ep) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/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 1b116e1..92df2cd 100644 --- a/src/java/org/apache/cassandra/gms/GossiperMBean.java +++ b/src/java/org/apache/cassandra/gms/GossiperMBean.java @@ -19,6 +19,7 @@ package org.apache.cassandra.gms; import java.net.UnknownHostException; import java.util.List; +import java.util.Map; public interface GossiperMBean { @@ -34,4 +35,7 @@ public interface GossiperMBean public List<String> getSeeds(); + /** Returns each node's database release version */ + public Map<String, List<String>> getReleaseVersionsWithPort(); + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/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 91206c1..e5911f3 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -79,6 +79,7 @@ import org.apache.cassandra.repair.messages.RepairOption; import org.apache.cassandra.schema.CompactionParams.TombstoneOption; import org.apache.cassandra.schema.KeyspaceMetadata; import org.apache.cassandra.schema.MigrationManager; +import org.apache.cassandra.schema.ReplicationParams; import org.apache.cassandra.schema.Schema; import org.apache.cassandra.schema.SchemaConstants; import org.apache.cassandra.schema.SchemaPullVerbHandler; @@ -2968,6 +2969,16 @@ public class StorageService extends NotificationBroadcasterSupport implements IE return Schema.instance.getVersion().toString(); } + public String getKeyspaceReplicationInfo(String keyspaceName) + { + Keyspace keyspaceInstance = Schema.instance.getKeyspaceInstance(keyspaceName); + if (keyspaceInstance == null) + throw new IllegalArgumentException(); // ideally should never happen + ReplicationParams replicationParams = keyspaceInstance.getMetadata().params.replication; + String replicationInfo = replicationParams.klass.getSimpleName() + " " + replicationParams.options.toString(); + return replicationInfo; + } + @Deprecated public List<String> getLeavingNodes() { http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/src/java/org/apache/cassandra/service/StorageServiceMBean.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageServiceMBean.java b/src/java/org/apache/cassandra/service/StorageServiceMBean.java index 0676419..206a37b 100644 --- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java +++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java @@ -100,6 +100,11 @@ public interface StorageServiceMBean extends NotificationEmitter */ public String getSchemaVersion(); + /** + * Fetch the replication factor for a given keyspace. + * @return An integer that represents replication factor for the given keyspace. + */ + public String getKeyspaceReplicationInfo(String keyspaceName); /** * Get the list of all data file locations from conf http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/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 1bace2e..04a5781 100644 --- a/src/java/org/apache/cassandra/tools/NodeProbe.java +++ b/src/java/org/apache/cassandra/tools/NodeProbe.java @@ -387,6 +387,11 @@ public class NodeProbe implements AutoCloseable ssProxy.forceKeyspaceFlush(keyspaceName, tableNames); } + public String getKeyspaceReplicationInfo(String keyspaceName) + { + return ssProxy.getKeyspaceReplicationInfo(keyspaceName); + } + public void repairAsync(final PrintStream out, final String keyspace, Map<String, String> options) throws IOException { RepairRunner runner = new RepairRunner(out, ssProxy, keyspace, options); @@ -906,6 +911,11 @@ public class NodeProbe implements AutoCloseable return spProxy; } + public GossiperMBean getGossProxy() + { + return gossProxy; + } + public String getEndpoint() { Map<String, String> hostIdToEndpoint = ssProxy.getHostIdToEndpoint(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/40aeaf0c/src/java/org/apache/cassandra/tools/nodetool/DescribeCluster.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/tools/nodetool/DescribeCluster.java b/src/java/org/apache/cassandra/tools/nodetool/DescribeCluster.java index ed91b8b..da02db6 100644 --- a/src/java/org/apache/cassandra/tools/nodetool/DescribeCluster.java +++ b/src/java/org/apache/cassandra/tools/nodetool/DescribeCluster.java @@ -17,19 +17,29 @@ */ package org.apache.cassandra.tools.nodetool; -import static java.lang.String.format; -import io.airlift.airline.Command; - +import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.SortedMap; + +import com.google.common.collect.ArrayListMultimap; +import io.airlift.airline.Command; import org.apache.cassandra.locator.DynamicEndpointSnitch; +import org.apache.cassandra.locator.InetAddressAndPort; import org.apache.cassandra.tools.NodeProbe; +import org.apache.cassandra.tools.NodeTool; import org.apache.cassandra.tools.NodeTool.NodeToolCmd; +import static java.lang.String.format; + @Command(name = "describecluster", description = "Print the name, snitch, partitioner and schema version of a cluster") public class DescribeCluster extends NodeToolCmd { + private boolean resolveIp = false; + private String keyspace = null; + private Collection<String> joiningNodes, leavingNodes, movingNodes, liveNodes, unreachableNodes; + @Override public void execute(NodeProbe probe) { @@ -54,5 +64,83 @@ public class DescribeCluster extends NodeToolCmd { System.out.println(format("\t\t%s: %s%n", version, schemaVersions.get(version))); } + + // Collect status information of all nodes + boolean withPort = true; + joiningNodes = probe.getJoiningNodes(withPort); + leavingNodes = probe.getLeavingNodes(withPort); + movingNodes = probe.getMovingNodes(withPort); + liveNodes = probe.getLiveNodes(withPort); + unreachableNodes = probe.getUnreachableNodes(withPort); + + // Get the list of all keyspaces + List<String> keyspaces = probe.getKeyspaces(); + + System.out.println("Stats for all nodes:"); + System.out.println("\tLive: " + liveNodes.size()); + System.out.println("\tJoining: " + joiningNodes.size()); + System.out.println("\tMoving: " + movingNodes.size()); + System.out.println("\tLeaving: " + leavingNodes.size()); + System.out.println("\tUnreachable: " + unreachableNodes.size()); + + Map<String, String> tokensToEndpoints = probe.getTokenToEndpointMap(withPort); + Map<String, Float> ownerships = null; + try + { + ownerships = probe.effectiveOwnershipWithPort(keyspace); + } + catch (IllegalStateException ex) + { + ownerships = probe.getOwnershipWithPort(); + System.out.println("Error: " + ex.getMessage()); + } + catch (IllegalArgumentException ex) + { + System.out.println("%nError: " + ex.getMessage()); + System.exit(1); + } + + SortedMap<String, SetHostStatWithPort> dcs = NodeTool.getOwnershipByDcWithPort(probe, resolveIp, tokensToEndpoints, ownerships); + + System.out.println("\nData Centers: "); + for (Map.Entry<String, SetHostStatWithPort> dc : dcs.entrySet()) + { + System.out.print("\t" + dc.getKey()); + + ArrayListMultimap<InetAddressAndPort, HostStatWithPort> hostToTokens = ArrayListMultimap.create(); + for (HostStatWithPort stat : dc.getValue()) + hostToTokens.put(stat.endpoint, stat); + + int totalNodes = 0; // total number of nodes in a datacenter + int downNodes = 0; // number of down nodes in a datacenter + + for (InetAddressAndPort endpoint : hostToTokens.keySet()) + { + totalNodes++; + if (unreachableNodes.contains(endpoint.toString())) + downNodes++; + } + System.out.print(" #Nodes: " + totalNodes); + System.out.println(" #Down: " + downNodes); + } + + // display database version for each node + System.out.println("\nDatabase versions:"); + Map<String, List<String>> databaseVersions = probe.getGossProxy().getReleaseVersionsWithPort(); + for (String version : databaseVersions.keySet()) + { + System.out.println(format("\t%s: %s%n", version, databaseVersions.get(version))); + } + + System.out.println("Keyspaces:"); + for (String keyspaceName : keyspaces) + { + String replicationInfo = probe.getKeyspaceReplicationInfo(keyspaceName); + if (replicationInfo == null) + { + System.out.println("something went wrong for keyspace: " + keyspaceName); + } + System.out.println("\t" + keyspaceName + " -> Replication class: " + replicationInfo); + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org