blob: 8612ac1a333155088325a8ba30b59c3353330977 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.dht.tokenallocator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Random;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Token;
/**
* Base class for {@link NoReplicationTokenAllocatorTest} and {@link AbstractReplicationAwareTokenAllocatorTest},
*/
abstract class TokenAllocatorTestBase
{
protected static final int TARGET_CLUSTER_SIZE = 250;
protected static final int MAX_VNODE_COUNT = 64;
interface TestReplicationStrategy extends ReplicationStrategy<Unit>
{
void addUnit(Unit n);
void removeUnit(Unit n);
/**
* Returns a list of all replica units for given token.
*/
List<Unit> getReplicas(Token token, NavigableMap<Token, Unit> sortedTokens);
/**
* Returns the start of the token span that is replicated in this token.
* Note: Though this is not trivial to see, the replicated span is always contiguous. A token in the same
* group acts as a barrier; if one is not found the token replicates everything up to the replica'th distinct
* group seen in front of it.
*/
Token replicationStart(Token token, Unit unit, NavigableMap<Token, Unit> sortedTokens);
/**
* Multiplier for the acceptable disbalance in the cluster. With some strategies it is harder to achieve good
* results.
*/
double spreadExpectation();
}
interface TokenCount
{
int tokenCount(int perUnitCount, Random rand);
double spreadExpectation();
}
TokenCount fixedTokenCount = new TokenCount()
{
public int tokenCount(int perUnitCount, Random rand)
{
return perUnitCount;
}
public double spreadExpectation()
{
return 4; // High tolerance to avoid flakiness.
}
};
TokenCount varyingTokenCount = new TokenCount()
{
public int tokenCount(int perUnitCount, Random rand)
{
if (perUnitCount == 1) return 1;
// 25 to 175%
return rand.nextInt(perUnitCount * 3 / 2) + (perUnitCount + 3) / 4;
}
public double spreadExpectation()
{
return 8; // High tolerance to avoid flakiness.
}
};
Random seededRand = new Random(2);
public void random(Map<Token, Unit> map, TestReplicationStrategy rs,
int unitCount, TokenCount tc, int perUnitCount, IPartitioner partitioner)
{
System.out.format("\nRandom generation of %d units with %d tokens each\n", unitCount, perUnitCount);
Random rand = seededRand;
for (int i = 0; i < unitCount; i++)
{
Unit unit = new Unit();
rs.addUnit(unit);
int tokens = tc.tokenCount(perUnitCount, rand);
for (int j = 0; j < tokens; j++)
{
map.put(partitioner.getRandomToken(rand), unit);
}
}
}
public String mms(SummaryStatistics s)
{
return String.format("max %.2f min %.2f stddev %.4f", s.getMax(), s.getMin(), s.getStandardDeviation());
}
class Summary
{
double min = 1;
double max = 1;
double stddev = 0;
void update(SummaryStatistics stat)
{
min = Math.min(min, stat.getMin());
max = Math.max(max, stat.getMax());
stddev = Math.max(stddev, stat.getStandardDeviation());
}
public String toString()
{
return String.format("max %.2f min %.2f stddev %.4f", max, min, stddev);
}
}
int nextUnitId = 0;
final class Unit implements Comparable<Unit>
{
int unitId = nextUnitId++;
public String toString()
{
return Integer.toString(unitId);
}
@Override
public int compareTo(Unit o)
{
return Integer.compare(unitId, o.unitId);
}
}
}