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