use of com.linkedin.d2.balancer.util.hashing.HashRingProvider in project rest.li by linkedin.
the class RingBasedURIMapperTest method testNonStickyAndNonPartitioning.
@Test
public void testNonStickyAndNonPartitioning() throws ServiceUnavailableException {
int partitionCount = 1;
int requestPerPartition = 1000;
int totalHostCount = 100;
HashRingProvider ringProvider = createStaticHashRingProvider(totalHostCount, partitionCount, getHashFunction(false));
PartitionInfoProvider infoProvider = createRangeBasedPartitionInfoProvider(partitionCount);
URIMapper mapper = new RingBasedUriMapper(ringProvider, infoProvider);
List<URIKeyPair<Integer>> requests = testUtil.generateRequests(partitionCount, requestPerPartition);
URIMappingResult<Integer> results = mapper.mapUris(requests);
Map<URI, Set<Integer>> mapping = results.getMappedKeys();
Map<Integer, Set<Integer>> unmappedKeys = results.getUnmappedKeys();
Map<URI, Integer> hostToPartitionId = results.getHostPartitionInfo();
Assert.assertTrue(unmappedKeys.isEmpty());
Assert.assertEquals(1, mapping.size());
Assert.assertEquals(1, hostToPartitionId.size());
Assert.assertEquals(1000, mapping.values().iterator().next().size());
}
use of com.linkedin.d2.balancer.util.hashing.HashRingProvider in project rest.li by linkedin.
the class RingBasedURIMapperTest method testMapUrisPartitionedOnly.
@Test
public void testMapUrisPartitionedOnly() throws ServiceUnavailableException {
int partitionCount = 10;
int requestPerPartition = 100;
int totalHostCount = 100;
HashRingProvider ringProvider = createStaticHashRingProvider(totalHostCount, partitionCount, getHashFunction(false));
PartitionInfoProvider infoProvider = createRangeBasedPartitionInfoProvider(partitionCount);
URIMapper mapper = new RingBasedUriMapper(ringProvider, infoProvider);
List<URIKeyPair<Integer>> requests = testUtil.generateRequests(partitionCount, requestPerPartition);
URIMappingResult<Integer> results = mapper.mapUris(requests);
Map<URI, Set<Integer>> mapping = results.getMappedKeys();
Map<URI, Integer> hostToPartitionId = results.getHostPartitionInfo();
// No unmapped keys
Assert.assertTrue(results.getUnmappedKeys().isEmpty());
// Without sticky routing, one host should be returned for each partition
Assert.assertEquals(10, mapping.size());
Assert.assertEquals(10, hostToPartitionId.size());
for (Map.Entry<URI, Integer> entry : hostToPartitionId.entrySet()) {
// partition ids are correctly assigned for each URI
Assert.assertTrue(entry.getKey().toString().contains(String.valueOf(entry.getValue())));
}
Set<Integer> mappedKeys = mapping.values().stream().reduce(new HashSet<>(), (e1, e2) -> {
e1.addAll(e2);
return e1;
});
int mappedKeyCount = mapping.values().stream().map(Set::size).reduce(Integer::sum).get();
// Collective exhaustiveness and mutual exclusiveness
Assert.assertEquals(partitionCount * requestPerPartition, mappedKeys.size());
Assert.assertEquals(partitionCount * requestPerPartition, mappedKeyCount);
}
use of com.linkedin.d2.balancer.util.hashing.HashRingProvider in project rest.li by linkedin.
the class RingBasedURIMapperTest method testUniversalStickiness.
@Test
public void testUniversalStickiness() throws ServiceUnavailableException, URISyntaxException {
int partitionCount = 4;
int totalHostCount = 200;
HashRingProvider ringProvider = createStaticHashRingProvider(totalHostCount, partitionCount, getHashFunction(true));
HashFunction<Request> hashFunction = ringProvider.getRequestHashFunction(TEST_SERVICE);
PartitionInfoProvider infoProvider = createRangeBasedPartitionInfoProvider(partitionCount);
URIMapper mapper = new RingBasedUriMapper(ringProvider, infoProvider);
// no partition, will be unmapped
URIKeyPair<Integer> request1 = new URIKeyPair<>(1, new URI("d2://testService/1"));
// partition 0
URIKeyPair<Integer> request2 = new URIKeyPair<>(2, new URI("d2://testService/2?partition=0"));
// partition 1
URIKeyPair<Integer> request3 = new URIKeyPair<>(3, new URI("d2://testService/3?partition=1"));
// partition 2
URIKeyPair<Integer> request4 = new URIKeyPair<>(4, new URI("d2://testService/4?partition=2"));
// partition 3
URIKeyPair<Integer> request5 = new URIKeyPair<>(5, new URI("d2://testService/5?partition=3"));
URIKeyPair<Integer> request6 = // partition 0 with different sticky key
new URIKeyPair<>(6, new URI("d2://testService/6?partition=0"));
URIKeyPair<Integer> request7 = // partition 1 with different sticky key
new URIKeyPair<>(7, new URI("d2://testService/7?partition=1"));
URIKeyPair<Integer> request8 = // partition 2 with different sticky key
new URIKeyPair<>(8, new URI("d2://testService/8?partition=2"));
URIKeyPair<Integer> request9 = // partition 3 with different sticky key
new URIKeyPair<>(9, new URI("d2://testService/9?partition=3"));
URIKeyPair<Integer> request10 = // with extra parameters
new URIKeyPair<>(10, new URI("d2://testService/10?partition=0&uuid=1"));
List<URIKeyPair<Integer>> requests = Arrays.asList(request1, request2, request3, request4, request5, request6, request7, request8, request9, request10);
// uriMapper mapping
URIMappingResult<Integer> uriMapperResult = mapper.mapUris(requests);
// normal mapping
Map<Integer, Set<Integer>> normalUnmapped = new HashMap<>();
Map<URI, Set<Integer>> normalHostToKeySet = new HashMap<>();
for (URIKeyPair<Integer> request : requests) {
int partitionId = 0;
try {
partitionId = infoProvider.getPartitionAccessor(TEST_SERVICE).getPartitionId(request.getRequestUri());
} catch (PartitionAccessException e) {
normalUnmapped.computeIfAbsent(-1, k -> new HashSet<>()).add(request.getKey());
}
Ring<URI> ring = ringProvider.getRings(request.getRequestUri()).get(partitionId);
URI uri = ring.get(hashFunction.hash(new URIRequest(request.getRequestUri())));
normalHostToKeySet.computeIfAbsent(uri, k -> new HashSet<>());
normalHostToKeySet.get(uri).add(request.getKey());
}
// they should have the same results
Assert.assertEquals(uriMapperResult.getUnmappedKeys(), normalUnmapped);
for (Map.Entry<URI, Set<Integer>> resolvedKeys : uriMapperResult.getMappedKeys().entrySet()) {
Set<Integer> uriMapperKeySet = resolvedKeys.getValue();
Assert.assertTrue(normalHostToKeySet.containsKey(resolvedKeys.getKey()));
Set<Integer> normalKeySet = normalHostToKeySet.get(resolvedKeys.getKey());
Assert.assertEquals(uriMapperKeySet, normalKeySet);
}
}
use of com.linkedin.d2.balancer.util.hashing.HashRingProvider in project rest.li by linkedin.
the class URIMapperTestUtil method createStaticHashRingProvider.
/**
* Create {@link StaticRingProvider} for testing purpose
*/
public static HashRingProvider createStaticHashRingProvider(int totalHostCount, int partitionCount, HashFunction<Request> hashFunction) {
int hostsPerPartition = totalHostCount / partitionCount;
final AtomicInteger hostCounter = new AtomicInteger();
Collection<List<Integer>> hostsIdsByPartition = IntStream.range(0, totalHostCount).boxed().collect(Collectors.groupingBy(s -> hostCounter.getAndIncrement() / hostsPerPartition)).values();
List<Ring<URI>> rings = new ArrayList<>();
int partiitonId = 0;
for (List<Integer> uriList : hostsIdsByPartition) {
int parId = partiitonId;
Map<URI, Integer> hostMap = uriList.stream().collect(Collectors.toMap(e -> createHostURI(parId, e), e -> 100));
Ring<URI> ring = new MPConsistentHashRing<>(hostMap);
rings.add(ring);
partiitonId++;
}
StaticRingProvider ringProvider = new StaticRingProvider(rings);
ringProvider.setHashFunction(hashFunction);
return ringProvider;
}
use of com.linkedin.d2.balancer.util.hashing.HashRingProvider in project rest.li by linkedin.
the class TestRestLiScatterGather method getURIMapper.
private static URIMapper getURIMapper(boolean sticky, boolean partitioned, String regex) throws ServiceUnavailableException {
int partitionCount = partitioned ? 10 : 1;
int totalHostCount = 100;
HashRingProvider ringProvider = createStaticHashRingProvider(totalHostCount, partitionCount, getHashFunction(sticky));
PartitionInfoProvider infoProvider = createHashBasedPartitionInfoProvider(partitionCount, regex);
return new RingBasedUriMapper(ringProvider, infoProvider);
}
Aggregations