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 2010/11/19 23:23:07 UTC

svn commit: r1037056 - in /cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra: dht/ service/ tools/

Author: brandonwilliams
Date: Fri Nov 19 22:23:06 2010
New Revision: 1037056

URL: http://svn.apache.org/viewvc?rev=1037056&view=rev
Log:
nodetool ring shows the percentage each node owns.  Patch by Jon Hermes, reviewed by brandonwilliams for CASSANDRA-1553

Modified:
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/IPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/LocalPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/RandomPartitioner.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageService.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageServiceMBean.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeCmd.java
    cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeProbe.java

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/ByteOrderedPartitioner.java Fri Nov 19 22:23:06 2010
@@ -19,6 +19,9 @@
 package org.apache.cassandra.dht;
 
 import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class ByteOrderedPartitioner extends AbstractByteOrderedPartitioner
 {
@@ -28,4 +31,6 @@ public class ByteOrderedPartitioner exte
             return MINIMUM;
         return new BytesToken(key);
     }
+
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens){ throw new UnsupportedOperationException(); }
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/CollatingOrderPreservingPartitioner.java Fri Nov 19 22:23:06 2010
@@ -21,7 +21,10 @@ package org.apache.cassandra.dht;
 import java.nio.ByteBuffer;
 import java.nio.charset.CharacterCodingException;
 import java.text.Collator;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 import org.apache.cassandra.utils.FBUtilities;
 
@@ -45,4 +48,6 @@ public class CollatingOrderPreservingPar
         }
         return new BytesToken(ByteBuffer.wrap(collator.getCollationKey(skey).toByteArray()));
     }
+
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens){ throw new UnsupportedOperationException(); }
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/IPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/IPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/IPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/IPartitioner.java Fri Nov 19 22:23:06 2010
@@ -19,6 +19,8 @@
 package org.apache.cassandra.dht;
 
 import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.cassandra.db.DecoratedKey;
 
@@ -73,4 +75,13 @@ public interface IPartitioner<T extends 
      * it generates.
      */
     public boolean preservesOrder();
+
+    /**
+     * Calculate the deltas between tokens in the ring in order to compare
+     *  relative sizes.
+     *
+     * @param sortedTokens a sorted List of Tokens
+     * @return the mapping from 'token' to 'percentage of the ring owned by that token'.
+     */
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens);
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/LocalPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/LocalPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/LocalPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/LocalPartitioner.java Fri Nov 19 22:23:06 2010
@@ -20,6 +20,7 @@
 package org.apache.cassandra.dht;
 
 import java.nio.ByteBuffer;
+import java.util.*;
 
 import org.apache.cassandra.db.DecoratedKey;
 import org.apache.cassandra.db.marshal.AbstractType;
@@ -74,4 +75,9 @@ public class LocalPartitioner implements
     {
         return true;
     }
+
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens)
+    {
+        return Collections.singletonMap((Token)getMinimumToken(), new Float(1.0));
+    }
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/OrderPreservingPartitioner.java Fri Nov 19 22:23:06 2010
@@ -21,11 +21,14 @@ package org.apache.cassandra.dht;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
 import java.nio.charset.CharacterCodingException;
-import java.util.Random;
+import java.util.*;
 
 import com.google.common.base.Charsets;
 
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.FBUtilities;
 import org.apache.cassandra.utils.Pair;
@@ -157,4 +160,41 @@ public class OrderPreservingPartitioner 
         }
         return new StringToken(skey);
     }
+
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens)
+    {
+        // alltokens will contain the count and be returned, sorted_ranges is shorthand for token<->token math.
+        Map<Token, Float> alltokens = new HashMap<Token, Float>();
+        List<Range> sorted_ranges = new ArrayList<Range>();
+
+        // this initializes the counts to 0 and calcs the ranges in order.
+        Token last_t = sortedTokens.get(sortedTokens.size()-1);
+        for (Token node : sortedTokens)
+        {
+            alltokens.put(node, new Float(0.0));
+            sorted_ranges.add(new Range(last_t, node));
+            last_t = node;
+        }
+
+        for(String ks : DatabaseDescriptor.getTables())
+        {
+            for (CFMetaData cfmd : DatabaseDescriptor.getKSMetaData(ks).cfMetaData().values())
+            {
+                for (Range r : sorted_ranges)
+                {
+                    // Looping over every KS:CF:Range, get the splits size and add it to the count
+                    alltokens.put(r.right, alltokens.get(r.right) + StorageService.instance.getSplits(ks, cfmd.cfName, r, 1).size());
+                }
+            }
+        }
+
+        // Sum every count up and divide count/total for the fractional ownership.
+        Float total = new Float(0.0);
+        for (Float f : alltokens.values()) { total += f; }
+        for (Map.Entry<Token, Float> row : alltokens.entrySet()) {
+            alltokens.put(row.getKey(), row.getValue() / total);
+        }
+        
+        return alltokens;
+    }
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/RandomPartitioner.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/RandomPartitioner.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/RandomPartitioner.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/dht/RandomPartitioner.java Fri Nov 19 22:23:06 2010
@@ -20,9 +20,10 @@ package org.apache.cassandra.dht;
 
 import static com.google.common.base.Charsets.UTF_8;
 
+import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
-import java.util.Arrays;
+import java.util.*;
 
 import org.apache.cassandra.db.DecoratedKey;
 import org.apache.cassandra.utils.FBUtilities;
@@ -127,4 +128,36 @@ public class RandomPartitioner implement
             return MINIMUM;
         return new BigIntegerToken(FBUtilities.md5hash(key));
     }
+
+    public Map<Token, Float> describeOwnership(List<Token> sortedTokens)
+    {
+        Map<Token, Float> ownerships = new HashMap<Token, Float>();
+        Iterator i = sortedTokens.iterator();
+
+        // 0-case
+        if (!i.hasNext()) { throw new RuntimeException("No nodes present in the cluster. How did you call this?"); }
+        // 1-case
+        if (sortedTokens.size() == 1) {
+            ownerships.put((Token)i.next(), new Float(1.0));
+        }
+        // n-case
+        else {
+            // NOTE: All divisions must take place in BigDecimals, and all modulo operators must take place in BigIntegers.
+            final BigInteger ri = new BigInteger("2").pow(127);                             //  (used for addition later)
+            final BigDecimal r  = new BigDecimal(ri);                                       // The entire range, 2**127
+            Token start = (Token)i.next(); BigInteger ti = ((BigIntegerToken)start).token;  // The first token and its value
+            Token t; BigInteger tim1 = ti;                                                  // The last token and its value (after loop)
+            while (i.hasNext()) {
+                t = (Token)i.next(); ti = ((BigIntegerToken)t).token;                       // The next token and its value
+                float x = new BigDecimal(ti.subtract(tim1)).divide(r).floatValue();         // %age = T(i) - T(i-1) / R
+                ownerships.put(t, x);                                                       // save (T(i) -> %age)
+                tim1 = ti;                                                                  // -> advance loop
+            }
+            // The start token's range extends backward to the last token, which is why both were saved
+            //  above. The simple calculation for this is: T(start) - T(end) + r % r / r.
+            //  (In the 1-case, this produces 0% instead of 100%.)
+            ownerships.put(start, new BigDecimal(((BigIntegerToken)start).token.subtract(ti).add(ri).mod(ri)).divide(r).floatValue());
+        }
+        return ownerships;
+    }
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageService.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageService.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageService.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageService.java Fri Nov 19 22:23:06 2010
@@ -2058,4 +2058,11 @@ public class StorageService implements I
         logger_.debug("cache saves completed");
     }
 
+    public Map<Token, Float> getOwnership()
+    {
+        List<Token> sortedTokens = new ArrayList<Token>(getTokenToEndpointMap().keySet());
+        Collections.sort(sortedTokens);
+        return partitioner_.describeOwnership(sortedTokens);
+    }
+
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageServiceMBean.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageServiceMBean.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageServiceMBean.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/service/StorageServiceMBean.java Fri Nov 19 22:23:06 2010
@@ -29,6 +29,7 @@ import java.util.concurrent.ExecutionExc
 import java.util.concurrent.TimeoutException;
 
 import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.dht.IPartitioner;
 import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.thrift.UnavailableException;
@@ -263,4 +264,10 @@ public interface StorageServiceMBean
 
     /** save row and key caches */
     public void saveCaches() throws ExecutionException, InterruptedException;
+
+    /**
+     * given a list of tokens (representing the nodes in the cluster), returns
+     *   a mapping from "token -> %age of cluster owned by that token"
+     */
+    public Map<Token, Float> getOwnership();
 }

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeCmd.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeCmd.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeCmd.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeCmd.java Fri Nov 19 22:23:06 2010
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.io.PrintStream;
 import java.lang.management.MemoryUsage;
 import java.net.InetAddress;
+import java.text.DecimalFormat;
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
@@ -34,6 +35,7 @@ import org.apache.commons.cli.*;
 
 import org.apache.cassandra.cache.JMXInstrumentedCacheMBean;
 import org.apache.cassandra.concurrent.IExecutorMBean;
+import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.db.ColumnFamilyStoreMBean;
 import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.net.MessagingServiceMBean;
@@ -95,23 +97,33 @@ public class NodeCmd {
         Collection<String> leavingNodes = probe.getLeavingNodes();
         Map<String, String> loadMap = probe.getLoadMap();
 
-        outs.printf("%-16s%-7s%-8s%-16s%-44s\n", "Address", "Status", "State", "Load", "Token");
+        outs.printf("%-16s%-7s%-8s%-16s%-8s%-44s\n", "Address", "Status", "State", "Load", "Owns", "Token");
         // show pre-wrap token twice so you can always read a node's range as
         // (previous line token, current line token]
         if (sortedTokens.size() > 1)
-            outs.printf("%-14s%-11s%-14s%-43s\n", "", "", "", sortedTokens.get(sortedTokens.size() - 1));
+            outs.printf("%-16s%-7s%-8s%-16s%-8s%-44s\n", "", "", "", "", "", sortedTokens.get(sortedTokens.size() - 1));
+
+        // Calculate per-token ownership of the ring
+        Map<Token, Float> ownerships = probe.getOwnership();
 
         for (Token token : sortedTokens)
         {
             String primaryEndpoint = tokenToEndpoint.get(token);
             String status = liveNodes.contains(primaryEndpoint)
                             ? "Up"
-                            : deadNodes.contains(primaryEndpoint) ? "Down" : "?";
+                            : deadNodes.contains(primaryEndpoint)
+                              ? "Down"
+                              : "?";
             String state = joiningNodes.contains(primaryEndpoint)
                            ? "Joining"
-                           : leavingNodes.contains(primaryEndpoint) ? "Leaving" : "Normal";
-            String load = loadMap.containsKey(primaryEndpoint) ? loadMap.get(primaryEndpoint) : "?";
-            outs.printf("%-16s%-7s%-8s%-16s%-44s\n", primaryEndpoint, status, state, load, token);
+                           : leavingNodes.contains(primaryEndpoint)
+                             ? "Leaving"
+                             : "Normal";
+            String load = loadMap.containsKey(primaryEndpoint)
+                          ? loadMap.get(primaryEndpoint)
+                          : "?";
+            String owns = new DecimalFormat("##0.00%").format(ownerships.get(token));
+            outs.printf("%-16s%-7s%-8s%-16s%-8s%-44s\n", primaryEndpoint, status, state, load, owns, token);
         }
     }
 

Modified: cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeProbe.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeProbe.java?rev=1037056&r1=1037055&r2=1037056&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeProbe.java (original)
+++ cassandra/branches/cassandra-0.7/src/java/org/apache/cassandra/tools/NodeProbe.java Fri Nov 19 22:23:06 2010
@@ -24,6 +24,7 @@ import java.lang.management.ManagementFa
 import java.lang.management.MemoryMXBean;
 import java.lang.management.MemoryUsage;
 import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Constructor;
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
 import java.util.*;
@@ -44,12 +45,17 @@ import org.apache.cassandra.cache.JMXIns
 import org.apache.cassandra.concurrent.IExecutorMBean;
 import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.db.ColumnFamilyStoreMBean;
+import org.apache.cassandra.dht.IPartitioner;
 import org.apache.cassandra.dht.Token;
+import org.apache.cassandra.locator.IEndpointSnitch;
+import org.apache.cassandra.locator.TokenMetadata;
 import org.apache.cassandra.net.MessagingServiceMBean;
+import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.service.StorageServiceMBean;
 import org.apache.cassandra.streaming.StreamingService;
 import org.apache.cassandra.streaming.StreamingServiceMBean;
 import org.apache.cassandra.thrift.UnavailableException;
+import org.apache.cassandra.utils.FBUtilities;
 
 import static com.google.common.base.Charsets.UTF_8;
 
@@ -197,6 +203,11 @@ public class NodeProbe
         return ssProxy.getLoadMap();
     }
 
+    public Map<Token, Float> getOwnership()
+    {
+        return ssProxy.getOwnership();
+    }
+
     public Iterator<Map.Entry<String, ColumnFamilyStoreMBean>> getColumnFamilyStoreMBeanProxies()
     {
         try