This is an automated email from the ASF dual-hosted git repository.
konstantinov pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push:
new e621d8a6c1 Introduce separate GCInspector thresholds for concurrent GC
events. For GC like ShenandoahGC/ZGC etc., there are GC events that do not have
STW pauses (Concurrent phases). Operator might find it reasonable to use lower
thresholds for events require STW pauses and higher thresholds for concurrent
phases. gc_concurrent_phase_log_threshold and
gc_concurrent_phase_warn_threshold configuration options are introduced in
cassandra.yaml
e621d8a6c1 is described below
commit e621d8a6c1bb175bea4e7e25f1f39dcd3d648f76
Author: Yuqi Yan <[email protected]>
AuthorDate: Fri Oct 17 13:50:16 2025 -0700
Introduce separate GCInspector thresholds for concurrent GC events.
For GC like ShenandoahGC/ZGC etc., there are GC events that do not have STW
pauses (Concurrent phases).
Operator might find it reasonable to use lower thresholds for events
require STW pauses and higher thresholds for concurrent phases.
gc_concurrent_phase_log_threshold and gc_concurrent_phase_warn_threshold
configuration options are introduced in cassandra.yaml
Patch by Yuqi Yan; reviewed by Dmitry Konstantinov, Stefan Miklosovic for
CASSANDRA-20980
Co-authored-by: Stefan Miklosovic
---
CHANGES.txt | 1 +
conf/cassandra.yaml | 16 ++++
conf/cassandra_latest.yaml | 16 ++++
src/java/org/apache/cassandra/config/Config.java | 2 +
.../cassandra/config/DatabaseDescriptor.java | 80 ++++++++++++++++--
.../org/apache/cassandra/service/GCInspector.java | 95 ++++++++++++++++------
.../cassandra/service/GCInspectorMXBean.java | 4 +
.../apache/cassandra/service/GCInspectorTest.java | 84 +++++++++++++++----
8 files changed, 251 insertions(+), 47 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 7b0116f005..858864ddd9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
5.1
+ * Introduce separate GCInspector thresholds for concurrent GC events
(CASSANDRA-20980)
* Reduce contention in MemtableAllocator.allocate (CASSANDRA-20226)
* Add export, list, import sub-commands for nodetool compressiondictionary
(CASSANDRA-20941)
* Add support in the binary protocol to allow transactions to have multiple
conditions (CASSANDRA-20883)
diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml
index d000f6be36..20476ee547 100644
--- a/conf/cassandra.yaml
+++ b/conf/cassandra.yaml
@@ -2048,6 +2048,11 @@ batch_size_fail_threshold: 50KiB
# Log WARN on any batches not of type LOGGED than span across more partitions
than this limit
unlogged_batch_across_partitions_warn_threshold: 10
+# GCInspector configs:
+# For GC like ShenandoahGC/ZGC etc., there are GC events that do not have STW
pauses (Concurrent phases)
+# Operator might find it reasonable to use lower thresholds for events require
STW pauses and higher thresholds
+# for concurrent phases.
+#
# GC Pauses greater than 200 ms will be logged at INFO level
# This threshold can be adjusted to minimize logging if necessary
# Min unit: ms
@@ -2059,6 +2064,17 @@ unlogged_batch_across_partitions_warn_threshold: 10
# Min unit: ms
# gc_warn_threshold: 1000ms
+# GC Concurrent phase greater than 1000 ms will be logged at INFO level
+# This threshold can be adjusted to minimize logging if necessary
+# Min unit: ms
+# gc_concurrent_phase_log_threshold: 1000ms
+
+# GC Concurrent phase than gc_concurrent_phase_warn_threshold will be logged
at WARN level
+# Adjust the threshold based on your application throughput requirement.
Setting to 0
+# will deactivate the feature.
+# Min unit: ms
+# gc_concurrent_phase_warn_threshold: 2000ms
+
# Maximum size of any value in SSTables. Safety measure to detect SSTable
corruption
# early. Any value size larger than this threshold will result into marking an
SSTable
# as corrupted. This should be positive and less than 2GiB.
diff --git a/conf/cassandra_latest.yaml b/conf/cassandra_latest.yaml
index 6d3f7b7a49..b43f6cf45c 100644
--- a/conf/cassandra_latest.yaml
+++ b/conf/cassandra_latest.yaml
@@ -1913,6 +1913,11 @@ batch_size_fail_threshold: 50KiB
# Log WARN on any batches not of type LOGGED than span across more partitions
than this limit
unlogged_batch_across_partitions_warn_threshold: 10
+# GCInspector configs:
+# For GC like ShenandoahGC/ZGC etc., there are GC events that do not have STW
pauses.
+# Such events are called Concurrent phases. Operator might find it reasonable
to use lower thresholds
+# for events require STW pauses and higher thresholds for concurrent phases.
+#
# GC Pauses greater than 200 ms will be logged at INFO level
# This threshold can be adjusted to minimize logging if necessary
# Min unit: ms
@@ -1924,6 +1929,17 @@ unlogged_batch_across_partitions_warn_threshold: 10
# Min unit: ms
# gc_warn_threshold: 1000ms
+# GC Concurrent phase greater than 1000 ms will be logged at INFO level
+# This threshold can be adjusted to minimize logging if necessary
+# Min unit: ms
+# gc_concurrent_phase_log_threshold: 1000ms
+
+# GC Concurrent phase than gc_concurrent_phase_warn_threshold will be logged
at WARN level
+# Adjust the threshold based on your application throughput requirement.
Setting to 0
+# will deactivate the feature.
+# Min unit: ms
+# gc_concurrent_phase_warn_threshold: 2000ms
+
# Maximum size of any value in SSTables. Safety measure to detect SSTable
corruption
# early. Any value size larger than this threshold will result into marking an
SSTable
# as corrupted. This should be positive and less than 2GiB.
diff --git a/src/java/org/apache/cassandra/config/Config.java
b/src/java/org/apache/cassandra/config/Config.java
index 33a0a25283..7ea67ebc4c 100644
--- a/src/java/org/apache/cassandra/config/Config.java
+++ b/src/java/org/apache/cassandra/config/Config.java
@@ -593,6 +593,8 @@ public class Config
public volatile DurationSpec.IntMillisecondsBound gc_log_threshold = new
DurationSpec.IntMillisecondsBound("200ms");
@Replaces(oldName = "gc_warn_threshold_in_ms", converter =
Converters.MILLIS_DURATION_INT, deprecated = true)
public volatile DurationSpec.IntMillisecondsBound gc_warn_threshold = new
DurationSpec.IntMillisecondsBound("1s");
+ public volatile DurationSpec.IntMillisecondsBound
gc_concurrent_phase_log_threshold = new DurationSpec.IntMillisecondsBound("1s");
+ public volatile DurationSpec.IntMillisecondsBound
gc_concurrent_phase_warn_threshold = new
DurationSpec.IntMillisecondsBound("2s");
// TTL for different types of trace events.
@Replaces(oldName = "tracetype_query_ttl", converter =
Converters.SECONDS_DURATION, deprecated=true)
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 753a7413ea..dec260f9b9 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -1220,6 +1220,22 @@ public class DatabaseDescriptor
// run audit logging options through sanitation and validation
if (conf.audit_logging_options != null)
setAuditLoggingOptions(conf.audit_logging_options);
+
+ try
+ {
+ // Run through the validation by setting current values back to
their setters, so we are sure that their values are valid.
+ // We are catching IllegalArgumentException and translating it to
ConfigurationException to comply with
+ // rest of the logic in this method. These setters are also called
in GCInspectorMXBean were IllegalArgumentException
+ // is thrown when arguments are invalid instead
ConfigurationException, on purpose.
+ DatabaseDescriptor.setGCLogThreshold((int)
DatabaseDescriptor.getGCLogThreshold());
+ DatabaseDescriptor.setGCWarnThreshold((int)
DatabaseDescriptor.getGCWarnThreshold());
+
DatabaseDescriptor.setGCConcurrentPhaseLogThreshold(DatabaseDescriptor.getGCConcurrentPhaseLogThreshold());
+
DatabaseDescriptor.setGCConcurrentPhaseWarnThreshold(DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold());
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new ConfigurationException(ex.getMessage());
+ }
}
@VisibleForTesting
@@ -4719,14 +4735,17 @@ public class DatabaseDescriptor
return conf.gc_log_threshold.toMilliseconds();
}
- public static void setGCLogThreshold(int gcLogThreshold)
+ public static void setGCLogThreshold(int threshold)
{
- conf.gc_log_threshold = new
DurationSpec.IntMillisecondsBound(gcLogThreshold);
- }
+ if (threshold <= 0)
+ throw new IllegalArgumentException("Threshold value for
gc_log_threshold must be greater than 0");
- public static EncryptionContext getEncryptionContext()
- {
- return encryptionContext;
+ long gcWarnThresholdInMs = getGCWarnThreshold();
+ if (gcWarnThresholdInMs != 0 && threshold > gcWarnThresholdInMs)
+ throw new IllegalArgumentException("Threshold value for
gc_log_threshold (" + threshold + ") must be less than gc_warn_threshold which
is currently "
+ + gcWarnThresholdInMs);
+
+ conf.gc_log_threshold = new
DurationSpec.IntMillisecondsBound(threshold);
}
public static long getGCWarnThreshold()
@@ -4736,9 +4755,58 @@ public class DatabaseDescriptor
public static void setGCWarnThreshold(int threshold)
{
+ if (threshold < 0)
+ throw new IllegalArgumentException("Threshold value for
gc_warn_threshold must be greater than or equal to 0");
+
+ long gcLogThresholdInMs = getGCLogThreshold();
+ if (threshold != 0 && threshold <= gcLogThresholdInMs)
+ throw new IllegalArgumentException("Threshold value for
gc_warn_threshold (" + threshold + ") must be greater than gc_log_threshold
which is currently "
+ + gcLogThresholdInMs);
+
conf.gc_warn_threshold = new
DurationSpec.IntMillisecondsBound(threshold);
}
+ public static int getGCConcurrentPhaseLogThreshold()
+ {
+ return conf.gc_concurrent_phase_log_threshold.toMilliseconds();
+ }
+
+ public static void setGCConcurrentPhaseLogThreshold(int threshold)
+ {
+ if (threshold <= 0)
+ throw new IllegalArgumentException("Threshold must be greater than
0");
+
+ long gcConcurrentPhaseWarnThresholdInMs =
getGCConcurrentPhaseWarnThreshold();
+ if (gcConcurrentPhaseWarnThresholdInMs != 0 && threshold >
gcConcurrentPhaseWarnThresholdInMs)
+ throw new IllegalArgumentException("Threshold value for
gc_concurrent_phase_log_threshold (" + threshold + ") must be less than
gc_concurrent_phase_warn_threshold which is currently "
+ +
gcConcurrentPhaseWarnThresholdInMs);
+
+ conf.gc_concurrent_phase_log_threshold = new
DurationSpec.IntMillisecondsBound(threshold);
+ }
+
+ public static int getGCConcurrentPhaseWarnThreshold()
+ {
+ return conf.gc_concurrent_phase_warn_threshold.toMilliseconds();
+ }
+
+ public static void setGCConcurrentPhaseWarnThreshold(int threshold)
+ {
+ if (threshold < 0)
+ throw new IllegalArgumentException("Threshold value for
gc_concurrent_phase_warn_threshold must be greater than or equal to 0");
+
+ long gcConcurrentPhaseLogThresholdInMs =
getGCConcurrentPhaseLogThreshold();
+ if (threshold != 0 && threshold <= gcConcurrentPhaseLogThresholdInMs)
+ throw new IllegalArgumentException("Threshold value for
gc_concurrent_phase_warn_threshold (" + threshold + ") must be greater than
gc_concurrent_phase_log_threshold which is currently "
+ +
gcConcurrentPhaseLogThresholdInMs);
+
+ conf.gc_concurrent_phase_warn_threshold = new
DurationSpec.IntMillisecondsBound(threshold);
+ }
+
+ public static EncryptionContext getEncryptionContext()
+ {
+ return encryptionContext;
+ }
+
public static boolean isCDCEnabled()
{
return conf.cdc_enabled;
diff --git a/src/java/org/apache/cassandra/service/GCInspector.java
b/src/java/org/apache/cassandra/service/GCInspector.java
index 4bdc3a05ba..25d741b847 100644
--- a/src/java/org/apache/cassandra/service/GCInspector.java
+++ b/src/java/org/apache/cassandra/service/GCInspector.java
@@ -173,6 +173,7 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
ObjectName gcName = new
ObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");
for (ObjectName name : server.queryNames(gcName, null))
{
+ logger.info("Notification listener is added for: {}", name);
server.addNotificationListener(name, inspector, null, null);
}
}
@@ -261,6 +262,11 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
duration = total - previousTotal; // may be zero for a really
fast collection
}
+ logger.trace("Received GarbageCollectionNotificationInfo with
gcId: {}, gcName: {}, " +
+ "gcCause: {}, gcAction: {}, event duration: {} ms,
calculated duration: {} ms",
+ gcInfo.getId(), info.getGcName(), info.getGcCause(),
info.getGcAction(),
+ gcInfo.getDuration(), duration);
+
StringBuilder sb = new StringBuilder();
sb.append(info.getGcName()).append(" GC in
").append(duration).append("ms. ");
long bytes = 0;
@@ -287,16 +293,31 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
if (state.compareAndSet(prev, new State(duration, bytes,
prev)))
break;
}
-
- if (getGcWarnThresholdInMs() != 0 && duration >
getGcWarnThresholdInMs())
- logger.warn(sb.toString());
- else if (duration > getGcLogThresholdInMs())
- logger.info(sb.toString());
- else if (logger.isTraceEnabled())
- logger.trace(sb.toString());
- if (duration > this.getStatusThresholdInMs())
- StatusLogger.log();
+ if (isConcurrentPhase(info.getGcCause(), info.getGcName()))
+ {
+ if (getGcConcurrentPhaseWarnThresholdInMs() != 0 && duration >
getGcConcurrentPhaseWarnThresholdInMs())
+ logger.warn(sb.toString());
+ else if (duration > getGcConcurrentPhaseLogThresholdInMs())
+ logger.info(sb.toString());
+ else if (logger.isTraceEnabled())
+ logger.trace(sb.toString());
+
+ if (duration > this.getConcurrentStatusThresholdInMs())
+ StatusLogger.log();
+ }
+ else
+ {
+ if (getGcWarnThresholdInMs() != 0 && duration >
getGcWarnThresholdInMs())
+ logger.warn(sb.toString());
+ else if (duration > getGcLogThresholdInMs())
+ logger.info(sb.toString());
+ else if (logger.isTraceEnabled())
+ logger.trace(sb.toString());
+
+ if (duration > this.getStatusThresholdInMs())
+ StatusLogger.log();
+ }
// if we just finished an old gen collection and we're still using
a lot of memory, try to reduce the pressure
if (gcState.assumeGCIsOldGen)
@@ -304,6 +325,24 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
}
}
+ static boolean isConcurrentPhase(String cause, String name) {
+ // Mostly taken from:
https://github.com/Netflix/spectator/blob/v1.7.x/spectator-ext-gc/src/main/java/com/netflix/spectator/gc/GcLogger.java
+ // So far the only indicator known is that the cause will be reported
as "No GC"
+ // when using CMS.
+ //
+ // For ZGC, behavior was changed in JDK17:
https://bugs.openjdk.java.net/browse/JDK-8265136
+ // For ZGC in older versions, there is no way to accurately get the
amount of time
+ // in STW pauses.
+ //
+ // For G1, a new bean is added in JDK20 to indicate time spent in
concurrent phases:
+ // https://bugs.openjdk.org/browse/JDK-8297247
+
+ return "No GC".equals(cause) // CMS
+ || "G1 Concurrent GC".equals(name) // G1 in JDK20+
+ || name.endsWith(" Cycles"); // Shenandoah, ZGC
+ }
+
+
public State getTotalSinceLastCheck()
{
return state.getAndSet(new State());
@@ -378,14 +417,6 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
public void setGcWarnThresholdInMs(long threshold)
{
- long gcLogThresholdInMs = getGcLogThresholdInMs();
- if (threshold < 0)
- throw new IllegalArgumentException("Threshold must be greater than
or equal to 0");
- if (threshold != 0 && threshold <= gcLogThresholdInMs)
- throw new IllegalArgumentException("Threshold must be greater than
gcLogThresholdInMs which is currently "
- + gcLogThresholdInMs);
- if (threshold > Integer.MAX_VALUE)
- throw new IllegalArgumentException("Threshold must be less than
Integer.MAX_VALUE");
DatabaseDescriptor.setGCWarnThreshold((int)threshold);
}
@@ -396,15 +427,27 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
public void setGcLogThresholdInMs(long threshold)
{
- if (threshold <= 0)
- throw new IllegalArgumentException("Threshold must be greater than
0");
+ DatabaseDescriptor.setGCLogThreshold((int) threshold);
+ }
+
+ public int getGcConcurrentPhaseWarnThresholdInMs()
+ {
+ return DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold();
+ }
- long gcWarnThresholdInMs = getGcWarnThresholdInMs();
- if (gcWarnThresholdInMs != 0 && threshold > gcWarnThresholdInMs)
- throw new IllegalArgumentException("Threshold must be less than
gcWarnThresholdInMs which is currently "
- + gcWarnThresholdInMs);
+ public void setGcConcurrentPhaseWarnThresholdInMs(int threshold)
+ {
+ DatabaseDescriptor.setGCConcurrentPhaseWarnThreshold(threshold);
+ }
- DatabaseDescriptor.setGCLogThreshold((int) threshold);
+ public int getGcConcurrentPhaseLogThresholdInMs()
+ {
+ return DatabaseDescriptor.getGCConcurrentPhaseLogThreshold();
+ }
+
+ public void setGcConcurrentPhaseLogThresholdInMs(int threshold)
+ {
+ DatabaseDescriptor.setGCConcurrentPhaseLogThreshold(threshold);
}
public long getGcLogThresholdInMs()
@@ -417,4 +460,8 @@ public class GCInspector implements NotificationListener,
GCInspectorMXBean
return getGcWarnThresholdInMs() != 0 ? getGcWarnThresholdInMs() :
getGcLogThresholdInMs();
}
+ public long getConcurrentStatusThresholdInMs()
+ {
+ return getGcConcurrentPhaseWarnThresholdInMs() != 0 ?
getGcConcurrentPhaseWarnThresholdInMs() :
getGcConcurrentPhaseLogThresholdInMs();
+ }
}
diff --git a/src/java/org/apache/cassandra/service/GCInspectorMXBean.java
b/src/java/org/apache/cassandra/service/GCInspectorMXBean.java
index 08795ed269..9765e9813c 100644
--- a/src/java/org/apache/cassandra/service/GCInspectorMXBean.java
+++ b/src/java/org/apache/cassandra/service/GCInspectorMXBean.java
@@ -27,6 +27,10 @@ public interface GCInspectorMXBean
void setGcWarnThresholdInMs(long threshold);
long getGcWarnThresholdInMs();
void setGcLogThresholdInMs(long threshold);
+ int getGcConcurrentPhaseLogThresholdInMs();
+ void setGcConcurrentPhaseWarnThresholdInMs(int threshold);
+ int getGcConcurrentPhaseWarnThresholdInMs();
+ void setGcConcurrentPhaseLogThresholdInMs(int threshold);
long getGcLogThresholdInMs();
long getStatusThresholdInMs();
}
diff --git a/test/unit/org/apache/cassandra/service/GCInspectorTest.java
b/test/unit/org/apache/cassandra/service/GCInspectorTest.java
index bcdf023294..51d6a22a56 100644
--- a/test/unit/org/apache/cassandra/service/GCInspectorTest.java
+++ b/test/unit/org/apache/cassandra/service/GCInspectorTest.java
@@ -18,11 +18,16 @@
package org.apache.cassandra.service;
import org.apache.cassandra.config.DatabaseDescriptor;
-import org.junit.Assert;
+
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
public class GCInspectorTest
{
@@ -43,38 +48,61 @@ public class GCInspectorTest
@Test
public void ensureStaticFieldsHydrateFromConfig()
{
- Assert.assertEquals(DatabaseDescriptor.getGCLogThreshold(),
gcInspector.getGcLogThresholdInMs());
- Assert.assertEquals(DatabaseDescriptor.getGCWarnThreshold(),
gcInspector.getGcWarnThresholdInMs());
+ assertEquals(DatabaseDescriptor.getGCLogThreshold(),
gcInspector.getGcLogThresholdInMs());
+ assertEquals(DatabaseDescriptor.getGCWarnThreshold(),
gcInspector.getGcWarnThresholdInMs());
+ assertEquals(DatabaseDescriptor.getGCConcurrentPhaseLogThreshold(),
gcInspector.getGcConcurrentPhaseLogThresholdInMs());
+ assertEquals(DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold(),
gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
}
@Test
public void ensureStatusIsCalculated()
{
- Assert.assertTrue(gcInspector.getStatusThresholdInMs() > 0);
+ assertTrue(gcInspector.getStatusThresholdInMs() > 0);
}
- @Test(expected=IllegalArgumentException.class)
+ @Test
public void ensureWarnGreaterThanLog()
{
-
gcInspector.setGcWarnThresholdInMs(gcInspector.getGcLogThresholdInMs());
+ assertThatThrownBy(() ->
gcInspector.setGcWarnThresholdInMs(gcInspector.getGcLogThresholdInMs()))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Threshold value for gc_warn_threshold (200) must be
greater than gc_log_threshold which is currently 200");
+
+ assertThatThrownBy(() ->
gcInspector.setGcConcurrentPhaseWarnThresholdInMs(gcInspector.getGcConcurrentPhaseLogThresholdInMs()))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Threshold value for gc_concurrent_phase_warn_threshold
(1000) must be greater than gc_concurrent_phase_log_threshold which is
currently 1000");
}
@Test
public void ensureZeroIsOk()
{
gcInspector.setGcWarnThresholdInMs(0);
- Assert.assertEquals(gcInspector.getStatusThresholdInMs(),
gcInspector.getGcLogThresholdInMs());
- Assert.assertEquals(0, DatabaseDescriptor.getGCWarnThreshold());
- Assert.assertEquals(200, DatabaseDescriptor.getGCLogThreshold());
+ assertEquals(gcInspector.getStatusThresholdInMs(),
gcInspector.getGcLogThresholdInMs());
+ assertEquals(0, DatabaseDescriptor.getGCWarnThreshold());
+ assertEquals(200, DatabaseDescriptor.getGCLogThreshold());
+
+ gcInspector.setGcConcurrentPhaseWarnThresholdInMs(0);
+ assertEquals(0,
DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold());
+ assertEquals(1000,
DatabaseDescriptor.getGCConcurrentPhaseLogThreshold());
}
- @Test(expected=IllegalArgumentException.class)
+ @Test
public void ensureLogLessThanWarn()
{
- Assert.assertEquals(200, gcInspector.getGcLogThresholdInMs());
+ assertEquals(200, gcInspector.getGcLogThresholdInMs());
gcInspector.setGcWarnThresholdInMs(1000);
- Assert.assertEquals(1000, gcInspector.getGcWarnThresholdInMs());
- gcInspector.setGcLogThresholdInMs(gcInspector.getGcWarnThresholdInMs()
+ 1);
+ assertEquals(1000, gcInspector.getGcWarnThresholdInMs());
+
+ assertThatThrownBy(() ->
gcInspector.setGcLogThresholdInMs(gcInspector.getGcWarnThresholdInMs() + 1))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Threshold value for gc_log_threshold (1001) must be less
than gc_warn_threshold which is currently 1000");
+
+ assertEquals(1000, gcInspector.getGcConcurrentPhaseLogThresholdInMs());
+ gcInspector.setGcConcurrentPhaseWarnThresholdInMs(2000);
+ assertEquals(2000,
gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
+
+ assertThatThrownBy(() ->
gcInspector.setGcConcurrentPhaseLogThresholdInMs(gcInspector.getGcConcurrentPhaseWarnThresholdInMs()
+ 1))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Threshold value for gc_concurrent_phase_log_threshold
(2001) must be less than gc_concurrent_phase_warn_threshold which is currently
2000");
}
@Test
@@ -82,10 +110,16 @@ public class GCInspectorTest
{
gcInspector.setGcLogThresholdInMs(200);
gcInspector.setGcWarnThresholdInMs(1000);
- Assert.assertEquals(200, DatabaseDescriptor.getGCLogThreshold());
- Assert.assertEquals(200, gcInspector.getGcLogThresholdInMs());
- Assert.assertEquals(1000, DatabaseDescriptor.getGCWarnThreshold());
- Assert.assertEquals(1000, gcInspector.getGcWarnThresholdInMs());
+ gcInspector.setGcConcurrentPhaseLogThresholdInMs(1000);
+ gcInspector.setGcConcurrentPhaseWarnThresholdInMs(2000);
+ assertEquals(200, DatabaseDescriptor.getGCLogThreshold());
+ assertEquals(200, gcInspector.getGcLogThresholdInMs());
+ assertEquals(1000, DatabaseDescriptor.getGCWarnThreshold());
+ assertEquals(1000, gcInspector.getGcWarnThresholdInMs());
+ assertEquals(1000,
DatabaseDescriptor.getGCConcurrentPhaseLogThreshold());
+ assertEquals(1000, gcInspector.getGcConcurrentPhaseLogThresholdInMs());
+ assertEquals(2000,
DatabaseDescriptor.getGCConcurrentPhaseWarnThreshold());
+ assertEquals(2000,
gcInspector.getGcConcurrentPhaseWarnThresholdInMs());
}
@Test(expected=IllegalArgumentException.class)
@@ -94,4 +128,20 @@ public class GCInspectorTest
gcInspector.setGcLogThresholdInMs(200);
gcInspector.setGcWarnThresholdInMs(Integer.MAX_VALUE+1L);
}
+
+ @Test
+ public void testIsConcurrentPhase()
+ {
+ assertTrue("No GC cause should be considered concurrent",
+ GCInspector.isConcurrentPhase("No GC", "SomeGCName"));
+ assertTrue("Shenandoah Cycles should be considered concurrent",
+ GCInspector.isConcurrentPhase("SomeCause",
"Shenandoah Cycles"));
+ assertTrue("ZGC Cycles should be considered concurrent",
+ GCInspector.isConcurrentPhase("SomeCause", "ZGC
Cycles"));
+
+ assertFalse("ParallelGC should not be considered concurrent",
+ GCInspector.isConcurrentPhase("Allocation Failure",
"PS Scavenge"));
+ assertFalse("G1 Young Generation should not be considered concurrent",
+ GCInspector.isConcurrentPhase("G1 Evacuation Pause",
"G1 Young Generation"));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]