diff --git a/src/main/java/org/glassfish/grizzly/memcached/pool/BaseObjectPool.java b/src/main/java/org/glassfish/grizzly/memcached/pool/BaseObjectPool.java index 5f04256..69268b5 100644 --- a/src/main/java/org/glassfish/grizzly/memcached/pool/BaseObjectPool.java +++ b/src/main/java/org/glassfish/grizzly/memcached/pool/BaseObjectPool.java @@ -18,9 +18,11 @@ import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.monitoring.DefaultMonitoringConfig; +import org.glassfish.grizzly.monitoring.MonitoringAware; import org.glassfish.grizzly.monitoring.MonitoringConfig; import org.glassfish.grizzly.monitoring.MonitoringUtils; +import java.util.Collection; import java.util.Map; import java.util.OptionalInt; import java.util.concurrent.BlockingQueue; @@ -110,7 +112,7 @@ public void createAllMinObjects(final K key) throws NoValidObjectException, Time } QueuePool pool = keyedObjectPool.get(key); if (pool == null) { - final QueuePool newPool = new QueuePool(max); + final QueuePool newPool = new QueuePool(key.toString(), max); final QueuePool oldPool = keyedObjectPool.putIfAbsent(key, newPool); pool = oldPool == null ? newPool : oldPool; } @@ -189,7 +191,7 @@ public V borrowObject(final K key, final long timeoutInMillis) } QueuePool pool = keyedObjectPool.get(key); if (pool == null) { - final QueuePool newPool = new QueuePool(max); + final QueuePool newPool = new QueuePool(key.toString(), max); final QueuePool oldPool = keyedObjectPool.putIfAbsent(key, newPool); pool = oldPool == null ? newPool : oldPool; } @@ -610,6 +612,11 @@ public String getKeys() { return keyedObjectPool.keySet().toString(); } + public Collection> getValues() { + return keyedObjectPool.values(); + } + + /** * {@inheritDoc} */ @@ -633,36 +640,61 @@ private Object createJmxManagementObject() { * If this pool has max size(bounded pool), it uses {@link LinkedBlockingQueue}. * Otherwise, this pool uses unbounded queue like {@link LinkedBlockingQueue} for idle objects. */ - private static class QueuePool { + public static class QueuePool implements MonitoringAware { private final AtomicInteger poolSizeHint = new AtomicInteger(); private volatile int peakSizeHint = 0; private final BlockingQueue queue; private final AtomicBoolean destroyed = new AtomicBoolean(); + private final String name; + + private final DefaultMonitoringConfig queuePoolMonitoringConfig = + new DefaultMonitoringConfig(ObjectPoolProbe.class) { - private QueuePool(final int max) { + @Override + public Object createManagementObject() { + return createJmxManagementObject(); + } + }; + + private QueuePool(final String name, final int max) { if (max <= 0 || max == Integer.MAX_VALUE) { queue = new LinkedTransferQueue<>(); } else { queue = new LinkedBlockingQueue(max); } + this.name = name; } - private int getPoolSize() { + public int getPoolSize() { return poolSizeHint.get(); } - private int getPeakCount() { + public int getPeakCount() { return peakSizeHint; } - private int getActiveCount() { + public int getActiveCount() { return poolSizeHint.get() - queue.size(); } - private int getIdleCount() { + public int getIdleCount() { return queue.size(); } + + @Override + public MonitoringConfig getMonitoringConfig() { + return queuePoolMonitoringConfig; + } + + public String getName() { + return name; + } + + private Object createJmxManagementObject() { + return MonitoringUtils + .loadJmxObject("org.glassfish.grizzly.memcached.pool.jmx.KeyedObject", this, QueuePool.class); + } } /** diff --git a/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/BaseObjectPool.java b/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/BaseObjectPool.java index 586e079..0787c50 100644 --- a/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/BaseObjectPool.java +++ b/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/BaseObjectPool.java @@ -25,16 +25,22 @@ import org.glassfish.gmbal.GmbalMBean; import org.glassfish.gmbal.ManagedObject; +import java.util.Collection; +import java.util.HashSet; + /** * JMX managed object for object pool implementations. */ @ManagedObject @Description("Basic object pool with a pool of objects (generally related to network connections) for each key.") -public class BaseObjectPool extends JmxObject { +public class BaseObjectPool extends JmxObject { + + private final org.glassfish.grizzly.memcached.pool.BaseObjectPool pool; - private final org.glassfish.grizzly.memcached.pool.BaseObjectPool pool; + private GrizzlyJmxManager mom; + private final Collection keyedObjectJmx = new HashSet<>(); - public BaseObjectPool(final org.glassfish.grizzly.memcached.pool.BaseObjectPool pool) { + public BaseObjectPool(final org.glassfish.grizzly.memcached.pool.BaseObjectPool pool) { this.pool = pool; } @@ -45,10 +51,13 @@ public String getJmxName() { @Override protected void onRegister(GrizzlyJmxManager mom, GmbalMBean bean) { + this.mom = mom; + rebuildSubTree(); } @Override protected void onDeregister(GrizzlyJmxManager mom) { + this.mom = null; } /** @@ -161,6 +170,18 @@ public String getKeys() { return pool.getKeys(); } + private void rebuildSubTree() { + keyedObjectJmx.forEach(jmxObj -> mom.deregister(jmxObj)); + keyedObjectJmx.clear(); + + final Collection> keyedObjects = pool.getValues(); + keyedObjects.forEach(keyedObj -> { + final Object jmxObj = keyedObj.getMonitoringConfig().createManagementObject(); + mom.register(this, jmxObj); + keyedObjectJmx.add(jmxObj); + }); + } + @ManagedData(name = "Object Pool Stat") private static class CompositeObjectPoolStat { @ManagedAttribute(id = "total-pools") diff --git a/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/KeyedObject.java b/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/KeyedObject.java new file mode 100644 index 0000000..41e0afb --- /dev/null +++ b/src/main/java/org/glassfish/grizzly/memcached/pool/jmx/KeyedObject.java @@ -0,0 +1,81 @@ +package org.glassfish.grizzly.memcached.pool.jmx; + +import org.glassfish.gmbal.Description; +import org.glassfish.gmbal.GmbalMBean; +import org.glassfish.gmbal.ManagedAttribute; +import org.glassfish.gmbal.ManagedData; +import org.glassfish.gmbal.ManagedObject; +import org.glassfish.grizzly.jmxbase.GrizzlyJmxManager; +import org.glassfish.grizzly.memcached.pool.BaseObjectPool; +import org.glassfish.grizzly.monitoring.jmx.JmxObject; + +/** + * JMX managed object for object pool's keyed object implementations. + */ +@ManagedObject +@Description("Keyed object managed in the basic object pool(generally related to network connection)") +public class KeyedObject extends JmxObject { + + private final BaseObjectPool.QueuePool pool; + + public KeyedObject(final BaseObjectPool.QueuePool pool) { + this.pool = pool; + } + + @Override + public String getJmxName() { + return pool.getName(); + } + + @Override + protected void onRegister(GrizzlyJmxManager mom, GmbalMBean bean) { + } + + @Override + protected void onDeregister(GrizzlyJmxManager mom) { + } + + /** + * Returns the Java type of the managed object pool + * + * @return the Java type of the managed object pool. + */ + @ManagedAttribute(id = "keyed-object-type") + @Description("The Java type of the keyed object implementation being used.") + public String getKeyedObjectType() { + return pool.getClass().getName(); + } + + @ManagedAttribute(id = "object-stat") + @Description("The stat of objects in this pool.") + public CompositeObjectStat getObjectStat() { + return new CompositeObjectStat(pool.getPoolSize(), pool.getPeakCount(), pool.getActiveCount(), + pool.getIdleCount()); + } + + @ManagedData(name="Object Stat") + private static class CompositeObjectStat { + @ManagedAttribute(id = "objects") + @Description("The total number of objects currently idle and active in this pool or a negative value if unsupported.") + private final int objectSize; + + @ManagedAttribute(id = "peak") + @Description("The peak number of objects or a negative value if unsupported.") + private final int peakCount; + + @ManagedAttribute(id = "active") + @Description("The number of objects currently borrowed in this pool or a negative value if unsupported.") + private final int activeCount; + + @ManagedAttribute(id = "idle") + @Description("The number of objects currently idle in this pool or a negative value if unsupported.") + private final int idleCount; + + private CompositeObjectStat(int objectSize, int peakCount, int activeCount, int idleCount) { + this.objectSize = objectSize; + this.peakCount = peakCount; + this.activeCount = activeCount; + this.idleCount = idleCount; + } + } +}