You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jb...@apache.org on 2010/06/15 23:32:30 UTC

svn commit: r955060 - in /cassandra/trunk: src/java/org/apache/cassandra/locator/ src/java/org/apache/cassandra/service/ test/unit/org/apache/cassandra/locator/ test/unit/org/apache/cassandra/service/

Author: jbellis
Date: Tue Jun 15 21:32:30 2010
New Revision: 955060

URL: http://svn.apache.org/viewvc?rev=955060&view=rev
Log:
clean up of TokenMetadata and ARS.  patch by mdennis; reviewed by jbellis for CASSANDRA-1194

Modified:
    cassandra/trunk/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
    cassandra/trunk/src/java/org/apache/cassandra/locator/RackAwareStrategy.java
    cassandra/trunk/src/java/org/apache/cassandra/locator/RackUnawareStrategy.java
    cassandra/trunk/src/java/org/apache/cassandra/locator/TokenMetadata.java
    cassandra/trunk/src/java/org/apache/cassandra/service/StorageProxy.java
    cassandra/trunk/test/unit/org/apache/cassandra/locator/RackUnawareStrategyTest.java
    cassandra/trunk/test/unit/org/apache/cassandra/service/MoveTest.java

Modified: cassandra/trunk/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/locator/AbstractReplicationStrategy.java Tue Jun 15 21:32:30 2010
@@ -22,11 +22,11 @@ package org.apache.cassandra.locator;
 import java.net.InetAddress;
 import java.util.*;
 
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
@@ -53,7 +53,7 @@ public abstract class AbstractReplicatio
 
     AbstractReplicationStrategy(TokenMetadata tokenMetadata, IEndpointSnitch snitch)
     {
-        // TODO assert snitch != null some test code violates this
+        assert snitch != null;
         assert tokenMetadata != null;
         this.tokenMetadata = tokenMetadata;
         this.snitch = snitch;
@@ -71,14 +71,13 @@ public abstract class AbstractReplicatio
      */
     public ArrayList<InetAddress> getNaturalEndpoints(Token searchToken, String table)
     {
-        // TODO creating a iterator object just to get the closest token is wasteful -- we do in multiple places w/ ringIterator
-        Token keyToken = TokenMetadata.ringIterator(tokenMetadata.sortedTokens(), searchToken).next();
+        Token keyToken = TokenMetadata.firstToken(tokenMetadata.sortedTokens(), searchToken);
         EndpointCacheKey cacheKey = new EndpointCacheKey(table, keyToken);
         ArrayList<InetAddress> endpoints = cachedEndpoints.get(cacheKey);
         if (endpoints == null)
         {
             TokenMetadata tokenMetadataClone = tokenMetadata.cloneOnlyTokenMap();
-            keyToken = TokenMetadata.ringIterator(tokenMetadataClone.sortedTokens(), searchToken).next();
+            keyToken = TokenMetadata.firstToken(tokenMetadataClone.sortedTokens(), searchToken);
             cacheKey = new EndpointCacheKey(table, keyToken);
             endpoints = new ArrayList<InetAddress>(calculateNaturalEndpoints(searchToken, tokenMetadataClone, table));
             cachedEndpoints.put(cacheKey, endpoints);
@@ -141,35 +140,6 @@ public abstract class AbstractReplicatio
         return map;
     }
 
-    /**
-     * write endpoints may be different from read endpoints, because read endpoints only need care about the
-     * "natural" nodes for a token, but write endpoints also need to account for nodes that are bootstrapping
-     * into the ring, and write data there too so that they stay up to date during the bootstrap process.
-     * Thus, this method may return more nodes than the Replication Factor.
-     *
-     * If possible, will return the same collection it was passed, for efficiency.
-     *
-     * Only ReplicationStrategy should care about this method (higher level users should only ask for Hinted).
-     * todo: this method should be moved into TokenMetadata.
-     */
-    public Collection<InetAddress> getWriteEndpoints(Token token, String table, Collection<InetAddress> naturalEndpoints)
-    {
-        if (tokenMetadata.getPendingRanges(table).isEmpty())
-            return naturalEndpoints;
-
-        List<InetAddress> endpoints = new ArrayList<InetAddress>(naturalEndpoints);
-
-        for (Map.Entry<Range, Collection<InetAddress>> entry : tokenMetadata.getPendingRanges(table).entrySet())
-        {
-            if (entry.getKey().contains(token))
-            {
-                endpoints.addAll(entry.getValue());
-            }
-        }
-
-        return endpoints;
-    }
-
     /*
      * NOTE: this is pretty inefficient. also the inverse (getRangeAddresses) below.
      * this is fine as long as we don't use this on any critical path.

Modified: cassandra/trunk/src/java/org/apache/cassandra/locator/RackAwareStrategy.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/RackAwareStrategy.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/locator/RackAwareStrategy.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/locator/RackAwareStrategy.java Tue Jun 15 21:32:30 2010
@@ -20,7 +20,10 @@
 package org.apache.cassandra.locator;
 
 import java.net.InetAddress;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.dht.Token;
@@ -45,7 +48,7 @@ public class RackAwareStrategy extends A
     {
         int replicas = DatabaseDescriptor.getReplicationFactor(table);
         Set<InetAddress> endpoints = new HashSet<InetAddress>(replicas);
-        List<Token> tokens = metadata.sortedTokens();
+        ArrayList<Token> tokens = metadata.sortedTokens();
 
         if (tokens.isEmpty())
             return endpoints;

Modified: cassandra/trunk/src/java/org/apache/cassandra/locator/RackUnawareStrategy.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/RackUnawareStrategy.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/locator/RackUnawareStrategy.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/locator/RackUnawareStrategy.java Tue Jun 15 21:32:30 2010
@@ -20,7 +20,10 @@
 package org.apache.cassandra.locator;
 
 import java.net.InetAddress;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
 
 import org.apache.cassandra.config.DatabaseDescriptor;
 import org.apache.cassandra.dht.Token;
@@ -41,7 +44,7 @@ public class RackUnawareStrategy extends
     public Set<InetAddress> calculateNaturalEndpoints(Token token, TokenMetadata metadata, String table)
     {
         int replicas = DatabaseDescriptor.getReplicationFactor(table);
-        List<Token> tokens = metadata.sortedTokens();
+        ArrayList<Token> tokens = metadata.sortedTokens();
         Set<InetAddress> endpoints = new HashSet<InetAddress>(replicas);
 
         if (tokens.isEmpty())

Modified: cassandra/trunk/src/java/org/apache/cassandra/locator/TokenMetadata.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/locator/TokenMetadata.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/locator/TokenMetadata.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/locator/TokenMetadata.java Tue Jun 15 21:32:30 2010
@@ -62,7 +62,7 @@ public class TokenMetadata
 
     /* Use this lock for manipulating the token map */
     private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
-    private List<Token> sortedTokens;
+    private ArrayList<Token> sortedTokens;
 
     /* list of subscribers that are notified when the tokenToEndpointMap changed */
     private final CopyOnWriteArrayList<AbstractReplicationStrategy> subscribers;
@@ -84,11 +84,11 @@ public class TokenMetadata
         subscribers = new CopyOnWriteArrayList<AbstractReplicationStrategy>();
     }
 
-    private List<Token> sortTokens()
+    private ArrayList<Token> sortTokens()
     {
-        List<Token> tokens = new ArrayList<Token>(tokenToEndpointMap.keySet());
+        ArrayList<Token> tokens = new ArrayList<Token>(tokenToEndpointMap.keySet());
         Collections.sort(tokens);
-        return Collections.unmodifiableList(tokens);
+        return tokens;
     }
 
     /** @return the number of nodes bootstrapping into source's primary range */
@@ -136,7 +136,7 @@ public class TokenMetadata
         lock.writeLock().lock();
         try
         {
-            InetAddress oldEndpoint = null;
+            InetAddress oldEndpoint;
 
             oldEndpoint = bootstrapTokens.get(token);
             if (oldEndpoint != null && !oldEndpoint.equals(endpoint))
@@ -264,21 +264,6 @@ public class TokenMetadata
         }
     }
 
-    public InetAddress getFirstEndpoint()
-    {
-        assert tokenToEndpointMap.size() > 0;
-
-        lock.readLock().lock();
-        try
-        {
-            return tokenToEndpointMap.get(sortedTokens.get(0));
-        }
-        finally
-        {
-            lock.readLock().unlock();
-        }
-    }
-
     /**
      * Create a copy of TokenMetadata with only tokenToEndpointMap. That is, pending ranges,
      * bootstrap tokens and leaving endpoints are not included in the copy.
@@ -334,7 +319,7 @@ public class TokenMetadata
         return new Range(getPredecessor(right), right);
     }
 
-    public List<Token> sortedTokens()
+    public ArrayList<Token> sortedTokens()
     {
         lock.readLock().lock();
         try
@@ -398,11 +383,6 @@ public class TokenMetadata
         return (Token) ((index == (tokens.size() - 1)) ? tokens.get(0) : tokens.get(index + 1));
     }
 
-    public InetAddress getSuccessor(InetAddress endpoint)
-    {
-        return getEndpoint(getSuccessor(getToken(endpoint)));
-    }
-
     /** caller should not modify bootstrapTokens */
     public Map<Token, InetAddress> getBootstrapTokens()
     {
@@ -415,11 +395,7 @@ public class TokenMetadata
         return leavingEndpoints;
     }
 
-    /**
-     * <tt>Iterator</tt> over the <tt>Token</tt>s in the given ring, starting with the token for the node owning start
-     * (which does not have to be a <tt>Token</tt> in the ring)
-     */
-    public static Iterator<Token> ringIterator(final List ring, Token start)
+    public static int firstTokenIndex(final ArrayList ring, Token start)
     {
         assert ring.size() > 0;
         int i = Collections.binarySearch(ring, start);
@@ -431,7 +407,21 @@ public class TokenMetadata
                 i = 0;
             }
         }
-        final int startIndex = i;
+        return i;
+    }
+
+    public static Token firstToken(final ArrayList<Token> ring, Token start)
+    {
+        return ring.get(firstTokenIndex(ring, start));
+    }
+
+    /**
+     * <tt>Iterator</tt> over the <tt>Token</tt>s in the given ring, starting with the token for the node owning start
+     * (which does not have to be a <tt>Token</tt> in the ring)
+     */
+    public static Iterator<Token> ringIterator(final ArrayList<Token> ring, Token start)
+    {
+        final int startIndex = firstTokenIndex(ring, start);
         return new AbstractIterator<Token>()
         {
             int j = startIndex;
@@ -441,7 +431,7 @@ public class TokenMetadata
                     return endOfData();
                 try
                 {
-                    return (Token) ring.get(j);
+                    return ring.get(j);
                 }
                 finally
                 {
@@ -549,4 +539,32 @@ public class TokenMetadata
     {
         subscribers.add(subscriber);
     }
+
+    /**
+     * write endpoints may be different from read endpoints, because read endpoints only need care about the
+     * "natural" nodes for a token, but write endpoints also need to account for nodes that are bootstrapping
+     * into the ring, and write data there too so that they stay up to date during the bootstrap process.
+     * Thus, this method may return more nodes than the Replication Factor.
+     *
+     * If possible, will return the same collection it was passed, for efficiency.
+     *
+     * Only ReplicationStrategy should care about this method (higher level users should only ask for Hinted).
+     */
+    public Collection<InetAddress> getWriteEndpoints(Token token, String table, Collection<InetAddress> naturalEndpoints)
+    {
+        if (getPendingRanges(table).isEmpty())
+            return naturalEndpoints;
+
+        List<InetAddress> endpoints = new ArrayList<InetAddress>(naturalEndpoints);
+
+        for (Map.Entry<Range, Collection<InetAddress>> entry : getPendingRanges(table).entrySet())
+        {
+            if (entry.getKey().contains(token))
+            {
+                endpoints.addAll(entry.getValue());
+            }
+        }
+
+        return endpoints;
+    }
 }

Modified: cassandra/trunk/src/java/org/apache/cassandra/service/StorageProxy.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/service/StorageProxy.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/service/StorageProxy.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/service/StorageProxy.java Tue Jun 15 21:32:30 2010
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.cassandra.service;
 
 import java.io.ByteArrayInputStream;
@@ -22,38 +23,23 @@ import java.io.DataInputStream;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
+import java.util.*;
+import java.util.concurrent.*;
 import javax.management.MBeanServer;
 import javax.management.ObjectName;
 
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Multimap;
 import org.apache.cassandra.concurrent.StageManager;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.cassandra.db.RangeSliceCommand;
-import org.apache.cassandra.db.ReadCommand;
-import org.apache.cassandra.db.ReadResponse;
-import org.apache.cassandra.db.Row;
-import org.apache.cassandra.db.RowMutation;
-import org.apache.cassandra.db.Table;
-import org.apache.cassandra.db.Truncation;
+import org.apache.cassandra.db.*;
 import org.apache.cassandra.dht.AbstractBounds;
 import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
@@ -70,14 +56,6 @@ import org.apache.cassandra.utils.FBUtil
 import org.apache.cassandra.utils.LatencyTracker;
 import org.apache.cassandra.utils.Pair;
 import org.apache.cassandra.utils.WrappedRunnable;
-import org.apache.commons.lang.ArrayUtils;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.AbstractIterator;
-import com.google.common.collect.Multimap;
-
 
 public class StorageProxy implements StorageProxyMBean
 {
@@ -216,7 +194,7 @@ public class StorageProxy implements Sto
                 AbstractReplicationStrategy rs = ss.getReplicationStrategy(table);
 
                 List<InetAddress> naturalEndpoints = ss.getNaturalEndpoints(table, rm.key());
-                Collection<InetAddress> writeEndpoints = rs.getWriteEndpoints(StorageService.getPartitioner().getToken(rm.key()), table, naturalEndpoints);
+                Collection<InetAddress> writeEndpoints = ss.getTokenMetadata().getWriteEndpoints(StorageService.getPartitioner().getToken(rm.key()), table, naturalEndpoints);
                 Multimap<InetAddress, InetAddress> hintedEndpoints = rs.getHintedEndpoints(writeEndpoints);
                 
                 // send out the writes, as in mutate() above, but this time with a callback that tracks responses

Modified: cassandra/trunk/test/unit/org/apache/cassandra/locator/RackUnawareStrategyTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/locator/RackUnawareStrategyTest.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/locator/RackUnawareStrategyTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/locator/RackUnawareStrategyTest.java Tue Jun 15 21:32:30 2010
@@ -16,6 +16,7 @@
 * specific language governing permissions and limitations
 * under the License.
 */
+
 package org.apache.cassandra.locator;
 
 import java.net.InetAddress;
@@ -56,7 +57,7 @@ public class RackUnawareStrategyTest ext
     public void testBigIntegerEndpoints() throws UnknownHostException
     {
         TokenMetadata tmd = new TokenMetadata();
-        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         List<Token> endpointTokens = new ArrayList<Token>();
         List<Token> keyTokens = new ArrayList<Token>();
@@ -72,7 +73,7 @@ public class RackUnawareStrategyTest ext
     {
         TokenMetadata tmd = new TokenMetadata();
         IPartitioner partitioner = new OrderPreservingPartitioner();
-        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         List<Token> endpointTokens = new ArrayList<Token>();
         List<Token> keyTokens = new ArrayList<Token>();
@@ -116,7 +117,7 @@ public class RackUnawareStrategyTest ext
         final int RING_SIZE = 10;
         TokenMetadata tmd = new TokenMetadata();
         TokenMetadata oldTmd = StorageServiceAccessor.setTokenMetadata(tmd);
-        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy strategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         Token[] endpointTokens = new Token[RING_SIZE];
         Token[] keyTokens = new Token[RING_SIZE];
@@ -147,7 +148,7 @@ public class RackUnawareStrategyTest ext
 
             for (int i = 0; i < keyTokens.length; i++)
             {
-                Collection<InetAddress> endpoints = strategy.getWriteEndpoints(keyTokens[i], table, strategy.getNaturalEndpoints(keyTokens[i], table));
+                Collection<InetAddress> endpoints = tmd.getWriteEndpoints(keyTokens[i], table, strategy.getNaturalEndpoints(keyTokens[i], table));
                 assertTrue(endpoints.size() >= replicationFactor);
 
                 for (int j = 0; j < replicationFactor; j++)

Modified: cassandra/trunk/test/unit/org/apache/cassandra/service/MoveTest.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/unit/org/apache/cassandra/service/MoveTest.java?rev=955060&r1=955059&r2=955060&view=diff
==============================================================================
--- cassandra/trunk/test/unit/org/apache/cassandra/service/MoveTest.java (original)
+++ cassandra/trunk/test/unit/org/apache/cassandra/service/MoveTest.java Tue Jun 15 21:32:30 2010
@@ -19,30 +19,23 @@
 
 package org.apache.cassandra.service;
 
-import java.util.*;
-
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.*;
+
+import org.junit.Test;
 
+import static org.junit.Assert.*;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 import org.apache.cassandra.CleanupHelper;
 import org.apache.cassandra.config.DatabaseDescriptor;
-import org.apache.commons.lang.StringUtils;
-import org.junit.Test;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import org.apache.cassandra.dht.IPartitioner;
-import org.apache.cassandra.dht.RandomPartitioner;
-import org.apache.cassandra.dht.Token;
-import org.apache.cassandra.dht.Range;
-import org.apache.cassandra.dht.BigIntegerToken;
+import org.apache.cassandra.dht.*;
+import org.apache.cassandra.gms.ApplicationState;
 import org.apache.cassandra.locator.AbstractReplicationStrategy;
 import org.apache.cassandra.locator.RackUnawareStrategy;
+import org.apache.cassandra.locator.SimpleSnitch;
 import org.apache.cassandra.locator.TokenMetadata;
-import org.apache.cassandra.gms.ApplicationState;
 
 public class MoveTest extends CleanupHelper
 {
@@ -70,7 +63,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategies = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
@@ -118,7 +111,7 @@ public class MoveTest extends CleanupHel
             final int replicaStart = (LEAVING_NODE-replicationFactor+RING_SIZE)%RING_SIZE;
             for (int i=0; i<keyTokens.size(); ++i)
             {
-                Collection<InetAddress> endpoints = testStrategy.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
+                Collection<InetAddress> endpoints = tmd.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
                 // figure out if this node is one of the nodes previous to the failed node (2).
                 boolean isReplica = (i - replicaStart + RING_SIZE) % RING_SIZE < replicationFactor;
                 // the preceeding leaving_node-replication_factor nodes should have and additional ep (replication_factor+1);
@@ -146,7 +139,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategy = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
@@ -222,7 +215,7 @@ public class MoveTest extends CleanupHel
         {
             for (int i = 0; i < keyTokens.size(); i++)
             {
-                endpoints = testStrategy.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
+                endpoints = tmd.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
                 assertTrue(expectedEndpoints.get(table).get(keyTokens.get(i)).size() == endpoints.size());
                 assertTrue(expectedEndpoints.get(table).get(keyTokens.get(i)).containsAll(endpoints));
             }
@@ -233,7 +226,7 @@ public class MoveTest extends CleanupHel
             // tokens 5, 15 and 25 should go three nodes
             for (int i=0; i<3; ++i)
             {
-                endpoints = testStrategy.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
+                endpoints = tmd.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
                 assertTrue(endpoints.size() == 3);
                 assertTrue(endpoints.contains(hosts.get(i+1)));
                 assertTrue(endpoints.contains(hosts.get(i+2)));
@@ -241,7 +234,7 @@ public class MoveTest extends CleanupHel
             }
 
             // token 35 should go to nodes 4, 5, 6, 7 and boot1
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(3), table, testStrategy.getNaturalEndpoints(keyTokens.get(3), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(3), table, testStrategy.getNaturalEndpoints(keyTokens.get(3), table));
             assertTrue(endpoints.size() == 5);
             assertTrue(endpoints.contains(hosts.get(4)));
             assertTrue(endpoints.contains(hosts.get(5)));
@@ -250,7 +243,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(boot1));
 
             // token 45 should go to nodes 5, 6, 7, 0, boot1 and boot2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(4), table, testStrategy.getNaturalEndpoints(keyTokens.get(4), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(4), table, testStrategy.getNaturalEndpoints(keyTokens.get(4), table));
             assertTrue(endpoints.size() == 6);
             assertTrue(endpoints.contains(hosts.get(5)));
             assertTrue(endpoints.contains(hosts.get(6)));
@@ -260,7 +253,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(boot2));
 
             // token 55 should go to nodes 6, 7, 8, 0, 1, boot1 and boot2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(5), table, testStrategy.getNaturalEndpoints(keyTokens.get(5), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(5), table, testStrategy.getNaturalEndpoints(keyTokens.get(5), table));
             assertTrue(endpoints.size() == 7);
             assertTrue(endpoints.contains(hosts.get(6)));
             assertTrue(endpoints.contains(hosts.get(7)));
@@ -271,7 +264,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(boot2));
 
             // token 65 should go to nodes 7, 8, 9, 0, 1 and boot2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(6), table, testStrategy.getNaturalEndpoints(keyTokens.get(6), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(6), table, testStrategy.getNaturalEndpoints(keyTokens.get(6), table));
             assertTrue(endpoints.size() == 6);
             assertTrue(endpoints.contains(hosts.get(7)));
             assertTrue(endpoints.contains(hosts.get(8)));
@@ -281,7 +274,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(boot2));
 
             // token 75 should to go nodes 8, 9, 0, 1, 2 and boot2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(7), table, testStrategy.getNaturalEndpoints(keyTokens.get(7), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(7), table, testStrategy.getNaturalEndpoints(keyTokens.get(7), table));
             assertTrue(endpoints.size() == 6);
             assertTrue(endpoints.contains(hosts.get(8)));
             assertTrue(endpoints.contains(hosts.get(9)));
@@ -291,7 +284,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(boot2));
 
             // token 85 should go to nodes 9, 0, 1 and 2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(8), table, testStrategy.getNaturalEndpoints(keyTokens.get(8), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(8), table, testStrategy.getNaturalEndpoints(keyTokens.get(8), table));
             assertTrue(endpoints.size() == 4);
             assertTrue(endpoints.contains(hosts.get(9)));
             assertTrue(endpoints.contains(hosts.get(0)));
@@ -299,7 +292,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(hosts.get(2)));
 
             // token 95 should go to nodes 0, 1 and 2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(9), table, testStrategy.getNaturalEndpoints(keyTokens.get(9), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(9), table, testStrategy.getNaturalEndpoints(keyTokens.get(9), table));
             assertTrue(endpoints.size() == 3);
             assertTrue(endpoints.contains(hosts.get(0)));
             assertTrue(endpoints.contains(hosts.get(1)));
@@ -337,7 +330,7 @@ public class MoveTest extends CleanupHel
         {
             for (int i = 0; i < keyTokens.size(); i++)
             {
-                endpoints = testStrategy.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
+                endpoints = tmd.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
                 assertTrue(expectedEndpoints.get(table).get(keyTokens.get(i)).size() == endpoints.size());
                 assertTrue(expectedEndpoints.get(table).get(keyTokens.get(i)).containsAll(endpoints));
             }
@@ -348,7 +341,7 @@ public class MoveTest extends CleanupHel
             // tokens 5, 15 and 25 should go three nodes
             for (int i=0; i<3; ++i)
             {
-                endpoints = testStrategy.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
+                endpoints = tmd.getWriteEndpoints(keyTokens.get(i), table, testStrategy.getNaturalEndpoints(keyTokens.get(i), table));
                 assertTrue(endpoints.size() == 3);
                 assertTrue(endpoints.contains(hosts.get(i+1)));
                 assertTrue(endpoints.contains(hosts.get(i+2)));
@@ -356,21 +349,21 @@ public class MoveTest extends CleanupHel
             }
 
             // token 35 goes to nodes 4, 5 and boot1
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(3), table, testStrategy.getNaturalEndpoints(keyTokens.get(3), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(3), table, testStrategy.getNaturalEndpoints(keyTokens.get(3), table));
             assertTrue(endpoints.size() == 3);
             assertTrue(endpoints.contains(hosts.get(4)));
             assertTrue(endpoints.contains(hosts.get(5)));
             assertTrue(endpoints.contains(boot1));
 
             // token 45 goes to nodes 5, boot1 and node7
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(4), table, testStrategy.getNaturalEndpoints(keyTokens.get(4), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(4), table, testStrategy.getNaturalEndpoints(keyTokens.get(4), table));
             assertTrue(endpoints.size() == 3);
             assertTrue(endpoints.contains(hosts.get(5)));
             assertTrue(endpoints.contains(boot1));
             assertTrue(endpoints.contains(hosts.get(7)));
 
             // token 55 goes to boot1, 7, boot2, 8 and 0
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(5), table, testStrategy.getNaturalEndpoints(keyTokens.get(5), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(5), table, testStrategy.getNaturalEndpoints(keyTokens.get(5), table));
             assertTrue(endpoints.size() == 5);
             assertTrue(endpoints.contains(boot1));
             assertTrue(endpoints.contains(hosts.get(7)));
@@ -379,7 +372,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(hosts.get(0)));
 
             // token 65 goes to nodes 7, boot2, 8, 0 and 1
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(6), table, testStrategy.getNaturalEndpoints(keyTokens.get(6), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(6), table, testStrategy.getNaturalEndpoints(keyTokens.get(6), table));
             assertTrue(endpoints.size() == 5);
             assertTrue(endpoints.contains(hosts.get(7)));
             assertTrue(endpoints.contains(boot2));
@@ -388,7 +381,7 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(hosts.get(1)));
 
             // token 75 goes to nodes boot2, 8, 0, 1 and 2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(7), table, testStrategy.getNaturalEndpoints(keyTokens.get(7), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(7), table, testStrategy.getNaturalEndpoints(keyTokens.get(7), table));
             assertTrue(endpoints.size() == 5);
             assertTrue(endpoints.contains(boot2));
             assertTrue(endpoints.contains(hosts.get(8)));
@@ -397,14 +390,14 @@ public class MoveTest extends CleanupHel
             assertTrue(endpoints.contains(hosts.get(2)));
 
             // token 85 goes to nodes 0, 1 and 2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(8), table, testStrategy.getNaturalEndpoints(keyTokens.get(8), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(8), table, testStrategy.getNaturalEndpoints(keyTokens.get(8), table));
             assertTrue(endpoints.size() == 3);
             assertTrue(endpoints.contains(hosts.get(0)));
             assertTrue(endpoints.contains(hosts.get(1)));
             assertTrue(endpoints.contains(hosts.get(2)));
 
             // token 95 goes to nodes 0, 1 and 2
-            endpoints = testStrategy.getWriteEndpoints(keyTokens.get(9), table, testStrategy.getNaturalEndpoints(keyTokens.get(9), table));
+            endpoints = tmd.getWriteEndpoints(keyTokens.get(9), table, testStrategy.getNaturalEndpoints(keyTokens.get(9), table));
             assertTrue(endpoints.size() == 3);
             assertTrue(endpoints.contains(hosts.get(0)));
             assertTrue(endpoints.contains(hosts.get(1)));
@@ -422,7 +415,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategy = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
@@ -491,7 +484,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategy = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
@@ -535,7 +528,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategy = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
@@ -585,7 +578,7 @@ public class MoveTest extends CleanupHel
         TokenMetadata tmd = ss.getTokenMetadata();
         tmd.clearUnsafe();
         IPartitioner partitioner = new RandomPartitioner();
-        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
+        AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, new SimpleSnitch());
 
         IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
         Map<String, AbstractReplicationStrategy> oldStrategy = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));