Skip to content

Commit

Permalink
Make priority granularity configurable (#610)
Browse files Browse the repository at this point in the history
  • Loading branch information
SajidRiaz138 authored Oct 25, 2023
1 parent c06fbf9 commit cc17727
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Version 5.0.0 (Not yet released)

* Make priority granularity configurable - Issue #599
* Bump springboot from 2.7.12 to 2.7.17 - Issue #604
* Bump io.micrometer from 1.9.2 to 1.9.16 - Issue #604
* Bump io.dropwizard.metrics from 4.2.10 to 4.2.21 - Issue #604
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2023 Telefonaktiebolaget LM Ericsson
*
* Licensed 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 com.ericsson.bss.cassandra.ecchronos.application.config.repair;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.EnumSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class Priority
{

private static final Set<TimeUnit> ALLOWED_UNITS = EnumSet.of(TimeUnit.HOURS, TimeUnit.MINUTES, TimeUnit.SECONDS);
private static final String ALLOWED_VALUES_STR = String.join(", ", ALLOWED_UNITS.stream()
.map(TimeUnit::name)
.collect(Collectors.toList()));

private TimeUnit myGranularityUnit = TimeUnit.HOURS;

public Priority()
{
// Default constructor for jackson
}

@JsonCreator
public Priority(@JsonProperty("granularity_unit") final TimeUnit granularityUnit)
{
myGranularityUnit = granularityUnit;
}

public final TimeUnit getPriorityGranularityUnit()
{
return myGranularityUnit;
}

@JsonProperty ("granularity_unit")
public final void setPriorityGranularityUnit(final TimeUnit granularityUnit)
{
Optional.ofNullable(granularityUnit)
.orElseThrow(() -> new IllegalArgumentException(String.format(
"Granularity unit cannot be null. Allowed values are: %s.", ALLOWED_VALUES_STR)));

if (!ALLOWED_UNITS.contains(granularityUnit))
{
throw new IllegalArgumentException(String.format(
"Invalid granularity unit '%s'. Allowed values are: %s.",
granularityUnit.name(), ALLOWED_VALUES_STR));
}

myGranularityUnit = granularityUnit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ public class RepairConfig
private boolean myIgnoreTwcsTables = false;
private RepairOptions.RepairType myRepairType = RepairOptions.RepairType.VNODE;

private Priority myPriority = new Priority();

public final Priority getPriority()
{
return myPriority;
}

@JsonProperty("priority")
public final void setPriority(final Priority priority)
{
myPriority = priority;
}

@JsonProperty("interval")
public final void setRepairInterval(final Interval repairInterval)
{
Expand Down Expand Up @@ -126,7 +139,7 @@ public final void validate(final String repairConfigType)
if (warningIntervalSeconds >= errorIntervalSeconds)
{
throw new IllegalArgumentException(String.format("%s warning interval must be shorter than error interval."
+ " Current warning interval: %d seconds, error interval: %d seconds", repairConfigType,
+ " Current warning interval: %d seconds, error interval: %d seconds", repairConfigType,
warningIntervalSeconds, errorIntervalSeconds));
}
}
Expand All @@ -149,6 +162,7 @@ public RepairConfiguration asRepairConfiguration()
.withTargetRepairSizeInBytes(mySizeTarget)
.withBackoff(myBackoff.getInterval(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
.withRepairType(myRepairType)
.withPriorityGranularityUnit(myPriority.getPriorityGranularityUnit())
.build();
}
}
11 changes: 11 additions & 0 deletions application/src/main/resources/ecc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ repair:
time: 7
unit: days
##
## The unit of time granularity for priority calculation, can be HOURS, MINUTES, or SECONDS.
## This unit is used in the calculation of priority.
## Default is HOURS for backward compatibility.
## Ensure to pause repair operations prior to changing the granularity.
## Not doing so may lead to inconsistencies as some ecchronos instances
## could have different priorities compared to others for the same repair.
## Possible values are HOURS, MINUTES, or SECONDS.
##
priority:
granularity_unit: HOURS
##
## Specifies the type of lock to use for repairs.
## "vnode" will lock each node involved in a repair individually and increase the number of
## parallel repairs that can run in a single data center.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public void testAllValues() throws Exception
.withIgnoreTWCSTables(true)
.withBackoff(13, TimeUnit.SECONDS)
.withTargetRepairSizeInBytes(UnitConverter.toBytes("5m"))
.withPriorityGranularityUnit(TimeUnit.MINUTES)
.build();

GlobalRepairConfig repairConfig = config.getRepairConfig();
Expand All @@ -122,6 +123,7 @@ public void testAllValues() throws Exception
assertThat(repairConfig.getAlarm().getFaultReporterClass()).isEqualTo(TestFaultReporter.class);
assertThat(repairConfig.getIgnoreTWCSTables()).isTrue();
assertThat(repairConfig.getBackoff().getInterval(TimeUnit.SECONDS)).isEqualTo(13);
assertThat(repairConfig.getPriority().getPriorityGranularityUnit()).isEqualTo(TimeUnit.MINUTES);

StatisticsConfig statisticsConfig = config.getStatisticsConfig();
assertThat(statisticsConfig.isEnabled()).isFalse();
Expand Down Expand Up @@ -217,6 +219,7 @@ public void testWithDefaultFile() throws Exception
assertThat(repairConfig.getAlarm().getFaultReporterClass()).isEqualTo(LoggingFaultReporter.class);
assertThat(repairConfig.getIgnoreTWCSTables()).isFalse();
assertThat(repairConfig.getBackoff().getInterval(TimeUnit.MINUTES)).isEqualTo(30);
assertThat(repairConfig.getPriority().getPriorityGranularityUnit()).isEqualTo(TimeUnit.HOURS);

StatisticsConfig statisticsConfig = config.getStatisticsConfig();
assertThat(statisticsConfig.isEnabled()).isTrue();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2023 Telefonaktiebolaget LM Ericsson
*
* Licensed 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 com.ericsson.bss.cassandra.ecchronos.application.config.repair;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

public class TestPriority
{
private Priority priority;

@Before
public void setUp() {
priority = new Priority();
}

@Test
public void testDefaultConstructorSetsHours()
{
assertThat(priority.getPriorityGranularityUnit()).isEqualTo(TimeUnit.HOURS);
}

@Test
public void testSetValidGranularityUnit()
{
priority.setPriorityGranularityUnit(TimeUnit.MINUTES);
assertThat(priority.getPriorityGranularityUnit()).isEqualTo(TimeUnit.MINUTES);
}

@Test(expected = IllegalArgumentException.class)
public void testSetInvalidGranularityUnit()
{
priority.setPriorityGranularityUnit(TimeUnit.DAYS);
}

@Test(expected = IllegalArgumentException.class)
public void testSetNullGranularityUnit()
{
priority.setPriorityGranularityUnit(null);
}
}
2 changes: 2 additions & 0 deletions application/src/test/resources/all_set.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ repair:
backoff:
time: 13
unit: seconds
priority:
granularity_unit: MINUTES

statistics:
enabled: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package com.ericsson.bss.cassandra.ecchronos.core.repair;

import static com.ericsson.bss.cassandra.ecchronos.core.repair.RepairOptions.RepairParallelism;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

Expand All @@ -29,8 +31,7 @@ public class RepairConfiguration
private static final long DEFAULT_REPAIR_INTERVAL_IN_MS = TimeUnit.DAYS.toMillis(7);
private static final long DEFAULT_REPAIR_WARNING_TIME_IN_MS = TimeUnit.DAYS.toMillis(8);
private static final long DEFAULT_REPAIR_ERROR_TIME_IN_MS = TimeUnit.DAYS.toMillis(10);
private static final RepairOptions.RepairParallelism DEFAULT_REPAIR_PARALLELISM
= RepairOptions.RepairParallelism.PARALLEL;
private static final RepairParallelism DEFAULT_REPAIR_PARALLELISM = RepairParallelism.PARALLEL;
private static final RepairOptions.RepairType DEFAULT_REPAIR_TYPE = RepairOptions.RepairType.VNODE;
private static final double DEFAULT_UNWIND_RATIO = NO_UNWIND;
private static final long DEFAULT_TARGET_REPAIR_SIZE_IN_BYTES = FULL_REPAIR_SIZE;
Expand All @@ -39,8 +40,9 @@ public class RepairConfiguration
private static final boolean DEFAULT_IGNORE_TWCS_TABLES = false;

public static final RepairConfiguration DEFAULT = newBuilder().build();
public static final RepairConfiguration DISABLED
= newBuilder().withRepairInterval(0, TimeUnit.MILLISECONDS).build();
public static final RepairConfiguration DISABLED = newBuilder()
.withRepairInterval(0, TimeUnit.MILLISECONDS)
.build();

private final RepairOptions.RepairParallelism myRepairParallelism;
private final long myRepairIntervalInMs;
Expand All @@ -50,6 +52,7 @@ public class RepairConfiguration
private final long myTargetRepairSizeInBytes;
private final boolean myIgnoreTWCSTables;
private final long myBackoffInMs;
private final TimeUnit myPriorityGranularityUnit;

private final RepairOptions.RepairType myRepairType;

Expand All @@ -64,6 +67,12 @@ private RepairConfiguration(final Builder builder)
myIgnoreTWCSTables = builder.myIgnoreTWCSTables;
myBackoffInMs = builder.myBackoffInMs;
myRepairType = builder.myRepairType;
myPriorityGranularityUnit = builder.myPriorityGranularityUnit;
}

public TimeUnit getPriorityGranularityUnit()
{
return myPriorityGranularityUnit;
}

public RepairOptions.RepairParallelism getRepairParallelism()
Expand Down Expand Up @@ -126,9 +135,9 @@ public String toString()
{
return String.format(
"RepairConfiguration(interval=%dms,warning=%dms,error=%dms,parallelism=%s,unwindRatio=%.2f"
+ ",ignoreTWCS=%b,backoff=%dms,repairType=%s)",
+ ",ignoreTWCS=%b,backoff=%dms,repairType=%s)",
myRepairIntervalInMs, myRepairWarningTimeInMs, myRepairErrorTimeInMs, myRepairParallelism,
myRepairUnwindRatio, myIgnoreTWCSTables, myBackoffInMs, myRepairType);
myRepairUnwindRatio, myIgnoreTWCSTables, myBackoffInMs, myRepairType, myPriorityGranularityUnit);
}

@Override
Expand All @@ -151,15 +160,16 @@ public boolean equals(final Object o)
&& myRepairParallelism == that.myRepairParallelism
&& myIgnoreTWCSTables == that.myIgnoreTWCSTables
&& myBackoffInMs == that.myBackoffInMs
&& myRepairType == that.myRepairType;
&& myRepairType == that.myRepairType
&& myPriorityGranularityUnit == that.myPriorityGranularityUnit;
}

@Override
public int hashCode()
{
return Objects.hash(myRepairParallelism, myRepairIntervalInMs, myRepairWarningTimeInMs,
myRepairErrorTimeInMs, myRepairUnwindRatio, myTargetRepairSizeInBytes, myIgnoreTWCSTables,
myBackoffInMs, myRepairType);
myBackoffInMs, myRepairType, myPriorityGranularityUnit);
}

public static class Builder
Expand All @@ -173,6 +183,7 @@ public static class Builder
private long myTargetRepairSizeInBytes = DEFAULT_TARGET_REPAIR_SIZE_IN_BYTES;
private long myBackoffInMs = DEFAULT_BACKOFF_IN_MS;
private boolean myIgnoreTWCSTables = DEFAULT_IGNORE_TWCS_TABLES;
private TimeUnit myPriorityGranularityUnit = TimeUnit.HOURS;

/**
* Constructor.
Expand All @@ -196,6 +207,7 @@ public Builder(final RepairConfiguration from)
myRepairErrorTimeInMs = from.getRepairErrorTimeInMs();
myRepairUnwindRatio = from.getRepairUnwindRatio();
myBackoffInMs = from.getBackoffInMs();
myPriorityGranularityUnit = from.getPriorityGranularityUnit();
}

/**
Expand Down Expand Up @@ -324,6 +336,18 @@ public Builder withBackoff(final long backoff, final TimeUnit timeUnit)
return this;
}

/**
* Build with Priority Granularity Unit for the scheduling job.
*
* @param unit The Priority Granularity Unit.
* @return Builder
*/
public Builder withPriorityGranularityUnit(final TimeUnit unit)
{
myPriorityGranularityUnit = unit;
return this;
}

/**
* Build repair configuration.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ private ScheduledRepairJob createScheduledRepairJob(final TableReference tableRe
.withPriority(ScheduledJob.Priority.LOW)
.withRunInterval(repairConfiguration.getRepairIntervalInMs(), TimeUnit.MILLISECONDS)
.withBackoff(repairConfiguration.getBackoffInMs(), TimeUnit.MILLISECONDS)
.withPriorityGranularity(repairConfiguration.getPriorityGranularityUnit())
.build();
ScheduledRepairJob job;
if (repairConfiguration.getRepairType().equals(RepairOptions.RepairType.INCREMENTAL))
Expand Down
Loading

0 comments on commit cc17727

Please sign in to comment.