final int LEAVING_NODE = 2;
TokenMetadata tmd = ss.getTokenMetadata();
tmd.clearUnsafe();
IPartitioner partitioner = new RandomPartitioner();
AbstractReplicationStrategy testStrategy = new RackUnawareStrategy(tmd, null);
IPartitioner oldPartitioner = ss.setPartitionerUnsafe(partitioner);
Map<String, AbstractReplicationStrategy> oldStrategies = ss.setReplicationStrategyUnsafe(createReplacements(testStrategy));
ArrayList<Token> endPointTokens = new ArrayList<Token>();
ArrayList<Token> keyTokens = new ArrayList<Token>();
List<InetAddress> hosts = new ArrayList<InetAddress>();
createInitialRing(ss, partitioner, endPointTokens, keyTokens, hosts, RING_SIZE);
final Map<String, List<Range>> deadNodesRanges = new HashMap<String, List<Range>>();
for (String table : DatabaseDescriptor.getNonSystemTables())
{
List<Range> list = new ArrayList<Range>();
list.addAll(testStrategy.getAddressRanges(table).get(hosts.get(LEAVING_NODE)));
Collections.sort(list);
deadNodesRanges.put(table, list);
}
// Third node leaves
ss.onChange(hosts.get(LEAVING_NODE), StorageService.MOVE_STATE, new ApplicationState(StorageService.STATE_LEAVING + StorageService.Delimiter + partitioner.getTokenFactory().toString(endPointTokens.get(LEAVING_NODE))));
// check that it is correctly marked as leaving in tmd
assertTrue(tmd.isLeaving(hosts.get(LEAVING_NODE)));
// check that pending ranges are correct (primary range should go to 1st node, first
// replica range to 4th node and 2nd replica range to 5th node)
for (String table : DatabaseDescriptor.getNonSystemTables())
{
int replicationFactor = DatabaseDescriptor.getReplicationFactor(table);
// if the ring minus the leaving node leaves us with less than RF, we're hosed.
if (hosts.size()-1 < replicationFactor)
continue;
// verify that the replicationFactor nodes after the leaving node are gatherings it's pending ranges.
// in the case where rf==5, we're screwed because we basically just lost data.
for (int i = 0; i < replicationFactor; i++)
{
assertTrue(tmd.getPendingRanges(table, hosts.get((LEAVING_NODE + 1 + i) % RING_SIZE)).size() > 0);
assertEquals(tmd.getPendingRanges(table, hosts.get((LEAVING_NODE + 1 + i) % RING_SIZE)).get(0), deadNodesRanges.get(table).get(i));
}
// note that we're iterating over nodes and sample tokens.
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));
// 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);
if (isReplica)
assertTrue(endPoints.size() == replicationFactor + 1);