incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccu...@apache.org
Subject git commit: In preparation for supporting java 7 and the G1 collector, adding a java 7 enhanced version of the GCWatcher.
Date Mon, 07 Oct 2013 12:56:49 GMT
Updated Branches:
  refs/heads/master d6d83b487 -> 42c983384


In preparation for supporting java 7 and the G1 collector, adding a java 7 enhanced version
of the GCWatcher.


Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/42c98338
Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/42c98338
Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/42c98338

Branch: refs/heads/master
Commit: 42c9833843ce24922715402945e041f9466b3aa7
Parents: d6d83b4
Author: Aaron McCurry <amccurry@gmail.com>
Authored: Mon Oct 7 08:56:23 2013 -0400
Committer: Aaron McCurry <amccurry@gmail.com>
Committed: Mon Oct 7 08:56:44 2013 -0400

----------------------------------------------------------------------
 .../blur/manager/status/QueryStatusManager.java |   4 +-
 .../org/apache/blur/utils/CreateGarbage.java    |   4 +-
 .../java/org/apache/blur/utils/GCAction.java    |  25 ++
 .../java/org/apache/blur/utils/GCWatcher.java   | 256 ++++---------------
 .../org/apache/blur/utils/GCWatcherJdk6.java    | 242 ++++++++++++++++++
 .../org/apache/blur/utils/GCWatcherJdk7.java    | 162 ++++++++++++
 6 files changed, 477 insertions(+), 216 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/manager/status/QueryStatusManager.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/manager/status/QueryStatusManager.java
b/blur-core/src/main/java/org/apache/blur/manager/status/QueryStatusManager.java
index f9bd583..1cb0765 100644
--- a/blur-core/src/main/java/org/apache/blur/manager/status/QueryStatusManager.java
+++ b/blur-core/src/main/java/org/apache/blur/manager/status/QueryStatusManager.java
@@ -32,8 +32,8 @@ import org.apache.blur.log.LogFactory;
 import org.apache.blur.thrift.generated.BlurQuery;
 import org.apache.blur.thrift.generated.BlurQueryStatus;
 import org.apache.blur.thrift.generated.QueryState;
+import org.apache.blur.utils.GCAction;
 import org.apache.blur.utils.GCWatcher;
-import org.apache.blur.utils.GCWatcher.Action;
 
 public class QueryStatusManager {
 
@@ -56,7 +56,7 @@ public class QueryStatusManager {
         }
       }
     }, statusCleanupTimerDelay, statusCleanupTimerDelay);
-    GCWatcher.registerAction(new Action() {
+    GCWatcher.registerAction(new GCAction() {
       @Override
       public void takeAction() throws Exception {
         stopAllQueriesForBackPressure();

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/utils/CreateGarbage.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/utils/CreateGarbage.java b/blur-core/src/main/java/org/apache/blur/utils/CreateGarbage.java
index df28ad9..95512bd 100644
--- a/blur-core/src/main/java/org/apache/blur/utils/CreateGarbage.java
+++ b/blur-core/src/main/java/org/apache/blur/utils/CreateGarbage.java
@@ -19,13 +19,11 @@ package org.apache.blur.utils;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.blur.utils.GCWatcher.Action;
-
 public class CreateGarbage {
 
   public static void main(String[] args) throws InterruptedException {
     final Map<String, String> map = new ConcurrentHashMap<String, String>();
-    Action action = new Action() {
+    GCAction action = new GCAction() {
       @Override
       public void takeAction() throws Exception {
         map.clear();

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/utils/GCAction.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/utils/GCAction.java b/blur-core/src/main/java/org/apache/blur/utils/GCAction.java
new file mode 100644
index 0000000..a796784
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/utils/GCAction.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.blur.utils;
+
+/**
+ * The {@link GCAction} interface is used to implement an action that needs to
+ * be taken to prevent an {@link OutOfMemoryError} exception.
+ */
+public interface GCAction {
+  void takeAction() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/utils/GCWatcher.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/utils/GCWatcher.java b/blur-core/src/main/java/org/apache/blur/utils/GCWatcher.java
index e7b0cb1..c9c3774 100644
--- a/blur-core/src/main/java/org/apache/blur/utils/GCWatcher.java
+++ b/blur-core/src/main/java/org/apache/blur/utils/GCWatcher.java
@@ -1,5 +1,3 @@
-package org.apache.blur.utils;
-
 /**
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -16,231 +14,67 @@ package org.apache.blur.utils;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import java.lang.management.GarbageCollectorMXBean;
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryMXBean;
-import java.lang.management.MemoryUsage;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.blur.log.Log;
-import org.apache.blur.log.LogFactory;
+package org.apache.blur.utils;
 
-public class GCWatcher extends TimerTask {
+import java.util.Properties;
 
-  private static final Log LOG = LogFactory.getLog(GCWatcher.class);
-  private static final String GET_LAST_GC_INFO = "getLastGcInfo";
-  private static final String CONCURRENT_MARK_SWEEP = "ConcurrentMarkSweep";
-  private static final String CMS_OLD_GEN = "CMS Old Gen";
+public class GCWatcher {
 
-  private final Timer _timer;
-  private final long _period = TimeUnit.MILLISECONDS.toMillis(25);
-  private GarbageCollectorMXBean _bean;
-  private final double _ratio;
-  private Method _method;
-  private GcInfo _gcInfo;
-  private long _lastIndex;
-  private final List<Action> _actions = new ArrayList<Action>();
-  private final MemoryMXBean _memoryMXBean;
-  private static GCWatcher _instance;
+  private static final String JAVA_VERSION = "java.version";
+  private static final String _1_7 = "1.7";
+  private static final boolean JDK7;
 
-  public interface Action {
-    void takeAction() throws Exception;
-  }
-
-  private GCWatcher(double ratio) {
-    _memoryMXBean = ManagementFactory.getMemoryMXBean();
-    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
-    for (GarbageCollectorMXBean bean : garbageCollectorMXBeans) {
-      String name = bean.getName();
-      if (name.equals(CONCURRENT_MARK_SWEEP)) {
-        _bean = bean;
-        try {
-          _method = _bean.getClass().getDeclaredMethod(GET_LAST_GC_INFO, new Class[] {});
-        } catch (SecurityException e) {
-          throw new RuntimeException(e);
-        } catch (NoSuchMethodException e) {
-          throw new RuntimeException(e);
-        }
-        _method.setAccessible(true);
-      }
-    }
-    _ratio = ratio;
-    if (_bean != null) {
-      _timer = new Timer("gc-watch", true);
-      _timer.schedule(this, _period, _period);
-      LOG.info("GCWatcher was setup.");
+  static {
+    Properties properties = System.getProperties();
+    String javaVersion = properties.getProperty(JAVA_VERSION);
+    if (javaVersion.startsWith(_1_7)) {
+      JDK7 = true;
     } else {
-      _timer = null;
-      LOG.warn("GCWatcher was NOT setup.");
-    }
-  }
-
-  public static void registerAction(Action action) {
-    GCWatcher instance = instance();
-    if (instance != null) {
-      synchronized (instance._actions) {
-        instance._actions.add(action);
-      }
+      JDK7 = false;
     }
   }
 
-  public static synchronized void shutdown() {
-    GCWatcher instance = instance();
-    if (instance != null) {
-      if (instance._timer != null) {
-        instance._timer.purge();
-        instance._timer.cancel();
-      }
-    }
-  }
-
-  @Override
-  public void run() {
-    try {
-      Object gcInfo = getGcInfo(_bean);
-      if (gcInfo != null) {
-        if (_gcInfo == null) {
-          _gcInfo = new GcInfo(gcInfo);
-        } else {
-          _gcInfo.setGcInfo(gcInfo);
-        }
-        if (_lastIndex == _gcInfo.getIndex()) {
-          return;
-        }
-        long startTime = _gcInfo.getStartTime();
-        long endTime = _gcInfo.getEndTime();
-        Map<String, MemoryUsage> usageBeforeGc = _gcInfo.getUsageBeforeGc();
-        Map<String, MemoryUsage> usageAfterGc = _gcInfo.getUsageAfterGc();
-        
-        MemoryUsage before = usageBeforeGc.get(CMS_OLD_GEN);
-        long usedBefore = before.getUsed();
-        
-        MemoryUsage after = usageAfterGc.get(CMS_OLD_GEN);
-        long usedAfter = after.getUsed();
-        
-        long totalTime = endTime - startTime;
-        LOG.info("totalTime spent in GC [{0} ms] collected [{1} bytes]", totalTime, (usedBefore
- usedAfter));
-        MemoryUsage heapMemoryUsage = _memoryMXBean.getHeapMemoryUsage();
-        long max = heapMemoryUsage.getMax();
-        long used = heapMemoryUsage.getUsed();
-        long upperLimit = (long) (max * _ratio);
-        if (used > upperLimit) {
-          LOG.error("----- WARNING !!!! - Heap used [{0}] over limit of [{1}], taking action
to avoid an OOM error.", used,
-              upperLimit);
-          synchronized (_actions) {
-            for (Action action : _actions) {
-              try {
-                action.takeAction();
-              } catch (Exception e) {
-                LOG.error("Unknown error while trying to take action against an OOM [{0}]",
e, action);
-              }
-            }
-          }
-        }
-        _lastIndex = _gcInfo.getIndex();
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
+  /**
+   * Initializes the GCWatcher to watch for any garbage collection that leaves
+   * more then the given ratio free. If more remains then all the given
+   * {@link GCAction}s are taken to try and relief the JVM from an
+   * {@link OutOfMemoryError} exception.
+   * 
+   * @param ratio
+   *          the ratio of used heap to total heap.
+   */
+  public static void init(double ratio) {
+    if (JDK7) {
+      GCWatcherJdk7.init(ratio);
+    } else {
+      GCWatcherJdk6.init(ratio);
     }
   }
 
-  private Object getGcInfo(GarbageCollectorMXBean bean) throws Exception {
-    return _method.invoke(bean, new Object[] {});
-  }
-
-  static class GcInfo {
-
-    private Object _gcInfo;
-    private final Field _startTimeField;
-    private final Field _endTimeField;
-    private final Field _usageAfterGcField;
-    private final Field _usageBeforeGcField;
-    private final Field _indexField;
-
-    GcInfo(Object o) throws SecurityException, NoSuchFieldException {
-      Class<? extends Object> clazz = o.getClass();
-      _startTimeField = setup(clazz.getDeclaredField("startTime"));
-      _endTimeField = setup(clazz.getDeclaredField("endTime"));
-      _usageAfterGcField = setup(clazz.getDeclaredField("usageAfterGc"));
-      _usageBeforeGcField = setup(clazz.getDeclaredField("usageBeforeGc"));
-      _indexField = setup(clazz.getDeclaredField("index"));
-      setGcInfo(o);
-    }
-
-    void setGcInfo(Object o) {
-      _gcInfo = o;
-    }
-
-    private Field setup(Field field) {
-      field.setAccessible(true);
-      return field;
-    }
-
-    long getStartTime() {
-      try {
-        return _startTimeField.getLong(_gcInfo);
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-
-    long getEndTime() {
-      try {
-        return _endTimeField.getLong(_gcInfo);
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-
-    long getIndex() {
-      try {
-        return _indexField.getLong(_gcInfo);
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-
-    @SuppressWarnings("unchecked")
-    Map<String, MemoryUsage> getUsageAfterGc() {
-      try {
-        return (Map<String, MemoryUsage>) _usageAfterGcField.get(_gcInfo);
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
-    }
-
-    @SuppressWarnings("unchecked")
-    Map<String, MemoryUsage> getUsageBeforeGc() {
-      try {
-        return (Map<String, MemoryUsage>) _usageBeforeGcField.get(_gcInfo);
-      } catch (Exception e) {
-        throw new RuntimeException(e);
-      }
+  /**
+   * Registers an {@link GCAction} to be taken when the JVM is near an
+   * {@link OutOfMemoryError} condition.
+   * 
+   * @param action
+   *          the {@link GCAction}.
+   */
+  public static void registerAction(GCAction action) {
+    if (JDK7) {
+      GCWatcherJdk7.registerAction(action);
+    } else {
+      GCWatcherJdk6.registerAction(action);
     }
-
   }
 
-  public synchronized static void init(double ratio) {
-    if (_instance == null) {
-      try {
-        _instance = new GCWatcher(ratio);
-      } catch (Exception e) {
-        LOG.error("GCWatcher had error initializing", e);
-      }
+  /**
+   * Shuts down any internal threads watching the JVM.
+   */
+  public static void shutdown() {
+    if (JDK7) {
+      GCWatcherJdk7.shutdown();
     } else {
-      LOG.warn("GCWatcher has already been initialized");
+      GCWatcherJdk6.shutdown();
     }
   }
 
-  private static GCWatcher instance() {
-    return _instance;
-  }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk6.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk6.java b/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk6.java
new file mode 100644
index 0000000..6f374c6
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk6.java
@@ -0,0 +1,242 @@
+package org.apache.blur.utils;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.blur.log.Log;
+import org.apache.blur.log.LogFactory;
+
+public class GCWatcherJdk6 extends TimerTask {
+
+  private static final Log LOG = LogFactory.getLog(GCWatcherJdk6.class);
+  private static final String GET_LAST_GC_INFO = "getLastGcInfo";
+  private static final String CONCURRENT_MARK_SWEEP = "ConcurrentMarkSweep";
+  private static final String CMS_OLD_GEN = "CMS Old Gen";
+
+  private final Timer _timer;
+  private final long _period = TimeUnit.MILLISECONDS.toMillis(25);
+  private GarbageCollectorMXBean _bean;
+  private final double _ratio;
+  private Method _method;
+  private GcInfo _gcInfo;
+  private long _lastIndex;
+  private final List<GCAction> _actions = new ArrayList<GCAction>();
+  private final MemoryMXBean _memoryMXBean;
+  private static GCWatcherJdk6 _instance;
+
+  private GCWatcherJdk6(double ratio) {
+    _memoryMXBean = ManagementFactory.getMemoryMXBean();
+    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
+    for (GarbageCollectorMXBean bean : garbageCollectorMXBeans) {
+      String name = bean.getName();
+      if (name.equals(CONCURRENT_MARK_SWEEP)) {
+        _bean = bean;
+        try {
+          _method = _bean.getClass().getDeclaredMethod(GET_LAST_GC_INFO, new Class[] {});
+        } catch (SecurityException e) {
+          throw new RuntimeException(e);
+        } catch (NoSuchMethodException e) {
+          throw new RuntimeException(e);
+        }
+        _method.setAccessible(true);
+      }
+    }
+    _ratio = ratio;
+    if (_bean != null) {
+      _timer = new Timer("gc-watch", true);
+      _timer.schedule(this, _period, _period);
+      LOG.info("GCWatcherJdk6 was setup.");
+    } else {
+      _timer = null;
+      LOG.warn("GCWatcherJdk6 was NOT setup.");
+    }
+  }
+
+  public static void registerAction(GCAction action) {
+    GCWatcherJdk6 instance = instance();
+    if (instance != null) {
+      synchronized (instance._actions) {
+        instance._actions.add(action);
+      }
+    }
+  }
+
+  public static synchronized void shutdown() {
+    GCWatcherJdk6 instance = instance();
+    if (instance != null) {
+      if (instance._timer != null) {
+        instance._timer.purge();
+        instance._timer.cancel();
+      }
+    }
+  }
+
+  @Override
+  public void run() {
+    try {
+      Object gcInfo = getGcInfo(_bean);
+      if (gcInfo != null) {
+        if (_gcInfo == null) {
+          _gcInfo = new GcInfo(gcInfo);
+        } else {
+          _gcInfo.setGcInfo(gcInfo);
+        }
+        if (_lastIndex == _gcInfo.getIndex()) {
+          return;
+        }
+        long startTime = _gcInfo.getStartTime();
+        long endTime = _gcInfo.getEndTime();
+        Map<String, MemoryUsage> usageBeforeGc = _gcInfo.getUsageBeforeGc();
+        Map<String, MemoryUsage> usageAfterGc = _gcInfo.getUsageAfterGc();
+        
+        MemoryUsage before = usageBeforeGc.get(CMS_OLD_GEN);
+        long usedBefore = before.getUsed();
+        
+        MemoryUsage after = usageAfterGc.get(CMS_OLD_GEN);
+        long usedAfter = after.getUsed();
+        
+        long totalTime = endTime - startTime;
+        LOG.info("totalTime spent in GC [{0} ms] collected [{1} bytes]", totalTime, (usedBefore
- usedAfter));
+        MemoryUsage heapMemoryUsage = _memoryMXBean.getHeapMemoryUsage();
+        long max = heapMemoryUsage.getMax();
+        long used = heapMemoryUsage.getUsed();
+        long upperLimit = (long) (max * _ratio);
+        if (used > upperLimit) {
+          LOG.error("----- WARNING !!!! - Heap used [{0}] over limit of [{1}], taking action
to avoid an OOM error.", used,
+              upperLimit);
+          synchronized (_actions) {
+            for (GCAction action : _actions) {
+              try {
+                action.takeAction();
+              } catch (Exception e) {
+                LOG.error("Unknown error while trying to take action against an OOM [{0}]",
e, action);
+              }
+            }
+          }
+        }
+        _lastIndex = _gcInfo.getIndex();
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  private Object getGcInfo(GarbageCollectorMXBean bean) throws Exception {
+    return _method.invoke(bean, new Object[] {});
+  }
+
+  static class GcInfo {
+
+    private Object _gcInfo;
+    private final Field _startTimeField;
+    private final Field _endTimeField;
+    private final Field _usageAfterGcField;
+    private final Field _usageBeforeGcField;
+    private final Field _indexField;
+
+    GcInfo(Object o) throws SecurityException, NoSuchFieldException {
+      Class<? extends Object> clazz = o.getClass();
+      _startTimeField = setup(clazz.getDeclaredField("startTime"));
+      _endTimeField = setup(clazz.getDeclaredField("endTime"));
+      _usageAfterGcField = setup(clazz.getDeclaredField("usageAfterGc"));
+      _usageBeforeGcField = setup(clazz.getDeclaredField("usageBeforeGc"));
+      _indexField = setup(clazz.getDeclaredField("index"));
+      setGcInfo(o);
+    }
+
+    void setGcInfo(Object o) {
+      _gcInfo = o;
+    }
+
+    private Field setup(Field field) {
+      field.setAccessible(true);
+      return field;
+    }
+
+    long getStartTime() {
+      try {
+        return _startTimeField.getLong(_gcInfo);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    long getEndTime() {
+      try {
+        return _endTimeField.getLong(_gcInfo);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    long getIndex() {
+      try {
+        return _indexField.getLong(_gcInfo);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    @SuppressWarnings("unchecked")
+    Map<String, MemoryUsage> getUsageAfterGc() {
+      try {
+        return (Map<String, MemoryUsage>) _usageAfterGcField.get(_gcInfo);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    @SuppressWarnings("unchecked")
+    Map<String, MemoryUsage> getUsageBeforeGc() {
+      try {
+        return (Map<String, MemoryUsage>) _usageBeforeGcField.get(_gcInfo);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+  }
+
+  public synchronized static void init(double ratio) {
+    if (_instance == null) {
+      try {
+        _instance = new GCWatcherJdk6(ratio);
+      } catch (Exception e) {
+        LOG.error("GCWatcher had error initializing", e);
+      }
+    } else {
+      LOG.warn("GCWatcher has already been initialized");
+    }
+  }
+
+  private static GCWatcherJdk6 instance() {
+    return _instance;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/42c98338/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk7.java
----------------------------------------------------------------------
diff --git a/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk7.java b/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk7.java
new file mode 100644
index 0000000..b9de5a4
--- /dev/null
+++ b/blur-core/src/main/java/org/apache/blur/utils/GCWatcherJdk7.java
@@ -0,0 +1,162 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.blur.utils;
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+
+import org.apache.blur.log.Log;
+import org.apache.blur.log.LogFactory;
+
+import com.sun.management.GcInfo;
+
+public class GCWatcherJdk7 {
+
+  private static final Log LOG = LogFactory.getLog(GCWatcherJdk7.class);
+  private static final String GET_LAST_GC_INFO = "getLastGcInfo";
+  private static GCWatcherJdk7 _instance;
+
+  private final MemoryMXBean _memoryMXBean;
+  private final double _ratio;
+  private final List<GCAction> _actions = new ArrayList<GCAction>();
+
+  private GCWatcherJdk7(double ratio) {
+    _memoryMXBean = ManagementFactory.getMemoryMXBean();
+    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
+    for (GarbageCollectorMXBean bean : garbageCollectorMXBeans) {
+      NotificationListener listener = new NotificationListener() {
+        @Override
+        public void handleNotification(Notification notification, Object bean) {
+          GarbageCollectorMXBean garbageCollectorMXBean = (GarbageCollectorMXBean) bean;
+          GcInfo gcInfo = getGcInfo(garbageCollectorMXBean);
+          long startTime = gcInfo.getStartTime();
+          long endTime = gcInfo.getEndTime();
+          Map<String, MemoryUsage> usageBeforeGc = gcInfo.getMemoryUsageBeforeGc();
+          Map<String, MemoryUsage> usageAfterGc = gcInfo.getMemoryUsageAfterGc();
+          long usedBefore = getTotal(usageBeforeGc);
+          long usedAfter = getTotal(usageAfterGc);
+          long totalTime = endTime - startTime;
+
+          LOG.info("GC event totalTime spent in GC [{0} ms] collected [{1} bytes]", totalTime,
(usedBefore - usedAfter));
+
+          MemoryUsage heapMemoryUsage = _memoryMXBean.getHeapMemoryUsage();
+          long max = heapMemoryUsage.getMax();
+          long used = heapMemoryUsage.getUsed();
+          long upperLimit = (long) (max * _ratio);
+          if (used > upperLimit) {
+            LOG.error("----- WARNING !!!! - Heap used [{0}] over limit of [{1}], taking action
to avoid an OOM error.",
+                used, upperLimit);
+            takeAction();
+          }
+        }
+
+        private void takeAction() {
+          synchronized (_actions) {
+            for (GCAction action : _actions) {
+              try {
+                action.takeAction();
+              } catch (Exception e) {
+                LOG.error("Unknown error while trying to take action against an OOM [{0}]",
e, action);
+              }
+            }
+          }
+        }
+
+        private long getTotal(Map<String, MemoryUsage> memoryUsage) {
+          long used = 0;
+          for (Entry<String, MemoryUsage> e : memoryUsage.entrySet()) {
+            used += e.getValue().getUsed();
+          }
+          return used;
+        }
+      };
+
+      NotificationFilter filter = new NotificationFilter() {
+        private static final long serialVersionUID = 2971450191223596323L;
+
+        @Override
+        public boolean isNotificationEnabled(Notification notification) {
+          return true;
+        }
+      };
+
+      Method method;
+      try {
+        method = bean.getClass().getMethod("addNotificationListener",
+            new Class[] { NotificationListener.class, NotificationFilter.class, Object.class
});
+        method.setAccessible(true);
+        method.invoke(bean, new Object[] { listener, filter, bean });
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+
+    }
+    _ratio = ratio;
+    LOG.info("GCWatcherJdk7 was setup.");
+  }
+
+  public static synchronized void init(double ratio) {
+    if (_instance == null) {
+      try {
+        _instance = new GCWatcherJdk7(ratio);
+      } catch (Exception e) {
+        LOG.error("GCWatcher had error initializing", e);
+      }
+    } else {
+      LOG.warn("GCWatcher has already been initialized");
+    }
+  }
+
+  public static void registerAction(GCAction action) {
+    GCWatcherJdk7 instance = instance();
+    if (instance != null) {
+      synchronized (instance._actions) {
+        instance._actions.add(action);
+      }
+    }
+  }
+
+  public static void shutdown() {
+
+  }
+
+  private static GCWatcherJdk7 instance() {
+    return _instance;
+  }
+
+  private GcInfo getGcInfo(GarbageCollectorMXBean bean) {
+    try {
+      Method method = bean.getClass().getMethod(GET_LAST_GC_INFO, new Class[] {});
+      method.setAccessible(true);
+      return (GcInfo) method.invoke(bean, new Object[] {});
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}


Mime
View raw message