cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbel...@apache.org
Subject svn commit: r785178 - in /incubator/cassandra/trunk: bin/nodeprobe src/java/org/apache/cassandra/tools/NodeProbe.java
Date Tue, 16 Jun 2009 12:38:31 GMT
Author: jbellis
Date: Tue Jun 16 12:38:30 2009
New Revision: 785178

URL: http://svn.apache.org/viewvc?rev=785178&view=rev
Log:
add nodeprobe cli tool.  patch by Eric Evans; reviewed by jbellis for CASSANDRA-211

Added:
    incubator/cassandra/trunk/bin/nodeprobe   (with props)
    incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java

Added: incubator/cassandra/trunk/bin/nodeprobe
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/bin/nodeprobe?rev=785178&view=auto
==============================================================================
--- incubator/cassandra/trunk/bin/nodeprobe (added)
+++ incubator/cassandra/trunk/bin/nodeprobe Tue Jun 16 12:38:30 2009
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+if [ "x$CASSANDRA_INCLUDE" = "x" ]; then
+    for include in /usr/share/cassandra/cassandra.in.sh \
+                   /usr/local/share/cassandra/cassandra.in.sh \
+                   /opt/cassandra/cassandra.in.sh \
+                   `dirname $0`/cassandra.in.sh; do
+        if [ -r $include ]; then
+            . $include
+            break
+        fi
+    done
+elif [ -r $CASSANDRA_INCLUDE ]; then
+    . $CASSANDRA_INCLUDE
+fi
+
+if [ -z $CASSANDRA_CONF -o -z $CLASSPATH ]; then
+    echo "You must set the CASSANDRA_CONF and CLASSPATH vars" >&2
+    exit 1
+fi
+
+# Special-case path variables.
+case "`uname`" in
+    CYGWIN*) 
+        CLASSPATH=`cygpath -p -w "$CLASSPATH"`
+        CASSANDRA_CONF=`cygpath -p -w "$CASSANDRA_CONF"`
+    ;;
+esac
+
+java -cp $CLASSPATH -Dstorage-config=$CASSANDRA_CONF \
+        org.apache.cassandra.tools.NodeProbe $@
+
+# vi:ai sw=4 ts=4 tw=0 et

Propchange: incubator/cassandra/trunk/bin/nodeprobe
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java
URL: http://svn.apache.org/viewvc/incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java?rev=785178&view=auto
==============================================================================
--- incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java (added)
+++ incubator/cassandra/trunk/src/java/org/apache/cassandra/tools/NodeProbe.java Tue Jun 16
12:38:30 2009
@@ -0,0 +1,434 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.tools;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.RuntimeMXBean;
+import java.util.List;
+import java.util.Map;
+import javax.management.JMX;
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.net.EndPoint;
+import org.apache.cassandra.service.StorageServiceMBean;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+
+/**
+ * JMX client operations for Cassandra.
+ */
+public class NodeProbe
+{
+    private static final String fmtUrl = "service:jmx:rmi:///jndi/rmi://%s:%d/jmxrmi";
+    private static final String ssObjName = "org.apache.cassandra.service:type=StorageService";
+    private static final String HOST_OPTION = "host";
+    private static final String PORT_OPTION = "port";
+    private static final int defaultPort = 8080;
+    private static Options options = null;
+    private CommandLine cmd = null;
+    private String host;
+    private int port;
+    
+    private MBeanServerConnection mbeanServerConn;
+    private StorageServiceMBean ssProxy;
+    private MemoryMXBean memProxy;
+    private RuntimeMXBean runtimeProxy;
+    
+    static
+    {
+        options = new Options();
+        Option optHost = new Option(HOST_OPTION, true, "node hostname or ip address");
+        optHost.setRequired(true);
+        options.addOption(optHost);
+        options.addOption(PORT_OPTION, true, "remote jmx agent port number");
+    }
+    
+    /**
+     * Creates a NodeProbe using command-line arguments.
+     * 
+     * @param cmdArgs list of arguments passed on the command line
+     * @throws ParseException for missing required, or unrecognized options
+     * @throws IOException on connection failures
+     */
+    private NodeProbe(String[] cmdArgs) throws ParseException, IOException
+    {
+        parseArgs(cmdArgs);
+        this.host = cmd.getOptionValue(HOST_OPTION);
+        
+        String portNum = cmd.getOptionValue(PORT_OPTION);
+        if (portNum != null)
+        {
+            try
+            {
+                this.port = Integer.parseInt(portNum);
+            }
+            catch (NumberFormatException e)
+            {
+                throw new ParseException("Port must be a number");
+            }
+        }
+        else
+        {
+            this.port = defaultPort;
+        }
+        
+        connect();
+    }
+    
+    /**
+     * Creates a NodeProbe using the specified JMX host and port.
+     * 
+     * @param host hostname or IP address of the JMX agent
+     * @param port TCP port of the remote JMX agent
+     * @throws IOException on connection failures
+     */
+    public NodeProbe(String host, int port) throws IOException
+    {
+        this.host = host;
+        this.port = port;
+        connect();
+    }
+    
+    /**
+     * Creates a NodeProbe using the specified JMX host and default port.
+     * 
+     * @param host hostname or IP address of the JMX agent
+     * @throws IOException on connection failures
+     */
+    public NodeProbe(String host) throws IOException
+    {
+        this.host = host;
+        this.port = defaultPort;
+        connect();
+    }
+    
+    /**
+     * Create a connection to the JMX agent and setup the M[X]Bean proxies.
+     * 
+     * @throws IOException on connection failures
+     */
+    private void connect() throws IOException
+    {
+        JMXServiceURL jmxUrl = new JMXServiceURL(String.format(fmtUrl, host, port));
+        JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl, null);
+        mbeanServerConn = jmxc.getMBeanServerConnection();
+        
+        try
+        {
+            ObjectName name = new ObjectName(ssObjName);
+            ssProxy = JMX.newMBeanProxy(mbeanServerConn, name, StorageServiceMBean.class);
+        } catch (MalformedObjectNameException e)
+        {
+            throw new RuntimeException(
+                    "Invalid ObjectName? Please report this as a bug.", e);
+        }
+        
+        memProxy = ManagementFactory.newPlatformMXBeanProxy(mbeanServerConn, 
+                ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class);
+        runtimeProxy = ManagementFactory.newPlatformMXBeanProxy(
+                mbeanServerConn, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
+    }
+    
+    /**
+     * Retrieve a map of range to end points that describe the ring topology
+     * of a Cassandra cluster.
+     * 
+     * @return mapping of ranges to end points
+     */
+    public Map<Range, List<EndPoint>> getRangeToEndpointMap()
+    {
+        return ssProxy.getRangeToEndPointMap();
+    }
+    
+    /**
+     * Retrieve the list of live nodes in the cluster, where "liveness" is
+     * determined by the failure detector of the node being queried. The 
+     * returned string is a space delimited list of host:port end points.
+     * 
+     * @return space delimited list of nodes
+     */
+    public String getLiveNodes()
+    {
+        return ssProxy.getLiveNodes();
+    }
+    
+    /**
+     * Retrieve the list of unreachable nodes in the cluster, as determined
+     * by this node's failure detector. The returned string is a space
+     * delimited list of host:port end points.
+     * 
+     * @return space delimited list of nodes
+     */
+    public String getUnreachableNodes()
+    {
+        return ssProxy.getUnreachableNodes();
+    }
+    
+    /**
+     * Fetch a string representation of the token.
+     * 
+     * @return a string token
+     */
+    public String getToken()
+    {
+        return ssProxy.getToken();
+    }
+    
+    /**
+     * Return the generation value for this node.
+     * 
+     * @return generation number
+     */
+    public int getCurrentGenerationNumber()
+    {
+        return ssProxy.getCurrentGenerationNumber();
+    }
+    
+    /**
+     * Retrieve a textual representation of the on-disk size of data
+     * stored on this node.
+     * 
+     * @return the size description
+     */
+    public String getLoadInfo()
+    {
+        return ssProxy.getLoadInfo();
+    }
+    
+    /**
+     * Trigger a cleanup of keys on all tables.
+     */
+    public void forceTableCleanup()
+    {
+        ssProxy.forceTableCleanup();
+    }
+    
+    /**
+     * Trigger compaction of all tables.
+     */
+    public void forceTableCompaction()
+    {
+        ssProxy.forceTableCompaction();
+    }
+    
+    /**
+     * Write a textual representation of the Cassandra ring.
+     * 
+     * @param outs the stream to write to
+     */
+    public void printRing(PrintStream outs)
+    {
+        Map<Range, List<EndPoint>> rangeMap = getRangeToEndpointMap();
+        
+        // Print range-to-endpoint mapping
+        int counter = 0;
+        for (Range range : rangeMap.keySet()) {
+            List<EndPoint> endpoints = rangeMap.get(range);
+            
+            outs.print(String.format("%-46s ", range.left()));
+            outs.print(String.format("%2d ", endpoints.size()));
+            outs.print(String.format("%-15s", endpoints.get(0).getHost()));
+            
+            String asciiRingArt;
+            if (counter == 0)
+            {
+                asciiRingArt = "|<--|";
+            }
+            else if (counter == (rangeMap.size() - 1))
+            {
+                asciiRingArt = "|-->|";
+            }
+            else
+            {
+                if ((rangeMap.size() > 4) && ((counter % 2) == 0))
+                {
+                    asciiRingArt = "v   |";
+                }
+                else if ((rangeMap.size() > 4) && ((counter % 2) != 0))
+                {
+                    asciiRingArt = "|   ^";
+                }
+                else
+                {
+                    asciiRingArt = "|   |";
+                }
+            }
+            outs.println(asciiRingArt);
+            
+            counter++;
+        }
+    }
+    
+    /**
+     * Write a list of nodes with corresponding status.
+     * 
+     * @param outs the stream to write to
+     */
+    public void printCluster(PrintStream outs)
+    {
+        for (String upNode : getLiveNodes().split("\\s+"))
+        {
+            if (upNode.length() > 0)
+            {
+                outs.println(String.format("%-21s up", upNode));
+            }
+        }
+        
+        for (String downNode : getUnreachableNodes().split("\\s+"))
+        {
+            if (downNode.length() > 0)
+            {
+                outs.println(String.format("%-21s down", downNode));
+            }
+        }
+    }
+    
+    /**
+     * Write node information.
+     * 
+     * @param outs the stream to write to
+     */
+    public void printInfo(PrintStream outs)
+    {
+        outs.println(getToken());
+        outs.println(String.format("%-17s: %s", "Load Info", getLoadInfo()));
+        outs.println(String.format("%-17s: %s", "Generation No", getCurrentGenerationNumber()));
+        
+        // Uptime
+        long secondsUp = runtimeProxy.getUptime() / 1000;
+        outs.println(String.format("%-17s: %d", "Uptime (seconds)", secondsUp));
+
+        // Memory usage
+        MemoryUsage heapUsage = memProxy.getHeapMemoryUsage();
+        double memUsed = (double)heapUsage.getUsed() / (1024 * 1024);
+        double memMax = (double)heapUsage.getMax() / (1024 * 1024);
+        outs.println(String.format("%-17s: %.2f / %.2f", "Heap Memory (MB)", memUsed, memMax));
+    }
+    
+    /**
+     * Retrieve any non-option arguments passed on the command line.
+     * 
+     * @return non-option command args
+     */
+    private String[] getArgs()
+    {
+        return cmd.getArgs();
+    }
+    
+    /**
+     * Parse the supplied command line arguments.
+     * 
+     * @param args arguments passed on the command line
+     * @throws ParseException for missing required, or unrecognized options
+     */
+    private void parseArgs(String[] args) throws ParseException
+    {
+        CommandLineParser parser = new PosixParser();
+        cmd = parser.parse(options, args);
+    }
+    
+    /**
+     * Prints usage information to stdout.
+     */
+    private static void printUsage()
+    {
+        HelpFormatter hf = new HelpFormatter();
+        String header = String.format(
+                "%nAvailable commands: ring, cluster, info, cleanup, compact");
+        String usage = String.format("java %s -host <arg> <command>%n", NodeProbe.class.getName());
+        hf.printHelp(usage, "", options, header);
+    }
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        NodeProbe probe = null;
+        try
+        {
+            probe = new NodeProbe(args);
+        }
+        catch (ParseException pe)
+        {
+            System.err.println(pe.getMessage());
+            NodeProbe.printUsage();
+            System.exit(1);
+        }
+        catch (IOException ioe)
+        {
+            System.err.println("Error connecting to remote JMX agent!");
+            ioe.printStackTrace();
+            System.exit(3);
+        }
+        
+        if (probe.getArgs().length < 1)
+        {
+            System.err.println("Missing argument for command.");
+            NodeProbe.printUsage();
+            System.exit(1);
+        }
+        
+        // Execute the requested command.
+        String cmdName = probe.getArgs()[0];
+        if (cmdName.equals("ring"))
+        {
+            probe.printRing(System.out);
+        }
+        else if (cmdName.equals("cluster"))
+        {
+            probe.printCluster(System.out);
+        }
+        else if (cmdName.equals("info"))
+        {
+            probe.printInfo(System.out);
+        }
+        else if (cmdName.equals("cleanup"))
+        {
+            probe.forceTableCleanup();
+        }
+        else if (cmdName.equals("compact"))
+        {
+            probe.forceTableCompaction();
+        }
+        else
+        {
+            System.err.println("Unrecognized command: " + cmdName + ".");
+            NodeProbe.printUsage();
+            System.exit(1);
+        }
+
+        System.exit(0);
+    }
+
+}



Mime
View raw message