Skip to content

Commit

Permalink
Implemented "Support grizzly-memcached's monitoring features using Gr…
Browse files Browse the repository at this point in the history
…izzly JMX"(eclipse-ee4j#13)

+ Fixed an issue where the previous pool was monitored instead of the newly created pool when the pool was dynamically destroyed and recreated.
+ Remove unused(duplicated) mbean attributes.
  • Loading branch information
carryel committed Oct 2, 2024
1 parent 3003c13 commit d937db8
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -66,7 +66,7 @@ public class BaseObjectPool<K, V> implements ObjectPool<K, V> {
private final boolean disposable;
private final long keepAliveTimeoutInSecs;

private final ConcurrentMap<K, QueuePool<V>> keyedObjectPool = new ConcurrentHashMap<>();
private final ConcurrentMap<K, QueuePool<K, V>> keyedObjectPool = new ConcurrentHashMap<>();
private final ConcurrentMap<V, K> managedActiveObjects = new ConcurrentHashMap<>();
private final AtomicBoolean destroyed = new AtomicBoolean();
private final ScheduledExecutorService scheduledExecutor;
Expand Down Expand Up @@ -110,10 +110,10 @@ public void createAllMinObjects(final K key) throws NoValidObjectException, Time
if (key == null) {
throw new IllegalArgumentException("key must not be null");
}
QueuePool<V> pool = keyedObjectPool.get(key);
QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
final QueuePool<V> newPool = new QueuePool<V>(key.toString(), max);
final QueuePool<V> oldPool = keyedObjectPool.putIfAbsent(key, newPool);
final QueuePool<K, V> newPool = new QueuePool<K, V>(this, key, max);
final QueuePool<K, V> oldPool = keyedObjectPool.putIfAbsent(key, newPool);
pool = oldPool == null ? newPool : oldPool;
}
if (pool.destroyed.get()) {
Expand Down Expand Up @@ -146,7 +146,7 @@ public void removeAllObjects(final K key) {
if (key == null) {
throw new IllegalArgumentException("key must not be null");
}
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
return;
}
Expand All @@ -167,7 +167,7 @@ public void destroy(final K key) throws Exception {
if (key == null) {
throw new IllegalArgumentException("key must not be null");
}
final QueuePool<V> pool = keyedObjectPool.remove(key);
final QueuePool<K, V> pool = keyedObjectPool.remove(key);
if (pool == null) {
return;
}
Expand All @@ -189,10 +189,10 @@ public V borrowObject(final K key, final long timeoutInMillis)
if (key == null) {
throw new IllegalArgumentException("key must not be null");
}
QueuePool<V> pool = keyedObjectPool.get(key);
QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
final QueuePool<V> newPool = new QueuePool<V>(key.toString(), max);
final QueuePool<V> oldPool = keyedObjectPool.putIfAbsent(key, newPool);
final QueuePool<K, V> newPool = new QueuePool<K, V>(this, key, max);
final QueuePool<K, V> oldPool = keyedObjectPool.putIfAbsent(key, newPool);
pool = oldPool == null ? newPool : oldPool;
}
if (pool.destroyed.get()) {
Expand Down Expand Up @@ -270,7 +270,7 @@ public V borrowObject(final K key, final long timeoutInMillis)
return result;
}

private V createIfUnderSpecificSize(final int specificSize, final QueuePool<V> pool, final K key,
private V createIfUnderSpecificSize(final int specificSize, final QueuePool<K, V> pool, final K key,
final boolean validation) throws NoValidObjectException, TimeoutException {
if (destroyed.get()) {
throw new IllegalStateException("pool has already destroyed");
Expand Down Expand Up @@ -337,7 +337,7 @@ public void returnObject(final K key, final V value) {
return;
}
final K managed = managedActiveObjects.remove(value);
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null || managed == null) {
try {
factory.destroyObject(key, value);
Expand Down Expand Up @@ -385,7 +385,7 @@ public void removeObject(K key, V value) {
return;
}
final K managed = managedActiveObjects.remove(value);
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "the pool was not found. managed={0}, key={1}, value={2}", new Object[]{managed, key, value});
Expand Down Expand Up @@ -426,9 +426,9 @@ public void destroy() {
scheduledExecutor.shutdown();
}

for (Map.Entry<K, QueuePool<V>> entry : keyedObjectPool.entrySet()) {
for (Map.Entry<K, QueuePool<K, V>> entry : keyedObjectPool.entrySet()) {
final K key = entry.getKey();
final QueuePool<V> pool = entry.getValue();
final QueuePool<K, V> pool = entry.getValue();
pool.destroyed.compareAndSet(false, true);
clearPool(pool, key);
}
Expand All @@ -444,7 +444,7 @@ public void destroy() {
managedActiveObjects.clear();
}

private void clearPool(final QueuePool<V> pool, final K key) {
private void clearPool(final QueuePool<K, V> pool, final K key) {
if (pool == null || key == null) {
return;
}
Expand All @@ -458,6 +458,16 @@ private void clearPool(final QueuePool<V> pool, final K key) {
}
}

public QueuePool<K, V> getPool(final K key) {
if (destroyed.get()) {
return null;
}
if (key == null) {
return null;
}
return keyedObjectPool.get(key);
}

/**
* {@inheritDoc}
*/
Expand All @@ -469,7 +479,7 @@ public int getPoolSize(final K key) {
if (key == null) {
return -1;
}
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
return -1;
}
Expand All @@ -487,7 +497,7 @@ public int getPeakCount(final K key) {
if (key == null) {
return -1;
}
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
return -1;
}
Expand All @@ -505,7 +515,7 @@ public int getActiveCount(final K key) {
if (key == null) {
return -1;
}
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
return -1;
}
Expand All @@ -523,7 +533,7 @@ public int getIdleCount(final K key) {
if (key == null) {
return -1;
}
final QueuePool<V> pool = keyedObjectPool.get(key);
final QueuePool<K, V> pool = keyedObjectPool.get(key);
if (pool == null) {
return -1;
}
Expand Down Expand Up @@ -612,7 +622,7 @@ public String getKeys() {
return keyedObjectPool.keySet().toString();
}

public Collection<QueuePool<V>> getValues() {
public Collection<QueuePool<K, V>> getValues() {
return keyedObjectPool.values();
}

Expand Down Expand Up @@ -640,11 +650,13 @@ 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.
*/
public static class QueuePool<V> implements MonitoringAware<ObjectPoolProbe> {
public static class QueuePool<K, V> implements MonitoringAware<ObjectPoolProbe> {
private final AtomicInteger poolSizeHint = new AtomicInteger();
private volatile int peakSizeHint = 0;
private final BlockingQueue<V> queue;
private final AtomicBoolean destroyed = new AtomicBoolean();
private final BaseObjectPool<K, V> pool;
private final K key;
private final String name;

private final DefaultMonitoringConfig<ObjectPoolProbe> queuePoolMonitoringConfig =
Expand All @@ -656,14 +668,16 @@ public Object createManagementObject() {
}
};

private QueuePool(final String name, final int max) {
private QueuePool(final BaseObjectPool<K, V> pool, final K key, final int max) {
this.pool = pool;
this.key = key;
this.name = key.toString();
if (max <= 0 || max == Integer.MAX_VALUE) {
queue = new LinkedTransferQueue<>();

} else {
queue = new LinkedBlockingQueue<V>(max);
}
this.name = name;
}

public int getPoolSize() {
Expand Down Expand Up @@ -692,8 +706,7 @@ public String getName() {
}

private Object createJmxManagementObject() {
return MonitoringUtils
.loadJmxObject("org.glassfish.grizzly.memcached.pool.jmx.KeyedObject", this, QueuePool.class);
return new org.glassfish.grizzly.memcached.pool.jmx.KeyedObject<K, V>(pool, key);
}
}

Expand All @@ -711,9 +724,9 @@ public void run() {
return;
}
try {
for (Map.Entry<K, QueuePool<V>> entry : keyedObjectPool.entrySet()) {
for (Map.Entry<K, QueuePool<K, V>> entry : keyedObjectPool.entrySet()) {
final K key = entry.getKey();
final QueuePool<V> pool = entry.getValue();
final QueuePool<K, V> pool = entry.getValue();
if (pool.destroyed.get()) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -71,51 +71,6 @@ public String getPoolType() {
return pool.getClass().getName();
}

/**
* Returns the total number of instances for all keys
*
* @return the total number of instances for all keys managed by this object pool or a negative value if unsupported
*/
@ManagedAttribute(id = "object-pool-total-pool-size")
@Description("The total number of instances for all keys managed by this object pool.")
public int getTotalPoolSize() {
return pool.getTotalPoolSize();
}

/**
* Returns the highest peak number of instances among all keys
*
* @return the highest peak number of instances among all keys managed by this object pool or a negative value if unsupported
*/
@ManagedAttribute(id = "object-pool-highest-peak-count")
@Description("The highest peak number of instances among all keys managed by this object pool.")
public int getHighestPeakCount() {
return pool.getHighestPeakCount();
}

/**
* Returns the total number of instances currently borrowed from but not yet returned to the pool for all keys
*
* @return the total number of instances currently borrowed from but not yet returned to the pool for all keys or a negative value if unsupported
*/
@ManagedAttribute(id = "object-pool-total-active-count")
@Description(
"The total number of instances currently borrowed from but not yet returned to the pool for all keys managed by this object pool.")
public int getTotalActiveCount() {
return pool.getTotalActiveCount();
}

/**
* Returns the total number of instances currently idle in this pool for all keys
*
* @return the total number of instances currently idle in this pool for all keys or a negative value if unsupported
*/
@ManagedAttribute(id = "object-pool-total-idle-count")
@Description("The total number of instances currently idle for all keys managed by this object pool.")
public int getTotalIdleCount() {
return pool.getTotalIdleCount();
}

@ManagedAttribute(id = "object-pool-stat")
public CompositeObjectPoolStat getPoolStat() {
return new CompositeObjectPoolStat(pool.getTotalPoolSize(), pool.getHighestPeakCount(),
Expand Down Expand Up @@ -174,7 +129,7 @@ private void rebuildSubTree() {
keyedObjectJmx.forEach(jmxObj -> mom.deregister(jmxObj));
keyedObjectJmx.clear();

final Collection<org.glassfish.grizzly.memcached.pool.BaseObjectPool.QueuePool<V>> keyedObjects = pool.getValues();
final Collection<org.glassfish.grizzly.memcached.pool.BaseObjectPool.QueuePool<K, V>> keyedObjects = pool.getValues();
keyedObjects.forEach(keyedObj -> {
final Object jmxObj = keyedObj.getMonitoringConfig().createManagementObject();
mom.register(this, jmxObj);
Expand All @@ -183,7 +138,7 @@ private void rebuildSubTree() {
}

@ManagedData(name = "Object Pool Stat")
private static class CompositeObjectPoolStat {
public static class CompositeObjectPoolStat {
@ManagedAttribute(id = "total-pools")
@Description("The total number of instances for all keys managed by this object pool.")
private final int totalPoolSize;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.grizzly.memcached.pool.jmx;

import org.glassfish.gmbal.Description;
Expand All @@ -14,17 +30,25 @@
*/
@ManagedObject
@Description("Keyed object managed in the basic object pool(generally related to network connection)")
public class KeyedObject extends JmxObject {
public class KeyedObject<K, V> extends JmxObject {

private static final CompositeObjectStat INVALID_STAT = new CompositeObjectStat(-1, -1, -1, -1);

private final BaseObjectPool.QueuePool pool;
private final BaseObjectPool<K, V> pool;
private final K key;

public KeyedObject(final BaseObjectPool.QueuePool pool) {
public KeyedObject(final BaseObjectPool<K, V> pool, final K key) {
this.pool = pool;
this.key = key;
}

@Override
public String getJmxName() {
return pool.getName();
final BaseObjectPool.QueuePool<K, V> queuePool = pool.getPool(key);
if (queuePool == null) {
return "(invalid)" + key;
}
return queuePool.getName();
}

@Override
Expand All @@ -43,18 +67,26 @@ protected void onDeregister(GrizzlyJmxManager mom) {
@ManagedAttribute(id = "keyed-object-type")
@Description("The Java type of the keyed object implementation being used.")
public String getKeyedObjectType() {
return pool.getClass().getName();
final BaseObjectPool.QueuePool<K, V> queuePool = pool.getPool(key);
if (queuePool == null) {
return "(invalid)" + BaseObjectPool.QueuePool.class.getName();
}
return queuePool.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());
final BaseObjectPool.QueuePool<K, V> queuePool = pool.getPool(key);
if (queuePool == null) {
return INVALID_STAT;
}
return new CompositeObjectStat(queuePool.getPoolSize(), queuePool.getPeakCount(), queuePool.getActiveCount(),
queuePool.getIdleCount());
}

@ManagedData(name="Object Stat")
private static class CompositeObjectStat {
public 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;
Expand Down
Loading

0 comments on commit d937db8

Please sign in to comment.