From 3adc03e6e4373f5d5a514f4eab81386f48b3533a Mon Sep 17 00:00:00 2001 From: Gary Dusbabek Date: Fri, 30 Jul 2010 14:02:56 +0000 Subject: [PATCH] merge from 0.6 git-svn-id: https://svn.apache.org/repos/asf/cassandra/trunk@980796 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 6 + debian/changelog | 6 + .../apache/cassandra/service/GCInspector.java | 129 +++++++++++++++--- 3 files changed, 123 insertions(+), 18 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c91c468c15..aa377c89b5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -44,6 +44,12 @@ dev * add IntegerType (CASSANDRA-1282) * page within a single row during hinted handoff (CASSANDRA-1327) + +0.6.5 + * page within a single row during hinted handoff (CASSANDRA-1327) + * fix compilation on non-sun JKDs (CASSANDRA-1061) + + 0.6.4 * avoid queuing multiple hint deliveries for the same endpoint (CASSANDRA-1229) diff --git a/debian/changelog b/debian/changelog index 4420f38608..466728d5bb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cassandra (0.6.4) unstable; urgency=low + + * New stable point release. + + -- Eric Evans Tue, 27 Jul 2010 15:47:09 -0500 + cassandra (0.6.3) unstable; urgency=low * New stable point release. diff --git a/src/java/org/apache/cassandra/service/GCInspector.java b/src/java/org/apache/cassandra/service/GCInspector.java index 0afcc17c3b..dc6c97b095 100644 --- a/src/java/org/apache/cassandra/service/GCInspector.java +++ b/src/java/org/apache/cassandra/service/GCInspector.java @@ -23,15 +23,12 @@ package org.apache.cassandra.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.*; -import java.util.concurrent.ExecutorService; -import org.apache.cassandra.concurrent.JMXEnabledThreadPoolExecutor; -import org.apache.cassandra.utils.WrappedRunnable; import org.apache.cassandra.concurrent.IExecutorMBean; import org.apache.cassandra.db.CompactionManagerMBean; -import com.sun.management.GarbageCollectorMXBean; -import com.sun.management.GcInfo; import java.lang.management.MemoryUsage; import java.lang.management.ManagementFactory; import javax.management.JMX; @@ -51,17 +48,30 @@ public class GCInspector private HashMap gctimes = new HashMap(); private final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - List beans = new ArrayList(); + List beans = new ArrayList(); // these are instances of com.sun.management.GarbageCollectorMXBean public GCInspector() { + // we only want this class to do its thing on sun jdks, or when the sun classes are present. + Class gcBeanClass = null; + try + { + gcBeanClass = Class.forName("com.sun.management.GarbageCollectorMXBean"); + Class.forName("com.sun.management.GcInfo"); + } + catch (ClassNotFoundException ex) + { + // this happens when using a non-sun jdk. + logger.warn("Cannot load sun GC monitoring classes. GCInspector is disabled."); + } + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); try { ObjectName gcName = new ObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*"); for (ObjectName name : server.queryNames(gcName, null)) { - GarbageCollectorMXBean gc = ManagementFactory.newPlatformMXBeanProxy(server, name.getCanonicalName(), GarbageCollectorMXBean.class); + Object gc = ManagementFactory.newPlatformMXBeanProxy(server, name.getCanonicalName(), gcBeanClass); beans.add(gc); } } @@ -73,6 +83,9 @@ public class GCInspector public void start() { + // don't bother starting a thread that will do nothing. + if (beans.size() == 0) + return; TimerTask t = new TimerTask() { public void run() @@ -85,25 +98,25 @@ public class GCInspector private void logIntervalGCStats() { - for (GarbageCollectorMXBean gc : beans) + for (Object gc : beans) { - GcInfo gci = gc.getLastGcInfo(); - if (gci == null) + SunGcWrapper gcw = new SunGcWrapper(gc); + if (gcw.isLastGcInfoNull()) continue; - Long previous = gctimes.get(gc.getName()); - if (previous != null && previous == gc.getCollectionTime()) + Long previous = gctimes.get(gcw.getName()); + if (previous != null && previous.longValue() == gcw.getCollectionTime().longValue()) continue; - gctimes.put(gc.getName(), gc.getCollectionTime()); + gctimes.put(gcw.getName(), gcw.getCollectionTime()); long previousMemoryUsed = 0; long memoryUsed = 0; long memoryMax = 0; - for (Map.Entry entry : gci.getMemoryUsageBeforeGc().entrySet()) + for (Map.Entry entry : gcw.getMemoryUsageBeforeGc().entrySet()) { previousMemoryUsed += entry.getValue().getUsed(); } - for (Map.Entry entry : gci.getMemoryUsageAfterGc().entrySet()) + for (Map.Entry entry : gcw.getMemoryUsageAfterGc().entrySet()) { MemoryUsage mu = entry.getValue(); memoryUsed += mu.getUsed(); @@ -111,12 +124,12 @@ public class GCInspector } String st = String.format("GC for %s: %s ms, %s reclaimed leaving %s used; max is %s", - gc.getName(), gci.getDuration(), previousMemoryUsed - memoryUsed, memoryUsed, memoryMax); - if (gci.getDuration() > MIN_DURATION) + gcw.getName(), gcw.getDuration(), previousMemoryUsed - memoryUsed, memoryUsed, memoryMax); + if (gcw.getDuration() > MIN_DURATION) logger.info(st); else if (logger.isDebugEnabled()) logger.debug(st); - if (gci.getDuration() > MIN_DURATION_TPSTATS) + if (gcw.getDuration() > MIN_DURATION_TPSTATS) { try { @@ -147,4 +160,84 @@ public class GCInspector CompactionManagerMBean cmProxy = JMX.newMBeanProxy(server, cm, CompactionManagerMBean.class); logger.info(String.format("%-25s%10s%10s", "CompactionManager", "n/a", cmProxy.getPendingTasks())); } + + + // wrapper for sun class. this enables other jdks to compile this class. + private final class SunGcWrapper + { + + private Map usageBeforeGc = null; + private Map usageAfterGc = null; + private String name; + private Long collectionTime; + private Long duration; + + SunGcWrapper(Object gcMxBean) + { + // if we've gotten this far, we've already verified that the right classes are in the CP. Now we just + // need to check for boneheadedness. + // grab everything we need here so that we don't have to deal with try/catch everywhere. + try + { + assert Class.forName("com.sun.management.GarbageCollectorMXBean").isAssignableFrom(gcMxBean.getClass()); + Method getGcInfo = gcMxBean.getClass().getDeclaredMethod("getLastGcInfo"); + Object lastGcInfo = getGcInfo.invoke(gcMxBean); + if (lastGcInfo != null) + { + usageBeforeGc = (Map)lastGcInfo.getClass().getDeclaredMethod("getMemoryUsageBeforeGc").invoke(lastGcInfo); + usageAfterGc = (Map)lastGcInfo.getClass().getDeclaredMethod("getMemoryUsageAfterGc").invoke(lastGcInfo); + duration = (Long)lastGcInfo.getClass().getDeclaredMethod("getDuration").invoke(lastGcInfo); + name = (String)gcMxBean.getClass().getDeclaredMethod("getName").invoke(gcMxBean); + collectionTime = (Long)gcMxBean.getClass().getDeclaredMethod("getCollectionTime").invoke(gcMxBean); + } + } + catch (ClassNotFoundException e) + { + throw new RuntimeException(e); + } + catch (NoSuchMethodException e) + { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) + { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) + { + throw new RuntimeException(e); + } + } + + String getName() + { + return name; + } + + Long getCollectionTime() + { + return collectionTime; + } + + Long getDuration() + { + return duration; + } + + Map getMemoryUsageAfterGc() + { + return usageAfterGc; + } + + Map getMemoryUsageBeforeGc() + { + return usageBeforeGc; + } + + boolean isLastGcInfoNull() + { + return usageBeforeGc == null; + } + } + }