optimize calculateNaturalEndpoints by batch-updating TokenMetadata patch by Peter Schuller; reviewed by jbellis for CASSANDRA-3831
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/7b1dd3d8 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/7b1dd3d8 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/7b1dd3d8 Branch: refs/heads/cassandra-1.1 Commit: 7b1dd3d8f0191c7d53211a6312e591cd29128184 Parents: 7236465 Author: Jonathan Ellis <jbel...@apache.org> Authored: Tue Feb 7 13:06:31 2012 -0600 Committer: Jonathan Ellis <jbel...@apache.org> Committed: Tue Feb 7 13:09:43 2012 -0600 ---------------------------------------------------------------------- .../cassandra/locator/NetworkTopologyStrategy.java | 10 ++- .../apache/cassandra/locator/TokenMetadata.java | 52 +++++++++++---- 2 files changed, 47 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/7b1dd3d8/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java b/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java index 2ae0a98..ffbabd6 100644 --- a/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java +++ b/src/java/org/apache/cassandra/locator/NetworkTopologyStrategy.java @@ -35,6 +35,7 @@ import org.apache.cassandra.dht.Token; import org.apache.cassandra.service.*; import org.apache.cassandra.thrift.ConsistencyLevel; import org.apache.cassandra.utils.FBUtilities; +import org.apache.cassandra.utils.Pair; /** * This Replication Strategy takes a property file that gives the intended @@ -86,13 +87,16 @@ public class NetworkTopologyStrategy extends AbstractReplicationStrategy String dcName = dcEntry.getKey(); int dcReplicas = dcEntry.getValue(); - // collect endpoints in this DC - TokenMetadata dcTokens = new TokenMetadata(); + // collect endpoints in this DC; add in bulk to token meta data for computational complexity + // reasons (CASSANDRA-3831). + Set<Pair<Token, InetAddress>> dcTokensToUpdate = new HashSet<Pair<Token, InetAddress>>(); for (Entry<Token, InetAddress> tokenEntry : tokenMetadata.entrySet()) { if (snitch.getDatacenter(tokenEntry.getValue()).equals(dcName)) - dcTokens.updateNormalToken(tokenEntry.getKey(), tokenEntry.getValue()); + dcTokensToUpdate.add(Pair.create(tokenEntry.getKey(), tokenEntry.getValue())); } + TokenMetadata dcTokens = new TokenMetadata(); + dcTokens.updateNormalTokens(dcTokensToUpdate); List<InetAddress> dcEndpoints = new ArrayList<InetAddress>(dcReplicas); Set<String> racks = new HashSet<String>(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/7b1dd3d8/src/java/org/apache/cassandra/locator/TokenMetadata.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/locator/TokenMetadata.java b/src/java/org/apache/cassandra/locator/TokenMetadata.java index bf8e190..b02daae 100644 --- a/src/java/org/apache/cassandra/locator/TokenMetadata.java +++ b/src/java/org/apache/cassandra/locator/TokenMetadata.java @@ -118,26 +118,54 @@ public class TokenMetadata return n; } + /** + * Update token map with a single token/endpoint pair in normal state. + */ public void updateNormalToken(Token token, InetAddress endpoint) { - assert token != null; - assert endpoint != null; + updateNormalTokens(Collections.singleton(Pair.create(token, endpoint))); + } + + /** + * Update token map with a set of token/endpoint pairs in normal state. + * + * Prefer this whenever there are multiple pairs to update, as each update (whether a single or multiple) + * is expensive (CASSANDRA-3831). + * + * @param tokenPairs + */ + public void updateNormalTokens(Set<Pair<Token, InetAddress>> tokenPairs) + { + if (tokenPairs.isEmpty()) + return; lock.writeLock().lock(); try { - bootstrapTokens.inverse().remove(endpoint); - tokenToEndpointMap.inverse().remove(endpoint); - InetAddress prev = tokenToEndpointMap.put(token, endpoint); - if (!endpoint.equals(prev)) + boolean shouldSortTokens = false; + for (Pair<Token, InetAddress> tokenEndpointPair : tokenPairs) { - if (prev != null) - logger.warn("Token " + token + " changing ownership from " + prev + " to " + endpoint); - sortedTokens = sortTokens(); + Token token = tokenEndpointPair.left; + InetAddress endpoint = tokenEndpointPair.right; + + assert token != null; + assert endpoint != null; + + bootstrapTokens.inverse().remove(endpoint); + tokenToEndpointMap.inverse().remove(endpoint); + InetAddress prev = tokenToEndpointMap.put(token, endpoint); + if (!endpoint.equals(prev)) + { + if (prev != null) + logger.warn("Token " + token + " changing ownership from " + prev + " to " + endpoint); + shouldSortTokens = true; + } + leavingEndpoints.remove(endpoint); + removeFromMoving(endpoint); // also removing this endpoint from moving } - leavingEndpoints.remove(endpoint); - removeFromMoving(endpoint); // also removing this endpoint from moving - invalidateCaches(); + + if (shouldSortTokens) + sortedTokens = sortTokens(); } finally {