Repository: cassandra Updated Branches: refs/heads/trunk b207f0d95 -> 1096f9f5e
Make gc_log and gc_warn settable at runtime Patch by Edward Capriolo; reviewed by Jon Haddad for CASSANDRA-12661 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1096f9f5 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1096f9f5 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1096f9f5 Branch: refs/heads/trunk Commit: 1096f9f5e77ff7b17cc7f9fe5aba008834899251 Parents: b207f0d Author: Edward Capriolo <edlinuxg...@gmail.com> Authored: Sat Sep 17 12:07:20 2016 -0400 Committer: Blake Eggleston <bdeggles...@gmail.com> Committed: Tue Apr 11 17:14:11 2017 -0700 ---------------------------------------------------------------------- CHANGES.txt | 1 + conf/cassandra.yaml | 14 ++-- .../org/apache/cassandra/config/Config.java | 2 +- .../apache/cassandra/service/GCInspector.java | 75 ++++++++++++++++---- .../cassandra/service/GCInspectorMXBean.java | 11 ++- .../cassandra/service/GCInspectorTest.java | 60 ++++++++++++++++ 6 files changed, 139 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 5c38307..4f3cb3b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0 + * Make gc_log and gc_warn settable at runtime (CASSANDRA-12661) * Take number of files in L0 in account when estimating remaining compaction tasks (CASSANDRA-13354) * Skip building views during base table streams on range movements (CASSANDRA-13065) * Improve error messages for +/- operations on maps and tuples (CASSANDRA-13197) http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/conf/cassandra.yaml ---------------------------------------------------------------------- diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index f2c4c84..1c54830 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -981,10 +981,6 @@ inter_dc_tcp_nodelay: false tracetype_query_ttl: 86400 tracetype_repair_ttl: 604800 -# By default, Cassandra logs GC Pauses greater than 200 ms at INFO level -# This threshold can be adjusted to minimize logging if necessary -# gc_log_threshold_in_ms: 200 - # If unset, all GC Pauses greater than gc_log_threshold_in_ms will log at # INFO level # UDFs (user defined functions) are disabled by default. @@ -1062,10 +1058,14 @@ unlogged_batch_across_partitions_warn_threshold: 10 # Log a warning when compacting partitions larger than this value compaction_large_partition_warning_threshold_mb: 100 +# GC Pauses greater than 200 ms will be logged at INFO level +# This threshold can be adjusted to minimize logging if necessary +# gc_log_threshold_in_ms: 200 + # GC Pauses greater than gc_warn_threshold_in_ms will be logged at WARN level -# Adjust the threshold based on your application throughput requirement -# By default, Cassandra logs GC Pauses greater than 200 ms at INFO level -gc_warn_threshold_in_ms: 1000 +# Adjust the threshold based on your application throughput requirement. Setting to 0 +# will deactivate the feature. +# gc_warn_threshold_in_ms: 1000 # 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 http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/src/java/org/apache/cassandra/config/Config.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 1461cd4..b86429c 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -267,7 +267,7 @@ public class Config public volatile int index_summary_resize_interval_in_minutes = 60; public int gc_log_threshold_in_ms = 200; - public int gc_warn_threshold_in_ms = 0; + public int gc_warn_threshold_in_ms = 1000; // TTL for different types of trace events. public int tracetype_query_ttl = (int) TimeUnit.DAYS.toSeconds(1); http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/src/java/org/apache/cassandra/service/GCInspector.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/GCInspector.java b/src/java/org/apache/cassandra/service/GCInspector.java index e7cfcd0..b016249 100644 --- a/src/java/org/apache/cassandra/service/GCInspector.java +++ b/src/java/org/apache/cassandra/service/GCInspector.java @@ -17,6 +17,7 @@ */ package org.apache.cassandra.service; +import java.io.IOException; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryUsage; @@ -27,7 +28,11 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectName; @@ -48,9 +53,8 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean { public static final String MBEAN_NAME = "org.apache.cassandra.service:type=GCInspector"; private static final Logger logger = LoggerFactory.getLogger(GCInspector.class); - final static long MIN_LOG_DURATION = DatabaseDescriptor.getGCLogThreshold(); - final static long GC_WARN_THRESHOLD_IN_MS = DatabaseDescriptor.getGCWarnThreshold(); - final static long STAT_THRESHOLD = GC_WARN_THRESHOLD_IN_MS != 0 ? GC_WARN_THRESHOLD_IN_MS : MIN_LOG_DURATION; + private volatile static long gcLogThreshholdInMs = DatabaseDescriptor.getGCLogThreshold(); + private volatile static long gcWarnThreasholdInMs = DatabaseDescriptor.getGCWarnThreshold(); /* * The field from java.nio.Bits that tracks the total number of allocated @@ -58,6 +62,7 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean */ final static Field BITS_TOTAL_CAPACITY; + static { Field temp = null; @@ -146,10 +151,12 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean GarbageCollectorMXBean gc = ManagementFactory.newPlatformMXBeanProxy(mbs, name.getCanonicalName(), GarbageCollectorMXBean.class); gcStates.put(gc.getName(), new GCState(gc, assumeGCIsPartiallyConcurrent(gc), assumeGCIsOldGen(gc))); } - - mbs.registerMBean(this, new ObjectName(MBEAN_NAME)); + ObjectName me = new ObjectName(MBEAN_NAME); + if (!mbs.isRegistered(me)) + mbs.registerMBean(this, new ObjectName(MBEAN_NAME)); } - catch (Exception e) + catch (RuntimeException | InstanceAlreadyExistsException | MBeanRegistrationException | + NotCompliantMBeanException | MalformedObjectNameException | IOException e) { throw new RuntimeException(e); } @@ -276,16 +283,15 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean if (state.compareAndSet(prev, new State(duration, bytes, prev))) break; } - - String st = sb.toString(); - if (GC_WARN_THRESHOLD_IN_MS != 0 && duration > GC_WARN_THRESHOLD_IN_MS) - logger.warn(st); - else if (duration > MIN_LOG_DURATION) - logger.info(st); + + if (gcWarnThreasholdInMs != 0 && duration > gcWarnThreasholdInMs) + logger.warn(sb.toString()); + else if (duration > gcLogThreshholdInMs) + logger.info(sb.toString()); else if (logger.isTraceEnabled()) - logger.trace(st); + logger.trace(sb.toString()); - if (duration > STAT_THRESHOLD) + 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 @@ -328,4 +334,45 @@ public class GCInspector implements NotificationListener, GCInspectorMXBean return -1; } } + + @Override + public void setGcWarnThresholdInMs(long threshold) + { + if (threshold < 0) + throw new IllegalArgumentException("Threashold must be greater than 0"); + if (threshold != 0 && threshold <= gcLogThreshholdInMs) + throw new IllegalArgumentException("Threashold must be greater than gcLogTreasholdInMs which is currently " + + gcLogThreshholdInMs); + gcWarnThreasholdInMs = threshold; + } + + @Override + public long getGcWarnThresholdInMs() + { + return gcWarnThreasholdInMs; + } + + @Override + public void setGcLogThresholdInMs(long threshold) + { + if (threshold <= 0) + throw new IllegalArgumentException("Threashold must be greater than 0"); + if (gcWarnThreasholdInMs != 0 && threshold > gcWarnThreasholdInMs) + throw new IllegalArgumentException("Threashold must be less than gcWarnTreasholdInMs which is currently " + + gcWarnThreasholdInMs); + gcLogThreshholdInMs = threshold; + } + + @Override + public long getGcLogThresholdInMs() + { + return gcLogThreshholdInMs; + } + + @Override + public long getStatusThresholdInMs() + { + return gcWarnThreasholdInMs != 0 ? gcWarnThreasholdInMs : gcLogThreshholdInMs; + } + } http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/src/java/org/apache/cassandra/service/GCInspectorMXBean.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/GCInspectorMXBean.java b/src/java/org/apache/cassandra/service/GCInspectorMXBean.java index c26a67c..08795ed 100644 --- a/src/java/org/apache/cassandra/service/GCInspectorMXBean.java +++ b/src/java/org/apache/cassandra/service/GCInspectorMXBean.java @@ -20,6 +20,13 @@ package org.apache.cassandra.service; public interface GCInspectorMXBean { - // returns { interval (ms), max(gc real time (ms)), sum(gc real time (ms)), sum((gc real time (ms))^2), sum(gc bytes), count(gc) } - public double[] getAndResetStats(); + /* @returns { interval (ms), max(gc real time (ms)), sum(gc real time (ms)), sum((gc real time (ms))^2), sum(gc bytes), count(gc) } + * + */ + double[] getAndResetStats(); + void setGcWarnThresholdInMs(long threshold); + long getGcWarnThresholdInMs(); + void setGcLogThresholdInMs(long threshold); + long getGcLogThresholdInMs(); + long getStatusThresholdInMs(); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/1096f9f5/test/unit/org/apache/cassandra/service/GCInspectorTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/service/GCInspectorTest.java b/test/unit/org/apache/cassandra/service/GCInspectorTest.java new file mode 100644 index 0000000..872c736 --- /dev/null +++ b/test/unit/org/apache/cassandra/service/GCInspectorTest.java @@ -0,0 +1,60 @@ +package org.apache.cassandra.service; + +import org.apache.cassandra.OrderedJUnit4ClassRunner; +import org.apache.cassandra.config.DatabaseDescriptor; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(OrderedJUnit4ClassRunner.class) +public class GCInspectorTest +{ + + GCInspector gcInspector; + + @BeforeClass + public static void setupDatabaseDescriptor() + { + DatabaseDescriptor.daemonInitialization(); + } + + @Before + public void before(){ + gcInspector = new GCInspector(); + } + + @Test + public void ensureStaticFieldsHydrateFromConfig() + { + Assert.assertEquals(DatabaseDescriptor.getGCLogThreshold(), gcInspector.getGcLogThresholdInMs()); + Assert.assertEquals(DatabaseDescriptor.getGCWarnThreshold(), gcInspector.getGcWarnThresholdInMs()); + } + + @Test + public void ensureStatusIsCalculated() + { + Assert.assertTrue(gcInspector.getStatusThresholdInMs() > 0); + } + + @Test(expected=IllegalArgumentException.class) + public void ensureWarnGreaterThanLog() + { + gcInspector.setGcWarnThresholdInMs(gcInspector.getGcLogThresholdInMs()); + } + + @Test + public void ensureZeroIsOk() + { + gcInspector.setGcWarnThresholdInMs(0); + Assert.assertEquals(gcInspector.getStatusThresholdInMs(), gcInspector.getGcLogThresholdInMs()); + } + + @Test(expected=IllegalArgumentException.class) + public void ensureLogLessThanWarn() + { + gcInspector.setGcLogThresholdInMs(gcInspector.getGcWarnThresholdInMs() + 1); + } + +}