From e46c6d744ad40707335478e539edba1935f8c39a Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Wed, 19 Sep 2007 17:05:42 +0000
Subject: [PATCH] Add a new monitor provider that can be used to monitor memory usage within the JVM, including:

---
 opends/resource/schema/02-config.ldif                                                         |    3 
 opends/src/admin/defn/org/opends/server/admin/std/MemoryUsageMonitorProviderConfiguration.xml |   61 +++++++
 opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java                  |  335 +++++++++++++++++++++++++++++++++++++++++
 opends/resource/config/config.ldif                                                            |   24 ++-
 4 files changed, 415 insertions(+), 8 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index 240ee9e..ba10ec3 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1155,6 +1155,22 @@
 ds-cfg-monitor-provider-class: org.opends.server.monitors.ClientConnectionMonitorProvider
 ds-cfg-monitor-provider-enabled: true
 
+dn: cn=Entry Cache,cn=Monitor Providers,cn=config
+objectClass: top
+objectClass: ds-cfg-monitor-provider
+objectClass: ds-cfg-entry-cache-monitor-provider
+cn: Entry Cache
+ds-cfg-monitor-provider-class: org.opends.server.monitors.EntryCacheMonitorProvider
+ds-cfg-monitor-provider-enabled: true
+
+dn: cn=JVM Memory Usage,cn=Monitor Providers,cn=config
+objectClass: top
+objectClass: ds-cfg-monitor-provider
+objectClass: ds-cfg-memory-usage-monitor-provider
+cn: JVM Memory Usage
+ds-cfg-monitor-provider-class: org.opends.server.monitors.MemoryUsageMonitorProvider
+ds-cfg-monitor-provider-enabled: true
+
 dn: cn=JVM Stack Trace,cn=Monitor Providers,cn=config
 objectClass: top
 objectClass: ds-cfg-monitor-provider
@@ -1179,14 +1195,6 @@
 ds-cfg-monitor-provider-class: org.opends.server.monitors.VersionMonitorProvider
 ds-cfg-monitor-provider-enabled: true
 
-dn: cn=Entry Cache,cn=Monitor Providers,cn=config
-objectClass: top
-objectClass: ds-cfg-monitor-provider
-objectClass: ds-cfg-entry-cache-monitor-provider
-cn: Entry Cache
-ds-cfg-monitor-provider-class: org.opends.server.monitors.EntryCacheMonitorProvider
-ds-cfg-monitor-provider-enabled: true
-
 dn: cn=Password Generators,cn=config
 objectClass: top
 objectClass: ds-cfg-branch
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 5eafa48..816c4dc 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -2509,4 +2509,7 @@
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.173
   NAME 'ds-cfg-entry-cache-monitor-provider' SUP ds-cfg-monitor-provider
   STRUCTURAL X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.174
+  NAME 'ds-cfg-memory-usage-monitor-provider' SUP ds-cfg-monitor-provider
+  STRUCTURAL X-ORIGIN 'OpenDS Directory Server' )
 
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/MemoryUsageMonitorProviderConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/MemoryUsageMonitorProviderConfiguration.xml
new file mode 100644
index 0000000..f44ab07
--- /dev/null
+++ b/opends/src/admin/defn/org/opends/server/admin/std/MemoryUsageMonitorProviderConfiguration.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+! CDDL HEADER START
+!
+! The contents of this file are subject to the terms of the
+! Common Development and Distribution License, Version 1.0 only
+! (the "License").  You may not use this file except in compliance
+! with the License.
+!
+! You can obtain a copy of the license at
+! trunk/opends/resource/legal-notices/OpenDS.LICENSE
+! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+! See the License for the specific language governing permissions
+! and limitations under the License.
+!
+! When distributing Covered Code, include this CDDL HEADER in each
+! file and include the License file at
+! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+! add the following below this CDDL HEADER, with the fields enclosed
+! by brackets "[]" replaced with your own identifying information:
+!      Portions Copyright [yyyy] [name of copyright owner]
+!
+! CDDL HEADER END
+!
+!
+!      Portions Copyright 2007 Sun Microsystems, Inc.
+! -->
+
+<adm:managed-object
+  name="memory-usage-monitor-provider"
+  plural-name="memory-usage-monitor-providers"
+  package="org.opends.server.admin.std"
+  extends="monitor-provider"
+  xmlns:adm="http://www.opends.org/admin"
+  xmlns:ldap="http://www.opends.org/admin-ldap">
+
+  <adm:synopsis>
+    The <adm:user-friendly-name /> may be used to publish information about
+    memory consumption and garbage collection activity in the JVM.
+  </adm:synopsis>
+
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:oid>1.3.6.1.4.1.26027.1.2.174</ldap:oid>
+      <ldap:name>ds-cfg-memory-usage-monitor-provider</ldap:name>
+      <ldap:superior>ds-cfg-monitor-provider</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+
+  <adm:property-override name="monitor-class">
+    <adm:default-behavior>
+      <adm:defined>
+        <adm:value>
+          org.opends.server.monitors.MemoryUsageMonitorProvider
+        </adm:value>
+      </adm:defined>
+    </adm:default-behavior>
+  </adm:property-override>
+
+</adm:managed-object>
+
diff --git a/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java b/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java
new file mode 100644
index 0000000..1b4f419
--- /dev/null
+++ b/opends/src/server/org/opends/server/monitors/MemoryUsageMonitorProvider.java
@@ -0,0 +1,335 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.monitors;
+
+
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+
+import org.opends.server.admin.std.server.MemoryUsageMonitorProviderCfg;
+import org.opends.server.api.MonitorProvider;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.InitializationException;
+
+
+
+/**
+ * This class defines a monitor provider that reports information about
+ * Directory Server memory usage.
+ */
+public class MemoryUsageMonitorProvider
+       extends MonitorProvider<MemoryUsageMonitorProviderCfg>
+{
+  // A map of the last GC counts seen by this monitor for calculating recent
+  // stats.
+  private HashMap<String,Long> lastGCCounts = new HashMap<String,Long>();
+
+  // A map of the last GC times seen by this monitor for calculating recent
+  // stats.
+  private HashMap<String,Long> lastGCTimes = new HashMap<String,Long>();
+
+  // A map of the most recent GC durations seen by this monitor.
+  private HashMap<String,Long> recentGCDurations = new HashMap<String,Long>();
+
+  // A map of the memory manager names to names that are safe for use in
+  // attribute names.
+  private HashMap<String,String> gcSafeNames = new HashMap<String,String>();
+
+
+
+  /**
+   * Initializes this monitor provider.
+   */
+  public MemoryUsageMonitorProvider()
+  {
+    super("JVM Memory Usage Monitor Provider");
+
+    // No initialization should be performed here.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void initializeMonitorProvider(
+                   MemoryUsageMonitorProviderCfg configuration)
+         throws ConfigException, InitializationException
+  {
+    // No initialization is required.
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public String getMonitorInstanceName()
+  {
+    return "JVM Memory Usage";
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public long getUpdateInterval()
+  {
+    // Update the information once every second.
+    return 1000;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public void updateMonitorData()
+  {
+    for (GarbageCollectorMXBean gc :
+         ManagementFactory.getGarbageCollectorMXBeans())
+    {
+      String gcName  = gc.getName();
+      long   gcCount = gc.getCollectionCount();
+      long   gcTime  = gc.getCollectionTime();
+
+      long lastGCCount      = 0L;
+      long lastGCTime       = 0L;
+      long recentGCDuration = 0L;
+      if (lastGCCounts.containsKey(gcName))
+      {
+        lastGCCount      = lastGCCounts.get(gcName);
+        lastGCTime       = lastGCTimes.get(gcName);
+        recentGCDuration = recentGCDurations.get(gcName);
+      }
+
+      if (gcCount > lastGCCount)
+      {
+        long recentGCCount = gcCount - lastGCCount;
+        long recentGCTime  = gcTime  - lastGCTime;
+        recentGCDuration   = (recentGCTime / recentGCCount);
+      }
+
+      lastGCCounts.put(gcName, gcCount);
+      lastGCTimes.put(gcName, gcTime);
+      recentGCDurations.put(gcName, recentGCDuration);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public ArrayList<Attribute> getMonitorData()
+  {
+    ArrayList<Attribute> attrs = new ArrayList<Attribute>();
+
+    for (GarbageCollectorMXBean gc :
+         ManagementFactory.getGarbageCollectorMXBeans())
+    {
+      String gcName  = gc.getName();
+      long   gcCount = gc.getCollectionCount();
+      long   gcTime  = gc.getCollectionTime();
+
+      long avgGCDuration = 0L;
+      if (gcCount > 0)
+      {
+        avgGCDuration = gcTime / gcCount;
+      }
+
+      long recentGCDuration = 0L;
+      if (recentGCDurations.containsKey(gcName))
+      {
+        recentGCDuration = recentGCDurations.get(gcName);
+      }
+
+      String safeName = gcSafeNames.get(gcName);
+      if (safeName == null)
+      {
+        safeName = generateSafeName(gcName);
+        gcSafeNames.put(gcName, safeName);
+      }
+
+      attrs.add(createAttribute(safeName + "-total-collection-count",
+                                String.valueOf(gcCount)));
+      attrs.add(createAttribute(safeName + "-total-collection-duration",
+                                String.valueOf(gcTime)));
+      attrs.add(createAttribute(safeName + "-average-collection-duration",
+                                String.valueOf(avgGCDuration)));
+      attrs.add(createAttribute(safeName + "-recent-collection-duration",
+                                String.valueOf(recentGCDuration)));
+    }
+
+    for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans())
+    {
+      String      poolName        = mp.getName();
+      MemoryUsage currentUsage    = mp.getUsage();
+      MemoryUsage collectionUsage = mp.getCollectionUsage();
+
+      String safeName = gcSafeNames.get(poolName);
+      if (safeName == null)
+      {
+        safeName = generateSafeName(poolName);
+        gcSafeNames.put(poolName, safeName);
+      }
+
+      if (currentUsage == null)
+      {
+        attrs.add(createAttribute(safeName + "-current-bytes-used", "0"));
+      }
+      else
+      {
+        attrs.add(createAttribute(safeName + "-current-bytes-used",
+                                  String.valueOf(currentUsage.getUsed())));
+      }
+
+      if (collectionUsage == null)
+      {
+        attrs.add(createAttribute(safeName +
+                                       "-bytes-used-after-last-collection",
+                                  "0"));
+      }
+      else
+      {
+        attrs.add(createAttribute(safeName +
+                                       "-bytes-used-after-last-collection",
+                                  String.valueOf(collectionUsage.getUsed())));
+      }
+    }
+
+    return attrs;
+  }
+
+
+
+  /**
+   * Constructs an attribute using the provided information.  It will have the
+   * default syntax.
+   *
+   * @param  name   The name to use for the attribute.
+   * @param  value  The value to use for the attribute.
+   *
+   * @return  The attribute created from the provided information.
+   */
+  private Attribute createAttribute(String name, String value)
+  {
+    AttributeType attrType = DirectoryServer.getDefaultAttributeType(name);
+
+    ASN1OctetString encodedValue = new ASN1OctetString(value);
+    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
+
+    try
+    {
+      values.add(new AttributeValue(encodedValue,
+                                    attrType.normalize(encodedValue)));
+    }
+    catch (Exception e)
+    {
+      values.add(new AttributeValue(encodedValue, encodedValue));
+    }
+
+    return new Attribute(attrType, name, values);
+  }
+
+
+
+  /**
+   * Creates a "safe" version of the provided name, which is acceptable for
+   * use as part of an attribute name.
+   *
+   * @param  name  The name for which to obtain the safe name.
+   *
+   * @return  The calculated safe name.
+   */
+  private String generateSafeName(String name)
+  {
+    StringBuilder buffer = new StringBuilder();
+    boolean lastWasUppercase = false;
+    boolean lastWasDash      = false;
+    for (int i=0; i  < name.length(); i++)
+    {
+      char c = name.charAt(i);
+      if (Character.isLetter(c))
+      {
+        if (Character.isUpperCase(c))
+        {
+          char lowerCaseCharacter = Character.toLowerCase(c);
+          if ((buffer.length() > 0) && (! lastWasUppercase) && (! lastWasDash))
+          {
+            buffer.append('-');
+          }
+
+          buffer.append(lowerCaseCharacter);
+          lastWasUppercase = true;
+          lastWasDash = false;
+        }
+        else
+        {
+          buffer.append(c);
+          lastWasUppercase = false;
+          lastWasDash = false;
+        }
+      }
+      else if (Character.isDigit(c))
+      {
+        buffer.append(c);
+        lastWasUppercase = false;
+        lastWasDash = false;
+      }
+      else if ((c == ' ') || (c == '_') || (c == '-'))
+      {
+        if (! lastWasDash)
+        {
+          buffer.append('-');
+        }
+
+        lastWasUppercase = false;
+        lastWasDash = true;
+      }
+    }
+
+    return buffer.toString();
+  }
+}
+

--
Gitblit v1.10.0