diff --git a/CHANGES.md b/CHANGES.md index 92e65aee9..2447e630d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Version 1.2.0 (Not yet released) +* Fix calculation of tokens per repair - Issue #570 * Repairs not scheduled when statistics disabled - Issue #175 ### Merged from 1.0 diff --git a/core/src/main/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TableRepairJob.java b/core/src/main/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TableRepairJob.java index 93f0b1a74..bcdcc0424 100644 --- a/core/src/main/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TableRepairJob.java +++ b/core/src/main/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TableRepairJob.java @@ -267,8 +267,11 @@ private BigInteger getTokensPerRepair(VnodeRepairStates vnodeRepairStates) BigInteger targetSizeInBytes = BigInteger.valueOf(myRepairConfiguration.getTargetRepairSizeInBytes()); - BigInteger targetRepairs = tableSizeInBytes.divide(targetSizeInBytes); - tokensPerRepair = fullRangeSize.divide(targetRepairs); + if (tableSizeInBytes.compareTo(targetSizeInBytes) > 0) + { + BigInteger targetRepairs = tableSizeInBytes.divide(targetSizeInBytes); + tokensPerRepair = fullRangeSize.divide(targetRepairs); + } } } diff --git a/core/src/test/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TestTableRepairJob.java b/core/src/test/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TestTableRepairJob.java index b1ddcee9d..ac6a0ab82 100644 --- a/core/src/test/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TestTableRepairJob.java +++ b/core/src/test/java/com/ericsson/bss/cassandra/ecchronos/core/repair/TestTableRepairJob.java @@ -82,6 +82,7 @@ public class TestTableRepairJob private static final long RUN_INTERVAL_IN_DAYS = 1; private static final long GC_GRACE_DAYS = 10; + private static final long ONE_MB_IN_BYTES = 1 * 1024 * 1024; private static final long HUNDRED_MB_IN_BYTES = 100 * 1024 * 1024; private static final long THOUSAND_MB_IN_BYTES = 1000 * 1024 * 1024; @@ -624,6 +625,108 @@ public void testIteratorWithTargetSize() } } + @Test + public void testIteratorWithTargetSizeBiggerThanTableSize() + { + LongTokenRange tokenRange1 = new LongTokenRange(0, 10); + LongTokenRange tokenRange2 = new LongTokenRange(10, 20); + LongTokenRange tokenRange3 = new LongTokenRange(20, 30); + List expectedTokenRanges = Arrays.asList( + tokenRange1, + tokenRange2, + tokenRange3 + ); + ImmutableSet replicas = ImmutableSet.of(mock(Host.class), mock(Host.class)); + ImmutableList vnodes = ImmutableList.of(tokenRange1, tokenRange2, tokenRange3); + + VnodeRepairStates vnodeRepairStates = VnodeRepairStatesImpl.newBuilder( + ImmutableList.of( + new VnodeRepairState(tokenRange1, replicas, 1234L), + new VnodeRepairState(tokenRange2, replicas, 1234L), + new VnodeRepairState(tokenRange3, replicas, 1234L))).build(); + ReplicaRepairGroup replicaRepairGroup = new ReplicaRepairGroup(replicas, vnodes, System.currentTimeMillis()); + + RepairStateSnapshot repairStateSnapshot = RepairStateSnapshot.newBuilder() + .withReplicaRepairGroups(Collections.singletonList(replicaRepairGroup)) + .withLastRepairedAt(1234L) + .withVnodeRepairStates(vnodeRepairStates) + .build(); + when(myRepairState.getSnapshot()).thenReturn(repairStateSnapshot); + // 100 MB target size, 1 MB in table + when(myTableStorageStates.getDataSize(eq(myTableReference))).thenReturn(ONE_MB_IN_BYTES); + + Iterator iterator = myRepairJob.iterator(); + + ScheduledTask task = iterator.next(); + assertThat(task).isInstanceOf(RepairGroup.class); + Collection repairTasks = ((RepairGroup) task).getRepairTasks(); + + assertThat(repairTasks).hasSize(expectedTokenRanges.size()); + + Iterator repairTaskIterator = repairTasks.iterator(); + for (LongTokenRange expectedRange : expectedTokenRanges) + { + assertThat(repairTaskIterator.hasNext()).isTrue(); + RepairTask repairTask = repairTaskIterator.next(); + assertThat(repairTask.getReplicas()).containsExactlyInAnyOrderElementsOf(replicas); + assertThat(repairTask.getRepairConfiguration()).isEqualTo(myRepairConfiguration); + assertThat(repairTask.getTableReference()).isEqualTo(myTableReference); + + assertThat(repairTask.getTokenRanges()).containsExactly(expectedRange); + } + } + + @Test + public void testIteratorWithTargetSizeSameAsTableSize() + { + LongTokenRange tokenRange1 = new LongTokenRange(0, 10); + LongTokenRange tokenRange2 = new LongTokenRange(10, 20); + LongTokenRange tokenRange3 = new LongTokenRange(20, 30); + List expectedTokenRanges = Arrays.asList( + tokenRange1, + tokenRange2, + tokenRange3 + ); + ImmutableSet replicas = ImmutableSet.of(mock(Host.class), mock(Host.class)); + ImmutableList vnodes = ImmutableList.of(tokenRange1, tokenRange2, tokenRange3); + + VnodeRepairStates vnodeRepairStates = VnodeRepairStatesImpl.newBuilder( + ImmutableList.of( + new VnodeRepairState(tokenRange1, replicas, 1234L), + new VnodeRepairState(tokenRange2, replicas, 1234L), + new VnodeRepairState(tokenRange3, replicas, 1234L))).build(); + ReplicaRepairGroup replicaRepairGroup = new ReplicaRepairGroup(replicas, vnodes, System.currentTimeMillis()); + + RepairStateSnapshot repairStateSnapshot = RepairStateSnapshot.newBuilder() + .withReplicaRepairGroups(Collections.singletonList(replicaRepairGroup)) + .withLastRepairedAt(1234L) + .withVnodeRepairStates(vnodeRepairStates) + .build(); + when(myRepairState.getSnapshot()).thenReturn(repairStateSnapshot); + // 100 MB target size, 100 MB in table + when(myTableStorageStates.getDataSize(eq(myTableReference))).thenReturn(HUNDRED_MB_IN_BYTES); + + Iterator iterator = myRepairJob.iterator(); + + ScheduledTask task = iterator.next(); + assertThat(task).isInstanceOf(RepairGroup.class); + Collection repairTasks = ((RepairGroup) task).getRepairTasks(); + + assertThat(repairTasks).hasSize(expectedTokenRanges.size()); + + Iterator repairTaskIterator = repairTasks.iterator(); + for (LongTokenRange expectedRange : expectedTokenRanges) + { + assertThat(repairTaskIterator.hasNext()).isTrue(); + RepairTask repairTask = repairTaskIterator.next(); + assertThat(repairTask.getReplicas()).containsExactlyInAnyOrderElementsOf(replicas); + assertThat(repairTask.getRepairConfiguration()).isEqualTo(myRepairConfiguration); + assertThat(repairTask.getTableReference()).isEqualTo(myTableReference); + + assertThat(repairTask.getTokenRanges()).containsExactly(expectedRange); + } + } + public void testGetRealPriority() { long lastRepaired = System.currentTimeMillis();