Skip to content

Commit f8f456f

Browse files
committed
Fix default max interval calculation in FailureDetector
Patch by Sam Tunnicliffe; reviewed by Maxim Muzafarov and Stefan Miklosovic for CASSANDRA-21025
1 parent 1a12cbb commit f8f456f

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
5.0.7
2+
* Correctly calculate default for FailureDetector max interval (CASSANDRA-21025)
23
* Adding missing configs in system_views.settings to be backward compatible (CASSANDRA-20863)
34
* Heap dump should not be generated on handled exceptions (CASSANDRA-20974)
45
Merged from 4.1:

src/java/org/apache/cassandra/gms/FailureDetector.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import javax.management.openmbean.TabularDataSupport;
4444
import javax.management.openmbean.TabularType;
4545

46+
import com.google.common.annotations.VisibleForTesting;
4647
import org.slf4j.Logger;
4748
import org.slf4j.LoggerFactory;
4849

@@ -416,6 +417,17 @@ public String toString()
416417
sb.append("-----------------------------------------------------------------------");
417418
return sb.toString();
418419
}
420+
421+
/**
422+
* Only for testing. In production code, ArrivalWindow instances call getMaxInterval() during
423+
* intitialization and use the value to set the private final field MAX_INTERVAL_IN_NANO
424+
* @return the value that would be used for to populate any new ArrivalWindow instance
425+
*/
426+
@VisibleForTesting
427+
static long calculateMaxInterval()
428+
{
429+
return ArrivalWindow.getMaxInterval();
430+
}
419431
}
420432

421433
/*
@@ -485,9 +497,10 @@ class ArrivalWindow
485497
arrivalIntervals = new ArrayBackedBoundedStats(size);
486498
}
487499

488-
private static long getMaxInterval()
500+
@VisibleForTesting
501+
static long getMaxInterval()
489502
{
490-
long newValue = FD_MAX_INTERVAL_MS.getLong(FailureDetector.INITIAL_VALUE_NANOS);
503+
long newValue = FD_MAX_INTERVAL_MS.getLong(TimeUnit.NANOSECONDS.toMillis(FailureDetector.INITIAL_VALUE_NANOS));
491504
if (newValue != FailureDetector.INITIAL_VALUE_NANOS)
492505
logger.info("Overriding {} from {}ms to {}ms", FD_MAX_INTERVAL_MS.getKey(), FailureDetector.INITIAL_VALUE_NANOS, newValue);
493506
return TimeUnit.NANOSECONDS.convert(newValue, TimeUnit.MILLISECONDS);

test/unit/org/apache/cassandra/gms/FailureDetectorTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
import java.util.Collections;
2424
import java.util.List;
2525
import java.util.UUID;
26+
import java.util.concurrent.TimeUnit;
2627

2728
import org.junit.BeforeClass;
2829
import org.junit.Test;
2930

3031
import org.apache.cassandra.Util;
32+
import org.apache.cassandra.config.CassandraRelevantProperties;
3133
import org.apache.cassandra.config.DatabaseDescriptor;
3234
import org.apache.cassandra.db.commitlog.CommitLog;
3335
import org.apache.cassandra.dht.IPartitioner;
@@ -38,6 +40,7 @@
3840
import org.apache.cassandra.service.StorageService;
3941

4042
import static org.apache.cassandra.config.CassandraRelevantProperties.MAX_LOCAL_PAUSE_IN_MS;
43+
import static org.junit.Assert.assertEquals;
4144
import static org.junit.Assert.assertFalse;
4245

4346
public class FailureDetectorTest
@@ -87,4 +90,36 @@ public void testConvictAfterLeft() throws UnknownHostException
8790
FailureDetector.instance.interpret(leftHost);
8891
assertFalse("Left endpoint not convicted", FailureDetector.instance.isAlive(leftHost));
8992
}
93+
94+
@Test
95+
public void testMaxIntervalCalculation()
96+
{
97+
// Default value for ArrivalWindow.MAX_INTERVAL_IN_NANO, which is supplied by
98+
// ArrivalWindow::getMaxInterval should be 2000000000ns/2 seconds.
99+
Long initialPropertyValue = CassandraRelevantProperties.FD_MAX_INTERVAL_MS.isPresent()
100+
? CassandraRelevantProperties.FD_MAX_INTERVAL_MS.getLong()
101+
: null;
102+
try
103+
{
104+
// verify that max interval isn't being set directly using system property
105+
CassandraRelevantProperties.FD_MAX_INTERVAL_MS.reset();
106+
assertFalse(CassandraRelevantProperties.FD_MAX_INTERVAL_MS.isPresent());
107+
// in which case, max interval should default to INITIAL_VALUE_NANOS
108+
assertEquals(FailureDetector.INITIAL_VALUE_NANOS, FailureDetector.calculateMaxInterval());
109+
110+
// max interval can be overridden, but it's value should be supplied in millis
111+
long overrideMillis = TimeUnit.NANOSECONDS.toMillis(FailureDetector.INITIAL_VALUE_NANOS * 2);
112+
CassandraRelevantProperties.FD_MAX_INTERVAL_MS.setLong(overrideMillis);
113+
// max interval is a nanos value, so convert the override to get the expected value
114+
long expectedNanos = TimeUnit.NANOSECONDS.convert(overrideMillis, TimeUnit.MILLISECONDS);
115+
assertEquals(expectedNanos, FailureDetector.calculateMaxInterval());
116+
}
117+
finally
118+
{
119+
if (initialPropertyValue == null)
120+
CassandraRelevantProperties.FD_MAX_INTERVAL_MS.reset();
121+
else
122+
CassandraRelevantProperties.FD_MAX_INTERVAL_MS.setLong(initialPropertyValue);
123+
}
124+
}
90125
}

0 commit comments

Comments
 (0)