SegmentGenerator { List<Segment> generateSegments( int totalSegmentCount, List<BigInteger> ringTokens, Boolean incrementalRepair, Map<List<String>, List<RingRange>> replicasToRange, String cassandraVersion) throws ReaperException { List<Segment> repairSegments = Lists.newArrayList(); int tokenRangeCount = ringTokens.size(); if (tokenRangeCount < totalSegmentCount || !supportsSegmentCoalescing(cassandraVersion)) { for (int i = 0; i < tokenRangeCount; i++) { BigInteger start = ringTokens.get(i); BigInteger stop = ringTokens.get((i + 1) % tokenRangeCount); if (!inRange(start) || !inRange(stop)) { throw new ReaperException( String.format("Tokens (%s,%s) not in range of %s", start, stop, partitioner)); } if (start.equals(stop) && tokenRangeCount != 1) { throw new ReaperException( String.format("Tokens (%s,%s): two nodes have the same token", start, stop)); } BigInteger rs = stop.subtract(start); if (lowerThanOrEqual(rs, BigInteger.ZERO)) { rs = rs.add(rangeSize); } BigInteger[] segmentCountAndRemainder = rs.multiply(BigInteger.valueOf(totalSegmentCount)).divideAndRemainder(rangeSize); int segmentCount = segmentCountAndRemainder[0].intValue() + (segmentCountAndRemainder[1].equals(BigInteger.ZERO) ? 0 : 1); LOG.info("Dividing token range [{},{}) into {} segments", start, stop, segmentCount); List<BigInteger> endpointTokens = Lists.newArrayList(); for (int j = 0; j <= segmentCount; j++) { BigInteger offset = rs.multiply(BigInteger.valueOf(j)).divide(BigInteger.valueOf(segmentCount)); BigInteger reaperToken = start.add(offset); if (greaterThan(reaperToken, rangeMax)) { reaperToken = reaperToken.subtract(rangeSize); } endpointTokens.add(reaperToken); } for (int j = 0; j < segmentCount; j++) { repairSegments.add( Segment.builder() .withTokenRanges( Arrays.asList( new RingRange(endpointTokens.get(j), endpointTokens.get(j + 1)))) .build()); LOG.debug( "Segment #{}: [{},{})", j + 1, endpointTokens.get(j), endpointTokens.get(j + 1)); } } BigInteger total = BigInteger.ZERO; for (Segment segment : repairSegments) { for (RingRange range : segment.getTokenRanges()) { BigInteger size = range.span(rangeSize); total = total.add(size); } } if (!total.equals(rangeSize) && !incrementalRepair) { throw new ReaperException("Not entire ring would get repaired"); } } else { LOG.info("Less segments required than there are vnode. Coalescing eligible token ranges..."); repairSegments = coalesceTokenRanges(getTargetSegmentSize(totalSegmentCount), replicasToRange); } return repairSegments; } SegmentGenerator(String partitioner);   SegmentGenerator(BigInteger rangeMin, BigInteger rangeMax);   }
@Test public void testGenerateSegments() throws Exception { List<BigInteger> tokens = Lists.transform(Lists.newArrayList( "0", "1", "56713727820156410577229101238628035242", "56713727820156410577229101238628035243", "113427455640312821154458202477256070484", "113427455640312821154458202477256070485"), (String string) -> new BigInteger(string)); SegmentGenerator generator = new SegmentGenerator("foo.bar.RandomPartitioner"); List<Segment> segments = generator.generateSegments(10, tokens, Boolean.FALSE, Maps.newHashMap(), "2.2.10"); assertEquals(15, segments.size()); assertEquals("(0,1]", segments.get(0).getBaseRange().toString()); assertEquals( "(56713727820156410577229101238628035242,56713727820156410577229101238628035243]", segments.get(5).getBaseRange().toString()); assertEquals( "(113427455640312821154458202477256070484,113427455640312821154458202477256070485]", segments.get(10).getBaseRange().toString()); tokens = Lists.transform(Lists.newArrayList( "5", "6", "56713727820156410577229101238628035242", "56713727820156410577229101238628035243", "113427455640312821154458202477256070484", "113427455640312821154458202477256070485"), (String string) -> new BigInteger(string)); segments = generator.generateSegments(10, tokens, Boolean.FALSE, Maps.newHashMap(), "2.2.10"); assertEquals(15, segments.size()); assertEquals("(5,6]", segments.get(0).getBaseRange().toString()); assertEquals( "(56713727820156410577229101238628035242,56713727820156410577229101238628035243]", segments.get(5).getBaseRange().toString()); assertEquals( "(113427455640312821154458202477256070484,113427455640312821154458202477256070485]", segments.get(10).getBaseRange().toString()); }
@Test(expected = ReaperException.class) public void testZeroSizeRange() throws Exception { List<String> tokenStrings = Lists.newArrayList( "0", "1", "56713727820156410577229101238628035242", "56713727820156410577229101238628035242", "113427455640312821154458202477256070484", "113427455640312821154458202477256070485"); List<BigInteger> tokens = Lists.transform(tokenStrings, (String string) -> new BigInteger(string)); SegmentGenerator generator = new SegmentGenerator("foo.bar.RandomPartitioner"); generator.generateSegments(10, tokens, Boolean.FALSE, Maps.newHashMap(), "2.2.10"); }
@Test public void testRotatedRing() throws Exception { List<String> tokenStrings = Lists.newArrayList( "56713727820156410577229101238628035243", "113427455640312821154458202477256070484", "113427455640312821154458202477256070485", "5", "6", "56713727820156410577229101238628035242"); List<BigInteger> tokens = Lists.transform(tokenStrings, (String string) -> new BigInteger(string)); SegmentGenerator generator = new SegmentGenerator("foo.bar.RandomPartitioner"); List<Segment> segments = generator.generateSegments(10, tokens, Boolean.FALSE, Maps.newHashMap(), "2.2.10"); assertEquals(15, segments.size()); assertEquals( "(113427455640312821154458202477256070484,113427455640312821154458202477256070485]", segments.get(4).getBaseRange().toString()); assertEquals("(5,6]", segments.get(9).getBaseRange().toString()); assertEquals( "(56713727820156410577229101238628035242,56713727820156410577229101238628035243]", segments.get(14).getBaseRange().toString()); }
@Test(expected = ReaperException.class) public void testDisorderedRing() throws Exception { List<String> tokenStrings = Lists.newArrayList( "0", "113427455640312821154458202477256070485", "1", "56713727820156410577229101238628035242", "56713727820156410577229101238628035243", "113427455640312821154458202477256070484"); List<BigInteger> tokens = Lists.transform(tokenStrings, (String string) -> new BigInteger(string)); SegmentGenerator generator = new SegmentGenerator("foo.bar.RandomPartitioner"); generator.generateSegments(10, tokens, Boolean.FALSE, Maps.newHashMap(), "2.2.10"); }