You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/09/02 15:11:18 UTC
[tomcat] 01/02: Update internal fork of Commons Pool to 2.11.1
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit fbd85f4cfce632c1e667a295b067dde35a9975b2
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Sep 2 12:27:20 2021 +0100
Update internal fork of Commons Pool to 2.11.1
---
MERGE.txt | 2 +-
.../dbcp/pool2/BaseKeyedPooledObjectFactory.java | 70 +-
.../apache/tomcat/dbcp/pool2/BaseObjectPool.java | 84 +-
.../tomcat/dbcp/pool2/BasePooledObjectFactory.java | 53 +-
java/org/apache/tomcat/dbcp/pool2/DestroyMode.java | 10 +-
.../apache/tomcat/dbcp/pool2/KeyedObjectPool.java | 23 +-
.../dbcp/pool2/KeyedPooledObjectFactory.java | 58 +-
java/org/apache/tomcat/dbcp/pool2/ObjectPool.java | 14 +-
java/org/apache/tomcat/dbcp/pool2/PoolUtils.java | 2360 ++++++++++----------
.../org/apache/tomcat/dbcp/pool2/PooledObject.java | 308 ++-
.../tomcat/dbcp/pool2/PooledObjectFactory.java | 48 +-
.../tomcat/dbcp/pool2/PooledObjectState.java | 28 +-
.../dbcp/pool2/SwallowedExceptionListener.java | 2 +-
java/org/apache/tomcat/dbcp/pool2/TrackedUse.java | 30 +-
.../apache/tomcat/dbcp/pool2/UsageTracking.java | 15 +-
.../tomcat/dbcp/pool2/impl/AbandonedConfig.java | 325 +--
.../dbcp/pool2/impl/BaseGenericObjectPool.java | 2279 +++++++++++--------
.../dbcp/pool2/impl/BaseObjectPoolConfig.java | 906 +++++---
.../apache/tomcat/dbcp/pool2/impl/CallStack.java | 24 +-
.../tomcat/dbcp/pool2/impl/CallStackUtils.java | 2 +-
.../dbcp/pool2/impl/DefaultEvictionPolicy.java | 33 +-
.../dbcp/pool2/impl/DefaultPooledObject.java | 321 +--
.../dbcp/pool2/impl/DefaultPooledObjectInfo.java | 38 +-
.../pool2/impl/DefaultPooledObjectInfoMBean.java | 47 +-
.../tomcat/dbcp/pool2/impl/EvictionConfig.java | 139 +-
.../tomcat/dbcp/pool2/impl/EvictionTimer.java | 206 +-
.../dbcp/pool2/impl/GenericKeyedObjectPool.java | 1910 ++++++++--------
.../pool2/impl/GenericKeyedObjectPoolConfig.java | 102 +-
.../pool2/impl/GenericKeyedObjectPoolMXBean.java | 217 +-
.../tomcat/dbcp/pool2/impl/GenericObjectPool.java | 1197 +++++-----
.../dbcp/pool2/impl/GenericObjectPoolConfig.java | 72 +-
.../dbcp/pool2/impl/GenericObjectPoolMXBean.java | 206 +-
.../pool2/impl/InterruptibleReentrantLock.java | 10 +-
.../dbcp/pool2/impl/LinkedBlockingDeque.java | 1671 +++++++-------
.../tomcat/dbcp/pool2/impl/NoOpCallStack.java | 8 +-
.../tomcat/dbcp/pool2/impl/PoolImplUtils.java | 125 +-
.../dbcp/pool2/impl/PooledSoftReference.java | 39 +-
.../dbcp/pool2/impl/SecurityManagerCallStack.java | 104 +-
.../dbcp/pool2/impl/SoftReferenceObjectPool.java | 396 ++--
.../tomcat/dbcp/pool2/impl/ThrowableCallStack.java | 41 +-
webapps/docs/changelog.xml | 4 +
41 files changed, 7465 insertions(+), 6062 deletions(-)
diff --git a/MERGE.txt b/MERGE.txt
index 73ecd41..4682268 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -62,7 +62,7 @@ Pool2
Sub-tree
src/main/java/org/apache/commons/pool2
The SHA1 ID / tag for the most recent commit to be merged to Tomcat is:
-a38c52529beb04bf0815b7d95fb4a393ea110dee
+rel/commons-pool-2.11.1 (2021-08-17)
DBCP2
Sub-tree
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
index b0f0c34..a9877f1 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
@@ -36,6 +36,21 @@ public abstract class BaseKeyedPooledObjectFactory<K, V> extends BaseObject
implements KeyedPooledObjectFactory<K, V> {
/**
+ * Reinitialize an instance to be returned by the pool.
+ * <p>
+ * The default implementation is a no-op.
+ * </p>
+ *
+ * @param key the key used when selecting the object
+ * @param p a {@code PooledObject} wrapping the instance to be activated
+ */
+ @Override
+ public void activateObject(final K key, final PooledObject<V> p)
+ throws Exception {
+ // The default implementation is a no-op.
+ }
+
+ /**
* Create an instance that can be served by the pool.
*
* @param key the key used when constructing the object
@@ -48,14 +63,19 @@ public abstract class BaseKeyedPooledObjectFactory<K, V> extends BaseObject
throws Exception;
/**
- * Wrap the provided instance with an implementation of
- * {@link PooledObject}.
- *
- * @param value the instance to wrap
+ * Destroy an instance no longer needed by the pool.
+ * <p>
+ * The default implementation is a no-op.
+ * </p>
*
- * @return The provided instance, wrapped by a {@link PooledObject}
+ * @param key the key used when selecting the instance
+ * @param p a {@code PooledObject} wrapping the instance to be destroyed
*/
- public abstract PooledObject<V> wrap(V value);
+ @Override
+ public void destroyObject(final K key, final PooledObject<V> p)
+ throws Exception {
+ // The default implementation is a no-op.
+ }
@Override
public PooledObject<V> makeObject(final K key) throws Exception {
@@ -63,16 +83,16 @@ public abstract class BaseKeyedPooledObjectFactory<K, V> extends BaseObject
}
/**
- * Destroy an instance no longer needed by the pool.
+ * Uninitialize an instance to be returned to the idle object pool.
* <p>
* The default implementation is a no-op.
* </p>
*
- * @param key the key used when selecting the instance
- * @param p a {@code PooledObject} wrapping the instance to be destroyed
+ * @param key the key used when selecting the object
+ * @param p a {@code PooledObject} wrapping the instance to be passivated
*/
@Override
- public void destroyObject(final K key, final PooledObject<V> p)
+ public void passivateObject(final K key, final PooledObject<V> p)
throws Exception {
// The default implementation is a no-op.
}
@@ -93,32 +113,12 @@ public abstract class BaseKeyedPooledObjectFactory<K, V> extends BaseObject
}
/**
- * Reinitialize an instance to be returned by the pool.
- * <p>
- * The default implementation is a no-op.
- * </p>
+ * Wrap the provided instance with an implementation of
+ * {@link PooledObject}.
*
- * @param key the key used when selecting the object
- * @param p a {@code PooledObject} wrapping the instance to be activated
- */
- @Override
- public void activateObject(final K key, final PooledObject<V> p)
- throws Exception {
- // The default implementation is a no-op.
- }
-
- /**
- * Uninitialize an instance to be returned to the idle object pool.
- * <p>
- * The default implementation is a no-op.
- * </p>
+ * @param value the instance to wrap
*
- * @param key the key used when selecting the object
- * @param p a {@code PooledObject} wrapping the instance to be passivated
+ * @return The provided instance, wrapped by a {@link PooledObject}
*/
- @Override
- public void passivateObject(final K key, final PooledObject<V> p)
- throws Exception {
- // The default implementation is a no-op.
- }
+ public abstract PooledObject<V> wrap(V value);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
index d17b494..d8c931c 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
@@ -30,55 +30,45 @@ package org.apache.tomcat.dbcp.pool2;
*/
public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool<T> {
- @Override
- public abstract T borrowObject() throws Exception;
-
- @Override
- public abstract void returnObject(T obj) throws Exception;
-
- @Override
- public abstract void invalidateObject(T obj) throws Exception;
+ private volatile boolean closed;
/**
- * Not supported in this base implementation.
+ * Not supported in this base implementation. Subclasses should override
+ * this behavior.
*
- * @return a negative value.
+ * @throws UnsupportedOperationException if the pool does not implement this
+ * method
*/
@Override
- public int getNumIdle() {
- return -1;
+ public void addObject() throws Exception, UnsupportedOperationException {
+ throw new UnsupportedOperationException();
}
/**
- * Not supported in this base implementation.
+ * Throws an {@code IllegalStateException} when this pool has been
+ * closed.
*
- * @return a negative value.
+ * @throws IllegalStateException when this pool has been closed.
+ *
+ * @see #isClosed()
*/
- @Override
- public int getNumActive() {
- return -1;
+ protected final void assertOpen() throws IllegalStateException {
+ if (isClosed()) {
+ throw new IllegalStateException("Pool not open");
+ }
}
- /**
- * Not supported in this base implementation.
- *
- * @throws UnsupportedOperationException if the pool does not implement this
- * method
- */
@Override
- public void clear() throws Exception, UnsupportedOperationException {
- throw new UnsupportedOperationException();
- }
+ public abstract T borrowObject() throws Exception;
/**
- * Not supported in this base implementation. Subclasses should override
- * this behavior.
+ * Not supported in this base implementation.
*
* @throws UnsupportedOperationException if the pool does not implement this
* method
*/
@Override
- public void addObject() throws Exception, UnsupportedOperationException {
+ public void clear() throws Exception, UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@@ -95,29 +85,39 @@ public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool
}
/**
- * Has this pool instance been closed.
+ * Not supported in this base implementation.
*
- * @return {@code true} when this pool has been closed.
+ * @return a negative value.
*/
- public final boolean isClosed() {
- return closed;
+ @Override
+ public int getNumActive() {
+ return -1;
}
/**
- * Throws an {@code IllegalStateException} when this pool has been
- * closed.
+ * Not supported in this base implementation.
*
- * @throws IllegalStateException when this pool has been closed.
+ * @return a negative value.
+ */
+ @Override
+ public int getNumIdle() {
+ return -1;
+ }
+
+ @Override
+ public abstract void invalidateObject(T obj) throws Exception;
+
+ /**
+ * Has this pool instance been closed.
*
- * @see #isClosed()
+ * @return {@code true} when this pool has been closed.
*/
- protected final void assertOpen() throws IllegalStateException {
- if (isClosed()) {
- throw new IllegalStateException("Pool not open");
- }
+ public final boolean isClosed() {
+ return closed;
}
- private volatile boolean closed = false;
+ @Override
+ public abstract void returnObject(T obj) throws Exception;
@Override
protected void toStringAppendFields(final StringBuilder builder) {
diff --git a/java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java
index 6714324..3a309f4 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BasePooledObjectFactory.java
@@ -31,6 +31,17 @@ package org.apache.tomcat.dbcp.pool2;
* @since 2.0
*/
public abstract class BasePooledObjectFactory<T> extends BaseObject implements PooledObjectFactory<T> {
+
+ /**
+ * No-op.
+ *
+ * @param p ignored
+ */
+ @Override
+ public void activateObject(final PooledObject<T> p) throws Exception {
+ // The default implementation is a no-op.
+ }
+
/**
* Creates an object instance, to be wrapped in a {@link PooledObject}.
* <p>This method <strong>must</strong> support concurrent, multi-threaded
@@ -44,14 +55,15 @@ public abstract class BasePooledObjectFactory<T> extends BaseObject implements P
public abstract T create() throws Exception;
/**
- * Wrap the provided instance with an implementation of
- * {@link PooledObject}.
- *
- * @param obj the instance to wrap
+ * No-op.
*
- * @return The provided instance, wrapped by a {@link PooledObject}
+ * @param p ignored
*/
- public abstract PooledObject<T> wrap(T obj);
+ @Override
+ public void destroyObject(final PooledObject<T> p)
+ throws Exception {
+ // The default implementation is a no-op.
+ }
@Override
public PooledObject<T> makeObject() throws Exception {
@@ -61,16 +73,16 @@ public abstract class BasePooledObjectFactory<T> extends BaseObject implements P
/**
* No-op.
*
- * @param p ignored
+ * @param p ignored
*/
@Override
- public void destroyObject(final PooledObject<T> p)
- throws Exception {
+ public void passivateObject(final PooledObject<T> p)
+ throws Exception {
// The default implementation is a no-op.
}
/**
- * This implementation always returns {@code true}.
+ * Always returns {@code true}.
*
* @param p ignored
*
@@ -82,23 +94,12 @@ public abstract class BasePooledObjectFactory<T> extends BaseObject implements P
}
/**
- * No-op.
+ * Wraps the provided instance with an implementation of
+ * {@link PooledObject}.
*
- * @param p ignored
- */
- @Override
- public void activateObject(final PooledObject<T> p) throws Exception {
- // The default implementation is a no-op.
- }
-
- /**
- * No-op.
+ * @param obj the instance to wrap
*
- * @param p ignored
+ * @return The provided instance, wrapped by a {@link PooledObject}
*/
- @Override
- public void passivateObject(final PooledObject<T> p)
- throws Exception {
- // The default implementation is a no-op.
- }
+ public abstract PooledObject<T> wrap(T obj);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java b/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
index ed8ca47..2b8b683 100644
--- a/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
+++ b/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
@@ -17,14 +17,16 @@
package org.apache.tomcat.dbcp.pool2;
/**
- * Destroy context provided to object factories via destroyObject methods. Values provide information about why the pool
- * is asking for a pooled object to be destroyed.
+ * Destroy context provided to object factories via {@code destroyObject} and {@code invalidateObject} methods. Values
+ * provide information about why the pool is asking for a pooled object to be destroyed.
*
* @since 2.9.0
*/
public enum DestroyMode {
- /** Normal destroy */
+
+ /** Normal destroy. */
NORMAL,
- /** Destroy abandoned object */
+
+ /** Destroy abandoned object. */
ABANDONED
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
index f2712d9..86d638a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
@@ -35,14 +35,14 @@ import java.util.NoSuchElementException;
* <code style="color:#00C">try</code> {
* obj = pool.borrowObject(key);
* <code style="color:#0C0">//...use the object...</code>
- * } <code style="color:#00C">catch</code>(Exception e) {
+ * } <code style="color:#00C">catch</code> (Exception e) {
* <code style="color:#0C0">// invalidate the object</code>
* pool.invalidateObject(key, obj);
* <code style="color:#0C0">// do not return the object to the pool twice</code>
* obj = <code style="color:#00C">null</code>;
* } <code style="color:#00C">finally</code> {
* <code style="color:#0C0">// make sure the object is returned to the pool</code>
- * <code style="color:#00C">if</code>(<code style="color:#00C">null</code> != obj) {
+ * <code style="color:#00C">if</code> (<code style="color:#00C">null</code> != obj) {
* pool.returnObject(key, obj);
* }
* }</pre>
@@ -69,7 +69,7 @@ import java.util.NoSuchElementException;
public interface KeyedObjectPool<K, V> extends Closeable {
/**
- * Create an object using the {@link KeyedPooledObjectFactory factory} or
+ * Creates an object using the {@link KeyedPooledObjectFactory factory} or
* other implementation dependent mechanism, passivate it, and then place it
* in the idle object pool. {@code addObject} is useful for
* "pre-loading" a pool with idle objects (Optional operation).
@@ -136,7 +136,7 @@ public interface KeyedObjectPool<K, V> extends Closeable {
}
/**
- * Obtains an instance from this pool for the specified {@code key}.
+ * Borrows an instance from this pool for the specified {@code key}.
* <p>
* Instances returned from this method will have been either newly created
* with {@link KeyedPooledObjectFactory#makeObject makeObject} or will be
@@ -197,7 +197,7 @@ public interface KeyedObjectPool<K, V> extends Closeable {
void clear(K key) throws Exception, UnsupportedOperationException;
/**
- * Close this pool, and free any resources associated with it.
+ * Closes this pool, and free any resources associated with it.
* <p>
* Calling {@link #addObject addObject} or
* {@link #borrowObject borrowObject} after invoking this method on a pool
@@ -211,7 +211,7 @@ public interface KeyedObjectPool<K, V> extends Closeable {
void close();
/**
- * Returns the total number of instances currently borrowed from this pool but
+ * Gets the total number of instances currently borrowed from this pool but
* not yet returned. Returns a negative value if this information is not
* available.
* @return the total number of instances currently borrowed from this pool but
@@ -220,7 +220,7 @@ public interface KeyedObjectPool<K, V> extends Closeable {
int getNumActive();
/**
- * Returns the number of instances currently borrowed from but not yet
+ * Gets the number of instances currently borrowed from but not yet
* returned to the pool corresponding to the given {@code key}.
* Returns a negative value if this information is not available.
*
@@ -231,14 +231,14 @@ public interface KeyedObjectPool<K, V> extends Closeable {
int getNumActive(K key);
/**
- * Returns the total number of instances currently idle in this pool.
+ * Gets the total number of instances currently idle in this pool.
* Returns a negative value if this information is not available.
* @return the total number of instances currently idle in this pool.
*/
int getNumIdle();
/**
- * Returns the number of instances corresponding to the given
+ * Gets the number of instances corresponding to the given
* {@code key} currently idle in this pool. Returns a negative value if
* this information is not available.
*
@@ -269,7 +269,6 @@ public interface KeyedObjectPool<K, V> extends Closeable {
*/
void invalidateObject(K key, V obj) throws Exception;
-
/**
* Invalidates an object from the pool, using the provided
* {@link DestroyMode}.
@@ -287,12 +286,12 @@ public interface KeyedObjectPool<K, V> extends Closeable {
*
* @param key the key used to obtain the object
* @param obj a {@link #borrowObject borrowed} instance to be returned.
- * @param mode destroy activation context provided to the factory
+ * @param destroyMode destroy activation context provided to the factory
*
* @throws Exception if the instance cannot be invalidated
* @since 2.9.0
*/
- default void invalidateObject(final K key, final V obj, final DestroyMode mode) throws Exception {
+ default void invalidateObject(final K key, final V obj, final DestroyMode destroyMode) throws Exception {
invalidateObject(key, obj);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
index 0a24a47..428155d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
@@ -77,21 +77,20 @@ package org.apache.tomcat.dbcp.pool2;
public interface KeyedPooledObjectFactory<K, V> {
/**
- * Create an instance that can be served by the pool and
- * wrap it in a {@link PooledObject} to be managed by the pool.
+ * Reinitializes an instance to be returned by the pool.
*
- * @param key the key used when constructing the object
+ * @param key the key used when selecting the object
+ * @param p a {@code PooledObject} wrapping the instance to be activated
*
- * @return a {@code PooledObject} wrapping an instance that can
- * be served by the pool.
+ * @throws Exception if there is a problem activating {@code obj},
+ * this exception may be swallowed by the pool.
*
- * @throws Exception if there is a problem creating a new instance,
- * this will be propagated to the code requesting an object.
+ * @see #destroyObject
*/
- PooledObject<V> makeObject(K key) throws Exception;
+ void activateObject(K key, PooledObject<V> p) throws Exception;
/**
- * Destroy an instance no longer needed by the pool.
+ * Destroys an instance no longer needed by the pool.
* <p>
* It is important for implementations of this method to be aware that there
* is no guarantee about what state {@code obj} will be in and the
@@ -114,11 +113,11 @@ public interface KeyedPooledObjectFactory<K, V> {
void destroyObject(K key, PooledObject<V> p) throws Exception;
/**
- * Destroy an instance no longer needed by the pool, using the provided {@link DestroyMode}.
+ * Destroys an instance no longer needed by the pool, using the provided {@link DestroyMode}.
*
* @param key the key used when selecting the instance
* @param p a {@code PooledObject} wrapping the instance to be destroyed
- * @param mode DestroyMode providing context to the factory
+ * @param destroyMode DestroyMode providing context to the factory
*
* @throws Exception should be avoided as it may be swallowed by
* the pool implementation.
@@ -129,45 +128,46 @@ public interface KeyedPooledObjectFactory<K, V> {
* @see DestroyMode
* @since 2.9.0
*/
- default void destroyObject(final K key, final PooledObject<V> p, final DestroyMode mode) throws Exception {
+ default void destroyObject(final K key, final PooledObject<V> p, final DestroyMode destroyMode) throws Exception {
destroyObject(key, p);
}
/**
- * Ensures that the instance is safe to be returned by the pool.
+ * Creates an instance that can be served by the pool and
+ * wrap it in a {@link PooledObject} to be managed by the pool.
*
- * @param key the key used when selecting the object
- * @param p a {@code PooledObject} wrapping the instance to be validated
+ * @param key the key used when constructing the object
*
- * @return {@code false} if {@code obj} is not valid and should
- * be dropped from the pool, {@code true} otherwise.
+ * @return a {@code PooledObject} wrapping an instance that can
+ * be served by the pool.
+ *
+ * @throws Exception if there is a problem creating a new instance,
+ * this will be propagated to the code requesting an object.
*/
- boolean validateObject(K key, PooledObject<V> p);
+ PooledObject<V> makeObject(K key) throws Exception;
/**
- * Reinitialize an instance to be returned by the pool.
+ * Uninitializes an instance to be returned to the idle object pool.
*
* @param key the key used when selecting the object
- * @param p a {@code PooledObject} wrapping the instance to be activated
+ * @param p a {@code PooledObject} wrapping the instance to be passivated
*
- * @throws Exception if there is a problem activating {@code obj},
+ * @throws Exception if there is a problem passivating {@code obj},
* this exception may be swallowed by the pool.
*
* @see #destroyObject
*/
- void activateObject(K key, PooledObject<V> p) throws Exception;
+ void passivateObject(K key, PooledObject<V> p) throws Exception;
/**
- * Uninitialize an instance to be returned to the idle object pool.
+ * Ensures that the instance is safe to be returned by the pool.
*
* @param key the key used when selecting the object
- * @param p a {@code PooledObject} wrapping the instance to be passivated
- *
- * @throws Exception if there is a problem passivating {@code obj},
- * this exception may be swallowed by the pool.
+ * @param p a {@code PooledObject} wrapping the instance to be validated
*
- * @see #destroyObject
+ * @return {@code false} if {@code obj} is not valid and should
+ * be dropped from the pool, {@code true} otherwise.
*/
- void passivateObject(K key, PooledObject<V> p) throws Exception;
+ boolean validateObject(K key, PooledObject<V> p);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
index 426bc96..656b29f 100644
--- a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
@@ -31,14 +31,14 @@ import java.util.NoSuchElementException;
* obj = pool.borrowObject();
* <code style="color:#00C">try</code> {
* <code style="color:#0C0">//...use the object...</code>
- * } <code style="color:#00C">catch</code>(Exception e) {
+ * } <code style="color:#00C">catch</code> (Exception e) {
* <code style="color:#0C0">// invalidate the object</code>
* pool.invalidateObject(obj);
* <code style="color:#0C0">// do not return the object to the pool twice</code>
* obj = <code style="color:#00C">null</code>;
* } <code style="color:#00C">finally</code> {
* <code style="color:#0C0">// make sure the object is returned to the pool</code>
- * <code style="color:#00C">if</code>(<code style="color:#00C">null</code> != obj) {
+ * <code style="color:#00C">if</code> (<code style="color:#00C">null</code> != obj) {
* pool.returnObject(obj);
* }
* }
@@ -92,7 +92,7 @@ public interface ObjectPool<T> extends Closeable {
}
/**
- * Obtains an instance from this pool.
+ * Borrows an instance from this pool.
* <p>
* Instances returned from this method will have been either newly created
* with {@link PooledObjectFactory#makeObject} or will be a previously
@@ -151,14 +151,14 @@ public interface ObjectPool<T> extends Closeable {
void close();
/**
- * Returns the number of instances currently borrowed from this pool. Returns
+ * Gets the number of instances currently borrowed from this pool. Returns
* a negative value if this information is not available.
* @return the number of instances currently borrowed from this pool.
*/
int getNumActive();
/**
- * Returns the number of instances currently idle in this pool. This may be
+ * Gets the number of instances currently idle in this pool. This may be
* considered an approximation of the number of objects that can be
* {@link #borrowObject borrowed} without creating any new instances.
* Returns a negative value if this information is not available.
@@ -198,12 +198,12 @@ public interface ObjectPool<T> extends Closeable {
* </p>
*
* @param obj a {@link #borrowObject borrowed} instance to be disposed.
- * @param mode destroy activation context provided to the factory
+ * @param destroyMode destroy activation context provided to the factory
*
* @throws Exception if the instance cannot be invalidated
* @since 2.9.0
*/
- default void invalidateObject(final T obj, final DestroyMode mode) throws Exception {
+ default void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception {
invalidateObject(obj);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
index 28e9531..d2d304d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
@@ -35,595 +35,274 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
*/
public final class PoolUtils {
- private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
- private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
- static final String MSG_NULL_KEY = "key must not be null.";
- private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
- static final String MSG_NULL_KEYS = "keys must not be null.";
- private static final String MSG_NULL_POOL = "pool must not be null.";
-
/**
- * Timer used to periodically check pools idle object count. Because a
- * {@link Timer} creates a {@link Thread}, an IODH is used.
+ * Encapsulate the logic for when the next poolable object should be
+ * discarded. Each time update is called, the next time to shrink is
+ * recomputed, based on the float factor, number of idle instances in the
+ * pool and high water mark. Float factor is assumed to be between 0 and 1.
+ * Values closer to 1 cause less frequent erosion events. Erosion event
+ * timing also depends on numIdle. When this value is relatively high (close
+ * to previously established high water mark), erosion occurs more
+ * frequently.
*/
- static class TimerHolder {
- static final Timer MIN_IDLE_TIMER = new Timer(true);
- }
+ private static final class ErodingFactor {
+ /** Determines frequency of "erosion" events */
+ private final float factor;
- /**
- * PoolUtils instances should NOT be constructed in standard programming.
- * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
- * This constructor is public to permit tools that require a JavaBean
- * instance to operate.
- */
- public PoolUtils() {
- }
+ /** Time of next shrink event */
+ private transient volatile long nextShrinkMillis;
- /**
- * Should the supplied Throwable be re-thrown (eg if it is an instance of
- * one of the Throwables that should never be swallowed). Used by the pool
- * error handling for operations that throw exceptions that normally need to
- * be ignored.
- *
- * @param t
- * The Throwable to check
- * @throws ThreadDeath
- * if that is passed in
- * @throws VirtualMachineError
- * if that is passed in
- */
- public static void checkRethrow(final Throwable t) {
- if (t instanceof ThreadDeath) {
- throw (ThreadDeath) t;
+ /** High water mark - largest numIdle encountered */
+ private transient volatile int idleHighWaterMark;
+
+ /**
+ * Creates a new ErodingFactor with the given erosion factor.
+ *
+ * @param factor
+ * erosion factor
+ */
+ public ErodingFactor(final float factor) {
+ this.factor = factor;
+ nextShrinkMillis = System.currentTimeMillis() + (long) (900000 * factor); // now + 15 min * factor
+ idleHighWaterMark = 1;
}
- if (t instanceof VirtualMachineError) {
- throw (VirtualMachineError) t;
+
+ /**
+ * Gets the time of the next erosion event.
+ *
+ * @return next shrink time
+ */
+ public long getNextShrink() {
+ return nextShrinkMillis;
}
- // All other instances of Throwable will be silently swallowed
- }
- /**
- * Periodically check the idle object count for the pool. At most one idle
- * object will be added per period. If there is an exception when calling
- * {@link ObjectPool#addObject()} then no more checks will be performed.
- *
- * @param pool
- * the pool to check periodically.
- * @param minIdle
- * if the {@link ObjectPool#getNumIdle()} is less than this then
- * add an idle object.
- * @param period
- * the frequency to check the number of idle objects in a pool,
- * see {@link Timer#schedule(TimerTask, long, long)}.
- * @param <T> the type of objects in the pool
- * @return the {@link TimerTask} that will periodically check the pools idle
- * object count.
- * @throws IllegalArgumentException
- * when {@code pool} is {@code null} or when {@code minIdle} is
- * negative or when {@code period} isn't valid for
- * {@link Timer#schedule(TimerTask, long, long)}
- */
- public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool,
- final int minIdle, final long period)
- throws IllegalArgumentException {
- if (pool == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "ErodingFactor{" + "factor=" + factor +
+ ", idleHighWaterMark=" + idleHighWaterMark + '}';
}
- if (minIdle < 0) {
- throw new IllegalArgumentException(MSG_MIN_IDLE);
+
+ /**
+ * Updates internal state using the supplied time and numIdle.
+ *
+ * @param nowMillis
+ * current time
+ * @param numIdle
+ * number of idle elements in the pool
+ */
+ public void update(final long nowMillis, final int numIdle) {
+ final int idle = Math.max(0, numIdle);
+ idleHighWaterMark = Math.max(idle, idleHighWaterMark);
+ final float maxInterval = 15f;
+ final float minutes = maxInterval +
+ ((1f - maxInterval) / idleHighWaterMark) * idle;
+ nextShrinkMillis = nowMillis + (long) (minutes * 60000f * factor);
}
- final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle);
- getMinIdleTimer().schedule(task, 0L, period);
- return task;
}
-
/**
- * Periodically check the idle object count for the key in the keyedPool. At
- * most one idle object will be added per period. If there is an exception
- * when calling {@link KeyedObjectPool#addObject(Object)} then no more
- * checks for that key will be performed.
+ * Decorates a keyed object pool, adding "eroding" behavior. Based on the
+ * configured erosion factor, objects returning to the pool
+ * may be invalidated instead of being added to idle capacity.
*
- * @param keyedPool
- * the keyedPool to check periodically.
- * @param key
- * the key to check the idle count of.
- * @param minIdle
- * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
- * this then add an idle object.
- * @param period
- * the frequency to check the number of idle objects in a
- * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @return the {@link TimerTask} that will periodically check the pools idle
- * object count.
- * @throws IllegalArgumentException
- * when {@code keyedPool}, {@code key} is {@code null} or
- * when {@code minIdle} is negative or when {@code period} isn't
- * valid for {@link Timer#schedule(TimerTask, long, long)}.
+ * @param <K> object pool key type
+ * @param <V> object pool value type
*/
- public static <K, V> TimerTask checkMinIdle(
- final KeyedObjectPool<K, V> keyedPool, final K key,
- final int minIdle, final long period)
- throws IllegalArgumentException {
- if (keyedPool == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
+ private static class ErodingKeyedObjectPool<K, V> implements
+ KeyedObjectPool<K, V> {
+
+ /** Underlying pool */
+ private final KeyedObjectPool<K, V> keyedPool;
+
+ /** Erosion factor */
+ private final ErodingFactor erodingFactor;
+
+ /**
+ * Creates an ErodingObjectPool wrapping the given pool using the
+ * specified erosion factor.
+ *
+ * @param keyedPool
+ * underlying pool - must not be null
+ * @param erodingFactor
+ * erosion factor - determines the frequency of erosion
+ * events
+ * @see #erodingFactor
+ */
+ protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
+ final ErodingFactor erodingFactor) {
+ if (keyedPool == null) {
+ throw new IllegalArgumentException(
+ MSG_NULL_KEYED_POOL);
+ }
+ this.keyedPool = keyedPool;
+ this.erodingFactor = erodingFactor;
}
- if (key == null) {
- throw new IllegalArgumentException(MSG_NULL_KEY);
+
+ /**
+ * Creates an ErodingObjectPool wrapping the given pool using the
+ * specified erosion factor.
+ *
+ * @param keyedPool
+ * underlying pool
+ * @param factor
+ * erosion factor - determines the frequency of erosion
+ * events
+ * @see #erodingFactor
+ */
+ public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
+ final float factor) {
+ this(keyedPool, new ErodingFactor(factor));
}
- if (minIdle < 0) {
- throw new IllegalArgumentException(MSG_MIN_IDLE);
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addObject(final K key) throws Exception,
+ IllegalStateException, UnsupportedOperationException {
+ keyedPool.addObject(key);
}
- final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>(
- keyedPool, key, minIdle);
- getMinIdleTimer().schedule(task, 0L, period);
- return task;
- }
- /**
- * Periodically check the idle object count for each key in the
- * {@code Collection keys} in the keyedPool. At most one idle object will be
- * added per period.
- *
- * @param keyedPool
- * the keyedPool to check periodically.
- * @param keys
- * a collection of keys to check the idle object count.
- * @param minIdle
- * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
- * this then add an idle object.
- * @param period
- * the frequency to check the number of idle objects in a
- * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @return a {@link Map} of key and {@link TimerTask} pairs that will
- * periodically check the pools idle object count.
- * @throws IllegalArgumentException
- * when {@code keyedPool}, {@code keys}, or any of the values in
- * the collection is {@code null} or when {@code minIdle} is
- * negative or when {@code period} isn't valid for
- * {@link Timer#schedule(TimerTask, long, long)}.
- * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
- */
- public static <K, V> Map<K, TimerTask> checkMinIdle(
- final KeyedObjectPool<K, V> keyedPool, final Collection<K> keys,
- final int minIdle, final long period)
- throws IllegalArgumentException {
- if (keys == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYS);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V borrowObject(final K key) throws Exception,
+ NoSuchElementException, IllegalStateException {
+ return keyedPool.borrowObject(key);
}
- final Map<K, TimerTask> tasks = new HashMap<>(keys.size());
- for (K key : keys) {
- final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
- tasks.put(key, task);
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear() throws Exception, UnsupportedOperationException {
+ keyedPool.clear();
}
- return tasks;
- }
- /**
- * Calls {@link ObjectPool#addObject()} on {@code pool} {@code count} number
- * of times.
- *
- * @param pool
- * the pool to prefill.
- * @param count
- * the number of idle objects to add.
- * @param <T> the type of objects in the pool
- * @throws Exception
- * when {@link ObjectPool#addObject()} fails.
- * @throws IllegalArgumentException
- * when {@code pool} is {@code null}.
- * @deprecated Use {@link ObjectPool#addObjects(int)}.
- */
- @Deprecated
- public static <T> void prefill(final ObjectPool<T> pool, final int count)
- throws Exception, IllegalArgumentException {
- if (pool == null) {
- throw new IllegalArgumentException(MSG_NULL_POOL);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear(final K key) throws Exception,
+ UnsupportedOperationException {
+ keyedPool.clear(key);
}
- pool.addObjects(count);
- }
- /**
- * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
- * {@code key} {@code count} number of times.
- *
- * @param keyedPool
- * the keyedPool to prefill.
- * @param key
- * the key to add objects for.
- * @param count
- * the number of idle objects to add for {@code key}.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @throws Exception
- * when {@link KeyedObjectPool#addObject(Object)} fails.
- * @throws IllegalArgumentException
- * when {@code keyedPool} or {@code key} is {@code null}.
- * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
- */
- @Deprecated
- public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
- final K key, final int count) throws Exception,
- IllegalArgumentException {
- if (keyedPool == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() {
+ try {
+ keyedPool.close();
+ } catch (final Exception e) {
+ // swallowed
+ }
}
- keyedPool.addObjects(key, count);
- }
- /**
- * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
- * each key in {@code keys} for {@code count} number of times. This has
- * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)}
- * for each key in the {@code keys} collection.
- *
- * @param keyedPool
- * the keyedPool to prefill.
- * @param keys
- * {@link Collection} of keys to add objects for.
- * @param count
- * the number of idle objects to add for each {@code key}.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @throws Exception
- * when {@link KeyedObjectPool#addObject(Object)} fails.
- * @throws IllegalArgumentException
- * when {@code keyedPool}, {@code keys}, or any value in
- * {@code keys} is {@code null}.
- * @see #prefill(KeyedObjectPool, Object, int)
- * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
- */
- @Deprecated
- public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
- final Collection<K> keys, final int count) throws Exception,
- IllegalArgumentException {
- if (keys == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYS);
+ /**
+ * Gets the eroding factor for the given key
+ *
+ * @param key
+ * key
+ * @return eroding factor for the given keyed pool
+ */
+ protected ErodingFactor getErodingFactor(final K key) {
+ return erodingFactor;
}
- keyedPool.addObjects(keys, count);
- }
- /**
- * Returns a synchronized (thread-safe) ObjectPool backed by the specified
- * ObjectPool.
- * <p>
- * <b>Note:</b> This should not be used on pool implementations that already
- * provide proper synchronization such as the pools provided in the Commons
- * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
- * objects to be returned before allowing another one to be borrowed with
- * another layer of synchronization will cause liveliness issues or a
- * deadlock.
- * </p>
- *
- * @param pool
- * the ObjectPool to be "wrapped" in a synchronized ObjectPool.
- * @param <T> the type of objects in the pool
- * @throws IllegalArgumentException
- * when {@code pool} is {@code null}.
- * @return a synchronized view of the specified ObjectPool.
- */
- public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
- if (pool == null) {
- throw new IllegalArgumentException(MSG_NULL_POOL);
- }
- /*
- * assert !(pool instanceof GenericObjectPool) :
- * "GenericObjectPool is already thread-safe"; assert !(pool instanceof
- * SoftReferenceObjectPool) :
- * "SoftReferenceObjectPool is already thread-safe"; assert !(pool
- * instanceof StackObjectPool) :
- * "StackObjectPool is already thread-safe"; assert
- * !"org.apache.commons.pool.composite.CompositeObjectPool"
- * .equals(pool.getClass().getName()) :
- * "CompositeObjectPools are already thread-safe";
+ /**
+ * Gets the underlying pool
+ *
+ * @return the keyed pool that this ErodingKeyedObjectPool wraps
*/
- return new SynchronizedObjectPool<>(pool);
- }
+ protected KeyedObjectPool<K, V> getKeyedPool() {
+ return keyedPool;
+ }
- /**
- * Returns a synchronized (thread-safe) KeyedObjectPool backed by the
- * specified KeyedObjectPool.
- * <p>
- * <b>Note:</b> This should not be used on pool implementations that already
- * provide proper synchronization such as the pools provided in the Commons
- * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
- * objects to be returned before allowing another one to be borrowed with
- * another layer of synchronization will cause liveliness issues or a
- * deadlock.
- * </p>
- *
- * @param keyedPool
- * the KeyedObjectPool to be "wrapped" in a synchronized
- * KeyedObjectPool.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @return a synchronized view of the specified KeyedObjectPool.
- */
- public static <K, V> KeyedObjectPool<K, V> synchronizedPool(
- final KeyedObjectPool<K, V> keyedPool) {
- /*
- * assert !(keyedPool instanceof GenericKeyedObjectPool) :
- * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool
- * instanceof StackKeyedObjectPool) :
- * "StackKeyedObjectPool is already thread-safe"; assert
- * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool"
- * .equals(keyedPool.getClass().getName()) :
- * "CompositeKeyedObjectPools are already thread-safe";
+ /**
+ * {@inheritDoc}
*/
- return new SynchronizedKeyedObjectPool<>(keyedPool);
- }
+ @Override
+ public int getNumActive() {
+ return keyedPool.getNumActive();
+ }
- /**
- * Returns a synchronized (thread-safe) PooledObjectFactory backed by the
- * specified PooledObjectFactory.
- *
- * @param factory
- * the PooledObjectFactory to be "wrapped" in a synchronized
- * PooledObjectFactory.
- * @param <T> the type of objects in the pool
- * @return a synchronized view of the specified PooledObjectFactory.
- */
- public static <T> PooledObjectFactory<T> synchronizedPooledFactory(
- final PooledObjectFactory<T> factory) {
- return new SynchronizedPooledObjectFactory<>(factory);
- }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getNumActive(final K key) {
+ return keyedPool.getNumActive(key);
+ }
- /**
- * Returns a synchronized (thread-safe) KeyedPooledObjectFactory backed by
- * the specified KeyedPoolableObjectFactory.
- *
- * @param keyedFactory
- * the KeyedPooledObjectFactory to be "wrapped" in a
- * synchronized KeyedPooledObjectFactory.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @return a synchronized view of the specified KeyedPooledObjectFactory.
- */
- public static <K, V> KeyedPooledObjectFactory<K, V> synchronizedKeyedPooledFactory(
- final KeyedPooledObjectFactory<K, V> keyedFactory) {
- return new SynchronizedKeyedPooledObjectFactory<>(keyedFactory);
- }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getNumIdle() {
+ return keyedPool.getNumIdle();
+ }
- /**
- * Returns a pool that adaptively decreases its size when idle objects are
- * no longer needed. This is intended as an always thread-safe alternative
- * to using an idle object evictor provided by many pool implementations.
- * This is also an effective way to shrink FIFO ordered pools that
- * experience load spikes.
- *
- * @param pool
- * the ObjectPool to be decorated so it shrinks its idle count
- * when possible.
- * @param <T> the type of objects in the pool
- * @throws IllegalArgumentException
- * when {@code pool} is {@code null}.
- * @return a pool that adaptively decreases its size when idle objects are
- * no longer needed.
- * @see #erodingPool(ObjectPool, float)
- */
- public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
- return erodingPool(pool, 1f);
- }
-
- /**
- * Returns a pool that adaptively decreases its size when idle objects are
- * no longer needed. This is intended as an always thread-safe alternative
- * to using an idle object evictor provided by many pool implementations.
- * This is also an effective way to shrink FIFO ordered pools that
- * experience load spikes.
- * <p>
- * The factor parameter provides a mechanism to tweak the rate at which the
- * pool tries to shrink its size. Values between 0 and 1 cause the pool to
- * try to shrink its size more often. Values greater than 1 cause the pool
- * to less frequently try to shrink its size.
- * </p>
- *
- * @param pool
- * the ObjectPool to be decorated so it shrinks its idle count
- * when possible.
- * @param factor
- * a positive value to scale the rate at which the pool tries to
- * reduce its size. If 0 < factor < 1 then the pool
- * shrinks more aggressively. If 1 < factor then the pool
- * shrinks less aggressively.
- * @param <T> the type of objects in the pool
- * @throws IllegalArgumentException
- * when {@code pool} is {@code null} or when {@code factor} is
- * not positive.
- * @return a pool that adaptively decreases its size when idle objects are
- * no longer needed.
- * @see #erodingPool(ObjectPool)
- */
- public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
- final float factor) {
- if (pool == null) {
- throw new IllegalArgumentException(MSG_NULL_POOL);
- }
- if (factor <= 0f) {
- throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
- }
- return new ErodingObjectPool<>(pool, factor);
- }
-
- /**
- * Returns a pool that adaptively decreases its size when idle objects are
- * no longer needed. This is intended as an always thread-safe alternative
- * to using an idle object evictor provided by many pool implementations.
- * This is also an effective way to shrink FIFO ordered pools that
- * experience load spikes.
- *
- * @param keyedPool
- * the KeyedObjectPool to be decorated so it shrinks its idle
- * count when possible.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @throws IllegalArgumentException
- * when {@code keyedPool} is {@code null}.
- * @return a pool that adaptively decreases its size when idle objects are
- * no longer needed.
- * @see #erodingPool(KeyedObjectPool, float)
- * @see #erodingPool(KeyedObjectPool, float, boolean)
- */
- public static <K, V> KeyedObjectPool<K, V> erodingPool(
- final KeyedObjectPool<K, V> keyedPool) {
- return erodingPool(keyedPool, 1f);
- }
-
- /**
- * Returns a pool that adaptively decreases its size when idle objects are
- * no longer needed. This is intended as an always thread-safe alternative
- * to using an idle object evictor provided by many pool implementations.
- * This is also an effective way to shrink FIFO ordered pools that
- * experience load spikes.
- * <p>
- * The factor parameter provides a mechanism to tweak the rate at which the
- * pool tries to shrink its size. Values between 0 and 1 cause the pool to
- * try to shrink its size more often. Values greater than 1 cause the pool
- * to less frequently try to shrink its size.
- * </p>
- *
- * @param keyedPool
- * the KeyedObjectPool to be decorated so it shrinks its idle
- * count when possible.
- * @param factor
- * a positive value to scale the rate at which the pool tries to
- * reduce its size. If 0 < factor < 1 then the pool
- * shrinks more aggressively. If 1 < factor then the pool
- * shrinks less aggressively.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @throws IllegalArgumentException
- * when {@code keyedPool} is {@code null} or when {@code factor}
- * is not positive.
- * @return a pool that adaptively decreases its size when idle objects are
- * no longer needed.
- * @see #erodingPool(KeyedObjectPool, float, boolean)
- */
- public static <K, V> KeyedObjectPool<K, V> erodingPool(
- final KeyedObjectPool<K, V> keyedPool, final float factor) {
- return erodingPool(keyedPool, factor, false);
- }
-
- /**
- * Returns a pool that adaptively decreases its size when idle objects are
- * no longer needed. This is intended as an always thread-safe alternative
- * to using an idle object evictor provided by many pool implementations.
- * This is also an effective way to shrink FIFO ordered pools that
- * experience load spikes.
- * <p>
- * The factor parameter provides a mechanism to tweak the rate at which the
- * pool tries to shrink its size. Values between 0 and 1 cause the pool to
- * try to shrink its size more often. Values greater than 1 cause the pool
- * to less frequently try to shrink its size.
- * </p>
- * <p>
- * The perKey parameter determines if the pool shrinks on a whole pool basis
- * or a per key basis. When perKey is false, the keys do not have an effect
- * on the rate at which the pool tries to shrink its size. When perKey is
- * true, each key is shrunk independently.
- * </p>
- *
- * @param keyedPool
- * the KeyedObjectPool to be decorated so it shrinks its idle
- * count when possible.
- * @param factor
- * a positive value to scale the rate at which the pool tries to
- * reduce its size. If 0 < factor < 1 then the pool
- * shrinks more aggressively. If 1 < factor then the pool
- * shrinks less aggressively.
- * @param perKey
- * when true, each key is treated independently.
- * @param <K> the type of the pool key
- * @param <V> the type of pool entries
- * @throws IllegalArgumentException
- * when {@code keyedPool} is {@code null} or when {@code factor}
- * is not positive.
- * @return a pool that adaptively decreases its size when idle objects are
- * no longer needed.
- * @see #erodingPool(KeyedObjectPool)
- * @see #erodingPool(KeyedObjectPool, float)
- */
- public static <K, V> KeyedObjectPool<K, V> erodingPool(
- final KeyedObjectPool<K, V> keyedPool, final float factor,
- final boolean perKey) {
- if (keyedPool == null) {
- throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
- }
- if (factor <= 0f) {
- throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
- }
- if (perKey) {
- return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
- }
- return new ErodingKeyedObjectPool<>(keyedPool, factor);
- }
-
- /**
- * Gets the {@code Timer} for checking keyedPool's idle count.
- *
- * @return the {@link Timer} for checking keyedPool's idle count.
- */
- private static Timer getMinIdleTimer() {
- return TimerHolder.MIN_IDLE_TIMER;
- }
-
- /**
- * Timer task that adds objects to the pool until the number of idle
- * instances reaches the configured minIdle. Note that this is not the same
- * as the pool's minIdle setting.
- *
- * @param <T> type of objects in the pool
- */
- private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask {
-
- /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
- private final int minIdle;
-
- /** Object pool */
- private final ObjectPool<T> pool;
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getNumIdle(final K key) {
+ return keyedPool.getNumIdle(key);
+ }
/**
- * Create a new ObjectPoolMinIdleTimerTask for the given pool with the
- * given minIdle setting.
- *
- * @param pool
- * object pool
- * @param minIdle
- * number of idle instances to maintain
- * @throws IllegalArgumentException
- * if the pool is null
+ * {@inheritDoc}
*/
- ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle)
- throws IllegalArgumentException {
- if (pool == null) {
- throw new IllegalArgumentException(MSG_NULL_POOL);
+ @Override
+ public void invalidateObject(final K key, final V obj) {
+ try {
+ keyedPool.invalidateObject(key, obj);
+ } catch (final Exception e) {
+ // swallowed
}
- this.pool = pool;
- this.minIdle = minIdle;
}
/**
- * {@inheritDoc}
+ * Returns obj to the pool, unless erosion is triggered, in which case
+ * obj is invalidated. Erosion is triggered when there are idle
+ * instances in the pool associated with the given key and more than the
+ * configured {@link #erodingFactor erosion factor} time has elapsed
+ * since the last returnObject activation.
+ *
+ * @param obj
+ * object to return or invalidate
+ * @param key
+ * key
+ * @see #erodingFactor
*/
@Override
- public void run() {
- boolean success = false;
+ public void returnObject(final K key, final V obj) throws Exception {
+ boolean discard = false;
+ final long nowMillis = System.currentTimeMillis();
+ final ErodingFactor factor = getErodingFactor(key);
+ synchronized (keyedPool) {
+ if (factor.getNextShrink() < nowMillis) {
+ final int numIdle = getNumIdle(key);
+ if (numIdle > 0) {
+ discard = true;
+ }
+
+ factor.update(nowMillis, numIdle);
+ }
+ }
try {
- if (pool.getNumIdle() < minIdle) {
- pool.addObject();
+ if (discard) {
+ keyedPool.invalidateObject(key, obj);
+ } else {
+ keyedPool.returnObject(key, obj);
}
- success = true;
-
} catch (final Exception e) {
- cancel();
- } finally {
- // detect other types of Throwable and cancel this Timer
- if (!success) {
- cancel();
- }
+ // swallowed
}
}
@@ -632,28 +311,222 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("ObjectPoolMinIdleTimerTask");
- sb.append("{minIdle=").append(minIdle);
- sb.append(", pool=").append(pool);
- sb.append('}');
- return sb.toString();
+ return "ErodingKeyedObjectPool{" + "factor=" +
+ erodingFactor + ", keyedPool=" + keyedPool + '}';
}
}
-
/**
- * Timer task that adds objects to the pool until the number of idle
- * instances for the given key reaches the configured minIdle. Note that
- * this is not the same as the pool's minIdle setting.
+ * Decorates an object pool, adding "eroding" behavior. Based on the
+ * configured {@link #factor erosion factor}, objects returning to the pool
+ * may be invalidated instead of being added to idle capacity.
*
- * @param <K> object pool key type
- * @param <V> object pool value type
+ * @param <T> type of objects in the pool
*/
- private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends
- TimerTask {
-
- /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
- private final int minIdle;
+ private static class ErodingObjectPool<T> implements ObjectPool<T> {
+
+ /** Underlying object pool */
+ private final ObjectPool<T> pool;
+
+ /** Erosion factor */
+ private final ErodingFactor factor;
+
+ /**
+ * Creates an ErodingObjectPool wrapping the given pool using the
+ * specified erosion factor.
+ *
+ * @param pool
+ * underlying pool
+ * @param factor
+ * erosion factor - determines the frequency of erosion
+ * events
+ * @see #factor
+ */
+ public ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
+ this.pool = pool;
+ this.factor = new ErodingFactor(factor);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addObject() throws Exception, IllegalStateException,
+ UnsupportedOperationException {
+ pool.addObject();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public T borrowObject() throws Exception, NoSuchElementException,
+ IllegalStateException {
+ return pool.borrowObject();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear() throws Exception, UnsupportedOperationException {
+ pool.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() {
+ try {
+ pool.close();
+ } catch (final Exception e) {
+ // swallowed
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getNumActive() {
+ return pool.getNumActive();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getNumIdle() {
+ return pool.getNumIdle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invalidateObject(final T obj) {
+ try {
+ pool.invalidateObject(obj);
+ } catch (final Exception e) {
+ // swallowed
+ }
+ }
+
+ /**
+ * Returns * Gets obj to the pool, unless erosion is triggered, in which case
+ * obj is invalidated. Erosion is triggered when there are idle
+ * instances in the pool and more than the {@link #factor erosion
+ * factor}-determined time has elapsed since the last returnObject
+ * activation.
+ *
+ * @param obj
+ * object to return or invalidate
+ * @see #factor
+ */
+ @Override
+ public void returnObject(final T obj) {
+ boolean discard = false;
+ final long nowMillis = System.currentTimeMillis();
+ synchronized (pool) {
+ if (factor.getNextShrink() < nowMillis) { // XXX: Pool 3: move test
+ // out of sync block
+ final int numIdle = pool.getNumIdle();
+ if (numIdle > 0) {
+ discard = true;
+ }
+
+ factor.update(nowMillis, numIdle);
+ }
+ }
+ try {
+ if (discard) {
+ pool.invalidateObject(obj);
+ } else {
+ pool.returnObject(obj);
+ }
+ } catch (final Exception e) {
+ // swallowed
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
+ pool + '}';
+ }
+ }
+ /**
+ * Extends ErodingKeyedObjectPool to allow erosion to take place on a
+ * per-key basis. Timing of erosion events is tracked separately for
+ * separate keyed pools.
+ *
+ * @param <K> object pool key type
+ * @param <V> object pool value type
+ */
+ private static final class ErodingPerKeyKeyedObjectPool<K, V> extends
+ ErodingKeyedObjectPool<K, V> {
+
+ /** Erosion factor - same for all pools */
+ private final float factor;
+
+ /** Map of ErodingFactor instances keyed on pool keys */
+ private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<>());
+
+ /**
+ * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed
+ * pool with the specified erosion factor.
+ *
+ * @param keyedPool
+ * underlying keyed pool
+ * @param factor
+ * erosion factor
+ */
+ public ErodingPerKeyKeyedObjectPool(
+ final KeyedObjectPool<K, V> keyedPool, final float factor) {
+ super(keyedPool, null);
+ this.factor = factor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ErodingFactor getErodingFactor(final K key) {
+ ErodingFactor eFactor = factors.get(key);
+ // this may result in two ErodingFactors being created for a key
+ // since they are small and cheap this is okay.
+ if (eFactor == null) {
+ eFactor = new ErodingFactor(this.factor);
+ factors.put(key, eFactor);
+ }
+ return eFactor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
+ ", keyedPool=" + getKeyedPool() + '}';
+ }
+ }
+ /**
+ * Timer task that adds objects to the pool until the number of idle
+ * instances for the given key reaches the configured minIdle. Note that
+ * this is not the same as the pool's minIdle setting.
+ *
+ * @param <K> object pool key type
+ * @param <V> object pool value type
+ */
+ private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends
+ TimerTask {
+
+ /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
+ private final int minIdle;
/** Key to ensure minIdle for */
private final K key;
@@ -721,166 +594,60 @@ public final class PoolUtils {
return sb.toString();
}
}
-
/**
- * A synchronized (thread-safe) ObjectPool backed by the specified
- * ObjectPool.
- * <p>
- * <b>Note:</b> This should not be used on pool implementations that already
- * provide proper synchronization such as the pools provided in the Commons
- * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
- * objects to be returned before allowing another one to be borrowed with
- * another layer of synchronization will cause liveliness issues or a
- * deadlock.
- * </p>
+ * Timer task that adds objects to the pool until the number of idle
+ * instances reaches the configured minIdle. Note that this is not the same
+ * as the pool's minIdle setting.
*
* @param <T> type of objects in the pool
*/
- private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
+ private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask {
- /**
- * Object whose monitor is used to synchronize methods on the wrapped
- * pool.
- */
- private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+ /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
+ private final int minIdle;
- /** the underlying object pool */
+ /** Object pool */
private final ObjectPool<T> pool;
/**
- * Creates a new SynchronizedObjectPool wrapping the given pool.
+ * Constructs a new ObjectPoolMinIdleTimerTask for the given pool with the
+ * given minIdle setting.
*
* @param pool
- * the ObjectPool to be "wrapped" in a synchronized
- * ObjectPool.
+ * object pool
+ * @param minIdle
+ * number of idle instances to maintain
* @throws IllegalArgumentException
* if the pool is null
*/
- SynchronizedObjectPool(final ObjectPool<T> pool)
+ ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle)
throws IllegalArgumentException {
if (pool == null) {
throw new IllegalArgumentException(MSG_NULL_POOL);
}
this.pool = pool;
+ this.minIdle = minIdle;
}
/**
* {@inheritDoc}
*/
@Override
- public T borrowObject() throws Exception, NoSuchElementException,
- IllegalStateException {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
+ public void run() {
+ boolean success = false;
try {
- return pool.borrowObject();
+ if (pool.getNumIdle() < minIdle) {
+ pool.addObject();
+ }
+ success = true;
+
+ } catch (final Exception e) {
+ cancel();
} finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void returnObject(final T obj) {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- pool.returnObject(obj);
- } catch (final Exception e) {
- // swallowed as of Pool 2
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void invalidateObject(final T obj) {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- pool.invalidateObject(obj);
- } catch (final Exception e) {
- // swallowed as of Pool 2
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addObject() throws Exception, IllegalStateException,
- UnsupportedOperationException {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- pool.addObject();
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumIdle() {
- final ReadLock readLock = readWriteLock.readLock();
- readLock.lock();
- try {
- return pool.getNumIdle();
- } finally {
- readLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumActive() {
- final ReadLock readLock = readWriteLock.readLock();
- readLock.lock();
- try {
- return pool.getNumActive();
- } finally {
- readLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear() throws Exception, UnsupportedOperationException {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- pool.clear();
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void close() {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- pool.close();
- } catch (final Exception e) {
- // swallowed as of Pool 2
- } finally {
- writeLock.unlock();
+ // detect other types of Throwable and cancel this Timer
+ if (!success) {
+ cancel();
+ }
}
}
@@ -890,8 +657,9 @@ public final class PoolUtils {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- sb.append("SynchronizedObjectPool");
- sb.append("{pool=").append(pool);
+ sb.append("ObjectPoolMinIdleTimerTask");
+ sb.append("{minIdle=").append(minIdle);
+ sb.append(", pool=").append(pool);
sb.append('}');
return sb.toString();
}
@@ -945,6 +713,21 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
+ public void addObject(final K key) throws Exception,
+ IllegalStateException, UnsupportedOperationException {
+ final WriteLock writeLock = readWriteLock.writeLock();
+ writeLock.lock();
+ try {
+ keyedPool.addObject(key);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public V borrowObject(final K key) throws Exception,
NoSuchElementException, IllegalStateException {
final WriteLock writeLock = readWriteLock.writeLock();
@@ -960,13 +743,11 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void returnObject(final K key, final V obj) {
+ public void clear() throws Exception, UnsupportedOperationException {
final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedPool.returnObject(key, obj);
- } catch (final Exception e) {
- // swallowed
+ keyedPool.clear();
} finally {
writeLock.unlock();
}
@@ -976,13 +757,12 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void invalidateObject(final K key, final V obj) {
+ public void clear(final K key) throws Exception,
+ UnsupportedOperationException {
final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedPool.invalidateObject(key, obj);
- } catch (final Exception e) {
- // swallowed as of Pool 2
+ keyedPool.clear(key);
} finally {
writeLock.unlock();
}
@@ -992,12 +772,13 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void addObject(final K key) throws Exception,
- IllegalStateException, UnsupportedOperationException {
+ public void close() {
final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedPool.addObject(key);
+ keyedPool.close();
+ } catch (final Exception e) {
+ // swallowed as of Pool 2
} finally {
writeLock.unlock();
}
@@ -1007,11 +788,11 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public int getNumIdle(final K key) {
+ public int getNumActive() {
final ReadLock readLock = readWriteLock.readLock();
readLock.lock();
try {
- return keyedPool.getNumIdle(key);
+ return keyedPool.getNumActive();
} finally {
readLock.unlock();
}
@@ -1049,11 +830,11 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public int getNumActive() {
+ public int getNumIdle(final K key) {
final ReadLock readLock = readWriteLock.readLock();
readLock.lock();
try {
- return keyedPool.getNumActive();
+ return keyedPool.getNumIdle(key);
} finally {
readLock.unlock();
}
@@ -1063,26 +844,13 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void clear() throws Exception, UnsupportedOperationException {
- final WriteLock writeLock = readWriteLock.writeLock();
- writeLock.lock();
- try {
- keyedPool.clear();
- } finally {
- writeLock.unlock();
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear(final K key) throws Exception,
- UnsupportedOperationException {
+ public void invalidateObject(final K key, final V obj) {
final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedPool.clear(key);
+ keyedPool.invalidateObject(key, obj);
+ } catch (final Exception e) {
+ // swallowed as of Pool 2
} finally {
writeLock.unlock();
}
@@ -1092,13 +860,13 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void close() {
+ public void returnObject(final K key, final V obj) {
final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedPool.close();
+ keyedPool.returnObject(key, obj);
} catch (final Exception e) {
- // swallowed as of Pool 2
+ // swallowed
} finally {
writeLock.unlock();
}
@@ -1118,8 +886,8 @@ public final class PoolUtils {
}
/**
- * A fully synchronized PooledObjectFactory that wraps a
- * PooledObjectFactory and synchronizes access to the wrapped factory
+ * A fully synchronized KeyedPooledObjectFactory that wraps a
+ * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
* methods.
* <p>
* <b>Note:</b> This should not be used on pool implementations that already
@@ -1127,42 +895,45 @@ public final class PoolUtils {
* Pool library.
* </p>
*
- * @param <T> pooled object factory type
+ * @param <K> pooled object factory key type
+ * @param <V> pooled object factory key value
*/
- private static final class SynchronizedPooledObjectFactory<T> implements
- PooledObjectFactory<T> {
+ private static final class SynchronizedKeyedPooledObjectFactory<K, V>
+ implements KeyedPooledObjectFactory<K, V> {
/** Synchronization lock */
private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
/** Wrapped factory */
- private final PooledObjectFactory<T> factory;
+ private final KeyedPooledObjectFactory<K, V> keyedFactory;
/**
- * Creates a SynchronizedPoolableObjectFactory wrapping the given
+ * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
* factory.
*
- * @param factory
+ * @param keyedFactory
* underlying factory to wrap
* @throws IllegalArgumentException
* if the factory is null
*/
- SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
+ SynchronizedKeyedPooledObjectFactory(
+ final KeyedPooledObjectFactory<K, V> keyedFactory)
throws IllegalArgumentException {
- if (factory == null) {
- throw new IllegalArgumentException("factory must not be null.");
+ if (keyedFactory == null) {
+ throw new IllegalArgumentException(
+ "keyedFactory must not be null.");
}
- this.factory = factory;
+ this.keyedFactory = keyedFactory;
}
/**
* {@inheritDoc}
*/
@Override
- public PooledObject<T> makeObject() throws Exception {
+ public void activateObject(final K key, final PooledObject<V> p) throws Exception {
writeLock.lock();
try {
- return factory.makeObject();
+ keyedFactory.activateObject(key, p);
} finally {
writeLock.unlock();
}
@@ -1172,10 +943,10 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void destroyObject(final PooledObject<T> p) throws Exception {
+ public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
writeLock.lock();
try {
- factory.destroyObject(p);
+ keyedFactory.destroyObject(key, p);
} finally {
writeLock.unlock();
}
@@ -1185,10 +956,10 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public boolean validateObject(final PooledObject<T> p) {
+ public PooledObject<V> makeObject(final K key) throws Exception {
writeLock.lock();
try {
- return factory.validateObject(p);
+ return keyedFactory.makeObject(key);
} finally {
writeLock.unlock();
}
@@ -1198,10 +969,10 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void activateObject(final PooledObject<T> p) throws Exception {
+ public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
writeLock.lock();
try {
- factory.activateObject(p);
+ keyedFactory.passivateObject(key, p);
} finally {
writeLock.unlock();
}
@@ -1211,77 +982,80 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void passivateObject(final PooledObject<T> p) throws Exception {
- writeLock.lock();
- try {
- factory.passivateObject(p);
- } finally {
- writeLock.unlock();
- }
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SynchronizedKeyedPoolableObjectFactory");
+ sb.append("{keyedFactory=").append(keyedFactory);
+ sb.append('}');
+ return sb.toString();
}
/**
* {@inheritDoc}
*/
@Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("SynchronizedPoolableObjectFactory");
- sb.append("{factory=").append(factory);
- sb.append('}');
- return sb.toString();
+ public boolean validateObject(final K key, final PooledObject<V> p) {
+ writeLock.lock();
+ try {
+ return keyedFactory.validateObject(key, p);
+ } finally {
+ writeLock.unlock();
+ }
}
}
/**
- * A fully synchronized KeyedPooledObjectFactory that wraps a
- * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
- * methods.
+ * A synchronized (thread-safe) ObjectPool backed by the specified
+ * ObjectPool.
* <p>
* <b>Note:</b> This should not be used on pool implementations that already
* provide proper synchronization such as the pools provided in the Commons
- * Pool library.
+ * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
+ * objects to be returned before allowing another one to be borrowed with
+ * another layer of synchronization will cause liveliness issues or a
+ * deadlock.
* </p>
*
- * @param <K> pooled object factory key type
- * @param <V> pooled object factory key value
+ * @param <T> type of objects in the pool
*/
- private static final class SynchronizedKeyedPooledObjectFactory<K, V>
- implements KeyedPooledObjectFactory<K, V> {
+ private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
- /** Synchronization lock */
- private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
+ /**
+ * Object whose monitor is used to synchronize methods on the wrapped
+ * pool.
+ */
+ private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
- /** Wrapped factory */
- private final KeyedPooledObjectFactory<K, V> keyedFactory;
+ /** the underlying object pool */
+ private final ObjectPool<T> pool;
/**
- * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
- * factory.
+ * Creates a new SynchronizedObjectPool wrapping the given pool.
*
- * @param keyedFactory
- * underlying factory to wrap
+ * @param pool
+ * the ObjectPool to be "wrapped" in a synchronized
+ * ObjectPool.
* @throws IllegalArgumentException
- * if the factory is null
+ * if the pool is null
*/
- SynchronizedKeyedPooledObjectFactory(
- final KeyedPooledObjectFactory<K, V> keyedFactory)
+ SynchronizedObjectPool(final ObjectPool<T> pool)
throws IllegalArgumentException {
- if (keyedFactory == null) {
- throw new IllegalArgumentException(
- "keyedFactory must not be null.");
+ if (pool == null) {
+ throw new IllegalArgumentException(MSG_NULL_POOL);
}
- this.keyedFactory = keyedFactory;
+ this.pool = pool;
}
/**
* {@inheritDoc}
*/
@Override
- public PooledObject<V> makeObject(final K key) throws Exception {
+ public void addObject() throws Exception, IllegalStateException,
+ UnsupportedOperationException {
+ final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- return keyedFactory.makeObject(key);
+ pool.addObject();
} finally {
writeLock.unlock();
}
@@ -1291,10 +1065,12 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
+ public T borrowObject() throws Exception, NoSuchElementException,
+ IllegalStateException {
+ final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedFactory.destroyObject(key, p);
+ return pool.borrowObject();
} finally {
writeLock.unlock();
}
@@ -1304,10 +1080,11 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public boolean validateObject(final K key, final PooledObject<V> p) {
+ public void clear() throws Exception, UnsupportedOperationException {
+ final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- return keyedFactory.validateObject(key, p);
+ pool.clear();
} finally {
writeLock.unlock();
}
@@ -1317,10 +1094,13 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void activateObject(final K key, final PooledObject<V> p) throws Exception {
+ public void close() {
+ final WriteLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
- keyedFactory.activateObject(key, p);
+ pool.close();
+ } catch (final Exception e) {
+ // swallowed as of Pool 2
} finally {
writeLock.unlock();
}
@@ -1330,12 +1110,13 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
- writeLock.lock();
+ public int getNumActive() {
+ final ReadLock readLock = readWriteLock.readLock();
+ readLock.lock();
try {
- keyedFactory.passivateObject(key, p);
+ return pool.getNumActive();
} finally {
- writeLock.unlock();
+ readLock.unlock();
}
}
@@ -1343,76 +1124,46 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("SynchronizedKeyedPoolableObjectFactory");
- sb.append("{keyedFactory=").append(keyedFactory);
- sb.append('}');
- return sb.toString();
- }
- }
-
- /**
- * Encapsulate the logic for when the next poolable object should be
- * discarded. Each time update is called, the next time to shrink is
- * recomputed, based on the float factor, number of idle instances in the
- * pool and high water mark. Float factor is assumed to be between 0 and 1.
- * Values closer to 1 cause less frequent erosion events. Erosion event
- * timing also depends on numIdle. When this value is relatively high (close
- * to previously established high water mark), erosion occurs more
- * frequently.
- */
- private static final class ErodingFactor {
- /** Determines frequency of "erosion" events */
- private final float factor;
-
- /** Time of next shrink event */
- private transient volatile long nextShrink;
-
- /** High water mark - largest numIdle encountered */
- private transient volatile int idleHighWaterMark;
-
- /**
- * Creates a new ErodingFactor with the given erosion factor.
- *
- * @param factor
- * erosion factor
- */
- public ErodingFactor(final float factor) {
- this.factor = factor;
- nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now
- // +
- // 15
- // min
- // *
- // factor
- idleHighWaterMark = 1;
+ public int getNumIdle() {
+ final ReadLock readLock = readWriteLock.readLock();
+ readLock.lock();
+ try {
+ return pool.getNumIdle();
+ } finally {
+ readLock.unlock();
+ }
}
/**
- * Updates internal state using the supplied time and numIdle.
- *
- * @param now
- * current time
- * @param numIdle
- * number of idle elements in the pool
+ * {@inheritDoc}
*/
- public void update(final long now, final int numIdle) {
- final int idle = Math.max(0, numIdle);
- idleHighWaterMark = Math.max(idle, idleHighWaterMark);
- final float maxInterval = 15f;
- final float minutes = maxInterval +
- ((1f - maxInterval) / idleHighWaterMark) * idle;
- nextShrink = now + (long) (minutes * 60000f * factor);
+ @Override
+ public void invalidateObject(final T obj) {
+ final WriteLock writeLock = readWriteLock.writeLock();
+ writeLock.lock();
+ try {
+ pool.invalidateObject(obj);
+ } catch (final Exception e) {
+ // swallowed as of Pool 2
+ } finally {
+ writeLock.unlock();
+ }
}
/**
- * Returns the time of the next erosion event.
- *
- * @return next shrink time
+ * {@inheritDoc}
*/
- public long getNextShrink() {
- return nextShrink;
+ @Override
+ public void returnObject(final T obj) {
+ final WriteLock writeLock = readWriteLock.writeLock();
+ writeLock.lock();
+ try {
+ pool.returnObject(obj);
+ } catch (final Exception e) {
+ // swallowed as of Pool 2
+ } finally {
+ writeLock.unlock();
+ }
}
/**
@@ -1420,85 +1171,62 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- return "ErodingFactor{" + "factor=" + factor +
- ", idleHighWaterMark=" + idleHighWaterMark + '}';
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SynchronizedObjectPool");
+ sb.append("{pool=").append(pool);
+ sb.append('}');
+ return sb.toString();
}
}
/**
- * Decorates an object pool, adding "eroding" behavior. Based on the
- * configured {@link #factor erosion factor}, objects returning to the pool
- * may be invalidated instead of being added to idle capacity.
+ * A fully synchronized PooledObjectFactory that wraps a
+ * PooledObjectFactory and synchronizes access to the wrapped factory
+ * methods.
+ * <p>
+ * <b>Note:</b> This should not be used on pool implementations that already
+ * provide proper synchronization such as the pools provided in the Commons
+ * Pool library.
+ * </p>
*
- * @param <T> type of objects in the pool
+ * @param <T> pooled object factory type
*/
- private static class ErodingObjectPool<T> implements ObjectPool<T> {
+ private static final class SynchronizedPooledObjectFactory<T> implements
+ PooledObjectFactory<T> {
- /** Underlying object pool */
- private final ObjectPool<T> pool;
+ /** Synchronization lock */
+ private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
- /** Erosion factor */
- private final ErodingFactor factor;
+ /** Wrapped factory */
+ private final PooledObjectFactory<T> factory;
/**
- * Creates an ErodingObjectPool wrapping the given pool using the
- * specified erosion factor.
+ * Creates a SynchronizedPoolableObjectFactory wrapping the given
+ * factory.
*
- * @param pool
- * underlying pool
- * @param factor
- * erosion factor - determines the frequency of erosion
- * events
- * @see #factor
+ * @param factory
+ * underlying factory to wrap
+ * @throws IllegalArgumentException
+ * if the factory is null
*/
- public ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
- this.pool = pool;
- this.factor = new ErodingFactor(factor);
+ SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
+ throws IllegalArgumentException {
+ if (factory == null) {
+ throw new IllegalArgumentException("factory must not be null.");
+ }
+ this.factory = factory;
}
/**
* {@inheritDoc}
*/
@Override
- public T borrowObject() throws Exception, NoSuchElementException,
- IllegalStateException {
- return pool.borrowObject();
- }
-
- /**
- * Returns obj to the pool, unless erosion is triggered, in which case
- * obj is invalidated. Erosion is triggered when there are idle
- * instances in the pool and more than the {@link #factor erosion
- * factor}-determined time has elapsed since the last returnObject
- * activation.
- *
- * @param obj
- * object to return or invalidate
- * @see #factor
- */
- @Override
- public void returnObject(final T obj) {
- boolean discard = false;
- final long now = System.currentTimeMillis();
- synchronized (pool) {
- if (factor.getNextShrink() < now) { // XXX: Pool 3: move test
- // out of sync block
- final int numIdle = pool.getNumIdle();
- if (numIdle > 0) {
- discard = true;
- }
-
- factor.update(now, numIdle);
- }
- }
+ public void activateObject(final PooledObject<T> p) throws Exception {
+ writeLock.lock();
try {
- if (discard) {
- pool.invalidateObject(obj);
- } else {
- pool.returnObject(obj);
- }
- } catch (final Exception e) {
- // swallowed
+ factory.activateObject(p);
+ } finally {
+ writeLock.unlock();
}
}
@@ -1506,11 +1234,12 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void invalidateObject(final T obj) {
+ public void destroyObject(final PooledObject<T> p) throws Exception {
+ writeLock.lock();
try {
- pool.invalidateObject(obj);
- } catch (final Exception e) {
- // swallowed
+ factory.destroyObject(p);
+ } finally {
+ writeLock.unlock();
}
}
@@ -1518,325 +1247,592 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void addObject() throws Exception, IllegalStateException,
- UnsupportedOperationException {
- pool.addObject();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumIdle() {
- return pool.getNumIdle();
+ public PooledObject<T> makeObject() throws Exception {
+ writeLock.lock();
+ try {
+ return factory.makeObject();
+ } finally {
+ writeLock.unlock();
+ }
}
/**
* {@inheritDoc}
*/
@Override
- public int getNumActive() {
- return pool.getNumActive();
+ public void passivateObject(final PooledObject<T> p) throws Exception {
+ writeLock.lock();
+ try {
+ factory.passivateObject(p);
+ } finally {
+ writeLock.unlock();
+ }
}
/**
* {@inheritDoc}
*/
@Override
- public void clear() throws Exception, UnsupportedOperationException {
- pool.clear();
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("SynchronizedPoolableObjectFactory");
+ sb.append("{factory=").append(factory);
+ sb.append('}');
+ return sb.toString();
}
/**
* {@inheritDoc}
*/
@Override
- public void close() {
+ public boolean validateObject(final PooledObject<T> p) {
+ writeLock.lock();
try {
- pool.close();
- } catch (final Exception e) {
- // swallowed
+ return factory.validateObject(p);
+ } finally {
+ writeLock.unlock();
}
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
- pool + '}';
- }
}
/**
- * Decorates a keyed object pool, adding "eroding" behavior. Based on the
- * configured erosion factor, objects returning to the pool
- * may be invalidated instead of being added to idle capacity.
- *
- * @param <K> object pool key type
- * @param <V> object pool value type
+ * Timer used to periodically check pools idle object count. Because a
+ * {@link Timer} creates a {@link Thread}, an IODH is used.
*/
- private static class ErodingKeyedObjectPool<K, V> implements
- KeyedObjectPool<K, V> {
+ static class TimerHolder {
+ static final Timer MIN_IDLE_TIMER = new Timer(true);
+ }
- /** Underlying pool */
- private final KeyedObjectPool<K, V> keyedPool;
+ private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
- /** Erosion factor */
- private final ErodingFactor erodingFactor;
+ private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
- /**
- * Creates an ErodingObjectPool wrapping the given pool using the
- * specified erosion factor.
- *
- * @param keyedPool
- * underlying pool
- * @param factor
- * erosion factor - determines the frequency of erosion
- * events
- * @see #erodingFactor
- */
- public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
- final float factor) {
- this(keyedPool, new ErodingFactor(factor));
- }
+ static final String MSG_NULL_KEY = "key must not be null.";
- /**
- * Creates an ErodingObjectPool wrapping the given pool using the
- * specified erosion factor.
- *
- * @param keyedPool
- * underlying pool - must not be null
- * @param erodingFactor
- * erosion factor - determines the frequency of erosion
- * events
- * @see #erodingFactor
- */
- protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
- final ErodingFactor erodingFactor) {
- if (keyedPool == null) {
- throw new IllegalArgumentException(
- MSG_NULL_KEYED_POOL);
- }
- this.keyedPool = keyedPool;
- this.erodingFactor = erodingFactor;
- }
+ private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
- /**
- * {@inheritDoc}
- */
- @Override
- public V borrowObject(final K key) throws Exception,
- NoSuchElementException, IllegalStateException {
- return keyedPool.borrowObject(key);
- }
+ static final String MSG_NULL_KEYS = "keys must not be null.";
- /**
- * Returns obj to the pool, unless erosion is triggered, in which case
- * obj is invalidated. Erosion is triggered when there are idle
- * instances in the pool associated with the given key and more than the
- * configured {@link #erodingFactor erosion factor} time has elapsed
- * since the last returnObject activation.
- *
- * @param obj
- * object to return or invalidate
- * @param key
- * key
- * @see #erodingFactor
- */
- @Override
- public void returnObject(final K key, final V obj) throws Exception {
- boolean discard = false;
- final long now = System.currentTimeMillis();
- final ErodingFactor factor = getErodingFactor(key);
- synchronized (keyedPool) {
- if (factor.getNextShrink() < now) {
- final int numIdle = getNumIdle(key);
- if (numIdle > 0) {
- discard = true;
- }
+ private static final String MSG_NULL_POOL = "pool must not be null.";
- factor.update(now, numIdle);
- }
- }
- try {
- if (discard) {
- keyedPool.invalidateObject(key, obj);
- } else {
- keyedPool.returnObject(key, obj);
- }
- } catch (final Exception e) {
- // swallowed
- }
+ /**
+ * Periodically check the idle object count for each key in the
+ * {@code Collection keys} in the keyedPool. At most one idle object will be
+ * added per period.
+ *
+ * @param keyedPool
+ * the keyedPool to check periodically.
+ * @param keys
+ * a collection of keys to check the idle object count.
+ * @param minIdle
+ * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
+ * this then add an idle object.
+ * @param periodMillis
+ * the frequency in milliseconds to check the number of idle objects in a
+ * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @return a {@link Map} of key and {@link TimerTask} pairs that will
+ * periodically check the pools idle object count.
+ * @throws IllegalArgumentException
+ * when {@code keyedPool}, {@code keys}, or any of the values in
+ * the collection is {@code null} or when {@code minIdle} is
+ * negative or when {@code period} isn't valid for
+ * {@link Timer#schedule(TimerTask, long, long)}.
+ * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
+ */
+ public static <K, V> Map<K, TimerTask> checkMinIdle(
+ final KeyedObjectPool<K, V> keyedPool, final Collection<K> keys,
+ final int minIdle, final long periodMillis)
+ throws IllegalArgumentException {
+ if (keys == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYS);
}
-
- /**
- * Returns the eroding factor for the given key
- *
- * @param key
- * key
- * @return eroding factor for the given keyed pool
- */
- protected ErodingFactor getErodingFactor(final K key) {
- return erodingFactor;
+ final Map<K, TimerTask> tasks = new HashMap<>(keys.size());
+ for (K key : keys) {
+ final TimerTask task = checkMinIdle(keyedPool, key, minIdle, periodMillis);
+ tasks.put(key, task);
}
+ return tasks;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void invalidateObject(final K key, final V obj) {
- try {
- keyedPool.invalidateObject(key, obj);
- } catch (final Exception e) {
- // swallowed
- }
+ /**
+ * Periodically check the idle object count for the key in the keyedPool. At
+ * most one idle object will be added per period. If there is an exception
+ * when calling {@link KeyedObjectPool#addObject(Object)} then no more
+ * checks for that key will be performed.
+ *
+ * @param keyedPool
+ * the keyedPool to check periodically.
+ * @param key
+ * the key to check the idle count of.
+ * @param minIdle
+ * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
+ * this then add an idle object.
+ * @param periodMillis
+ * the frequency in milliseconds to check the number of idle objects in a
+ * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @return the {@link TimerTask} that will periodically check the pools idle
+ * object count.
+ * @throws IllegalArgumentException
+ * when {@code keyedPool}, {@code key} is {@code null} or
+ * when {@code minIdle} is negative or when {@code period} isn't
+ * valid for {@link Timer#schedule(TimerTask, long, long)}.
+ */
+ public static <K, V> TimerTask checkMinIdle(
+ final KeyedObjectPool<K, V> keyedPool, final K key,
+ final int minIdle, final long periodMillis)
+ throws IllegalArgumentException {
+ if (keyedPool == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void addObject(final K key) throws Exception,
- IllegalStateException, UnsupportedOperationException {
- keyedPool.addObject(key);
+ if (key == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEY);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumIdle() {
- return keyedPool.getNumIdle();
+ if (minIdle < 0) {
+ throw new IllegalArgumentException(MSG_MIN_IDLE);
}
+ final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>(
+ keyedPool, key, minIdle);
+ getMinIdleTimer().schedule(task, 0L, periodMillis);
+ return task;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumIdle(final K key) {
- return keyedPool.getNumIdle(key);
+ /**
+ * Periodically check the idle object count for the pool. At most one idle
+ * object will be added per period. If there is an exception when calling
+ * {@link ObjectPool#addObject()} then no more checks will be performed.
+ *
+ * @param pool
+ * the pool to check periodically.
+ * @param minIdle
+ * if the {@link ObjectPool#getNumIdle()} is less than this then
+ * add an idle object.
+ * @param periodMillis
+ * the frequency in milliseconds to check the number of idle objects in a pool,
+ * see {@link Timer#schedule(TimerTask, long, long)}.
+ * @param <T> the type of objects in the pool
+ * @return the {@link TimerTask} that will periodically check the pools idle
+ * object count.
+ * @throws IllegalArgumentException
+ * when {@code pool} is {@code null} or when {@code minIdle} is
+ * negative or when {@code period} isn't valid for
+ * {@link Timer#schedule(TimerTask, long, long)}
+ */
+ public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool,
+ final int minIdle, final long periodMillis)
+ throws IllegalArgumentException {
+ if (pool == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumActive() {
- return keyedPool.getNumActive();
+ if (minIdle < 0) {
+ throw new IllegalArgumentException(MSG_MIN_IDLE);
}
+ final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle);
+ getMinIdleTimer().schedule(task, 0L, periodMillis);
+ return task;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public int getNumActive(final K key) {
- return keyedPool.getNumActive(key);
+ /**
+ * Should the supplied Throwable be re-thrown (eg if it is an instance of
+ * one of the Throwables that should never be swallowed). Used by the pool
+ * error handling for operations that throw exceptions that normally need to
+ * be ignored.
+ *
+ * @param t
+ * The Throwable to check
+ * @throws ThreadDeath
+ * if that is passed in
+ * @throws VirtualMachineError
+ * if that is passed in
+ */
+ public static void checkRethrow(final Throwable t) {
+ if (t instanceof ThreadDeath) {
+ throw (ThreadDeath) t;
+ }
+ if (t instanceof VirtualMachineError) {
+ throw (VirtualMachineError) t;
}
+ // All other instances of Throwable will be silently swallowed
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear() throws Exception, UnsupportedOperationException {
- keyedPool.clear();
+ /**
+ * Returns a pool that adaptively decreases its size when idle objects are
+ * no longer needed. This is intended as an always thread-safe alternative
+ * to using an idle object evictor provided by many pool implementations.
+ * This is also an effective way to shrink FIFO ordered pools that
+ * experience load spikes.
+ *
+ * @param keyedPool
+ * the KeyedObjectPool to be decorated so it shrinks its idle
+ * count when possible.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @throws IllegalArgumentException
+ * when {@code keyedPool} is {@code null}.
+ * @return a pool that adaptively decreases its size when idle objects are
+ * no longer needed.
+ * @see #erodingPool(KeyedObjectPool, float)
+ * @see #erodingPool(KeyedObjectPool, float, boolean)
+ */
+ public static <K, V> KeyedObjectPool<K, V> erodingPool(
+ final KeyedObjectPool<K, V> keyedPool) {
+ return erodingPool(keyedPool, 1f);
+ }
+
+ /**
+ * Returns a pool that adaptively decreases its size when idle objects are
+ * no longer needed. This is intended as an always thread-safe alternative
+ * to using an idle object evictor provided by many pool implementations.
+ * This is also an effective way to shrink FIFO ordered pools that
+ * experience load spikes.
+ * <p>
+ * The factor parameter provides a mechanism to tweak the rate at which the
+ * pool tries to shrink its size. Values between 0 and 1 cause the pool to
+ * try to shrink its size more often. Values greater than 1 cause the pool
+ * to less frequently try to shrink its size.
+ * </p>
+ *
+ * @param keyedPool
+ * the KeyedObjectPool to be decorated so it shrinks its idle
+ * count when possible.
+ * @param factor
+ * a positive value to scale the rate at which the pool tries to
+ * reduce its size. If 0 < factor < 1 then the pool
+ * shrinks more aggressively. If 1 < factor then the pool
+ * shrinks less aggressively.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @throws IllegalArgumentException
+ * when {@code keyedPool} is {@code null} or when {@code factor}
+ * is not positive.
+ * @return a pool that adaptively decreases its size when idle objects are
+ * no longer needed.
+ * @see #erodingPool(KeyedObjectPool, float, boolean)
+ */
+ public static <K, V> KeyedObjectPool<K, V> erodingPool(
+ final KeyedObjectPool<K, V> keyedPool, final float factor) {
+ return erodingPool(keyedPool, factor, false);
+ }
+
+ /**
+ * Returns a pool that adaptively decreases its size when idle objects are
+ * no longer needed. This is intended as an always thread-safe alternative
+ * to using an idle object evictor provided by many pool implementations.
+ * This is also an effective way to shrink FIFO ordered pools that
+ * experience load spikes.
+ * <p>
+ * The factor parameter provides a mechanism to tweak the rate at which the
+ * pool tries to shrink its size. Values between 0 and 1 cause the pool to
+ * try to shrink its size more often. Values greater than 1 cause the pool
+ * to less frequently try to shrink its size.
+ * </p>
+ * <p>
+ * The perKey parameter determines if the pool shrinks on a whole pool basis
+ * or a per key basis. When perKey is false, the keys do not have an effect
+ * on the rate at which the pool tries to shrink its size. When perKey is
+ * true, each key is shrunk independently.
+ * </p>
+ *
+ * @param keyedPool
+ * the KeyedObjectPool to be decorated so it shrinks its idle
+ * count when possible.
+ * @param factor
+ * a positive value to scale the rate at which the pool tries to
+ * reduce its size. If 0 < factor < 1 then the pool
+ * shrinks more aggressively. If 1 < factor then the pool
+ * shrinks less aggressively.
+ * @param perKey
+ * when true, each key is treated independently.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @throws IllegalArgumentException
+ * when {@code keyedPool} is {@code null} or when {@code factor}
+ * is not positive.
+ * @return a pool that adaptively decreases its size when idle objects are
+ * no longer needed.
+ * @see #erodingPool(KeyedObjectPool)
+ * @see #erodingPool(KeyedObjectPool, float)
+ */
+ public static <K, V> KeyedObjectPool<K, V> erodingPool(
+ final KeyedObjectPool<K, V> keyedPool, final float factor,
+ final boolean perKey) {
+ if (keyedPool == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
+ if (factor <= 0f) {
+ throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
+ }
+ if (perKey) {
+ return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
+ }
+ return new ErodingKeyedObjectPool<>(keyedPool, factor);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void clear(final K key) throws Exception,
- UnsupportedOperationException {
- keyedPool.clear(key);
+ /**
+ * Returns a pool that adaptively decreases its size when idle objects are
+ * no longer needed. This is intended as an always thread-safe alternative
+ * to using an idle object evictor provided by many pool implementations.
+ * This is also an effective way to shrink FIFO ordered pools that
+ * experience load spikes.
+ *
+ * @param pool
+ * the ObjectPool to be decorated so it shrinks its idle count
+ * when possible.
+ * @param <T> the type of objects in the pool
+ * @throws IllegalArgumentException
+ * when {@code pool} is {@code null}.
+ * @return a pool that adaptively decreases its size when idle objects are
+ * no longer needed.
+ * @see #erodingPool(ObjectPool, float)
+ */
+ public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
+ return erodingPool(pool, 1f);
+ }
+
+ /**
+ * Returns a pool that adaptively decreases its size when idle objects are
+ * no longer needed. This is intended as an always thread-safe alternative
+ * to using an idle object evictor provided by many pool implementations.
+ * This is also an effective way to shrink FIFO ordered pools that
+ * experience load spikes.
+ * <p>
+ * The factor parameter provides a mechanism to tweak the rate at which the
+ * pool tries to shrink its size. Values between 0 and 1 cause the pool to
+ * try to shrink its size more often. Values greater than 1 cause the pool
+ * to less frequently try to shrink its size.
+ * </p>
+ *
+ * @param pool
+ * the ObjectPool to be decorated so it shrinks its idle count
+ * when possible.
+ * @param factor
+ * a positive value to scale the rate at which the pool tries to
+ * reduce its size. If 0 < factor < 1 then the pool
+ * shrinks more aggressively. If 1 < factor then the pool
+ * shrinks less aggressively.
+ * @param <T> the type of objects in the pool
+ * @throws IllegalArgumentException
+ * when {@code pool} is {@code null} or when {@code factor} is
+ * not positive.
+ * @return a pool that adaptively decreases its size when idle objects are
+ * no longer needed.
+ * @see #erodingPool(ObjectPool)
+ */
+ public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
+ final float factor) {
+ if (pool == null) {
+ throw new IllegalArgumentException(MSG_NULL_POOL);
+ }
+ if (factor <= 0f) {
+ throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
}
+ return new ErodingObjectPool<>(pool, factor);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void close() {
- try {
- keyedPool.close();
- } catch (final Exception e) {
- // swallowed
- }
- }
+ /**
+ * Gets the {@code Timer} for checking keyedPool's idle count.
+ *
+ * @return the {@link Timer} for checking keyedPool's idle count.
+ */
+ private static Timer getMinIdleTimer() {
+ return TimerHolder.MIN_IDLE_TIMER;
+ }
- /**
- * Returns the underlying pool
- *
- * @return the keyed pool that this ErodingKeyedObjectPool wraps
- */
- protected KeyedObjectPool<K, V> getKeyedPool() {
- return keyedPool;
+ /**
+ * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
+ * each key in {@code keys} for {@code count} number of times. This has
+ * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)}
+ * for each key in the {@code keys} collection.
+ *
+ * @param keyedPool
+ * the keyedPool to prefill.
+ * @param keys
+ * {@link Collection} of keys to add objects for.
+ * @param count
+ * the number of idle objects to add for each {@code key}.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @throws Exception
+ * when {@link KeyedObjectPool#addObject(Object)} fails.
+ * @throws IllegalArgumentException
+ * when {@code keyedPool}, {@code keys}, or any value in
+ * {@code keys} is {@code null}.
+ * @see #prefill(KeyedObjectPool, Object, int)
+ * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
+ */
+ @Deprecated
+ public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
+ final Collection<K> keys, final int count) throws Exception,
+ IllegalArgumentException {
+ if (keys == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYS);
}
+ keyedPool.addObjects(keys, count);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "ErodingKeyedObjectPool{" + "factor=" +
- erodingFactor + ", keyedPool=" + keyedPool + '}';
+ /**
+ * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
+ * {@code key} {@code count} number of times.
+ *
+ * @param keyedPool
+ * the keyedPool to prefill.
+ * @param key
+ * the key to add objects for.
+ * @param count
+ * the number of idle objects to add for {@code key}.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @throws Exception
+ * when {@link KeyedObjectPool#addObject(Object)} fails.
+ * @throws IllegalArgumentException
+ * when {@code keyedPool} or {@code key} is {@code null}.
+ * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
+ */
+ @Deprecated
+ public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
+ final K key, final int count) throws Exception,
+ IllegalArgumentException {
+ if (keyedPool == null) {
+ throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
+ keyedPool.addObjects(key, count);
}
/**
- * Extends ErodingKeyedObjectPool to allow erosion to take place on a
- * per-key basis. Timing of erosion events is tracked separately for
- * separate keyed pools.
+ * Calls {@link ObjectPool#addObject()} on {@code pool} {@code count} number
+ * of times.
*
- * @param <K> object pool key type
- * @param <V> object pool value type
+ * @param pool
+ * the pool to prefill.
+ * @param count
+ * the number of idle objects to add.
+ * @param <T> the type of objects in the pool
+ * @throws Exception
+ * when {@link ObjectPool#addObject()} fails.
+ * @throws IllegalArgumentException
+ * when {@code pool} is {@code null}.
+ * @deprecated Use {@link ObjectPool#addObjects(int)}.
*/
- private static final class ErodingPerKeyKeyedObjectPool<K, V> extends
- ErodingKeyedObjectPool<K, V> {
-
- /** Erosion factor - same for all pools */
- private final float factor;
+ @Deprecated
+ public static <T> void prefill(final ObjectPool<T> pool, final int count)
+ throws Exception, IllegalArgumentException {
+ if (pool == null) {
+ throw new IllegalArgumentException(MSG_NULL_POOL);
+ }
+ pool.addObjects(count);
+ }
- /** Map of ErodingFactor instances keyed on pool keys */
- private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<K, ErodingFactor>());
+ /**
+ * Returns a synchronized (thread-safe) KeyedPooledObjectFactory backed by
+ * the specified KeyedPoolableObjectFactory.
+ *
+ * @param keyedFactory
+ * the KeyedPooledObjectFactory to be "wrapped" in a
+ * synchronized KeyedPooledObjectFactory.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @return a synchronized view of the specified KeyedPooledObjectFactory.
+ */
+ public static <K, V> KeyedPooledObjectFactory<K, V> synchronizedKeyedPooledFactory(
+ final KeyedPooledObjectFactory<K, V> keyedFactory) {
+ return new SynchronizedKeyedPooledObjectFactory<>(keyedFactory);
+ }
- /**
- * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed
- * pool with the specified erosion factor.
- *
- * @param keyedPool
- * underlying keyed pool
- * @param factor
- * erosion factor
+ /**
+ * Returns a synchronized (thread-safe) KeyedObjectPool backed by the
+ * specified KeyedObjectPool.
+ * <p>
+ * <b>Note:</b> This should not be used on pool implementations that already
+ * provide proper synchronization such as the pools provided in the Commons
+ * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
+ * objects to be returned before allowing another one to be borrowed with
+ * another layer of synchronization will cause liveliness issues or a
+ * deadlock.
+ * </p>
+ *
+ * @param keyedPool
+ * the KeyedObjectPool to be "wrapped" in a synchronized
+ * KeyedObjectPool.
+ * @param <K> the type of the pool key
+ * @param <V> the type of pool entries
+ * @return a synchronized view of the specified KeyedObjectPool.
+ */
+ public static <K, V> KeyedObjectPool<K, V> synchronizedPool(
+ final KeyedObjectPool<K, V> keyedPool) {
+ /*
+ * assert !(keyedPool instanceof GenericKeyedObjectPool) :
+ * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool
+ * instanceof StackKeyedObjectPool) :
+ * "StackKeyedObjectPool is already thread-safe"; assert
+ * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool"
+ * .equals(keyedPool.getClass().getName()) :
+ * "CompositeKeyedObjectPools are already thread-safe";
*/
- public ErodingPerKeyKeyedObjectPool(
- final KeyedObjectPool<K, V> keyedPool, final float factor) {
- super(keyedPool, null);
- this.factor = factor;
- }
+ return new SynchronizedKeyedObjectPool<>(keyedPool);
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- protected ErodingFactor getErodingFactor(final K key) {
- ErodingFactor eFactor = factors.get(key);
- // this may result in two ErodingFactors being created for a key
- // since they are small and cheap this is okay.
- if (eFactor == null) {
- eFactor = new ErodingFactor(this.factor);
- factors.put(key, eFactor);
- }
- return eFactor;
+ /**
+ * Returns a synchronized (thread-safe) ObjectPool backed by the specified
+ * ObjectPool.
+ * <p>
+ * <b>Note:</b> This should not be used on pool implementations that already
+ * provide proper synchronization such as the pools provided in the Commons
+ * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
+ * objects to be returned before allowing another one to be borrowed with
+ * another layer of synchronization will cause liveliness issues or a
+ * deadlock.
+ * </p>
+ *
+ * @param pool
+ * the ObjectPool to be "wrapped" in a synchronized ObjectPool.
+ * @param <T> the type of objects in the pool
+ * @throws IllegalArgumentException
+ * when {@code pool} is {@code null}.
+ * @return a synchronized view of the specified ObjectPool.
+ */
+ public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
+ if (pool == null) {
+ throw new IllegalArgumentException(MSG_NULL_POOL);
}
- /**
- * {@inheritDoc}
+ /*
+ * assert !(pool instanceof GenericObjectPool) :
+ * "GenericObjectPool is already thread-safe"; assert !(pool instanceof
+ * SoftReferenceObjectPool) :
+ * "SoftReferenceObjectPool is already thread-safe"; assert !(pool
+ * instanceof StackObjectPool) :
+ * "StackObjectPool is already thread-safe"; assert
+ * !"org.apache.commons.pool.composite.CompositeObjectPool"
+ * .equals(pool.getClass().getName()) :
+ * "CompositeObjectPools are already thread-safe";
*/
- @Override
- public String toString() {
- return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
- ", keyedPool=" + getKeyedPool() + '}';
- }
+ return new SynchronizedObjectPool<>(pool);
+ }
+
+ /**
+ * Returns a synchronized (thread-safe) PooledObjectFactory backed by the
+ * specified PooledObjectFactory.
+ *
+ * @param factory
+ * the PooledObjectFactory to be "wrapped" in a synchronized
+ * PooledObjectFactory.
+ * @param <T> the type of objects in the pool
+ * @return a synchronized view of the specified PooledObjectFactory.
+ */
+ public static <T> PooledObjectFactory<T> synchronizedPooledFactory(
+ final PooledObjectFactory<T> factory) {
+ return new SynchronizedPooledObjectFactory<>(factory);
+ }
+
+ /**
+ * PoolUtils instances should NOT be constructed in standard programming.
+ * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
+ * This constructor is public to permit tools that require a JavaBean
+ * instance to operate.
+ */
+ public PoolUtils() {
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
index 8901531..69caef2 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
@@ -17,6 +17,8 @@
package org.apache.tomcat.dbcp.pool2;
import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Deque;
/**
@@ -33,34 +35,93 @@ import java.util.Deque;
public interface PooledObject<T> extends Comparable<PooledObject<T>> {
/**
- * Obtains the underlying object that is wrapped by this instance of
- * {@link PooledObject}.
+ * Allocates the object.
*
- * @return The wrapped object
+ * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
*/
- T getObject();
+ boolean allocate();
/**
- * Obtains the time (using the same basis as
- * {@link System#currentTimeMillis()}) that this object was created.
+ * Orders instances based on idle time - i.e. the length of time since the
+ * instance was returned to the pool. Used by the GKOP idle object evictor.
+ *<p>
+ * Note: This class has a natural ordering that is inconsistent with
+ * equals if distinct objects have the same identity hash code.
+ * </p>
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ int compareTo(PooledObject<T> other);
+
+ /**
+ * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
+ * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}.
*
- * @return The creation time for the wrapped object
+ * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}.
*/
- long getCreateTime();
+ boolean deallocate();
+
+ /**
+ * Notifies the object that the eviction test has ended.
+ *
+ * @param idleQueue The queue of idle objects to which the object should be
+ * returned.
+ *
+ * @return Currently not used.
+ */
+ boolean endEvictionTest(Deque<PooledObject<T>> idleQueue);
+
+ @Override
+ boolean equals(Object obj);
+
+ /**
+ * Gets the amount of time this object last spent in the active state (it may still be active in which case
+ * subsequent calls will return an increased value).
+ *
+ * @return The duration last spent in the active state.
+ * @since 2.11.0
+ */
+ default Duration getActiveDuration() {
+ // Take copies to avoid threading issues
+ final Instant lastReturnInstant = getLastReturnInstant();
+ final Instant lastBorrowInstant = getLastBorrowInstant();
+ // @formatter:off
+ return lastReturnInstant.isAfter(lastBorrowInstant) ?
+ Duration.between(lastBorrowInstant, lastReturnInstant) :
+ Duration.between(lastBorrowInstant, Instant.now());
+ // @formatter:on
+ }
+
+ /**
+ * Gets the amount of time this object last spent in the active state (it may still be active in which case
+ * subsequent calls will return an increased value).
+ *
+ * @return The duration last spent in the active state.
+ * @since 2.10.0
+ * @deprecated Use {@link #getActiveDuration()}.
+ */
+ @Deprecated
+ default Duration getActiveTime() {
+ return getActiveDuration();
+ }
/**
- * Obtains the time in milliseconds that this object last spent in the
+ * Gets the amount of time in milliseconds this object last spent in the
* active state (it may still be active in which case subsequent calls will
* return an increased value).
*
- * @return The time in milliseconds last spent in the active state
+ * @return The time in milliseconds last spent in the active state.
+ * @deprecated Use {@link #getActiveTime()} which offers the best precision.
*/
+ @Deprecated
long getActiveTimeMillis();
/**
* Gets the number of times this object has been borrowed.
*
- * @return -1 by default for old implementations prior to release 2.7.0.
+ * @return -1 by default for implementations prior to release 2.7.0.
* @since 2.7.0
*/
default long getBorrowedCount() {
@@ -68,124 +129,192 @@ public interface PooledObject<T> extends Comparable<PooledObject<T>> {
}
/**
- * Obtains the time in milliseconds that this object last spend in the
- * idle state (it may still be idle in which case subsequent calls will
- * return an increased value).
+ * Gets the time (using the same basis as {@link Instant#now()}) that this object was created.
*
- * @return The time in milliseconds last spent in the idle state
+ * @return The creation time for the wrapped object.
+ * @since 2.11.0
*/
- long getIdleTimeMillis();
+ default Instant getCreateInstant() {
+ return Instant.ofEpochMilli(getCreateTime());
+ }
/**
- * Obtains the time the wrapped object was last borrowed.
+ * Gets the time (using the same basis as
+ * {@link System#currentTimeMillis()}) that this object was created.
*
- * @return The time the object was last borrowed
+ * @return The creation time for the wrapped object.
+ * @deprecated Use {@link #getCreateInstant()} which offers the best precision.
*/
- long getLastBorrowTime();
+ @Deprecated
+ long getCreateTime();
/**
- * Obtains the time the wrapped object was last returned.
+ * Computes the duration since this object was created (using {@link Instant#now()}).
*
- * @return The time the object was last returned
+ * @return The duration since this object was created.
+ * @since 2.12.0
*/
- long getLastReturnTime();
+ default Duration getFullDuration() {
+ return Duration.between(getCreateInstant(), Instant.now());
+ }
/**
- * Returns an estimate of the last time this object was used. If the class
- * of the pooled object implements {@link TrackedUse}, what is returned is
- * the maximum of {@link TrackedUse#getLastUsed()} and
- * {@link #getLastBorrowTime()}; otherwise this method gives the same
- * value as {@link #getLastBorrowTime()}.
+ * Gets the amount of time that this object last spend in the
+ * idle state (it may still be idle in which case subsequent calls will
+ * return an increased value).
*
- * @return the last time this object was used
+ * @return The amount of time in last spent in the idle state.
+ * @since 2.11.0
*/
- long getLastUsedTime();
+ default Duration getIdleDuration() {
+ return Duration.ofMillis(getIdleTimeMillis());
+ }
/**
- * Orders instances based on idle time - i.e. the length of time since the
- * instance was returned to the pool. Used by the GKOP idle object evictor.
- *<p>
- * Note: This class has a natural ordering that is inconsistent with
- * equals if distinct objects have the same identity hash code.
- * </p>
- * <p>
- * {@inheritDoc}
- * </p>
+ * Gets the amount of time that this object last spend in the
+ * idle state (it may still be idle in which case subsequent calls will
+ * return an increased value).
+ *
+ * @return The amount of time in last spent in the idle state.
+ * @since 2.10.0
+ * @deprecated Use {@link #getIdleDuration()}.
*/
- @Override
- int compareTo(PooledObject<T> other);
+ @Deprecated
+ default Duration getIdleTime() {
+ return Duration.ofMillis(getIdleTimeMillis());
+ }
- @Override
- boolean equals(Object obj);
+ /**
+ * Gets the amount of time in milliseconds that this object last spend in the
+ * idle state (it may still be idle in which case subsequent calls will
+ * return an increased value).
+ *
+ * @return The time in milliseconds last spent in the idle state.
+ * @deprecated Use {@link #getIdleTime()} which offers the best precision.
+ */
+ @Deprecated
+ long getIdleTimeMillis();
- @Override
- int hashCode();
+ /**
+ * Gets the time the wrapped object was last borrowed.
+ *
+ * @return The time the object was last borrowed.
+ * @since 2.11.0
+ */
+ default Instant getLastBorrowInstant() {
+ return Instant.ofEpochMilli(getLastBorrowTime());
+ }
/**
- * Provides a String form of the wrapper for debug purposes. The format is
- * not fixed and may change at any time.
- * <p>
- * {@inheritDoc}
+ * Gets the time the wrapped object was last borrowed.
+ *
+ * @return The time the object was last borrowed.
+ * @deprecated Use {@link #getLastBorrowInstant()} which offers the best precision.
*/
- @Override
- String toString();
+ @Deprecated
+ long getLastBorrowTime();
/**
- * Attempts to place the pooled object in the
- * {@link PooledObjectState#EVICTION} state.
+ * Gets the time the wrapped object was last borrowed.
*
- * @return {@code true} if the object was placed in the
- * {@link PooledObjectState#EVICTION} state otherwise
- * {@code false}
+ * @return The time the object was last borrowed.
+ * @since 2.11.0
*/
- boolean startEvictionTest();
+ default Instant getLastReturnInstant() {
+ return Instant.ofEpochMilli(getLastReturnTime());
+ }
/**
- * Called to inform the object that the eviction test has ended.
+ * Gets the time the wrapped object was last returned.
*
- * @param idleQueue The queue of idle objects to which the object should be
- * returned
+ * @return The time the object was last returned.
+ * @deprecated Use {@link #getLastReturnInstant()} which offers the best precision.
+ */
+ @Deprecated
+ long getLastReturnTime();
+
+ /**
+ * Gets an estimate of the last time this object was used. If the class of the pooled object implements
+ * {@link TrackedUse}, what is returned is the maximum of {@link TrackedUse#getLastUsedInstant()} and
+ * {@link #getLastBorrowTime()}; otherwise this method gives the same value as {@link #getLastBorrowTime()}.
*
- * @return Currently not used
+ * @return the last time this object was used
+ * @since 2.11.0
*/
- boolean endEvictionTest(Deque<PooledObject<T>> idleQueue);
+ default Instant getLastUsedInstant() {
+ return Instant.ofEpochMilli(getLastUsedTime());
+ }
/**
- * Allocates the object.
+ * Gets an estimate of the last time this object was used. If the class
+ * of the pooled object implements {@link TrackedUse}, what is returned is
+ * the maximum of {@link TrackedUse#getLastUsedInstant()} and
+ * {@link #getLastBorrowTime()}; otherwise this method gives the same
+ * value as {@link #getLastBorrowTime()}.
*
- * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
+ * @return the last time this object was used.
+ * @deprecated Use {@link #getLastUsedInstant()} which offers the best precision.
*/
- boolean allocate();
+ @Deprecated
+ long getLastUsedTime();
/**
- * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
- * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}.
+ * Gets the underlying object that is wrapped by this instance of
+ * {@link PooledObject}.
*
- * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
+ * @return The wrapped object.
*/
- boolean deallocate();
+ T getObject();
/**
- * Sets the state to {@link PooledObjectState#INVALID INVALID}
+ * Gets the state of this object.
+ * @return state
+ */
+ PooledObjectState getState();
+
+ @Override
+ int hashCode();
+
+ /**
+ * Sets the state to {@link PooledObjectState#INVALID INVALID}.
*/
void invalidate();
/**
- * Is abandoned object tracking being used? If this is true the
+ * Marks the pooled object as abandoned.
+ */
+ void markAbandoned();
+
+ /**
+ * Marks the object as returning to the pool.
+ */
+ void markReturning();
+
+ /**
+ * Prints the stack trace of the code that borrowed this pooled object and
+ * the stack trace of the last code to use this object (if available) to
+ * the supplied writer.
+ *
+ * @param writer The destination for the debug output.
+ */
+ void printStackTrace(PrintWriter writer);
+
+ /**
+ * Sets whether to use abandoned object tracking. If this is true the
* implementation will need to record the stack trace of the last caller to
* borrow this object.
*
* @param logAbandoned The new configuration setting for abandoned
- * object tracking
+ * object tracking.
*/
void setLogAbandoned(boolean logAbandoned);
/**
- * Configures the stack trace generation strategy based on whether or not fully detailed stack traces are required.
+ * Sets the stack trace generation strategy based on whether or not fully detailed stack traces are required.
* When set to false, abandoned logs may only include caller class information rather than method names, line
* numbers, and other normal metadata available in a full stack trace.
*
- * @param requireFullStackTrace the new configuration setting for abandoned object logging
+ * @param requireFullStackTrace the new configuration setting for abandoned object logging.
* @since 2.7.0
*/
default void setRequireFullStackTrace(final boolean requireFullStackTrace) {
@@ -193,32 +322,27 @@ public interface PooledObject<T> extends Comparable<PooledObject<T>> {
}
/**
- * Record the current stack trace as the last time the object was used.
- */
- void use();
-
- /**
- * Prints the stack trace of the code that borrowed this pooled object and
- * the stack trace of the last code to use this object (if available) to
- * the supplied writer.
+ * Attempts to place the pooled object in the
+ * {@link PooledObjectState#EVICTION} state.
*
- * @param writer The destination for the debug output
+ * @return {@code true} if the object was placed in the
+ * {@link PooledObjectState#EVICTION} state otherwise
+ * {@code false}.
*/
- void printStackTrace(PrintWriter writer);
+ boolean startEvictionTest();
/**
- * Returns the state of this object.
- * @return state
+ * Gets a String form of the wrapper for debug purposes. The format is
+ * not fixed and may change at any time.
+ *
+ * {@inheritDoc}
*/
- PooledObjectState getState();
+ @Override
+ String toString();
/**
- * Marks the pooled object as abandoned.
+ * Records the current stack trace as the last time the object was used.
*/
- void markAbandoned();
+ void use();
- /**
- * Marks the object as returning to the pool.
- */
- void markReturning();
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
index 9c95d0d..59a6f74 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
@@ -73,15 +73,16 @@ package org.apache.tomcat.dbcp.pool2;
public interface PooledObjectFactory<T> {
/**
- * Creates an instance that can be served by the pool and wrap it in a
- * {@link PooledObject} to be managed by the pool.
+ * Reinitializes an instance to be returned by the pool.
*
- * @return a {@code PooledObject} wrapping an instance that can be served by the pool
+ * @param p a {@code PooledObject} wrapping the instance to be activated
*
- * @throws Exception if there is a problem creating a new instance,
- * this will be propagated to the code requesting an object.
+ * @throws Exception if there is a problem activating {@code obj},
+ * this exception may be swallowed by the pool.
+ *
+ * @see #destroyObject
*/
- PooledObject<T> makeObject() throws Exception;
+ void activateObject(PooledObject<T> p) throws Exception;
/**
* Destroys an instance no longer needed by the pool, using the default (NORMAL)
@@ -111,7 +112,7 @@ public interface PooledObjectFactory<T> {
* DestroyMode.
*
* @param p a {@code PooledObject} wrapping the instance to be destroyed
- * @param mode DestroyMode providing context to the factory
+ * @param destroyMode DestroyMode providing context to the factory
*
* @throws Exception should be avoided as it may be swallowed by
* the pool implementation.
@@ -122,41 +123,40 @@ public interface PooledObjectFactory<T> {
* @see DestroyMode
* @since 2.9.0
*/
- default void destroyObject(final PooledObject<T> p, final DestroyMode mode) throws Exception {
+ default void destroyObject(final PooledObject<T> p, final DestroyMode destroyMode) throws Exception {
destroyObject(p);
}
/**
- * Ensures that the instance is safe to be returned by the pool.
+ * Creates an instance that can be served by the pool and wrap it in a
+ * {@link PooledObject} to be managed by the pool.
*
- * @param p a {@code PooledObject} wrapping the instance to be validated
+ * @return a {@code PooledObject} wrapping an instance that can be served by the pool
*
- * @return {@code false} if {@code obj} is not valid and should
- * be dropped from the pool, {@code true} otherwise.
+ * @throws Exception if there is a problem creating a new instance,
+ * this will be propagated to the code requesting an object.
*/
- boolean validateObject(PooledObject<T> p);
+ PooledObject<T> makeObject() throws Exception;
/**
- * Reinitializes an instance to be returned by the pool.
+ * Uninitializes an instance to be returned to the idle object pool.
*
- * @param p a {@code PooledObject} wrapping the instance to be activated
+ * @param p a {@code PooledObject} wrapping the instance to be passivated
*
- * @throws Exception if there is a problem activating {@code obj},
+ * @throws Exception if there is a problem passivating {@code obj},
* this exception may be swallowed by the pool.
*
* @see #destroyObject
*/
- void activateObject(PooledObject<T> p) throws Exception;
+ void passivateObject(PooledObject<T> p) throws Exception;
/**
- * Uninitializes an instance to be returned to the idle object pool.
- *
- * @param p a {@code PooledObject} wrapping the instance to be passivated
+ * Ensures that the instance is safe to be returned by the pool.
*
- * @throws Exception if there is a problem passivating {@code obj},
- * this exception may be swallowed by the pool.
+ * @param p a {@code PooledObject} wrapping the instance to be validated
*
- * @see #destroyObject
+ * @return {@code false} if {@code obj} is not valid and should
+ * be dropped from the pool, {@code true} otherwise.
*/
- void passivateObject(PooledObject<T> p) throws Exception;
+ boolean validateObject(PooledObject<T> p);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java b/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
index fa522fd..b405f94 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
@@ -17,7 +17,7 @@
package org.apache.tomcat.dbcp.pool2;
/**
- * Provides the possible states that a {@link PooledObject} may be in.
+ * Provides all possible states of a {@link PooledObject}.
*
* @since 2.0
*/
@@ -39,12 +39,12 @@ public enum PooledObjectState {
EVICTION,
/**
- * Not in the queue, currently being tested for possible eviction. An
- * attempt to borrow the object was made while being tested which removed it
- * from the queue. It should be returned to the head of the queue once
- * eviction testing completes.
- * TODO: Consider allocating object and ignoring the result of the eviction
- * test.
+ * Not in the queue, currently being tested for possible eviction. An attempt to borrow the object was made while
+ * being tested which removed it from the queue. It should be returned to the head of the queue once eviction
+ * testing completes.
+ * <p>
+ * TODO: Consider allocating object and ignoring the result of the eviction test.
+ * </p>
*/
EVICTION_RETURN_TO_HEAD,
@@ -54,24 +54,20 @@ public enum PooledObjectState {
VALIDATION,
/**
- * Not in queue, currently being validated. The object was borrowed while
- * being validated and since testOnBorrow was configured, it was removed
- * from the queue and pre-allocated. It should be allocated once validation
- * completes.
+ * Not in queue, currently being validated. The object was borrowed while being validated and since testOnBorrow was
+ * configured, it was removed from the queue and pre-allocated. It should be allocated once validation completes.
*/
VALIDATION_PREALLOCATED,
/**
- * Not in queue, currently being validated. An attempt to borrow the object
- * was made while previously being tested for eviction which removed it from
- * the queue. It should be returned to the head of the queue once validation
+ * Not in queue, currently being validated. An attempt to borrow the object was made while previously being tested
+ * for eviction which removed it from the queue. It should be returned to the head of the queue once validation
* completes.
*/
VALIDATION_RETURN_TO_HEAD,
/**
- * Failed maintenance (e.g. eviction test or validation) and will be / has
- * been destroyed
+ * Failed maintenance (e.g. eviction test or validation) and will be / has been destroyed
*/
INVALID,
diff --git a/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java b/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
index 53995c1..c80b05b 100644
--- a/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
+++ b/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
@@ -27,7 +27,7 @@ package org.apache.tomcat.dbcp.pool2;
public interface SwallowedExceptionListener {
/**
- * This method is called every time the implementation unavoidably swallows
+ * Notifies this instance every time the implementation unavoidably swallows
* an exception.
*
* @param e The exception that was swallowed
diff --git a/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java b/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
index 01349cb..cac0ce2 100644
--- a/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
+++ b/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
@@ -16,21 +16,37 @@
*/
package org.apache.tomcat.dbcp.pool2;
+import java.time.Instant;
+
/**
- * This interface allows pooled objects to make information available about when
- * and how they were used available to the object pool. The object pool may, but
- * is not required, to use this information to make more informed decisions when
- * determining the state of a pooled object - for instance whether or not the
- * object has been abandoned.
+ * Allows pooled objects to make information available about when and how they were used available to the object pool.
+ * The object pool may, but is not required, to use this information to make more informed decisions when determining
+ * the state of a pooled object - for instance whether or not the object has been abandoned.
*
* @since 2.0
*/
public interface TrackedUse {
/**
- * Get the last time this object was used in ms.
+ * Gets the last time this object was used in milliseconds.
*
- * @return long time in ms
+ * @return the last time this object was used in milliseconds.
+ * @deprecated Use {@link #getLastUsedInstant()} which offers the best precision.
*/
+ @Deprecated
long getLastUsed();
+
+ /**
+ * Gets the last Instant this object was used.
+ * <p>
+ * Starting with Java 9, the JRE {@code SystemClock} precision is increased usually down to microseconds, or tenth
+ * of microseconds, depending on the OS, Hardware, and JVM implementation.
+ * </p>
+ *
+ * @return the last Instant this object was used.
+ * @since 2.11.0
+ */
+ default Instant getLastUsedInstant() {
+ return Instant.ofEpochMilli(getLastUsed());
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java b/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
index afd33fd..9d49863 100644
--- a/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
+++ b/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
@@ -17,23 +17,20 @@
package org.apache.tomcat.dbcp.pool2;
/**
- * This interface may be implemented by an object pool to enable clients
- * (primarily those clients that wrap pools to provide pools with extended
- * features) to provide additional information to the pool relating to object
- * using allowing more informed decisions and reporting to be made regarding
- * abandoned objects.
+ * This interface may be implemented by an object pool to enable clients (primarily those clients that wrap pools to
+ * provide pools with extended features) to provide additional information to the pool relating to object using allowing
+ * more informed decisions and reporting to be made regarding abandoned objects.
*
- * @param <T> The type of object provided by the pool.
+ * @param <T> The type of object provided by the pool.
*
* @since 2.0
*/
public interface UsageTracking<T> {
/**
- * This method is called every time a pooled object is used to enable the pool to
- * better track borrowed objects.
+ * Called every time a pooled object is used to enable the pool to better track borrowed objects.
*
- * @param pooledObject The object that is being used
+ * @param pooledObject The object that is being used.
*/
void use(T pooledObject);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
index 395d2bbd..e3d1f67 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
@@ -19,6 +19,10 @@ package org.apache.tomcat.dbcp.pool2.impl;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
+import java.time.Duration;
+
+import org.apache.tomcat.dbcp.pool2.TrackedUse;
+import org.apache.tomcat.dbcp.pool2.UsageTracking;
/**
* Configuration settings for abandoned object removal.
@@ -28,117 +32,86 @@ import java.nio.charset.Charset;
public class AbandonedConfig {
/**
- * Whether or not borrowObject performs abandoned object removal.
+ * The 5 minutes Duration.
*/
- private boolean removeAbandonedOnBorrow = false;
+ private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION = Duration.ofMinutes(5);
/**
- * <p>Flag to remove abandoned objects if they exceed the
- * removeAbandonedTimeout when borrowObject is invoked.</p>
+ * Creates a new instance with values from the given instance.
*
- * <p>The default value is false.</p>
- *
- * <p>If set to true, abandoned objects are removed by borrowObject if
- * there are fewer than 2 idle objects available in the pool and
- * {@code getNumActive() > getMaxTotal() - 3}</p>
- *
- * @return true if abandoned objects are to be removed by borrowObject
+ * @param abandonedConfig the source, may be null.
+ * @return A new instance or null if the input is null.
+ * @since 2.11.0
*/
- public boolean getRemoveAbandonedOnBorrow() {
- return this.removeAbandonedOnBorrow;
+ public static AbandonedConfig copy(final AbandonedConfig abandonedConfig) {
+ return abandonedConfig == null ? null : new AbandonedConfig(abandonedConfig);
}
/**
- * <p>Flag to remove abandoned objects if they exceed the
- * removeAbandonedTimeout when borrowObject is invoked.</p>
- *
- * @param removeAbandonedOnBorrow true means abandoned objects will be
- * removed by borrowObject
- * @see #getRemoveAbandonedOnBorrow()
+ * Whether or not borrowObject performs abandoned object removal.
*/
- public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
- this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
- }
+ private boolean removeAbandonedOnBorrow;
/**
* Whether or not pool maintenance (evictor) performs abandoned object
* removal.
*/
- private boolean removeAbandonedOnMaintenance = false;
+ private boolean removeAbandonedOnMaintenance;
/**
- * <p>Flag to remove abandoned objects if they exceed the
- * removeAbandonedTimeout when pool maintenance (the "evictor")
- * runs.</p>
- *
- * <p>The default value is false.</p>
- *
- * <p>If set to true, abandoned objects are removed by the pool
- * maintenance thread when it runs. This setting has no effect
- * unless maintenance is enabled by setting
- *{@link GenericObjectPool#getTimeBetweenEvictionRunsMillis() timeBetweenEvictionRunsMillis}
- * to a positive number.</p>
- *
- * @return true if abandoned objects are to be removed by the evictor
+ * Timeout before an abandoned object can be removed.
*/
- public boolean getRemoveAbandonedOnMaintenance() {
- return this.removeAbandonedOnMaintenance;
- }
+ private Duration removeAbandonedTimeoutDuration = DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION;
/**
- * <p>Flag to remove abandoned objects if they exceed the
- * removeAbandonedTimeout when pool maintenance runs.</p>
+ * Determines whether or not to log stack traces for application code
+ * which abandoned an object.
+ */
+ private boolean logAbandoned;
+
+ /**
+ * Determines whether or not to log full stack traces when logAbandoned is true.
+ * If disabled, then a faster method for logging stack traces with only class data
+ * may be used if possible.
*
- * @param removeAbandonedOnMaintenance true means abandoned objects will be
- * removed by pool maintenance
- * @see #getRemoveAbandonedOnMaintenance
+ * @since 2.5
*/
- public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
- this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
- }
+ private boolean requireFullStackTrace = true;
/**
- * Timeout in seconds before an abandoned object can be removed.
+ * PrintWriter to use to log information on abandoned objects.
+ * Use of default system encoding is deliberate.
*/
- private int removeAbandonedTimeout = 300;
+ private PrintWriter logWriter = new PrintWriter(new OutputStreamWriter(System.out, Charset.defaultCharset()));
/**
- * <p>Timeout in seconds before an abandoned object can be removed.</p>
- *
- * <p>The time of most recent use of an object is the maximum (latest) of
- * {@link org.apache.tomcat.dbcp.pool2.TrackedUse#getLastUsed()}
- * (if this class of the object implements
- * TrackedUse) and the time when the object was borrowed from the pool.</p>
- *
- * <p>The default value is 300 seconds.</p>
- *
- * @return the abandoned object timeout in seconds
+ * If the pool implements {@link UsageTracking}, should the pool record a
+ * stack trace every time a method is called on a pooled object and retain
+ * the most recent stack trace to aid debugging of abandoned objects?
*/
- public int getRemoveAbandonedTimeout() {
- return this.removeAbandonedTimeout;
- }
+ private boolean useUsageTracking;
/**
- * <p>Sets the timeout in seconds before an abandoned object can be
- * removed</p>
- *
- * <p>Setting this property has no effect if
- * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
- * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
- * are both false.</p>
- *
- * @param removeAbandonedTimeout new abandoned timeout in seconds
- * @see #getRemoveAbandonedTimeout()
+ * Creates a new instance.
*/
- public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
- this.removeAbandonedTimeout = removeAbandonedTimeout;
+ public AbandonedConfig() {
+ // empty
}
/**
- * Determines whether or not to log stack traces for application code
- * which abandoned an object.
+ * Creates a new instance with values from the given instance.
+ *
+ * @param abandonedConfig the source.
*/
- private boolean logAbandoned = false;
+ private AbandonedConfig(final AbandonedConfig abandonedConfig) {
+ this.setLogAbandoned(abandonedConfig.getLogAbandoned());
+ this.setLogWriter(abandonedConfig.getLogWriter());
+ this.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
+ this.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
+ this.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeoutDuration());
+ this.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
+ this.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
+ }
/**
* Flag to log stack traces for application code which abandoned
@@ -157,25 +130,83 @@ public class AbandonedConfig {
}
/**
- * Sets the flag to log stack traces for application code which abandoned
- * an object.
+ * Gets the log writer being used by this configuration to log
+ * information on abandoned objects. If not set, a PrintWriter based on
+ * System.out with the system default encoding is used.
*
- * @param logAbandoned true turns on abandoned stack trace logging
- * @see #getLogAbandoned()
+ * @return log writer in use
+ */
+ public PrintWriter getLogWriter() {
+ return logWriter;
+ }
+
+ /**
+ * <p>Flag to remove abandoned objects if they exceed the
+ * removeAbandonedTimeout when borrowObject is invoked.</p>
+ *
+ * <p>The default value is false.</p>
+ *
+ * <p>If set to true, abandoned objects are removed by borrowObject if
+ * there are fewer than 2 idle objects available in the pool and
+ * {@code getNumActive() > getMaxTotal() - 3}</p>
*
+ * @return true if abandoned objects are to be removed by borrowObject
*/
- public void setLogAbandoned(final boolean logAbandoned) {
- this.logAbandoned = logAbandoned;
+ public boolean getRemoveAbandonedOnBorrow() {
+ return this.removeAbandonedOnBorrow;
}
/**
- * Determines whether or not to log full stack traces when logAbandoned is true.
- * If disabled, then a faster method for logging stack traces with only class data
- * may be used if possible.
+ * <p>Flag to remove abandoned objects if they exceed the
+ * removeAbandonedTimeout when pool maintenance (the "evictor")
+ * runs.</p>
*
- * @since 2.5
+ * <p>The default value is false.</p>
+ *
+ * <p>If set to true, abandoned objects are removed by the pool
+ * maintenance thread when it runs. This setting has no effect
+ * unless maintenance is enabled by setting
+ *{@link GenericObjectPool#getDurationBetweenEvictionRuns() durationBetweenEvictionRuns}
+ * to a positive number.</p>
+ *
+ * @return true if abandoned objects are to be removed by the evictor
*/
- private boolean requireFullStackTrace = true;
+ public boolean getRemoveAbandonedOnMaintenance() {
+ return this.removeAbandonedOnMaintenance;
+ }
+
+ /**
+ * <p>Timeout in seconds before an abandoned object can be removed.</p>
+ *
+ * <p>The time of most recent use of an object is the maximum (latest) of
+ * {@link TrackedUse#getLastUsedInstant()} (if this class of the object implements
+ * TrackedUse) and the time when the object was borrowed from the pool.</p>
+ *
+ * <p>The default value is 300 seconds.</p>
+ *
+ * @return the abandoned object timeout in seconds.
+ * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
+ */
+ @Deprecated
+ public int getRemoveAbandonedTimeout() {
+ return (int) this.removeAbandonedTimeoutDuration.getSeconds();
+ }
+
+ /**
+ * <p>Timeout before an abandoned object can be removed.</p>
+ *
+ * <p>The time of most recent use of an object is the maximum (latest) of
+ * {@link TrackedUse#getLastUsedInstant()} (if this class of the object implements
+ * TrackedUse) and the time when the object was borrowed from the pool.</p>
+ *
+ * <p>The default value is 300 seconds.</p>
+ *
+ * @return the abandoned object timeout.
+ * @since 2.10.0
+ */
+ public Duration getRemoveAbandonedTimeoutDuration() {
+ return this.removeAbandonedTimeoutDuration;
+ }
/**
* Indicates if full stack traces are required when {@link #getLogAbandoned() logAbandoned}
@@ -193,33 +224,26 @@ public class AbandonedConfig {
}
/**
- * Sets the flag to require full stack traces for logging abandoned connections when enabled.
+ * If the pool implements {@link UsageTracking}, should the pool record a
+ * stack trace every time a method is called on a pooled object and retain
+ * the most recent stack trace to aid debugging of abandoned objects?
*
- * @param requireFullStackTrace indicates whether or not full stack traces are required in
- * abandoned connection logs
- * @see CallStack
- * @see #getRequireFullStackTrace()
- * @since 2.5
+ * @return {@code true} if usage tracking is enabled
*/
- public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
- this.requireFullStackTrace = requireFullStackTrace;
+ public boolean getUseUsageTracking() {
+ return useUsageTracking;
}
/**
- * PrintWriter to use to log information on abandoned objects.
- * Use of default system encoding is deliberate.
- */
- private PrintWriter logWriter = new PrintWriter(new OutputStreamWriter(System.out, Charset.defaultCharset()));
-
- /**
- * Returns the log writer being used by this configuration to log
- * information on abandoned objects. If not set, a PrintWriter based on
- * System.out with the system default encoding is used.
+ * Sets the flag to log stack traces for application code which abandoned
+ * an object.
+ *
+ * @param logAbandoned true turns on abandoned stack trace logging
+ * @see #getLogAbandoned()
*
- * @return log writer in use
*/
- public PrintWriter getLogWriter() {
- return logWriter;
+ public void setLogAbandoned(final boolean logAbandoned) {
+ this.logAbandoned = logAbandoned;
}
/**
@@ -233,30 +257,79 @@ public class AbandonedConfig {
}
/**
- * If the pool implements
- * {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, should the pool
- * record a stack trace every time a method is called on a pooled object and
- * retain the most recent stack trace to aid debugging of abandoned objects?
+ * Flag to remove abandoned objects if they exceed the
+ * removeAbandonedTimeout when borrowObject is invoked.
+ *
+ * @param removeAbandonedOnBorrow true means abandoned objects will be
+ * removed by borrowObject
+ * @see #getRemoveAbandonedOnBorrow()
*/
- private boolean useUsageTracking = false;
+ public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
+ this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
+ }
/**
- * If the pool implements
- * {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, should the pool
- * record a
- * stack trace every time a method is called on a pooled object and retain
- * the most recent stack trace to aid debugging of abandoned objects?
+ * Flag to remove abandoned objects if they exceed the
+ * removeAbandonedTimeout when pool maintenance runs.
*
- * @return {@code true} if usage tracking is enabled
+ * @param removeAbandonedOnMaintenance true means abandoned objects will be
+ * removed by pool maintenance
+ * @see #getRemoveAbandonedOnMaintenance
*/
- public boolean getUseUsageTracking() {
- return useUsageTracking;
+ public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
+ this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
+ }
+
+ /**
+ * Sets the timeout before an abandoned object can be
+ * removed.
+ *
+ * <p>Setting this property has no effect if
+ * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
+ * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
+ * are both false.</p>
+ *
+ * @param removeAbandonedTimeout new abandoned timeout
+ * @see #getRemoveAbandonedTimeoutDuration()
+ * @since 2.10.0
+ */
+ public void setRemoveAbandonedTimeout(final Duration removeAbandonedTimeout) {
+ this.removeAbandonedTimeoutDuration = PoolImplUtils.nonNull(removeAbandonedTimeout, DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION);
+ }
+
+ /**
+ * Sets the timeout in seconds before an abandoned object can be
+ * removed.
+ *
+ * <p>Setting this property has no effect if
+ * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
+ * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
+ * are both false.</p>
+ *
+ * @param removeAbandonedTimeoutSeconds new abandoned timeout in seconds
+ * @see #getRemoveAbandonedTimeoutDuration()
+ * @deprecated Use {@link #setRemoveAbandonedTimeout(Duration)}.
+ */
+ @Deprecated
+ public void setRemoveAbandonedTimeout(final int removeAbandonedTimeoutSeconds) {
+ setRemoveAbandonedTimeout(Duration.ofSeconds(removeAbandonedTimeoutSeconds));
+ }
+
+ /**
+ * Sets the flag to require full stack traces for logging abandoned connections when enabled.
+ *
+ * @param requireFullStackTrace indicates whether or not full stack traces are required in
+ * abandoned connection logs
+ * @see CallStack
+ * @see #getRequireFullStackTrace()
+ * @since 2.5
+ */
+ public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
+ this.requireFullStackTrace = requireFullStackTrace;
}
/**
- * If the pool implements
- * {@link org.apache.tomcat.dbcp.pool2.UsageTracking}, configure whether the
- * pool
+ * If the pool implements {@link UsageTracking}, configure whether the pool
* should record a stack trace every time a method is called on a pooled
* object and retain the most recent stack trace to aid debugging of
* abandoned objects.
@@ -279,8 +352,8 @@ public class AbandonedConfig {
builder.append(removeAbandonedOnBorrow);
builder.append(", removeAbandonedOnMaintenance=");
builder.append(removeAbandonedOnMaintenance);
- builder.append(", removeAbandonedTimeout=");
- builder.append(removeAbandonedTimeout);
+ builder.append(", removeAbandonedTimeoutDuration=");
+ builder.append(removeAbandonedTimeoutDuration);
builder.append(", logAbandoned=");
builder.append(logAbandoned);
builder.append(", logWriter=");
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
index 3583731..039340b 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
@@ -22,13 +22,19 @@ import java.io.Writer;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
@@ -56,75 +62,329 @@ import org.apache.tomcat.dbcp.pool2.SwallowedExceptionListener;
*/
public abstract class BaseGenericObjectPool<T> extends BaseObject {
+ /**
+ * The idle object eviction iterator. Holds a reference to the idle objects.
+ */
+ class EvictionIterator implements Iterator<PooledObject<T>> {
+
+ private final Deque<PooledObject<T>> idleObjects;
+ private final Iterator<PooledObject<T>> idleObjectIterator;
+
+ /**
+ * Constructs an EvictionIterator for the provided idle instance deque.
+ * @param idleObjects underlying deque.
+ */
+ EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
+ this.idleObjects = idleObjects;
+
+ if (getLifo()) {
+ idleObjectIterator = idleObjects.descendingIterator();
+ } else {
+ idleObjectIterator = idleObjects.iterator();
+ }
+ }
+
+ /**
+ * Gets the idle object deque referenced by this iterator.
+ * @return the idle object deque
+ */
+ public Deque<PooledObject<T>> getIdleObjects() {
+ return idleObjects;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasNext() {
+ return idleObjectIterator.hasNext();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public PooledObject<T> next() {
+ return idleObjectIterator.next();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void remove() {
+ idleObjectIterator.remove();
+ }
+
+ }
+
+ /**
+ * The idle object evictor {@link TimerTask}.
+ *
+ * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
+ */
+ class Evictor implements Runnable {
+
+ private ScheduledFuture<?> scheduledFuture;
+
+ /**
+ * Cancels the scheduled future.
+ */
+ void cancel() {
+ scheduledFuture.cancel(false);
+ }
+
+
+ /**
+ * Run pool maintenance. Evict objects qualifying for eviction and then
+ * ensure that the minimum number of idle instances are available.
+ * Since the Timer that invokes Evictors is shared for all Pools but
+ * pools may exist in different class loaders, the Evictor ensures that
+ * any actions taken are under the class loader of the factory
+ * associated with the pool.
+ */
+ @Override
+ public void run() {
+ final ClassLoader savedClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ try {
+ if (factoryClassLoader != null) {
+ // Set the class loader for the factory
+ final ClassLoader cl = factoryClassLoader.get();
+ if (cl == null) {
+ // The pool has been dereferenced and the class loader
+ // GC'd. Cancel this timer so the pool can be GC'd as
+ // well.
+ cancel();
+ return;
+ }
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
+ // Evict from the pool
+ try {
+ evict();
+ } catch(final Exception e) {
+ swallowException(e);
+ } catch(final OutOfMemoryError oome) {
+ // Log problem but give evictor thread a chance to continue
+ // in case error is recoverable
+ oome.printStackTrace(System.err);
+ }
+ // Re-create idle instances.
+ try {
+ ensureMinIdle();
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ } finally {
+ // Restore the previous CCL
+ Thread.currentThread().setContextClassLoader(savedClassLoader);
+ }
+ }
+
+
+ /**
+ * Sets the scheduled future.
+ *
+ * @param scheduledFuture the scheduled future.
+ */
+ void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
+ this.scheduledFuture = scheduledFuture;
+ }
+
+ }
+
+ /**
+ * Wrapper for objects under management by the pool.
+ *
+ * GenericObjectPool and GenericKeyedObjectPool maintain references to all
+ * objects under management using maps keyed on the objects. This wrapper
+ * class ensures that objects can work as hash keys.
+ *
+ * @param <T> type of objects in the pool
+ */
+ static class IdentityWrapper<T> {
+ /** Wrapped object */
+ private final T instance;
+
+ /**
+ * Constructs a wrapper for an instance.
+ *
+ * @param instance object to wrap
+ */
+ public IdentityWrapper(final T instance) {
+ this.instance = instance;
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ public boolean equals(final Object other) {
+ return other instanceof IdentityWrapper && ((IdentityWrapper) other).instance == instance;
+ }
+
+ /**
+ * @return the wrapped object
+ */
+ public T getObject() {
+ return instance;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(instance);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("IdentityWrapper [instance=");
+ builder.append(instance);
+ builder.append("]");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * Maintains a cache of values for a single metric and reports
+ * statistics on the cached values.
+ */
+ private class StatsStore {
+
+ private static final int NULL = -1;
+ private final AtomicLong[] values;
+ private final int size;
+ private int index;
+
+ /**
+ * Constructs a StatsStore with the given cache size.
+ *
+ * @param size number of values to maintain in the cache.
+ */
+ StatsStore(final int size) {
+ this.size = size;
+ values = new AtomicLong[size];
+ for (int i = 0; i < size; i++) {
+ values[i] = new AtomicLong(NULL);
+ }
+ }
+
+ void add(final Duration value) {
+ add(value.toMillis());
+ }
+
+ /**
+ * Adds a value to the cache. If the cache is full, one of the
+ * existing values is replaced by the new value.
+ *
+ * @param value new value to add to the cache.
+ */
+ synchronized void add(final long value) {
+ values[index].set(value);
+ index++;
+ if (index == size) {
+ index = 0;
+ }
+ }
+
+ /**
+ * Gets the current values as a List.
+ *
+ * @return the current values as a List.
+ */
+ synchronized List<AtomicLong> getCurrentValues() {
+ return Arrays.stream(values, 0, index).collect(Collectors.toList());
+ }
+
+ /**
+ * Gets the mean of the cached values.
+ *
+ * @return the mean of the cache, truncated to long
+ */
+ public long getMean() {
+ double result = 0;
+ int counter = 0;
+ for (int i = 0; i < size; i++) {
+ final long value = values[i].get();
+ if (value != NULL) {
+ counter++;
+ result = result * ((counter - 1) / (double) counter) + value / (double) counter;
+ }
+ }
+ return (long) result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("StatsStore [");
+ // Only append what's been filled in.
+ builder.append(getCurrentValues());
+ builder.append("], size=");
+ builder.append(size);
+ builder.append(", index=");
+ builder.append(index);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ }
+
// Constants
/**
* The size of the caches used to store historical data for some attributes
* so that rolling means may be calculated.
*/
public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100;
-
private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName();
-
+ private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(Integer.MAX_VALUE);
// Configuration attributes
- private volatile int maxTotal =
- GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
- private volatile boolean blockWhenExhausted =
- BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
- private volatile long maxWaitMillis =
- BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+ private volatile int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
+ private volatile boolean blockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
+ private volatile Duration maxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
private final boolean fairness;
- private volatile boolean testOnCreate =
- BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
- private volatile boolean testOnBorrow =
- BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
- private volatile boolean testOnReturn =
- BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
- private volatile boolean testWhileIdle =
- BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
- private volatile long timeBetweenEvictionRunsMillis =
- BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
- private volatile int numTestsPerEvictionRun =
- BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
- private volatile long minEvictableIdleTimeMillis =
- BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
- private volatile long softMinEvictableIdleTimeMillis =
- BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private volatile boolean testOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
+ private volatile boolean testOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
+ private volatile boolean testOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
+ private volatile boolean testWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
+ private volatile Duration durationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS;
+ private volatile int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+
+ private volatile Duration minEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
+ private volatile Duration softMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION;
private volatile EvictionPolicy<T> evictionPolicy;
- private volatile long evictorShutdownTimeoutMillis =
- BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
-
-
+ private volatile Duration evictorShutdownTimeoutDuration = BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT;
// Internal (primarily state) attributes
final Object closeLock = new Object();
- volatile boolean closed = false;
+ volatile boolean closed;
+
final Object evictionLock = new Object();
- private Evictor evictor = null; // @GuardedBy("evictionLock")
- EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
- /*
+ private Evictor evictor; // @GuardedBy("evictionLock")
+ EvictionIterator evictionIterator; // @GuardedBy("evictionLock")
+
+ /**
* Class loader for evictor thread to use since, in a JavaEE or similar
* environment, the context class loader for the evictor thread may not have
* visibility of the correct factory. See POOL-161. Uses a weak reference to
* avoid potential memory leaks if the Pool is discarded rather than closed.
*/
private final WeakReference<ClassLoader> factoryClassLoader;
-
-
// Monitoring (primarily JMX) attributes
private final ObjectName objectName;
private final String creationStackTrace;
- private final AtomicLong borrowedCount = new AtomicLong(0);
- private final AtomicLong returnedCount = new AtomicLong(0);
- final AtomicLong createdCount = new AtomicLong(0);
- final AtomicLong destroyedCount = new AtomicLong(0);
- final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
- final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
+ private final AtomicLong borrowedCount = new AtomicLong();
+ private final AtomicLong returnedCount = new AtomicLong();
+ final AtomicLong createdCount = new AtomicLong();
+ final AtomicLong destroyedCount = new AtomicLong();
+ final AtomicLong destroyedByEvictorCount = new AtomicLong();
+ final AtomicLong destroyedByBorrowValidationCount = new AtomicLong();
+
private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
- private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
- private volatile SwallowedExceptionListener swallowedExceptionListener = null;
+ private final AtomicReference<Duration> maxBorrowWaitDuration = new AtomicReference<>(Duration.ZERO);
+
+ private volatile SwallowedExceptionListener swallowedExceptionListener;
+ private volatile boolean messageStatistics;
+
+ /** Additional configuration properties for abandoned object tracking. */
+ protected volatile AbandonedConfig abandonedConfig;
/**
* Handles JMX registration (if required) and the initialization required for
@@ -157,39 +417,78 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
fairness = config.getFairness();
}
-
/**
- * Returns the maximum number of objects that can be allocated by the pool
- * (checked out to clients, or idle awaiting checkout) at a given time. When
- * negative, there is no limit to the number of objects that can be
- * managed by the pool at one time.
+ * Appends statistics if enabled.
+ * <p>
+ * Statistics may not accurately reflect snapshot state at the time of the exception because we do not want to lock the pool when gathering this
+ * information.
+ * </p>
*
- * @return the cap on the total number of object instances managed by the
- * pool.
- *
- * @see #setMaxTotal
+ * @param string The root string.
+ * @return The root string plus statistics.
*/
- public final int getMaxTotal() {
- return maxTotal;
+ String appendStats(final String string) {
+ return messageStatistics ? string + ", " + getStatsString() : string;
}
/**
- * Sets the cap on the number of objects that can be allocated by the pool
- * (checked out to clients, or idle awaiting checkout) at a given time. Use
- * a negative value for no limit.
- *
- * @param maxTotal The cap on the total number of object instances managed
- * by the pool. Negative values mean that there is no limit
- * to the number of objects allocated by the pool.
- *
- * @see #getMaxTotal
+ * Verifies that the pool is open.
+ * @throws IllegalStateException if the pool is closed.
*/
- public final void setMaxTotal(final int maxTotal) {
- this.maxTotal = maxTotal;
+ final void assertOpen() throws IllegalStateException {
+ if (isClosed()) {
+ throw new IllegalStateException("Pool not open");
+ }
+ }
+
+ /**
+ * Closes the pool, destroys the remaining idle objects and, if registered
+ * in JMX, deregisters it.
+ */
+ public abstract void close();
+
+ /**
+ * Creates a list of pooled objects to remove based on their state.
+ * @param abandonedConfig The abandoned configuration.
+ * @param allObjects PooledObject instances to consider.
+ * @return a list of pooled objects to remove based on their state.
+ */
+ ArrayList<PooledObject<T>> createRemoveList(final AbandonedConfig abandonedConfig, final Map<IdentityWrapper<T>, PooledObject<T>> allObjects) {
+ final Instant timeout = Instant.now().minus(abandonedConfig.getRemoveAbandonedTimeoutDuration());
+ final ArrayList<PooledObject<T>> remove = new ArrayList<>();
+ allObjects.values().forEach(pooledObject -> {
+ synchronized (pooledObject) {
+ if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
+ pooledObject.getLastUsedInstant().compareTo(timeout) <= 0) {
+ pooledObject.markAbandoned();
+ remove.add(pooledObject);
+ }
+ }
+ });
+ return remove;
}
/**
- * Returns whether to block when the {@code borrowObject()} method is
+ * Tries to ensure that the configured minimum number of idle instances are
+ * available in the pool.
+ * @throws Exception if an error occurs creating idle instances
+ */
+ abstract void ensureMinIdle() throws Exception;
+
+ /**
+ * Perform {@code numTests} idle object eviction tests, evicting
+ * examined objects that meet the criteria for eviction. If
+ * {@code testWhileIdle} is true, examined objects are validated
+ * when visited (and removed if invalid); otherwise only objects that
+ * have been idle for more than {@code minEvicableIdleTimeMillis}
+ * are removed.
+ *
+ * @throws Exception when there is a problem evicting idle objects.
+ */
+ public abstract void evict() throws Exception;
+
+ /**
+ * Gets whether to block when the {@code borrowObject()} method is
* invoked when the pool is exhausted (the maximum number of "active"
* objects has been reached).
*
@@ -203,101 +502,144 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
}
/**
- * Sets whether to block when the {@code borrowObject()} method is
- * invoked when the pool is exhausted (the maximum number of "active"
- * objects has been reached).
+ * The total number of objects successfully borrowed from this pool over the
+ * lifetime of the pool.
+ * @return the borrowed object count
+ */
+ public final long getBorrowedCount() {
+ return borrowedCount.get();
+ }
+
+ /**
+ * The total number of objects created for this pool over the lifetime of
+ * the pool.
+ * @return the created object count
+ */
+ public final long getCreatedCount() {
+ return createdCount.get();
+ }
+
+ /**
+ * Provides the stack trace for the call that created this pool. JMX
+ * registration may trigger a memory leak so it is important that pools are
+ * deregistered when no longer used by calling the {@link #close()} method.
+ * This method is provided to assist with identifying code that creates but
+ * does not close it thereby creating a memory leak.
+ * @return pool creation stack trace
+ */
+ public final String getCreationStackTrace() {
+ return creationStackTrace;
+ }
+
+ /**
+ * The total number of objects destroyed by this pool as a result of failing
+ * validation during {@code borrowObject()} over the lifetime of the
+ * pool.
+ * @return validation destroyed object count
+ */
+ public final long getDestroyedByBorrowValidationCount() {
+ return destroyedByBorrowValidationCount.get();
+ }
+
+ /**
+ * The total number of objects destroyed by the evictor associated with this
+ * pool over the lifetime of the pool.
+ * @return the evictor destroyed object count
+ */
+ public final long getDestroyedByEvictorCount() {
+ return destroyedByEvictorCount.get();
+ }
+
+ /**
+ * The total number of objects destroyed by this pool over the lifetime of
+ * the pool.
+ * @return the destroyed object count
+ */
+ public final long getDestroyedCount() {
+ return destroyedCount.get();
+ }
+
+ /**
+ * Gets the duration to sleep between runs of the idle
+ * object evictor thread. When non-positive, no idle object evictor thread
+ * will be run.
*
- * @param blockWhenExhausted {@code true} if
- * {@code borrowObject()} should block
- * when the pool is exhausted
+ * @return number of milliseconds to sleep between evictor runs
*
- * @see #getBlockWhenExhausted
+ * @see #setTimeBetweenEvictionRuns
+ * @since 2.11.0
*/
- public final void setBlockWhenExhausted(final boolean blockWhenExhausted) {
- this.blockWhenExhausted = blockWhenExhausted;
+ public final Duration getDurationBetweenEvictionRuns() {
+ return durationBetweenEvictionRuns;
}
/**
- * Initializes the receiver with the given configuration.
+ * Gets the {@link EvictionPolicy} defined for this pool.
*
- * @param config Initialization source.
+ * @return the eviction policy
+ * @since 2.4
+ * @since 2.6.0 Changed access from protected to public.
*/
- protected void setConfig(final BaseObjectPoolConfig<T> config) {
- setLifo(config.getLifo());
- setMaxWaitMillis(config.getMaxWaitMillis());
- setBlockWhenExhausted(config.getBlockWhenExhausted());
- setTestOnCreate(config.getTestOnCreate());
- setTestOnBorrow(config.getTestOnBorrow());
- setTestOnReturn(config.getTestOnReturn());
- setTestWhileIdle(config.getTestWhileIdle());
- setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
- setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
- setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
- setSoftMinEvictableIdleTimeMillis(config.getSoftMinEvictableIdleTimeMillis());
- final EvictionPolicy<T> policy = config.getEvictionPolicy();
- if (policy == null) {
- // Use the class name (pre-2.6.0 compatible)
- setEvictionPolicyClassName(config.getEvictionPolicyClassName());
- } else {
- // Otherwise, use the class (2.6.0 feature)
- setEvictionPolicy(policy);
- }
- setEvictorShutdownTimeoutMillis(config.getEvictorShutdownTimeoutMillis());
+ public EvictionPolicy<T> getEvictionPolicy() {
+ return evictionPolicy;
}
/**
- * Returns the maximum amount of time (in milliseconds) the
- * {@code borrowObject()} method should block before throwing an
- * exception when the pool is exhausted and
- * {@link #getBlockWhenExhausted} is true. When less than 0, the
- * {@code borrowObject()} method may block indefinitely.
+ * Gets the name of the {@link EvictionPolicy} implementation that is
+ * used by this pool.
*
- * @return the maximum number of milliseconds {@code borrowObject()}
- * will block.
+ * @return The fully qualified class name of the {@link EvictionPolicy}
*
- * @see #setMaxWaitMillis
- * @see #setBlockWhenExhausted
+ * @see #setEvictionPolicyClassName(String)
*/
- public final long getMaxWaitMillis() {
- return maxWaitMillis;
+ public final String getEvictionPolicyClassName() {
+ return evictionPolicy.getClass().getName();
}
/**
- * Sets the maximum amount of time (in milliseconds) the
- * {@code borrowObject()} method should block before throwing an
- * exception when the pool is exhausted and
- * {@link #getBlockWhenExhausted} is true. When less than 0, the
- * {@code borrowObject()} method may block indefinitely.
- *
- * @param maxWaitMillis the maximum number of milliseconds
- * {@code borrowObject()} will block or negative
- * for indefinitely.
+ * Gets the timeout that will be used when waiting for the Evictor to
+ * shutdown if this pool is closed and it is the only pool still using the
+ * the value for the Evictor.
*
- * @see #getMaxWaitMillis
- * @see #setBlockWhenExhausted
+ * @return The timeout that will be used while waiting for
+ * the Evictor to shut down.
+ * @since 2.10.0
+ * @deprecated Use {@link #getEvictorShutdownTimeoutDuration()}.
*/
- public final void setMaxWaitMillis(final long maxWaitMillis) {
- this.maxWaitMillis = maxWaitMillis;
+ @Deprecated
+ public final Duration getEvictorShutdownTimeout() {
+ return evictorShutdownTimeoutDuration;
}
/**
- * Returns whether the pool has LIFO (last in, first out) behavior with
- * respect to idle objects - always returning the most recently used object
- * from the pool, or as a FIFO (first in, first out) queue, where the pool
- * always returns the oldest object in the idle object pool.
+ * Gets the timeout that will be used when waiting for the Evictor to
+ * shutdown if this pool is closed and it is the only pool still using the
+ * the value for the Evictor.
*
- * @return {@code true} if the pool is configured with LIFO behavior
- * or {@code false} if the pool is configured with FIFO
- * behavior
+ * @return The timeout that will be used while waiting for
+ * the Evictor to shut down.
+ * @since 2.11.0
+ */
+ public final Duration getEvictorShutdownTimeoutDuration() {
+ return evictorShutdownTimeoutDuration;
+ }
+
+ /**
+ * Gets the timeout that will be used when waiting for the Evictor to
+ * shutdown if this pool is closed and it is the only pool still using the
+ * the value for the Evictor.
*
- * @see #setLifo
+ * @return The timeout in milliseconds that will be used while waiting for
+ * the Evictor to shut down.
+ * @deprecated Use {@link #getEvictorShutdownTimeoutDuration()}.
*/
- public final boolean getLifo() {
- return lifo;
+ @Deprecated
+ public final long getEvictorShutdownTimeoutMillis() {
+ return evictorShutdownTimeoutDuration.toMillis();
}
/**
- * Returns whether or not the pool serves threads waiting to borrow objects fairly.
+ * Gets whether or not the pool serves threads waiting to borrow objects fairly.
* True means that waiting threads are served as if waiting in a FIFO queue.
*
* @return {@code true} if waiting threads are to be served
@@ -308,196 +650,211 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
}
/**
- * Sets whether the pool has LIFO (last in, first out) behavior with
+ * Provides the name under which the pool has been registered with the
+ * platform MBean server or {@code null} if the pool has not been
+ * registered.
+ * @return the JMX name
+ */
+ public final ObjectName getJmxName() {
+ return objectName;
+ }
+
+ /**
+ * Gets whether the pool has LIFO (last in, first out) behavior with
* respect to idle objects - always returning the most recently used object
* from the pool, or as a FIFO (first in, first out) queue, where the pool
* always returns the oldest object in the idle object pool.
*
- * @param lifo {@code true} if the pool is to be configured with LIFO
- * behavior or {@code false} if the pool is to be
- * configured with FIFO behavior
+ * @return {@code true} if the pool is configured with LIFO behavior
+ * or {@code false} if the pool is configured with FIFO
+ * behavior
*
- * @see #getLifo()
+ * @see #setLifo
*/
- public final void setLifo(final boolean lifo) {
- this.lifo = lifo;
+ public final boolean getLifo() {
+ return lifo;
}
/**
- * Returns whether objects created for the pool will be validated before
- * being returned from the {@code borrowObject()} method. Validation is
- * performed by the {@code validateObject()} method of the factory
- * associated with the pool. If the object fails to validate, then
- * {@code borrowObject()} will fail.
+ * Gets whether this pool identifies and logs any abandoned objects.
*
- * @return {@code true} if newly created objects are validated before
- * being returned from the {@code borrowObject()} method
- *
- * @see #setTestOnCreate
+ * @return {@code true} if abandoned object removal is configured for this
+ * pool and removal events are to be logged otherwise {@code false}
*
- * @since 2.2
+ * @see AbandonedConfig#getLogAbandoned()
+ * @since 2.11.0
*/
- public final boolean getTestOnCreate() {
- return testOnCreate;
+ public boolean getLogAbandoned() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getLogAbandoned();
}
/**
- * Sets whether objects created for the pool will be validated before
- * being returned from the {@code borrowObject()} method. Validation is
- * performed by the {@code validateObject()} method of the factory
- * associated with the pool. If the object fails to validate, then
- * {@code borrowObject()} will fail.
- *
- * @param testOnCreate {@code true} if newly created objects should be
- * validated before being returned from the
- * {@code borrowObject()} method
- *
- * @see #getTestOnCreate
- *
- * @since 2.2
+ * Gets the maximum time a thread has waited to borrow objects from the pool.
+ * @return maximum wait time in milliseconds since the pool was created
*/
- public final void setTestOnCreate(final boolean testOnCreate) {
- this.testOnCreate = testOnCreate;
+ public final long getMaxBorrowWaitTimeMillis() {
+ return maxBorrowWaitDuration.get().toMillis();
}
/**
- * Returns whether objects borrowed from the pool will be validated before
- * being returned from the {@code borrowObject()} method. Validation is
- * performed by the {@code validateObject()} method of the factory
- * associated with the pool. If the object fails to validate, it will be
- * removed from the pool and destroyed, and a new attempt will be made to
- * borrow an object from the pool.
+ * Gets the maximum number of objects that can be allocated by the pool
+ * (checked out to clients, or idle awaiting checkout) at a given time. When
+ * negative, there is no limit to the number of objects that can be
+ * managed by the pool at one time.
*
- * @return {@code true} if objects are validated before being returned
- * from the {@code borrowObject()} method
+ * @return the cap on the total number of object instances managed by the
+ * pool.
*
- * @see #setTestOnBorrow
+ * @see #setMaxTotal
*/
- public final boolean getTestOnBorrow() {
- return testOnBorrow;
+ public final int getMaxTotal() {
+ return maxTotal;
}
/**
- * Sets whether objects borrowed from the pool will be validated before
- * being returned from the {@code borrowObject()} method. Validation is
- * performed by the {@code validateObject()} method of the factory
- * associated with the pool. If the object fails to validate, it will be
- * removed from the pool and destroyed, and a new attempt will be made to
- * borrow an object from the pool.
+ * Gets the maximum duration the
+ * {@code borrowObject()} method should block before throwing an
+ * exception when the pool is exhausted and
+ * {@link #getBlockWhenExhausted} is true. When less than 0, the
+ * {@code borrowObject()} method may block indefinitely.
*
- * @param testOnBorrow {@code true} if objects should be validated
- * before being returned from the
- * {@code borrowObject()} method
+ * @return the maximum number of milliseconds {@code borrowObject()}
+ * will block.
*
- * @see #getTestOnBorrow
+ * @see #setMaxWait
+ * @see #setBlockWhenExhausted
+ * @since 2.11.0
*/
- public final void setTestOnBorrow(final boolean testOnBorrow) {
- this.testOnBorrow = testOnBorrow;
+ public final Duration getMaxWaitDuration() {
+ return maxWaitDuration;
}
/**
- * Returns whether objects borrowed from the pool will be validated when
- * they are returned to the pool via the {@code returnObject()} method.
- * Validation is performed by the {@code validateObject()} method of
- * the factory associated with the pool. Returning objects that fail validation
- * are destroyed rather then being returned the pool.
+ * Gets the maximum amount of time (in milliseconds) the
+ * {@code borrowObject()} method should block before throwing an
+ * exception when the pool is exhausted and
+ * {@link #getBlockWhenExhausted} is true. When less than 0, the
+ * {@code borrowObject()} method may block indefinitely.
*
- * @return {@code true} if objects are validated on return to
- * the pool via the {@code returnObject()} method
+ * @return the maximum number of milliseconds {@code borrowObject()}
+ * will block.
*
- * @see #setTestOnReturn
+ * @see #setMaxWait
+ * @see #setBlockWhenExhausted
+ * @deprecated Use {@link #getMaxWaitDuration()}.
*/
- public final boolean getTestOnReturn() {
- return testOnReturn;
+ @Deprecated
+ public final long getMaxWaitMillis() {
+ return maxWaitDuration.toMillis();
}
/**
- * Sets whether objects borrowed from the pool will be validated when
- * they are returned to the pool via the {@code returnObject()} method.
- * Validation is performed by the {@code validateObject()} method of
- * the factory associated with the pool. Returning objects that fail validation
- * are destroyed rather then being returned the pool.
- *
- * @param testOnReturn {@code true} if objects are validated on
- * return to the pool via the
- * {@code returnObject()} method
- *
- * @see #getTestOnReturn
+ * The mean time objects are active for based on the last {@link
+ * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
+ * @return mean time an object has been checked out from the pool among
+ * recently returned objects
*/
- public final void setTestOnReturn(final boolean testOnReturn) {
- this.testOnReturn = testOnReturn;
+ public final long getMeanActiveTimeMillis() {
+ return activeTimes.getMean();
}
/**
- * Returns whether objects sitting idle in the pool will be validated by the
- * idle object evictor (if any - see
- * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
- * by the {@code validateObject()} method of the factory associated
- * with the pool. If the object fails to validate, it will be removed from
- * the pool and destroyed.
- *
- * @return {@code true} if objects will be validated by the evictor
+ * The mean time threads wait to borrow an object based on the last {@link
+ * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
+ * @return mean time in milliseconds that a recently served thread has had
+ * to wait to borrow an object from the pool
+ */
+ public final long getMeanBorrowWaitTimeMillis() {
+ return waitTimes.getMean();
+ }
+
+ /**
+ * The mean time objects are idle for based on the last {@link
+ * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
+ * @return mean time an object has been idle in the pool among recently
+ * borrowed objects
+ */
+ public final long getMeanIdleTimeMillis() {
+ return idleTimes.getMean();
+ }
+
+ /**
+ * Gets whether to include statistics in exception messages.
+ * <p>
+ * Statistics may not accurately reflect snapshot state at the time of the exception because we do not want to lock the pool when gathering this
+ * information.
+ * </p>
*
- * @see #setTestWhileIdle
- * @see #setTimeBetweenEvictionRunsMillis
+ * @return whether to include statistics in exception messages.
+ * @since 2.11.0
*/
- public final boolean getTestWhileIdle() {
- return testWhileIdle;
+ public boolean getMessageStatistics() {
+ return messageStatistics;
}
/**
- * Returns whether objects sitting idle in the pool will be validated by the
- * idle object evictor (if any - see
- * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
- * by the {@code validateObject()} method of the factory associated
- * with the pool. If the object fails to validate, it will be removed from
- * the pool and destroyed. Note that setting this property has no effect
- * unless the idle object evictor is enabled by setting
- * {@code timeBetweenEvictionRunsMillis} to a positive value.
+ * Gets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
*
- * @param testWhileIdle
- * {@code true} so objects will be validated by the evictor
+ * @return minimum amount of time an object may sit idle in the pool before
+ * it is eligible for eviction
*
- * @see #getTestWhileIdle
+ * @see #setMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
+ * @since 2.11.0
*/
- public final void setTestWhileIdle(final boolean testWhileIdle) {
- this.testWhileIdle = testWhileIdle;
+ public final Duration getMinEvictableIdleDuration() {
+ return minEvictableIdleDuration;
}
/**
- * Returns the number of milliseconds to sleep between runs of the idle
- * object evictor thread. When non-positive, no idle object evictor thread
- * will be run.
+ * Gets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
*
- * @return number of milliseconds to sleep between evictor runs
+ * @return minimum amount of time an object may sit idle in the pool before
+ * it is eligible for eviction
*
+ * @see #setMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
+ * @since 2.10.0
+ * @deprecated Use {@link #getMinEvictableIdleDuration()}.
*/
- public final long getTimeBetweenEvictionRunsMillis() {
- return timeBetweenEvictionRunsMillis;
+ @Deprecated
+ public final Duration getMinEvictableIdleTime() {
+ return minEvictableIdleDuration;
}
/**
- * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
- * <ul>
- * <li>When positive, the idle object evictor thread starts.</li>
- * <li>When non-positive, no idle object evictor thread runs.</li>
- * </ul>
+ * Gets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
*
- * @param timeBetweenEvictionRunsMillis
- * number of milliseconds to sleep between evictor runs
+ * @return minimum amount of time an object may sit idle in the pool before
+ * it is eligible for eviction
*
- * @see #getTimeBetweenEvictionRunsMillis
+ * @see #setMinEvictableIdleTimeMillis
+ * @see #setTimeBetweenEvictionRunsMillis
+ * @deprecated Use {@link #getMinEvictableIdleDuration()}.
*/
- public final void setTimeBetweenEvictionRunsMillis(
- final long timeBetweenEvictionRunsMillis) {
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
- startEvictor(timeBetweenEvictionRunsMillis);
+ @Deprecated
+ public final long getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleDuration.toMillis();
}
/**
- * Returns the maximum number of objects to examine during each run (if any)
+ * The number of instances currently idle in this pool.
+ * @return count of instances available for checkout from the pool
+ */
+ public abstract int getNumIdle();
+
+ /**
+ * Gets the maximum number of objects to examine during each run (if any)
* of the idle object evictor thread. When positive, the number of tests
* performed for a run will be the minimum of the configured value and the
* number of idle instances in the pool. When negative, the number of tests
@@ -516,80 +873,120 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
}
/**
- * Sets the maximum number of objects to examine during each run (if any)
- * of the idle object evictor thread. When positive, the number of tests
- * performed for a run will be the minimum of the configured value and the
- * number of idle instances in the pool. When negative, the number of tests
- * performed will be <code>ceil({@link #getNumIdle}/
- * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
- * value is {@code -n} roughly one nth of the idle objects will be
- * tested per run.
+ * Gets whether a check is made for abandoned objects when an object is borrowed
+ * from this pool.
*
- * @param numTestsPerEvictionRun
- * max number of objects to examine during each evictor run
+ * @return {@code true} if abandoned object removal is configured to be
+ * activated by borrowObject otherwise {@code false}
*
- * @see #getNumTestsPerEvictionRun
- * @see #setTimeBetweenEvictionRunsMillis
+ * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
+ * @since 2.11.0
*/
- public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
- this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ public boolean getRemoveAbandonedOnBorrow() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getRemoveAbandonedOnBorrow();
}
/**
- * Returns the minimum amount of time an object may sit idle in the pool
- * before it is eligible for eviction by the idle object evictor (if any -
- * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
- * no objects will be evicted from the pool due to idle time alone.
+ * Gets whether a check is made for abandoned objects when the evictor runs.
*
- * @return minimum amount of time an object may sit idle in the pool before
- * it is eligible for eviction
+ * @return {@code true} if abandoned object removal is configured to be
+ * activated when the evictor runs otherwise {@code false}
*
- * @see #setMinEvictableIdleTimeMillis
- * @see #setTimeBetweenEvictionRunsMillis
+ * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
+ * @since 2.11.0
*/
- public final long getMinEvictableIdleTimeMillis() {
- return minEvictableIdleTimeMillis;
+ public boolean getRemoveAbandonedOnMaintenance() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getRemoveAbandonedOnMaintenance();
}
/**
- * Sets the minimum amount of time an object may sit idle in the pool
+ * Gets the timeout before which an object will be considered to be
+ * abandoned by this pool.
+ *
+ * @return The abandoned object timeout in seconds if abandoned object
+ * removal is configured for this pool; Integer.MAX_VALUE otherwise.
+ *
+ * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
+ * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
+ * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
+ * @since 2.11.0
+ */
+ @Deprecated
+ public int getRemoveAbandonedTimeout() {
+ return (int) getRemoveAbandonedTimeoutDuration().getSeconds();
+ }
+
+ /**
+ * Gets the timeout before which an object will be considered to be
+ * abandoned by this pool.
+ *
+ * @return The abandoned object timeout in seconds if abandoned object
+ * removal is configured for this pool; Integer.MAX_VALUE otherwise.
+ *
+ * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
+ * @since 2.11.0
+ */
+ public Duration getRemoveAbandonedTimeoutDuration() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null ? ac.getRemoveAbandonedTimeoutDuration() : DEFAULT_REMOVE_ABANDONED_TIMEOUT;
+ }
+
+ /**
+ * The total number of objects returned to this pool over the lifetime of
+ * the pool. This excludes attempts to return the same object multiple
+ * times.
+ * @return the returned object count
+ */
+ public final long getReturnedCount() {
+ return returnedCount.get();
+ }
+
+ /**
+ * Gets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor (if any -
- * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
- * no objects will be evicted from the pool due to idle time alone.
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}),
+ * with the extra condition that at least {@code minIdle} object
+ * instances remain in the pool. This setting is overridden by
+ * {@link #getMinEvictableIdleTime} (that is, if
+ * {@link #getMinEvictableIdleTime} is positive, then
+ * {@link #getSoftMinEvictableIdleTime} is ignored).
*
- * @param minEvictableIdleTimeMillis
- * minimum amount of time an object may sit idle in the pool
- * before it is eligible for eviction
+ * @return minimum amount of time an object may sit idle in the pool before
+ * it is eligible for eviction if minIdle instances are available
*
- * @see #getMinEvictableIdleTimeMillis
- * @see #setTimeBetweenEvictionRunsMillis
+ * @see #setSoftMinEvictableIdle(Duration)
+ * @since 2.11.0
*/
- public final void setMinEvictableIdleTimeMillis(
- final long minEvictableIdleTimeMillis) {
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ public final Duration getSoftMinEvictableIdleDuration() {
+ return softMinEvictableIdleDuration;
}
/**
- * Returns the minimum amount of time an object may sit idle in the pool
+ * Gets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor (if any -
- * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}),
* with the extra condition that at least {@code minIdle} object
* instances remain in the pool. This setting is overridden by
- * {@link #getMinEvictableIdleTimeMillis} (that is, if
- * {@link #getMinEvictableIdleTimeMillis} is positive, then
- * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
+ * {@link #getMinEvictableIdleTime} (that is, if
+ * {@link #getMinEvictableIdleTime} is positive, then
+ * {@link #getSoftMinEvictableIdleTime} is ignored).
*
* @return minimum amount of time an object may sit idle in the pool before
* it is eligible for eviction if minIdle instances are available
*
- * @see #setSoftMinEvictableIdleTimeMillis
+ * @see #setSoftMinEvictableIdle(Duration)
+ * @since 2.10.0
+ * @deprecated Use {@link #getSoftMinEvictableIdleDuration}.
*/
- public final long getSoftMinEvictableIdleTimeMillis() {
- return softMinEvictableIdleTimeMillis;
+ @Deprecated
+ public final Duration getSoftMinEvictableIdleTime() {
+ return softMinEvictableIdleDuration;
}
/**
- * Sets the minimum amount of time an object may sit idle in the pool
+ * Gets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor (if any -
* see {@link #setTimeBetweenEvictionRunsMillis(long)}),
* with the extra condition that at least {@code minIdle} object
@@ -598,773 +995,832 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
* {@link #getMinEvictableIdleTimeMillis} is positive, then
* {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
*
- * @param softMinEvictableIdleTimeMillis
- * minimum amount of time an object may sit idle in the pool
- * before it is eligible for eviction if minIdle instances are
- * available
+ * @return minimum amount of time an object may sit idle in the pool before
+ * it is eligible for eviction if minIdle instances are available
*
- * @see #getSoftMinEvictableIdleTimeMillis
+ * @see #setSoftMinEvictableIdleTimeMillis
+ * @deprecated Use {@link #getSoftMinEvictableIdleTime()}.
*/
- public final void setSoftMinEvictableIdleTimeMillis(
- final long softMinEvictableIdleTimeMillis) {
- this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+ @Deprecated
+ public final long getSoftMinEvictableIdleTimeMillis() {
+ return softMinEvictableIdleDuration.toMillis();
}
/**
- * Returns the name of the {@link EvictionPolicy} implementation that is
- * used by this pool.
- *
- * @return The fully qualified class name of the {@link EvictionPolicy}
+ * Gets the stack trace of an exception as a string.
+ * @param e exception to trace
+ * @return exception stack trace as a string
+ */
+ private String getStackTrace(final Exception e) {
+ // Need the exception in string form to prevent the retention of
+ // references to classes in the stack trace that could trigger a memory
+ // leak in a container environment.
+ final Writer w = new StringWriter();
+ final PrintWriter pw = new PrintWriter(w);
+ e.printStackTrace(pw);
+ return w.toString();
+ }
+
+ /**
+ * Gets a statistics string.
*
- * @see #setEvictionPolicyClassName(String)
+ * @return a statistics string.
*/
- public final String getEvictionPolicyClassName() {
- return evictionPolicy.getClass().getName();
+ @SuppressWarnings("boxing") // Commons Pool uses auto-boxing
+ String getStatsString() {
+ // Simply listed in AB order.
+ return String.format(
+ "activeTimes=%s, blockWhenExhausted=%s, borrowedCount=%,d, closed=%s, createdCount=%,d, destroyedByBorrowValidationCount=%,d, " +
+ "destroyedByEvictorCount=%,d, evictorShutdownTimeoutDuration=%s, fairness=%s, idleTimes=%s, lifo=%s, maxBorrowWaitDuration=%s, " +
+ "maxTotal=%s, maxWaitDuration=%s, minEvictableIdleDuration=%s, numTestsPerEvictionRun=%s, returnedCount=%s, " +
+ "softMinEvictableIdleDuration=%s, testOnBorrow=%s, testOnCreate=%s, testOnReturn=%s, testWhileIdle=%s, " +
+ "durationBetweenEvictionRuns=%s, waitTimes=%s",
+ activeTimes.getCurrentValues(), blockWhenExhausted, borrowedCount.get(), closed, createdCount.get(), destroyedByBorrowValidationCount.get(),
+ destroyedByEvictorCount.get(), evictorShutdownTimeoutDuration, fairness, idleTimes.getCurrentValues(), lifo, maxBorrowWaitDuration.get(),
+ maxTotal, maxWaitDuration, minEvictableIdleDuration, numTestsPerEvictionRun, returnedCount, softMinEvictableIdleDuration, testOnBorrow,
+ testOnCreate, testOnReturn, testWhileIdle, durationBetweenEvictionRuns, waitTimes.getCurrentValues());
}
/**
- * Sets the eviction policy for this pool.
+ * Gets the listener used (if any) to receive notifications of exceptions
+ * unavoidably swallowed by the pool.
*
- * @param evictionPolicy
- * the eviction policy for this pool.
- * @since 2.6.0
+ * @return The listener or {@code null} for no listener
*/
- public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
- this.evictionPolicy = evictionPolicy;
+ public final SwallowedExceptionListener getSwallowedExceptionListener() {
+ return swallowedExceptionListener;
}
/**
- * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
- * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
- * interface.
+ * Gets whether objects borrowed from the pool will be validated before
+ * being returned from the {@code borrowObject()} method. Validation is
+ * performed by the {@code validateObject()} method of the factory
+ * associated with the pool. If the object fails to validate, it will be
+ * removed from the pool and destroyed, and a new attempt will be made to
+ * borrow an object from the pool.
*
- * @param evictionPolicyClassName
- * the fully qualified class name of the new eviction policy
- * @param classLoader
- * the class loader to load the given {@code evictionPolicyClassName}.
+ * @return {@code true} if objects are validated before being returned
+ * from the {@code borrowObject()} method
*
- * @see #getEvictionPolicyClassName()
- * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the
- * {@link EvictionPolicy} interface.
+ * @see #setTestOnBorrow
*/
- public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) {
- // Getting epClass here and now best matches the caller's environment
- final Class<?> epClass = EvictionPolicy.class;
- final ClassLoader epClassLoader = epClass.getClassLoader();
- try {
- try {
- setEvictionPolicy(evictionPolicyClassName, classLoader);
- } catch (final ClassCastException | ClassNotFoundException e) {
- setEvictionPolicy(evictionPolicyClassName, epClassLoader);
- }
- } catch (final ClassCastException e) {
- throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders [" +
- classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME);
- } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException |
- InvocationTargetException | NoSuchMethodException e) {
- final String exMessage = "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type " +
- evictionPolicyClassName;
- throw new IllegalArgumentException(exMessage, e);
- }
+ public final boolean getTestOnBorrow() {
+ return testOnBorrow;
}
/**
- * Sets the eviction policy.
+ * Gets whether objects created for the pool will be validated before
+ * being returned from the {@code borrowObject()} method. Validation is
+ * performed by the {@code validateObject()} method of the factory
+ * associated with the pool. If the object fails to validate, then
+ * {@code borrowObject()} will fail.
*
- * @param className Eviction policy class name.
- * @param classLoader Load the class from this class loader.
+ * @return {@code true} if newly created objects are validated before
+ * being returned from the {@code borrowObject()} method
+ *
+ * @see #setTestOnCreate
+ *
+ * @since 2.2
*/
- @SuppressWarnings("unchecked")
- private void setEvictionPolicy(final String className, final ClassLoader classLoader)
- throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
- final Class<?> clazz = Class.forName(className, true, classLoader);
- final Object policy = clazz.getConstructor().newInstance();
- this.evictionPolicy = (EvictionPolicy<T>) policy;
+ public final boolean getTestOnCreate() {
+ return testOnCreate;
}
/**
- * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
- * load the class using the thread context class loader. If that fails, the use the class loader for the
- * {@link EvictionPolicy} interface.
+ * Gets whether objects borrowed from the pool will be validated when
+ * they are returned to the pool via the {@code returnObject()} method.
+ * Validation is performed by the {@code validateObject()} method of
+ * the factory associated with the pool. Returning objects that fail validation
+ * are destroyed rather then being returned the pool.
*
- * @param evictionPolicyClassName
- * the fully qualified class name of the new eviction policy
+ * @return {@code true} if objects are validated on return to
+ * the pool via the {@code returnObject()} method
*
- * @see #getEvictionPolicyClassName()
- * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
- * {@link EvictionPolicy} interface.
+ * @see #setTestOnReturn
*/
- public final void setEvictionPolicyClassName(final String evictionPolicyClassName) {
- setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader());
+ public final boolean getTestOnReturn() {
+ return testOnReturn;
}
/**
- * Gets the timeout that will be used when waiting for the Evictor to
- * shutdown if this pool is closed and it is the only pool still using the
- * the value for the Evictor.
+ * Gets whether objects sitting idle in the pool will be validated by the
+ * idle object evictor (if any - see
+ * {@link #setTimeBetweenEvictionRuns(Duration)}). Validation is performed
+ * by the {@code validateObject()} method of the factory associated
+ * with the pool. If the object fails to validate, it will be removed from
+ * the pool and destroyed.
*
- * @return The timeout in milliseconds that will be used while waiting for
- * the Evictor to shut down.
+ * @return {@code true} if objects will be validated by the evictor
+ *
+ * @see #setTestWhileIdle
+ * @see #setTimeBetweenEvictionRunsMillis
*/
- public final long getEvictorShutdownTimeoutMillis() {
- return evictorShutdownTimeoutMillis;
+ public final boolean getTestWhileIdle() {
+ return testWhileIdle;
}
/**
- * Sets the timeout that will be used when waiting for the Evictor to
- * shutdown if this pool is closed and it is the only pool still using the
- * the value for the Evictor.
+ * Gets the duration to sleep between runs of the idle
+ * object evictor thread. When non-positive, no idle object evictor thread
+ * will be run.
*
- * @param evictorShutdownTimeoutMillis the timeout in milliseconds that
- * will be used while waiting for the
- * Evictor to shut down.
+ * @return number of milliseconds to sleep between evictor runs
+ *
+ * @see #setTimeBetweenEvictionRuns
+ * @since 2.10.0
+ * @deprecated {@link #getDurationBetweenEvictionRuns()}.
*/
- public final void setEvictorShutdownTimeoutMillis(
- final long evictorShutdownTimeoutMillis) {
- this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
+ @Deprecated
+ public final Duration getTimeBetweenEvictionRuns() {
+ return durationBetweenEvictionRuns;
}
/**
- * Closes the pool, destroys the remaining idle objects and, if registered
- * in JMX, deregisters it.
- */
- public abstract void close();
-
- /**
- * Has this pool instance been closed.
- * @return {@code true} when this pool has been closed.
+ * Gets the number of milliseconds to sleep between runs of the idle
+ * object evictor thread. When non-positive, no idle object evictor thread
+ * will be run.
+ *
+ * @return number of milliseconds to sleep between evictor runs
+ *
+ * @see #setTimeBetweenEvictionRunsMillis
+ * @deprecated Use {@link #getDurationBetweenEvictionRuns()}.
*/
- public final boolean isClosed() {
- return closed;
+ @Deprecated
+ public final long getTimeBetweenEvictionRunsMillis() {
+ return durationBetweenEvictionRuns.toMillis();
}
- /**
- * <p>Perform {@code numTests} idle object eviction tests, evicting
- * examined objects that meet the criteria for eviction. If
- * {@code testWhileIdle} is true, examined objects are validated
- * when visited (and removed if invalid); otherwise only objects that
- * have been idle for more than {@code minEvicableIdleTimeMillis}
- * are removed.</p>
- *
- * @throws Exception when there is a problem evicting idle objects.
- */
- public abstract void evict() throws Exception;
+ // Monitoring (primarily JMX) related methods
/**
- * Returns the {@link EvictionPolicy} defined for this pool.
+ * Gets whether or not abandoned object removal is configured for this pool.
*
- * @return the eviction policy
- * @since 2.4
- * @since 2.6.0 Changed access from protected to public.
+ * @return true if this pool is configured to detect and remove
+ * abandoned objects
+ * @since 2.11.0
*/
- public EvictionPolicy<T> getEvictionPolicy() {
- return evictionPolicy;
+ public boolean isAbandonedConfig() {
+ return abandonedConfig != null;
}
/**
- * Verifies that the pool is open.
- * @throws IllegalStateException if the pool is closed.
+ * Has this pool instance been closed.
+ * @return {@code true} when this pool has been closed.
*/
- final void assertOpen() throws IllegalStateException {
- if (isClosed()) {
- throw new IllegalStateException("Pool not open");
- }
+ public final boolean isClosed() {
+ return closed;
}
/**
- * <p>Starts the evictor with the given delay. If there is an evictor
- * running when this method is called, it is stopped and replaced with a
- * new evictor with the specified delay.</p>
- *
- * <p>This method needs to be final, since it is called from a constructor.
- * See POOL-195.</p>
+ * Registers the pool with the platform MBean server.
+ * The registered name will be
+ * {@code jmxNameBase + jmxNamePrefix + i} where i is the least
+ * integer greater than or equal to 1 such that the name is not already
+ * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
+ * returning null.
*
- * @param delay time in milliseconds before start and between eviction runs
+ * @param config Pool configuration
+ * @param jmxNameBase default base JMX name for this pool
+ * @param jmxNamePrefix name prefix
+ * @return registered ObjectName, null if registration fails
*/
- final void startEvictor(final long delay) {
- synchronized (evictionLock) {
- if (evictor == null) { // Starting evictor for the first time or after a cancel
- if (delay > 0) { // Starting new evictor
- evictor = new Evictor();
- EvictionTimer.schedule(evictor, delay, delay);
+ private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config,
+ final String jmxNameBase, String jmxNamePrefix) {
+ ObjectName newObjectName = null;
+ final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ int i = 1;
+ boolean registered = false;
+ String base = config.getJmxNameBase();
+ if (base == null) {
+ base = jmxNameBase;
+ }
+ while (!registered) {
+ try {
+ ObjectName objName;
+ // Skip the numeric suffix for the first pool in case there is
+ // only one so the names are cleaner.
+ if (i == 1) {
+ objName = new ObjectName(base + jmxNamePrefix);
+ } else {
+ objName = new ObjectName(base + jmxNamePrefix + i);
}
- } else { // Stop or restart of existing evictor
- if (delay > 0) { // Restart
- synchronized (EvictionTimer.class) { // Ensure no cancel can happen between cancel / schedule calls
- EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS, true);
- evictor = null;
- evictionIterator = null;
- evictor = new Evictor();
- EvictionTimer.schedule(evictor, delay, delay);
- }
- } else { // Stopping evictor
- EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS, false);
+ mbs.registerMBean(this, objName);
+ newObjectName = objName;
+ registered = true;
+ } catch (final MalformedObjectNameException e) {
+ if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
+ jmxNamePrefix) && jmxNameBase.equals(base)) {
+ // Shouldn't happen. Skip registration if it does.
+ registered = true;
+ } else {
+ // Must be an invalid name. Use the defaults instead.
+ jmxNamePrefix =
+ BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
+ base = jmxNameBase;
}
+ } catch (final InstanceAlreadyExistsException e) {
+ // Increment the index and try again
+ i++;
+ } catch (final MBeanRegistrationException | NotCompliantMBeanException e) {
+ // Shouldn't happen. Skip registration if it does.
+ registered = true;
}
}
+ return newObjectName;
}
/**
- * Stops the evictor.
+ * Unregisters this pool's MBean.
*/
- void stopEvictor() {
- startEvictor(-1L);
+ final void jmxUnregister() {
+ if (objectName != null) {
+ try {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName);
+ } catch (final MBeanRegistrationException | InstanceNotFoundException e) {
+ swallowException(e);
+ }
+ }
}
- /**
- * Tries to ensure that the configured minimum number of idle instances are
- * available in the pool.
- * @throws Exception if an error occurs creating idle instances
- */
- abstract void ensureMinIdle() throws Exception;
-
-
- // Monitoring (primarily JMX) related methods
/**
- * Provides the name under which the pool has been registered with the
- * platform MBean server or {@code null} if the pool has not been
- * registered.
- * @return the JMX name
+ * Marks the object as returning to the pool.
+ * @param pooledObject instance to return to the keyed pool
*/
- public final ObjectName getJmxName() {
- return objectName;
+ protected void markReturningState(final PooledObject<T> pooledObject) {
+ synchronized (pooledObject) {
+ if (pooledObject.getState() != PooledObjectState.ALLOCATED) {
+ throw new IllegalStateException("Object has already been returned to this pool or is invalid");
+ }
+ pooledObject.markReturning(); // Keep from being marked abandoned
+ }
}
/**
- * Provides the stack trace for the call that created this pool. JMX
- * registration may trigger a memory leak so it is important that pools are
- * deregistered when no longer used by calling the {@link #close()} method.
- * This method is provided to assist with identifying code that creates but
- * does not close it thereby creating a memory leak.
- * @return pool creation stack trace
+ * Sets the abandoned object removal configuration.
+ *
+ * @param abandonedConfig the new configuration to use. This is used by value.
+ *
+ * @see AbandonedConfig
+ * @since 2.11.0
*/
- public final String getCreationStackTrace() {
- return creationStackTrace;
+ public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
+ this.abandonedConfig = AbandonedConfig.copy(abandonedConfig);
}
/**
- * The total number of objects successfully borrowed from this pool over the
- * lifetime of the pool.
- * @return the borrowed object count
+ * Sets whether to block when the {@code borrowObject()} method is
+ * invoked when the pool is exhausted (the maximum number of "active"
+ * objects has been reached).
+ *
+ * @param blockWhenExhausted {@code true} if
+ * {@code borrowObject()} should block
+ * when the pool is exhausted
+ *
+ * @see #getBlockWhenExhausted
*/
- public final long getBorrowedCount() {
- return borrowedCount.get();
+ public final void setBlockWhenExhausted(final boolean blockWhenExhausted) {
+ this.blockWhenExhausted = blockWhenExhausted;
}
/**
- * The total number of objects returned to this pool over the lifetime of
- * the pool. This excludes attempts to return the same object multiple
- * times.
- * @return the returned object count
+ * Initializes the receiver with the given configuration.
+ *
+ * @param config Initialization source.
*/
- public final long getReturnedCount() {
- return returnedCount.get();
- }
-
- /**
- * The total number of objects created for this pool over the lifetime of
- * the pool.
- * @return the created object count
- */
- public final long getCreatedCount() {
- return createdCount.get();
+ protected void setConfig(final BaseObjectPoolConfig<T> config) {
+ setLifo(config.getLifo());
+ setMaxWait(config.getMaxWaitDuration());
+ setBlockWhenExhausted(config.getBlockWhenExhausted());
+ setTestOnCreate(config.getTestOnCreate());
+ setTestOnBorrow(config.getTestOnBorrow());
+ setTestOnReturn(config.getTestOnReturn());
+ setTestWhileIdle(config.getTestWhileIdle());
+ setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun());
+ setMinEvictableIdle(config.getMinEvictableIdleDuration());
+ setTimeBetweenEvictionRuns(config.getDurationBetweenEvictionRuns());
+ setSoftMinEvictableIdle(config.getSoftMinEvictableIdleDuration());
+ final EvictionPolicy<T> policy = config.getEvictionPolicy();
+ if (policy == null) {
+ // Use the class name (pre-2.6.0 compatible)
+ setEvictionPolicyClassName(config.getEvictionPolicyClassName());
+ } else {
+ // Otherwise, use the class (2.6.0 feature)
+ setEvictionPolicy(policy);
+ }
+ setEvictorShutdownTimeout(config.getEvictorShutdownTimeoutDuration());
}
/**
- * The total number of objects destroyed by this pool over the lifetime of
- * the pool.
- * @return the destroyed object count
+ * Sets the eviction policy for this pool.
+ *
+ * @param evictionPolicy
+ * the eviction policy for this pool.
+ * @since 2.6.0
*/
- public final long getDestroyedCount() {
- return destroyedCount.get();
+ public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
+ this.evictionPolicy = evictionPolicy;
}
/**
- * The total number of objects destroyed by the evictor associated with this
- * pool over the lifetime of the pool.
- * @return the evictor destroyed object count
+ * Sets the eviction policy.
+ *
+ * @param className Eviction policy class name.
+ * @param classLoader Load the class from this class loader.
*/
- public final long getDestroyedByEvictorCount() {
- return destroyedByEvictorCount.get();
+ @SuppressWarnings("unchecked")
+ private void setEvictionPolicy(final String className, final ClassLoader classLoader)
+ throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ final Class<?> clazz = Class.forName(className, true, classLoader);
+ final Object policy = clazz.getConstructor().newInstance();
+ this.evictionPolicy = (EvictionPolicy<T>) policy;
}
/**
- * The total number of objects destroyed by this pool as a result of failing
- * validation during {@code borrowObject()} over the lifetime of the
- * pool.
- * @return validation destroyed object count
+ * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
+ * load the class using the thread context class loader. If that fails, the use the class loader for the
+ * {@link EvictionPolicy} interface.
+ *
+ * @param evictionPolicyClassName
+ * the fully qualified class name of the new eviction policy
+ *
+ * @see #getEvictionPolicyClassName()
+ * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
+ * {@link EvictionPolicy} interface.
*/
- public final long getDestroyedByBorrowValidationCount() {
- return destroyedByBorrowValidationCount.get();
+ public final void setEvictionPolicyClassName(final String evictionPolicyClassName) {
+ setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader());
}
/**
- * The mean time objects are active for based on the last {@link
- * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
- * @return mean time an object has been checked out from the pool among
- * recently returned objects
+ * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
+ * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
+ * interface.
+ *
+ * @param evictionPolicyClassName
+ * the fully qualified class name of the new eviction policy
+ * @param classLoader
+ * the class loader to load the given {@code evictionPolicyClassName}.
+ *
+ * @see #getEvictionPolicyClassName()
+ * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the
+ * {@link EvictionPolicy} interface.
*/
- public final long getMeanActiveTimeMillis() {
- return activeTimes.getMean();
+ public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) {
+ // Getting epClass here and now best matches the caller's environment
+ final Class<?> epClass = EvictionPolicy.class;
+ final ClassLoader epClassLoader = epClass.getClassLoader();
+ try {
+ try {
+ setEvictionPolicy(evictionPolicyClassName, classLoader);
+ } catch (final ClassCastException | ClassNotFoundException e) {
+ setEvictionPolicy(evictionPolicyClassName, epClassLoader);
+ }
+ } catch (final ClassCastException e) {
+ throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders [" +
+ classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME);
+ } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException |
+ InvocationTargetException | NoSuchMethodException e) {
+ throw new IllegalArgumentException(
+ "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type " + evictionPolicyClassName,
+ e);
+ }
}
/**
- * The mean time objects are idle for based on the last {@link
- * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
- * @return mean time an object has been idle in the pool among recently
- * borrowed objects
+ * Sets the timeout that will be used when waiting for the Evictor to shutdown if this pool is closed and it is the
+ * only pool still using the the value for the Evictor.
+ *
+ * @param evictorShutdownTimeout the timeout in milliseconds that will be used while waiting for the Evictor
+ * to shut down.
+ * @since 2.10.0
*/
- public final long getMeanIdleTimeMillis() {
- return idleTimes.getMean();
+ public final void setEvictorShutdownTimeout(final Duration evictorShutdownTimeout) {
+ this.evictorShutdownTimeoutDuration = PoolImplUtils.nonNull(evictorShutdownTimeout, BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT);
}
/**
- * The mean time threads wait to borrow an object based on the last {@link
- * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
- * @return mean time in milliseconds that a recently served thread has had
- * to wait to borrow an object from the pool
+ * Sets the timeout that will be used when waiting for the Evictor to shutdown if this pool is closed and it is the
+ * only pool still using the the value for the Evictor.
+ *
+ * @param evictorShutdownTimeoutMillis the timeout in milliseconds that will be used while waiting for the Evictor
+ * to shut down.
+ * @deprecated Use {@link #setEvictorShutdownTimeout(Duration)}.
*/
- public final long getMeanBorrowWaitTimeMillis() {
- return waitTimes.getMean();
+ @Deprecated
+ public final void setEvictorShutdownTimeoutMillis(final long evictorShutdownTimeoutMillis) {
+ setEvictorShutdownTimeout(Duration.ofMillis(evictorShutdownTimeoutMillis));
}
/**
- * The maximum time a thread has waited to borrow objects from the pool.
- * @return maximum wait time in milliseconds since the pool was created
+ * Sets whether the pool has LIFO (last in, first out) behavior with
+ * respect to idle objects - always returning the most recently used object
+ * from the pool, or as a FIFO (first in, first out) queue, where the pool
+ * always returns the oldest object in the idle object pool.
+ *
+ * @param lifo {@code true} if the pool is to be configured with LIFO
+ * behavior or {@code false} if the pool is to be
+ * configured with FIFO behavior
+ *
+ * @see #getLifo()
*/
- public final long getMaxBorrowWaitTimeMillis() {
- return maxBorrowWaitTimeMillis.get();
+ public final void setLifo(final boolean lifo) {
+ this.lifo = lifo;
}
/**
- * The number of instances currently idle in this pool.
- * @return count of instances available for checkout from the pool
+ * Sets the cap on the number of objects that can be allocated by the pool
+ * (checked out to clients, or idle awaiting checkout) at a given time. Use
+ * a negative value for no limit.
+ *
+ * @param maxTotal The cap on the total number of object instances managed
+ * by the pool. Negative values mean that there is no limit
+ * to the number of objects allocated by the pool.
+ *
+ * @see #getMaxTotal
*/
- public abstract int getNumIdle();
+ public final void setMaxTotal(final int maxTotal) {
+ this.maxTotal = maxTotal;
+ }
/**
- * The listener used (if any) to receive notifications of exceptions
- * unavoidably swallowed by the pool.
+ * Sets the maximum duration the
+ * {@code borrowObject()} method should block before throwing an
+ * exception when the pool is exhausted and
+ * {@link #getBlockWhenExhausted} is true. When less than 0, the
+ * {@code borrowObject()} method may block indefinitely.
*
- * @return The listener or {@code null} for no listener
+ * @param maxWaitDuration the maximum duration
+ * {@code borrowObject()} will block or negative
+ * for indefinitely.
+ *
+ * @see #getMaxWaitDuration
+ * @see #setBlockWhenExhausted
+ * @since 2.11.0
*/
- public final SwallowedExceptionListener getSwallowedExceptionListener() {
- return swallowedExceptionListener;
+ public final void setMaxWait(final Duration maxWaitDuration) {
+ this.maxWaitDuration = PoolImplUtils.nonNull(maxWaitDuration, BaseObjectPoolConfig.DEFAULT_MAX_WAIT);
}
/**
- * The listener used (if any) to receive notifications of exceptions
- * unavoidably swallowed by the pool.
+ * Sets the maximum amount of time (in milliseconds) the
+ * {@code borrowObject()} method should block before throwing an
+ * exception when the pool is exhausted and
+ * {@link #getBlockWhenExhausted} is true. When less than 0, the
+ * {@code borrowObject()} method may block indefinitely.
*
- * @param swallowedExceptionListener The listener or {@code null}
- * for no listener
+ * @param maxWaitMillis the maximum number of milliseconds
+ * {@code borrowObject()} will block or negative
+ * for indefinitely.
+ *
+ * @see #getMaxWaitDuration
+ * @see #setBlockWhenExhausted
+ * @deprecated Use {@link #setMaxWait}.
*/
- public final void setSwallowedExceptionListener(
- final SwallowedExceptionListener swallowedExceptionListener) {
- this.swallowedExceptionListener = swallowedExceptionListener;
+ @Deprecated
+ public final void setMaxWaitMillis(final long maxWaitMillis) {
+ setMaxWait(Duration.ofMillis(maxWaitMillis));
}
/**
- * Swallows an exception and notifies the configured listener for swallowed
- * exceptions queue.
+ * Sets whether to include statistics in exception messages.
+ * <p>
+ * Statistics may not accurately reflect snapshot state at the time of the exception because we do not want to lock the pool when gathering this
+ * information.
+ * </p>
*
- * @param swallowException exception to be swallowed
+ * @param messagesDetails whether to include statistics in exception messages.
+ * @since 2.11.0
*/
- final void swallowException(final Exception swallowException) {
- final SwallowedExceptionListener listener = getSwallowedExceptionListener();
-
- if (listener == null) {
- return;
- }
-
- try {
- listener.onSwallowException(swallowException);
- } catch (final VirtualMachineError e) {
- throw e;
- } catch (final Throwable t) {
- // Ignore. Enjoy the irony.
- }
+ public void setMessagesStatistics(final boolean messagesDetails) {
+ this.messageStatistics = messagesDetails;
}
/**
- * Updates statistics after an object is borrowed from the pool.
- * @param p object borrowed from the pool
- * @param waitTime time (in milliseconds) that the borrowing thread had to wait
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
+ *
+ * @param minEvictableIdleTime
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction
+ *
+ * @see #getMinEvictableIdleTime
+ * @see #setTimeBetweenEvictionRuns
+ * @since 2.11.0
*/
- final void updateStatsBorrow(final PooledObject<T> p, final long waitTime) {
- borrowedCount.incrementAndGet();
- idleTimes.add(p.getIdleTimeMillis());
- waitTimes.add(waitTime);
-
- // lock-free optimistic-locking maximum
- long currentMax;
- do {
- currentMax = maxBorrowWaitTimeMillis.get();
- if (currentMax >= waitTime) {
- break;
- }
- } while (!maxBorrowWaitTimeMillis.compareAndSet(currentMax, waitTime));
+ public final void setMinEvictableIdle(final Duration minEvictableIdleTime) {
+ this.minEvictableIdleDuration = PoolImplUtils.nonNull(minEvictableIdleTime, BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION);
}
/**
- * Updates statistics after an object is returned to the pool.
- * @param activeTime the amount of time (in milliseconds) that the returning
- * object was checked out
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
+ *
+ * @param minEvictableIdleTime
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction
+ *
+ * @see #getMinEvictableIdleTime
+ * @see #setTimeBetweenEvictionRuns
+ * @since 2.10.0
+ * @deprecated Use {@link #setMinEvictableIdle(Duration)}.
*/
- final void updateStatsReturn(final long activeTime) {
- returnedCount.incrementAndGet();
- activeTimes.add(activeTime);
+ @Deprecated
+ public final void setMinEvictableIdleTime(final Duration minEvictableIdleTime) {
+ this.minEvictableIdleDuration = PoolImplUtils.nonNull(minEvictableIdleTime, BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION);
}
/**
- * Marks the object as returning to the pool.
- * @param pooledObject instance to return to the keyed pool
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
+ * no objects will be evicted from the pool due to idle time alone.
+ *
+ * @param minEvictableIdleTimeMillis
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction
+ *
+ * @see #getMinEvictableIdleTimeMillis
+ * @see #setTimeBetweenEvictionRunsMillis
+ * @deprecated Use {@link #setMinEvictableIdleTime(Duration)}.
*/
- protected void markReturningState(final PooledObject<T> pooledObject) {
- synchronized(pooledObject) {
- final PooledObjectState state = pooledObject.getState();
- if (state != PooledObjectState.ALLOCATED) {
- throw new IllegalStateException(
- "Object has already been returned to this pool or is invalid");
- }
- pooledObject.markReturning(); // Keep from being marked abandoned
- }
+ @Deprecated
+ public final void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
+ setMinEvictableIdleTime(Duration.ofMillis(minEvictableIdleTimeMillis));
}
/**
- * Unregisters this pool's MBean.
+ * Sets the maximum number of objects to examine during each run (if any)
+ * of the idle object evictor thread. When positive, the number of tests
+ * performed for a run will be the minimum of the configured value and the
+ * number of idle instances in the pool. When negative, the number of tests
+ * performed will be <code>ceil({@link #getNumIdle}/
+ * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
+ * value is {@code -n} roughly one nth of the idle objects will be
+ * tested per run.
+ *
+ * @param numTestsPerEvictionRun
+ * max number of objects to examine during each evictor run
+ *
+ * @see #getNumTestsPerEvictionRun
+ * @see #setTimeBetweenEvictionRunsMillis
*/
- final void jmxUnregister() {
- if (objectName != null) {
- try {
- ManagementFactory.getPlatformMBeanServer().unregisterMBean(
- objectName);
- } catch (final MBeanRegistrationException | InstanceNotFoundException e) {
- swallowException(e);
- }
- }
+ public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
+ this.numTestsPerEvictionRun = numTestsPerEvictionRun;
}
/**
- * Registers the pool with the platform MBean server.
- * The registered name will be
- * {@code jmxNameBase + jmxNamePrefix + i} where i is the least
- * integer greater than or equal to 1 such that the name is not already
- * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
- * returning null.
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}),
+ * with the extra condition that at least {@code minIdle} object
+ * instances remain in the pool. This setting is overridden by
+ * {@link #getMinEvictableIdleTime} (that is, if
+ * {@link #getMinEvictableIdleTime} is positive, then
+ * {@link #getSoftMinEvictableIdleTime} is ignored).
*
- * @param config Pool configuration
- * @param jmxNameBase default base JMX name for this pool
- * @param jmxNamePrefix name prefix
- * @return registered ObjectName, null if registration fails
+ * @param softMinEvictableIdleTime
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction if minIdle instances are
+ * available
+ *
+ * @see #getSoftMinEvictableIdleTimeMillis
+ * @since 2.11.0
*/
- private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config,
- final String jmxNameBase, String jmxNamePrefix) {
- ObjectName newObjectName = null;
- final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- int i = 1;
- boolean registered = false;
- String base = config.getJmxNameBase();
- if (base == null) {
- base = jmxNameBase;
- }
- while (!registered) {
- try {
- ObjectName objName;
- // Skip the numeric suffix for the first pool in case there is
- // only one so the names are cleaner.
- if (i == 1) {
- objName = new ObjectName(base + jmxNamePrefix);
- } else {
- objName = new ObjectName(base + jmxNamePrefix + i);
- }
- mbs.registerMBean(this, objName);
- newObjectName = objName;
- registered = true;
- } catch (final MalformedObjectNameException e) {
- if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
- jmxNamePrefix) && jmxNameBase.equals(base)) {
- // Shouldn't happen. Skip registration if it does.
- registered = true;
- } else {
- // Must be an invalid name. Use the defaults instead.
- jmxNamePrefix =
- BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
- base = jmxNameBase;
- }
- } catch (final InstanceAlreadyExistsException e) {
- // Increment the index and try again
- i++;
- } catch (final MBeanRegistrationException | NotCompliantMBeanException e) {
- // Shouldn't happen. Skip registration if it does.
- registered = true;
- }
- }
- return newObjectName;
+ public final void setSoftMinEvictableIdle(final Duration softMinEvictableIdleTime) {
+ this.softMinEvictableIdleDuration = PoolImplUtils.nonNull(softMinEvictableIdleTime, BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION);
}
/**
- * Gets the stack trace of an exception as a string.
- * @param e exception to trace
- * @return exception stack trace as a string
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRuns(Duration)}),
+ * with the extra condition that at least {@code minIdle} object
+ * instances remain in the pool. This setting is overridden by
+ * {@link #getMinEvictableIdleTime} (that is, if
+ * {@link #getMinEvictableIdleTime} is positive, then
+ * {@link #getSoftMinEvictableIdleTime} is ignored).
+ *
+ * @param softMinEvictableIdleTime
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction if minIdle instances are
+ * available
+ *
+ * @see #getSoftMinEvictableIdleTimeMillis
+ * @since 2.10.0
+ * @deprecated Use {@link #setSoftMinEvictableIdle(Duration)}.
*/
- private String getStackTrace(final Exception e) {
- // Need the exception in string form to prevent the retention of
- // references to classes in the stack trace that could trigger a memory
- // leak in a container environment.
- final Writer w = new StringWriter();
- final PrintWriter pw = new PrintWriter(w);
- e.printStackTrace(pw);
- return w.toString();
+ @Deprecated
+ public final void setSoftMinEvictableIdleTime(final Duration softMinEvictableIdleTime) {
+ this.softMinEvictableIdleDuration = PoolImplUtils.nonNull(softMinEvictableIdleTime, BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION);
}
- // Inner classes
-
/**
- * The idle object evictor {@link TimerTask}.
+ * Sets the minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction by the idle object evictor (if any -
+ * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
+ * with the extra condition that at least {@code minIdle} object
+ * instances remain in the pool. This setting is overridden by
+ * {@link #getMinEvictableIdleTimeMillis} (that is, if
+ * {@link #getMinEvictableIdleTimeMillis} is positive, then
+ * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
*
- * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
+ * @param softMinEvictableIdleTimeMillis
+ * minimum amount of time an object may sit idle in the pool
+ * before it is eligible for eviction if minIdle instances are
+ * available
+ *
+ * @see #getSoftMinEvictableIdleTimeMillis
+ * @deprecated Use {@link #setSoftMinEvictableIdle(Duration)}.
*/
- class Evictor implements Runnable {
-
- private ScheduledFuture<?> scheduledFuture;
-
- /**
- * Run pool maintenance. Evict objects qualifying for eviction and then
- * ensure that the minimum number of idle instances are available.
- * Since the Timer that invokes Evictors is shared for all Pools but
- * pools may exist in different class loaders, the Evictor ensures that
- * any actions taken are under the class loader of the factory
- * associated with the pool.
- */
- @Override
- public void run() {
- final ClassLoader savedClassLoader =
- Thread.currentThread().getContextClassLoader();
- try {
- if (factoryClassLoader != null) {
- // Set the class loader for the factory
- final ClassLoader cl = factoryClassLoader.get();
- if (cl == null) {
- // The pool has been dereferenced and the class loader
- // GC'd. Cancel this timer so the pool can be GC'd as
- // well.
- cancel();
- return;
- }
- Thread.currentThread().setContextClassLoader(cl);
- }
-
- // Evict from the pool
- try {
- evict();
- } catch(final Exception e) {
- swallowException(e);
- } catch(final OutOfMemoryError oome) {
- // Log problem but give evictor thread a chance to continue
- // in case error is recoverable
- oome.printStackTrace(System.err);
- }
- // Re-create idle instances.
- try {
- ensureMinIdle();
- } catch (final Exception e) {
- swallowException(e);
- }
- } finally {
- // Restore the previous CCL
- Thread.currentThread().setContextClassLoader(savedClassLoader);
- }
- }
-
-
- /**
- * Sets the scheduled future.
- *
- * @param scheduledFuture the scheduled future.
- */
- void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
- this.scheduledFuture = scheduledFuture;
- }
+ @Deprecated
+ public final void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
+ setSoftMinEvictableIdleTime(Duration.ofMillis(softMinEvictableIdleTimeMillis));
+ }
+ /**
+ * The listener used (if any) to receive notifications of exceptions
+ * unavoidably swallowed by the pool.
+ *
+ * @param swallowedExceptionListener The listener or {@code null}
+ * for no listener
+ */
+ public final void setSwallowedExceptionListener(
+ final SwallowedExceptionListener swallowedExceptionListener) {
+ this.swallowedExceptionListener = swallowedExceptionListener;
+ }
- /**
- * Cancels the scheduled future.
- */
- void cancel() {
- scheduledFuture.cancel(false);
- }
+ /**
+ * Sets whether objects borrowed from the pool will be validated before
+ * being returned from the {@code borrowObject()} method. Validation is
+ * performed by the {@code validateObject()} method of the factory
+ * associated with the pool. If the object fails to validate, it will be
+ * removed from the pool and destroyed, and a new attempt will be made to
+ * borrow an object from the pool.
+ *
+ * @param testOnBorrow {@code true} if objects should be validated
+ * before being returned from the
+ * {@code borrowObject()} method
+ *
+ * @see #getTestOnBorrow
+ */
+ public final void setTestOnBorrow(final boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+ /**
+ * Sets whether objects created for the pool will be validated before
+ * being returned from the {@code borrowObject()} method. Validation is
+ * performed by the {@code validateObject()} method of the factory
+ * associated with the pool. If the object fails to validate, then
+ * {@code borrowObject()} will fail.
+ *
+ * @param testOnCreate {@code true} if newly created objects should be
+ * validated before being returned from the
+ * {@code borrowObject()} method
+ *
+ * @see #getTestOnCreate
+ *
+ * @since 2.2
+ */
+ public final void setTestOnCreate(final boolean testOnCreate) {
+ this.testOnCreate = testOnCreate;
}
/**
- * Maintains a cache of values for a single metric and reports
- * statistics on the cached values.
+ * Sets whether objects borrowed from the pool will be validated when
+ * they are returned to the pool via the {@code returnObject()} method.
+ * Validation is performed by the {@code validateObject()} method of
+ * the factory associated with the pool. Returning objects that fail validation
+ * are destroyed rather then being returned the pool.
+ *
+ * @param testOnReturn {@code true} if objects are validated on
+ * return to the pool via the
+ * {@code returnObject()} method
+ *
+ * @see #getTestOnReturn
*/
- private class StatsStore {
+ public final void setTestOnReturn(final boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
- private final AtomicLong values[];
- private final int size;
- private int index;
+ /**
+ * Sets whether objects sitting idle in the pool will be validated by the
+ * idle object evictor (if any - see
+ * {@link #setTimeBetweenEvictionRuns(Duration)}). Validation is performed
+ * by the {@code validateObject()} method of the factory associated
+ * with the pool. If the object fails to validate, it will be removed from
+ * the pool and destroyed. Note that setting this property has no effect
+ * unless the idle object evictor is enabled by setting
+ * {@code timeBetweenEvictionRunsMillis} to a positive value.
+ *
+ * @param testWhileIdle
+ * {@code true} so objects will be validated by the evictor
+ *
+ * @see #getTestWhileIdle
+ * @see #setTimeBetweenEvictionRuns
+ */
+ public final void setTestWhileIdle(final boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
- /**
- * Create a StatsStore with the given cache size.
- *
- * @param size number of values to maintain in the cache.
- */
- public StatsStore(final int size) {
- this.size = size;
- values = new AtomicLong[size];
- for (int i = 0; i < size; i++) {
- values[i] = new AtomicLong(-1);
- }
- }
+ /**
+ * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
+ * <ul>
+ * <li>When positive, the idle object evictor thread starts.</li>
+ * <li>When non-positive, no idle object evictor thread runs.</li>
+ * </ul>
+ *
+ * @param timeBetweenEvictionRuns
+ * duration to sleep between evictor runs
+ *
+ * @see #getDurationBetweenEvictionRuns()
+ * @since 2.10.0
+ */
+ public final void setTimeBetweenEvictionRuns(final Duration timeBetweenEvictionRuns) {
+ this.durationBetweenEvictionRuns = PoolImplUtils.nonNull(timeBetweenEvictionRuns, BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS);
+ startEvictor(this.durationBetweenEvictionRuns);
+ }
- /**
- * Adds a value to the cache. If the cache is full, one of the
- * existing values is replaced by the new value.
- *
- * @param value new value to add to the cache.
- */
- public synchronized void add(final long value) {
- values[index].set(value);
- index++;
- if (index == size) {
- index = 0;
- }
- }
+ /**
+ * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
+ * <ul>
+ * <li>When positive, the idle object evictor thread starts.</li>
+ * <li>When non-positive, no idle object evictor thread runs.</li>
+ * </ul>
+ *
+ * @param timeBetweenEvictionRunsMillis
+ * number of milliseconds to sleep between evictor runs
+ *
+ * @see #getDurationBetweenEvictionRuns()
+ * @deprecated Use {@link #setTimeBetweenEvictionRuns(Duration)}.
+ */
+ @Deprecated
+ public final void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+ setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
+ }
- /**
- * Returns the mean of the cached values.
- *
- * @return the mean of the cache, truncated to long
- */
- public long getMean() {
- double result = 0;
- int counter = 0;
- for (int i = 0; i < size; i++) {
- final long value = values[i].get();
- if (value != -1) {
- counter++;
- result = result * ((counter - 1) / (double) counter) +
- value/(double) counter;
+ /**
+ * <p>Starts the evictor with the given delay. If there is an evictor
+ * running when this method is called, it is stopped and replaced with a
+ * new evictor with the specified delay.</p>
+ *
+ * <p>This method needs to be final, since it is called from a constructor.
+ * See POOL-195.</p>
+ *
+ * @param delay time in milliseconds before start and between eviction runs
+ */
+ final void startEvictor(final Duration delay) {
+ synchronized (evictionLock) {
+ final boolean isPositiverDelay = PoolImplUtils.isPositive(delay);
+ if (evictor == null) { // Starting evictor for the first time or after a cancel
+ if (isPositiverDelay) { // Starting new evictor
+ evictor = new Evictor();
+ EvictionTimer.schedule(evictor, delay, delay);
+ }
+ } else if (isPositiverDelay) { // Stop or restart of existing evictor: Restart
+ synchronized (EvictionTimer.class) { // Ensure no cancel can happen between cancel / schedule calls
+ EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, true);
+ evictor = null;
+ evictionIterator = null;
+ evictor = new Evictor();
+ EvictionTimer.schedule(evictor, delay, delay);
}
+ } else { // Stopping evictor
+ EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, false);
}
- return (long) result;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("StatsStore [values=");
- builder.append(Arrays.toString(values));
- builder.append(", size=");
- builder.append(size);
- builder.append(", index=");
- builder.append(index);
- builder.append("]");
- return builder.toString();
}
}
/**
- * The idle object eviction iterator. Holds a reference to the idle objects.
+ * Stops the evictor.
*/
- class EvictionIterator implements Iterator<PooledObject<T>> {
-
- private final Deque<PooledObject<T>> idleObjects;
- private final Iterator<PooledObject<T>> idleObjectIterator;
-
- /**
- * Create an EvictionIterator for the provided idle instance deque.
- * @param idleObjects underlying deque
- */
- EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
- this.idleObjects = idleObjects;
-
- if (getLifo()) {
- idleObjectIterator = idleObjects.descendingIterator();
- } else {
- idleObjectIterator = idleObjects.iterator();
- }
- }
-
- /**
- * Returns the idle object deque referenced by this iterator.
- * @return the idle object deque
- */
- public Deque<PooledObject<T>> getIdleObjects() {
- return idleObjects;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean hasNext() {
- return idleObjectIterator.hasNext();
- }
-
- /** {@inheritDoc} */
- @Override
- public PooledObject<T> next() {
- return idleObjectIterator.next();
- }
-
- /** {@inheritDoc} */
- @Override
- public void remove() {
- idleObjectIterator.remove();
- }
-
+ void stopEvictor() {
+ startEvictor(Duration.ofMillis(-1L));
}
/**
- * Wrapper for objects under management by the pool.
- *
- * GenericObjectPool and GenericKeyedObjectPool maintain references to all
- * objects under management using maps keyed on the objects. This wrapper
- * class ensures that objects can work as hash keys.
+ * Swallows an exception and notifies the configured listener for swallowed
+ * exceptions queue.
*
- * @param <T> type of objects in the pool
+ * @param swallowException exception to be swallowed
*/
- static class IdentityWrapper<T> {
- /** Wrapped object */
- private final T instance;
-
- /**
- * Create a wrapper for an instance.
- *
- * @param instance object to wrap
- */
- public IdentityWrapper(final T instance) {
- this.instance = instance;
- }
-
- @Override
- public int hashCode() {
- return System.identityHashCode(instance);
- }
-
- @Override
- @SuppressWarnings("rawtypes")
- public boolean equals(final Object other) {
- return other instanceof IdentityWrapper &&
- ((IdentityWrapper) other).instance == instance;
- }
+ final void swallowException(final Exception swallowException) {
+ final SwallowedExceptionListener listener = getSwallowedExceptionListener();
- /**
- * @return the wrapped object
- */
- public T getObject() {
- return instance;
+ if (listener == null) {
+ return;
}
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("IdentityWrapper [instance=");
- builder.append(instance);
- builder.append("]");
- return builder.toString();
+ try {
+ listener.onSwallowException(swallowException);
+ } catch (final VirtualMachineError e) {
+ throw e;
+ } catch (final Throwable t) {
+ // Ignore. Enjoy the irony.
}
}
@@ -1374,8 +1830,8 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
builder.append(maxTotal);
builder.append(", blockWhenExhausted=");
builder.append(blockWhenExhausted);
- builder.append(", maxWaitMillis=");
- builder.append(maxWaitMillis);
+ builder.append(", maxWaitDuration=");
+ builder.append(maxWaitDuration);
builder.append(", lifo=");
builder.append(lifo);
builder.append(", fairness=");
@@ -1388,14 +1844,14 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
builder.append(testOnReturn);
builder.append(", testWhileIdle=");
builder.append(testWhileIdle);
- builder.append(", timeBetweenEvictionRunsMillis=");
- builder.append(timeBetweenEvictionRunsMillis);
+ builder.append(", durationBetweenEvictionRuns=");
+ builder.append(durationBetweenEvictionRuns);
builder.append(", numTestsPerEvictionRun=");
builder.append(numTestsPerEvictionRun);
- builder.append(", minEvictableIdleTimeMillis=");
- builder.append(minEvictableIdleTimeMillis);
- builder.append(", softMinEvictableIdleTimeMillis=");
- builder.append(softMinEvictableIdleTimeMillis);
+ builder.append(", minEvictableIdleTimeDuration=");
+ builder.append(minEvictableIdleDuration);
+ builder.append(", softMinEvictableIdleTimeDuration=");
+ builder.append(softMinEvictableIdleDuration);
builder.append(", evictionPolicy=");
builder.append(evictionPolicy);
builder.append(", closeLock=");
@@ -1432,11 +1888,46 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject {
builder.append(idleTimes);
builder.append(", waitTimes=");
builder.append(waitTimes);
- builder.append(", maxBorrowWaitTimeMillis=");
- builder.append(maxBorrowWaitTimeMillis);
+ builder.append(", maxBorrowWaitDuration=");
+ builder.append(maxBorrowWaitDuration);
builder.append(", swallowedExceptionListener=");
builder.append(swallowedExceptionListener);
}
+ /**
+ * Updates statistics after an object is borrowed from the pool.
+ *
+ * @param p object borrowed from the pool
+ * @param waitDuration that the borrowing thread had to wait
+ */
+ final void updateStatsBorrow(final PooledObject<T> p, final Duration waitDuration) {
+ borrowedCount.incrementAndGet();
+ idleTimes.add(p.getIdleDuration());
+ waitTimes.add(waitDuration);
+
+ // lock-free optimistic-locking maximum
+ Duration currentMaxDuration;
+ do {
+ currentMaxDuration = maxBorrowWaitDuration.get();
+// if (currentMaxDuration >= waitDuration) {
+// break;
+// }
+ if (currentMaxDuration.compareTo(waitDuration) >= 0) {
+ break;
+ }
+ } while (!maxBorrowWaitDuration.compareAndSet(currentMaxDuration, waitDuration));
+ }
+
+ /**
+ * Updates statistics after an object is returned to the pool.
+ *
+ * @param activeTime the amount of time (in milliseconds) that the returning
+ * object was checked out
+ */
+ final void updateStatsReturn(final Duration activeTime) {
+ returnedCount.incrementAndGet();
+ activeTimes.add(activeTime);
+ }
+
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
index 8e068f2..eee987a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
@@ -16,6 +16,8 @@
*/
package org.apache.tomcat.dbcp.pool2.impl;
+import java.time.Duration;
+
import org.apache.tomcat.dbcp.pool2.BaseObject;
/**
@@ -47,36 +49,104 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
/**
* The default value for the {@code maxWait} configuration attribute.
- * @see GenericObjectPool#getMaxWaitMillis()
- * @see GenericKeyedObjectPool#getMaxWaitMillis()
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @deprecated Use {@link #DEFAULT_MAX_WAIT}.
*/
+ @Deprecated
public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
/**
- * The default value for the {@code minEvictableIdleTimeMillis}
+ * The default value for the {@code maxWait} configuration attribute.
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @since 2.10.0
+ */
+ public static final Duration DEFAULT_MAX_WAIT = Duration.ofMillis(DEFAULT_MAX_WAIT_MILLIS);
+
+ /**
+ * The default value for the {@code minEvictableIdleDuration}
+ * configuration attribute.
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @deprecated Use {@link #DEFAULT_MIN_EVICTABLE_IDLE_TIME}.
+ */
+ @Deprecated
+ public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
+
+ /**
+ * The default value for the {@code minEvictableIdleDuration}
+ * configuration attribute.
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @since 2.11.0
+ */
+ public static final Duration DEFAULT_MIN_EVICTABLE_IDLE_DURATION =
+ Duration.ofMillis(DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
+
+ /**
+ * The default value for the {@code minEvictableIdleDuration}
* configuration attribute.
- * @see GenericObjectPool#getMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #DEFAULT_MIN_EVICTABLE_IDLE_DURATION}.
*/
- public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS =
- 1000L * 60L * 30L;
+ @Deprecated
+ public static final Duration DEFAULT_MIN_EVICTABLE_IDLE_TIME =
+ Duration.ofMillis(DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
/**
- * The default value for the {@code softMinEvictableIdleTimeMillis}
+ * The default value for the {@code softMinEvictableIdleTime}
* configuration attribute.
- * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @deprecated Use {@link #DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME}.
*/
+ @Deprecated
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
/**
- * The default value for {@code evictorShutdownTimeoutMillis} configuration
+ * The default value for the {@code softMinEvictableIdleTime}
+ * configuration attribute.
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION}.
+ */
+ @Deprecated
+ public static final Duration DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME =
+ Duration.ofMillis(DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
+
+ /**
+ * The default value for the {@code softMinEvictableIdleTime}
+ * configuration attribute.
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @since 2.11.0
+ */
+ public static final Duration DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION =
+ Duration.ofMillis(DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
+
+ /**
+ * The default value for {@code evictorShutdownTimeout} configuration
+ * attribute.
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @deprecated Use {@link #DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT}.
+ */
+ @Deprecated
+ public static final long DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS = 10L * 1000L;
+
+ /**
+ * The default value for {@code evictorShutdownTimeout} configuration
* attribute.
- * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
- * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @since 2.10.0
*/
- public static final long DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS =
- 10L * 1000L;
+ public static final Duration DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT =
+ Duration.ofMillis(DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS);
/**
* The default value for the {@code numTestsPerEvictionRun} configuration
@@ -117,14 +187,25 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
/**
- * The default value for the {@code timeBetweenEvictionRunsMillis}
+ * The default value for the {@code timeBetweenEvictionRuns}
* configuration attribute.
- * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
- * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @deprecated Use {@link #DEFAULT_TIME_BETWEEN_EVICTION_RUNS}.
*/
+ @Deprecated
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
/**
+ * The default value for the {@code timeBetweenEvictionRuns}
+ * configuration attribute.
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ */
+ public static final Duration DEFAULT_TIME_BETWEEN_EVICTION_RUNS = Duration
+ .ofMillis(DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
+
+ /**
* The default value for the {@code blockWhenExhausted} configuration
* attribute.
* @see GenericObjectPool#getBlockWhenExhausted()
@@ -167,21 +248,17 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
private boolean fairness = DEFAULT_FAIRNESS;
- private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;
+ private Duration maxWaitDuration = DEFAULT_MAX_WAIT;
- private long minEvictableIdleTimeMillis =
- DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration minEvictableIdleDuration = DEFAULT_MIN_EVICTABLE_IDLE_TIME;
- private long evictorShutdownTimeoutMillis =
- DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
+ private Duration evictorShutdownTimeoutDuration = DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT;
- private long softMinEvictableIdleTimeMillis =
- DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration softMinEvictableIdleDuration = DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME;
- private int numTestsPerEvictionRun =
- DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+ private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
- private EvictionPolicy<T> evictionPolicy = null; // Only 2.6.0 applications set this
+ private EvictionPolicy<T> evictionPolicy; // Only 2.6.0 applications set this
private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME;
@@ -193,8 +270,7 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
- private long timeBetweenEvictionRunsMillis =
- DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ private Duration durationBetweenEvictionRuns = DEFAULT_TIME_BETWEEN_EVICTION_RUNS;
private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;
@@ -207,241 +283,321 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
/**
- * Get the value for the {@code lifo} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code blockWhenExhausted} configuration attribute
+ * for pools created with this configuration instance.
*
- * @return The current setting of {@code lifo} for this configuration
- * instance
+ * @return The current setting of {@code blockWhenExhausted} for this
+ * configuration instance
*
- * @see GenericObjectPool#getLifo()
- * @see GenericKeyedObjectPool#getLifo()
+ * @see GenericObjectPool#getBlockWhenExhausted()
+ * @see GenericKeyedObjectPool#getBlockWhenExhausted()
*/
- public boolean getLifo() {
- return lifo;
+ public boolean getBlockWhenExhausted() {
+ return blockWhenExhausted;
}
/**
- * Get the value for the {@code fairness} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code timeBetweenEvictionRuns} configuration
+ * attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code fairness} for this configuration
- * instance
+ * @return The current setting of {@code timeBetweenEvictionRuns} for
+ * this configuration instance
*
- * @see GenericObjectPool#getFairness()
- * @see GenericKeyedObjectPool#getFairness()
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @since 2.11.0
*/
- public boolean getFairness() {
- return fairness;
+ public Duration getDurationBetweenEvictionRuns() {
+ return durationBetweenEvictionRuns;
}
/**
- * Set the value for the {@code lifo} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code evictionPolicyClass} configuration
+ * attribute for pools created with this configuration instance.
*
- * @param lifo The new setting of {@code lifo}
- * for this configuration instance
+ * @return The current setting of {@code evictionPolicyClass} for this
+ * configuration instance
*
- * @see GenericObjectPool#getLifo()
- * @see GenericKeyedObjectPool#getLifo()
+ * @see GenericObjectPool#getEvictionPolicy()
+ * @see GenericKeyedObjectPool#getEvictionPolicy()
+ * @since 2.6.0
*/
- public void setLifo(final boolean lifo) {
- this.lifo = lifo;
+ public EvictionPolicy<T> getEvictionPolicy() {
+ return evictionPolicy;
}
/**
- * Set the value for the {@code fairness} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code evictionPolicyClassName} configuration
+ * attribute for pools created with this configuration instance.
*
- * @param fairness The new setting of {@code fairness}
- * for this configuration instance
+ * @return The current setting of {@code evictionPolicyClassName} for this
+ * configuration instance
*
- * @see GenericObjectPool#getFairness()
- * @see GenericKeyedObjectPool#getFairness()
+ * @see GenericObjectPool#getEvictionPolicyClassName()
+ * @see GenericKeyedObjectPool#getEvictionPolicyClassName()
*/
- public void setFairness(final boolean fairness) {
- this.fairness = fairness;
+ public String getEvictionPolicyClassName() {
+ return evictionPolicyClassName;
}
/**
- * Get the value for the {@code maxWait} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code evictorShutdownTimeout} configuration
+ * attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code maxWait} for this
- * configuration instance
+ * @return The current setting of {@code evictorShutdownTimeout} for
+ * this configuration instance
*
- * @see GenericObjectPool#getMaxWaitMillis()
- * @see GenericKeyedObjectPool#getMaxWaitMillis()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #getEvictorShutdownTimeoutDuration()}.
*/
- public long getMaxWaitMillis() {
- return maxWaitMillis;
+ @Deprecated
+ public Duration getEvictorShutdownTimeout() {
+ return evictorShutdownTimeoutDuration;
}
/**
- * Set the value for the {@code maxWait} configuration attribute for pools
- * created with this configuration instance.
+ * Gets the value for the {@code evictorShutdownTimeout} configuration
+ * attribute for pools created with this configuration instance.
*
- * @param maxWaitMillis The new setting of {@code maxWaitMillis}
- * for this configuration instance
+ * @return The current setting of {@code evictorShutdownTimeout} for
+ * this configuration instance
*
- * @see GenericObjectPool#getMaxWaitMillis()
- * @see GenericKeyedObjectPool#getMaxWaitMillis()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @since 2.11.0
*/
- public void setMaxWaitMillis(final long maxWaitMillis) {
- this.maxWaitMillis = maxWaitMillis;
+ public Duration getEvictorShutdownTimeoutDuration() {
+ return evictorShutdownTimeoutDuration;
}
/**
- * Get the value for the {@code minEvictableIdleTimeMillis} configuration
+ * Gets the value for the {@code evictorShutdownTimeout} configuration
* attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code minEvictableIdleTimeMillis} for
+ * @return The current setting of {@code evictorShutdownTimeout} for
* this configuration instance
*
- * @see GenericObjectPool#getMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @deprecated Use {@link #getEvictorShutdownTimeout()}.
*/
- public long getMinEvictableIdleTimeMillis() {
- return minEvictableIdleTimeMillis;
+ @Deprecated
+ public long getEvictorShutdownTimeoutMillis() {
+ return evictorShutdownTimeoutDuration.toMillis();
}
/**
- * Set the value for the {@code minEvictableIdleTimeMillis} configuration
- * attribute for pools created with this configuration instance.
+ * Gets the value for the {@code fairness} configuration attribute for pools
+ * created with this configuration instance.
*
- * @param minEvictableIdleTimeMillis The new setting of
- * {@code minEvictableIdleTimeMillis} for this configuration instance
+ * @return The current setting of {@code fairness} for this configuration
+ * instance
*
- * @see GenericObjectPool#getMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
+ * @see GenericObjectPool#getFairness()
+ * @see GenericKeyedObjectPool#getFairness()
*/
- public void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ public boolean getFairness() {
+ return fairness;
}
/**
- * Get the value for the {@code softMinEvictableIdleTimeMillis}
- * configuration attribute for pools created with this configuration
- * instance.
+ * Gets the value of the flag that determines if JMX will be enabled for
+ * pools created with this configuration instance.
*
- * @return The current setting of {@code softMinEvictableIdleTimeMillis}
- * for this configuration instance
+ * @return The current setting of {@code jmxEnabled} for this configuration
+ * instance
+ */
+ public boolean getJmxEnabled() {
+ return jmxEnabled;
+ }
+
+ /**
+ * Gets the value of the JMX name base that will be used as part of the
+ * name assigned to JMX enabled pools created with this configuration
+ * instance. A value of {@code null} means that the pool will define
+ * the JMX name base.
*
- * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
+ * @return The current setting of {@code jmxNameBase} for this
+ * configuration instance
*/
- public long getSoftMinEvictableIdleTimeMillis() {
- return softMinEvictableIdleTimeMillis;
+ public String getJmxNameBase() {
+ return jmxNameBase;
}
/**
- * Set the value for the {@code softMinEvictableIdleTimeMillis}
- * configuration attribute for pools created with this configuration
+ * Gets the value of the JMX name prefix that will be used as part of the
+ * name assigned to JMX enabled pools created with this configuration
* instance.
*
- * @param softMinEvictableIdleTimeMillis The new setting of
- * {@code softMinEvictableIdleTimeMillis} for this configuration
- * instance
+ * @return The current setting of {@code jmxNamePrefix} for this
+ * configuration instance
+ */
+ public String getJmxNamePrefix() {
+ return jmxNamePrefix;
+ }
+
+ /**
+ * Gets the value for the {@code lifo} configuration attribute for pools
+ * created with this configuration instance.
+ *
+ * @return The current setting of {@code lifo} for this configuration
+ * instance
*
- * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis()
- * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()
+ * @see GenericObjectPool#getLifo()
+ * @see GenericKeyedObjectPool#getLifo()
*/
- public void setSoftMinEvictableIdleTimeMillis(
- final long softMinEvictableIdleTimeMillis) {
- this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+ public boolean getLifo() {
+ return lifo;
}
/**
- * Get the value for the {@code numTestsPerEvictionRun} configuration
- * attribute for pools created with this configuration instance.
+ * Gets the value for the {@code maxWait} configuration attribute for pools
+ * created with this configuration instance.
*
- * @return The current setting of {@code numTestsPerEvictionRun} for this
+ * @return The current setting of {@code maxWait} for this
* configuration instance
*
- * @see GenericObjectPool#getNumTestsPerEvictionRun()
- * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @since 2.11.0
*/
- public int getNumTestsPerEvictionRun() {
- return numTestsPerEvictionRun;
+ public Duration getMaxWaitDuration() {
+ return maxWaitDuration;
}
/**
- * Set the value for the {@code numTestsPerEvictionRun} configuration
+ * Gets the value for the {@code maxWait} configuration attribute for pools
+ * created with this configuration instance.
+ *
+ * @return The current setting of {@code maxWait} for this
+ * configuration instance
+ *
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @deprecated Use {@link #getMaxWaitDuration()}.
+ */
+ @Deprecated
+ public long getMaxWaitMillis() {
+ return maxWaitDuration.toMillis();
+ }
+
+ /**
+ * Gets the value for the {@code minEvictableIdleTime} configuration
* attribute for pools created with this configuration instance.
*
- * @param numTestsPerEvictionRun The new setting of
- * {@code numTestsPerEvictionRun} for this configuration instance
+ * @return The current setting of {@code minEvictableIdleTime} for
+ * this configuration instance
*
- * @see GenericObjectPool#getNumTestsPerEvictionRun()
- * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @since 2.11.0
*/
- public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
- this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ public Duration getMinEvictableIdleDuration() {
+ return minEvictableIdleDuration;
}
/**
- * Get the value for the {@code evictorShutdownTimeoutMillis} configuration
+ * Gets the value for the {@code minEvictableIdleTime} configuration
* attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code evictorShutdownTimeoutMillis} for
+ * @return The current setting of {@code minEvictableIdleTime} for
* this configuration instance
*
- * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
- * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #getMinEvictableIdleDuration()}.
*/
- public long getEvictorShutdownTimeoutMillis() {
- return evictorShutdownTimeoutMillis;
+ @Deprecated
+ public Duration getMinEvictableIdleTime() {
+ return minEvictableIdleDuration;
}
/**
- * Set the value for the {@code evictorShutdownTimeoutMillis} configuration
+ * Gets the value for the {@code minEvictableIdleTime} configuration
* attribute for pools created with this configuration instance.
*
- * @param evictorShutdownTimeoutMillis The new setting of
- * {@code evictorShutdownTimeoutMillis} for this configuration
- * instance
+ * @return The current setting of {@code minEvictableIdleTime} for
+ * this configuration instance
*
- * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
- * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @deprecated Use {@link #getMinEvictableIdleTime()}.
*/
- public void setEvictorShutdownTimeoutMillis(
- final long evictorShutdownTimeoutMillis) {
- this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
+ @Deprecated
+ public long getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleDuration.toMillis();
}
/**
- * Get the value for the {@code testOnCreate} configuration attribute for
- * pools created with this configuration instance.
+ * Gets the value for the {@code numTestsPerEvictionRun} configuration
+ * attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code testOnCreate} for this
+ * @return The current setting of {@code numTestsPerEvictionRun} for this
* configuration instance
*
- * @see GenericObjectPool#getTestOnCreate()
- * @see GenericKeyedObjectPool#getTestOnCreate()
+ * @see GenericObjectPool#getNumTestsPerEvictionRun()
+ * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
+ */
+ public int getNumTestsPerEvictionRun() {
+ return numTestsPerEvictionRun;
+ }
+
+ /**
+ * Gets the value for the {@code softMinEvictableIdleTime}
+ * configuration attribute for pools created with this configuration
+ * instance.
*
- * @since 2.2
+ * @return The current setting of {@code softMinEvictableIdleTime}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @since 2.11.0
*/
- public boolean getTestOnCreate() {
- return testOnCreate;
+ public Duration getSoftMinEvictableIdleDuration() {
+ return softMinEvictableIdleDuration;
}
/**
- * Set the value for the {@code testOnCreate} configuration attribute for
- * pools created with this configuration instance.
+ * Gets the value for the {@code softMinEvictableIdleTime}
+ * configuration attribute for pools created with this configuration
+ * instance.
*
- * @param testOnCreate The new setting of {@code testOnCreate}
- * for this configuration instance
+ * @return The current setting of {@code softMinEvictableIdleTime}
+ * for this configuration instance
*
- * @see GenericObjectPool#getTestOnCreate()
- * @see GenericKeyedObjectPool#getTestOnCreate()
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #getSoftMinEvictableIdleDuration()}.
+ */
+ @Deprecated
+ public Duration getSoftMinEvictableIdleTime() {
+ return softMinEvictableIdleDuration;
+ }
+
+ /**
+ * Gets the value for the {@code softMinEvictableIdleTime}
+ * configuration attribute for pools created with this configuration
+ * instance.
*
- * @since 2.2
+ * @return The current setting of {@code softMinEvictableIdleTime}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @deprecated Use {@link #getSoftMinEvictableIdleDuration()}.
*/
- public void setTestOnCreate(final boolean testOnCreate) {
- this.testOnCreate = testOnCreate;
+ @Deprecated
+ public long getSoftMinEvictableIdleTimeMillis() {
+ return softMinEvictableIdleDuration.toMillis();
}
/**
- * Get the value for the {@code testOnBorrow} configuration attribute for
+ * Gets the value for the {@code testOnBorrow} configuration attribute for
* pools created with this configuration instance.
*
* @return The current setting of {@code testOnBorrow} for this
@@ -455,21 +611,23 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
}
/**
- * Set the value for the {@code testOnBorrow} configuration attribute for
+ * Gets the value for the {@code testOnCreate} configuration attribute for
* pools created with this configuration instance.
*
- * @param testOnBorrow The new setting of {@code testOnBorrow}
- * for this configuration instance
+ * @return The current setting of {@code testOnCreate} for this
+ * configuration instance
*
- * @see GenericObjectPool#getTestOnBorrow()
- * @see GenericKeyedObjectPool#getTestOnBorrow()
+ * @see GenericObjectPool#getTestOnCreate()
+ * @see GenericKeyedObjectPool#getTestOnCreate()
+ *
+ * @since 2.2
*/
- public void setTestOnBorrow(final boolean testOnBorrow) {
- this.testOnBorrow = testOnBorrow;
+ public boolean getTestOnCreate() {
+ return testOnCreate;
}
/**
- * Get the value for the {@code testOnReturn} configuration attribute for
+ * Gets the value for the {@code testOnReturn} configuration attribute for
* pools created with this configuration instance.
*
* @return The current setting of {@code testOnReturn} for this
@@ -483,21 +641,7 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
}
/**
- * Set the value for the {@code testOnReturn} configuration attribute for
- * pools created with this configuration instance.
- *
- * @param testOnReturn The new setting of {@code testOnReturn}
- * for this configuration instance
- *
- * @see GenericObjectPool#getTestOnReturn()
- * @see GenericKeyedObjectPool#getTestOnReturn()
- */
- public void setTestOnReturn(final boolean testOnReturn) {
- this.testOnReturn = testOnReturn;
- }
-
- /**
- * Get the value for the {@code testWhileIdle} configuration attribute for
+ * Gets the value for the {@code testWhileIdle} configuration attribute for
* pools created with this configuration instance.
*
* @return The current setting of {@code testWhileIdle} for this
@@ -511,144 +655,144 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
}
/**
- * Set the value for the {@code testWhileIdle} configuration attribute for
- * pools created with this configuration instance.
+ * Gets the value for the {@code timeBetweenEvictionRuns} configuration
+ * attribute for pools created with this configuration instance.
*
- * @param testWhileIdle The new setting of {@code testWhileIdle}
- * for this configuration instance
+ * @return The current setting of {@code timeBetweenEvictionRuns} for
+ * this configuration instance
*
- * @see GenericObjectPool#getTestWhileIdle()
- * @see GenericKeyedObjectPool#getTestWhileIdle()
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @since 2.10.0
+ * @deprecated Use {@link #getDurationBetweenEvictionRuns()}.
*/
- public void setTestWhileIdle(final boolean testWhileIdle) {
- this.testWhileIdle = testWhileIdle;
+ @Deprecated
+ public Duration getTimeBetweenEvictionRuns() {
+ return durationBetweenEvictionRuns;
}
/**
- * Get the value for the {@code timeBetweenEvictionRunsMillis} configuration
+ * Gets the value for the {@code timeBetweenEvictionRuns} configuration
* attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code timeBetweenEvictionRunsMillis} for
+ * @return The current setting of {@code timeBetweenEvictionRuns} for
* this configuration instance
*
- * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
- * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @deprecated Use {@link #getDurationBetweenEvictionRuns()}.
*/
+ @Deprecated
public long getTimeBetweenEvictionRunsMillis() {
- return timeBetweenEvictionRunsMillis;
+ return durationBetweenEvictionRuns.toMillis();
}
/**
- * Set the value for the {@code timeBetweenEvictionRunsMillis} configuration
- * attribute for pools created with this configuration instance.
+ * Sets the value for the {@code blockWhenExhausted} configuration attribute
+ * for pools created with this configuration instance.
*
- * @param timeBetweenEvictionRunsMillis The new setting of
- * {@code timeBetweenEvictionRunsMillis} for this configuration
- * instance
+ * @param blockWhenExhausted The new setting of {@code blockWhenExhausted}
+ * for this configuration instance
*
- * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis()
- * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
+ * @see GenericObjectPool#getBlockWhenExhausted()
+ * @see GenericKeyedObjectPool#getBlockWhenExhausted()
*/
- public void setTimeBetweenEvictionRunsMillis(
- final long timeBetweenEvictionRunsMillis) {
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ public void setBlockWhenExhausted(final boolean blockWhenExhausted) {
+ this.blockWhenExhausted = blockWhenExhausted;
}
/**
- * Get the value for the {@code evictionPolicyClass} configuration
+ * Sets the value for the {@code evictionPolicyClass} configuration
* attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code evictionPolicyClass} for this
- * configuration instance
+ * @param evictionPolicy The new setting of
+ * {@code evictionPolicyClass} for this configuration instance
*
* @see GenericObjectPool#getEvictionPolicy()
* @see GenericKeyedObjectPool#getEvictionPolicy()
* @since 2.6.0
*/
- public EvictionPolicy<T> getEvictionPolicy() {
- return evictionPolicy;
+ public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
+ this.evictionPolicy = evictionPolicy;
}
/**
- * Get the value for the {@code evictionPolicyClassName} configuration
+ * Sets the value for the {@code evictionPolicyClassName} configuration
* attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code evictionPolicyClassName} for this
- * configuration instance
+ * @param evictionPolicyClassName The new setting of
+ * {@code evictionPolicyClassName} for this configuration instance
*
* @see GenericObjectPool#getEvictionPolicyClassName()
* @see GenericKeyedObjectPool#getEvictionPolicyClassName()
*/
- public String getEvictionPolicyClassName() {
- return evictionPolicyClassName;
+ public void setEvictionPolicyClassName(final String evictionPolicyClassName) {
+ this.evictionPolicyClassName = evictionPolicyClassName;
}
/**
- * Set the value for the {@code evictionPolicyClass} configuration
+ * Sets the value for the {@code evictorShutdownTimeout} configuration
* attribute for pools created with this configuration instance.
*
- * @param evictionPolicy The new setting of
- * {@code evictionPolicyClass} for this configuration instance
+ * @param evictorShutdownTimeoutDuration The new setting of
+ * {@code evictorShutdownTimeout} for this configuration
+ * instance
*
- * @see GenericObjectPool#getEvictionPolicy()
- * @see GenericKeyedObjectPool#getEvictionPolicy()
- * @since 2.6.0
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @since 2.11.0
*/
- public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
- this.evictionPolicy = evictionPolicy;
+ public void setEvictorShutdownTimeout(final Duration evictorShutdownTimeoutDuration) {
+ this.evictorShutdownTimeoutDuration = PoolImplUtils.nonNull(evictorShutdownTimeoutDuration, DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT);
}
/**
- * Set the value for the {@code evictionPolicyClassName} configuration
+ * Sets the value for the {@code evictorShutdownTimeout} configuration
* attribute for pools created with this configuration instance.
*
- * @param evictionPolicyClassName The new setting of
- * {@code evictionPolicyClassName} for this configuration instance
+ * @param evictorShutdownTimeout The new setting of
+ * {@code evictorShutdownTimeout} for this configuration
+ * instance
*
- * @see GenericObjectPool#getEvictionPolicyClassName()
- * @see GenericKeyedObjectPool#getEvictionPolicyClassName()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @since 2.10.0
+ * @deprecated Use {@link #setEvictorShutdownTimeout(Duration)}.
*/
- public void setEvictionPolicyClassName(final String evictionPolicyClassName) {
- this.evictionPolicyClassName = evictionPolicyClassName;
+ @Deprecated
+ public void setEvictorShutdownTimeoutMillis(final Duration evictorShutdownTimeout) {
+ setEvictorShutdownTimeout(evictorShutdownTimeout);
}
/**
- * Get the value for the {@code blockWhenExhausted} configuration attribute
- * for pools created with this configuration instance.
+ * Sets the value for the {@code evictorShutdownTimeout} configuration
+ * attribute for pools created with this configuration instance.
*
- * @return The current setting of {@code blockWhenExhausted} for this
- * configuration instance
+ * @param evictorShutdownTimeoutMillis The new setting of
+ * {@code evictorShutdownTimeout} for this configuration
+ * instance
*
- * @see GenericObjectPool#getBlockWhenExhausted()
- * @see GenericKeyedObjectPool#getBlockWhenExhausted()
+ * @see GenericObjectPool#getEvictorShutdownTimeoutDuration()
+ * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutDuration()
+ * @deprecated Use {@link #setEvictorShutdownTimeout(Duration)}.
*/
- public boolean getBlockWhenExhausted() {
- return blockWhenExhausted;
+ @Deprecated
+ public void setEvictorShutdownTimeoutMillis(final long evictorShutdownTimeoutMillis) {
+ setEvictorShutdownTimeout(Duration.ofMillis(evictorShutdownTimeoutMillis));
}
/**
- * Set the value for the {@code blockWhenExhausted} configuration attribute
- * for pools created with this configuration instance.
+ * Sets the value for the {@code fairness} configuration attribute for pools
+ * created with this configuration instance.
*
- * @param blockWhenExhausted The new setting of {@code blockWhenExhausted}
+ * @param fairness The new setting of {@code fairness}
* for this configuration instance
*
- * @see GenericObjectPool#getBlockWhenExhausted()
- * @see GenericKeyedObjectPool#getBlockWhenExhausted()
- */
- public void setBlockWhenExhausted(final boolean blockWhenExhausted) {
- this.blockWhenExhausted = blockWhenExhausted;
- }
-
- /**
- * Gets the value of the flag that determines if JMX will be enabled for
- * pools created with this configuration instance.
- *
- * @return The current setting of {@code jmxEnabled} for this configuration
- * instance
+ * @see GenericObjectPool#getFairness()
+ * @see GenericKeyedObjectPool#getFairness()
*/
- public boolean getJmxEnabled() {
- return jmxEnabled;
+ public void setFairness(final boolean fairness) {
+ this.fairness = fairness;
}
/**
@@ -663,53 +807,245 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
}
/**
- * Gets the value of the JMX name base that will be used as part of the
+ * Sets the value of the JMX name base that will be used as part of the
* name assigned to JMX enabled pools created with this configuration
* instance. A value of {@code null} means that the pool will define
* the JMX name base.
*
- * @return The current setting of {@code jmxNameBase} for this
- * configuration instance
+ * @param jmxNameBase The new setting of {@code jmxNameBase}
+ * for this configuration instance
*/
- public String getJmxNameBase() {
- return jmxNameBase;
+ public void setJmxNameBase(final String jmxNameBase) {
+ this.jmxNameBase = jmxNameBase;
}
/**
- * Sets the value of the JMX name base that will be used as part of the
+ * Sets the value of the JMX name prefix that will be used as part of the
* name assigned to JMX enabled pools created with this configuration
- * instance. A value of {@code null} means that the pool will define
- * the JMX name base.
+ * instance.
*
- * @param jmxNameBase The new setting of {@code jmxNameBase}
+ * @param jmxNamePrefix The new setting of {@code jmxNamePrefix}
* for this configuration instance
*/
- public void setJmxNameBase(final String jmxNameBase) {
- this.jmxNameBase = jmxNameBase;
+ public void setJmxNamePrefix(final String jmxNamePrefix) {
+ this.jmxNamePrefix = jmxNamePrefix;
}
/**
- * Gets the value of the JMX name prefix that will be used as part of the
- * name assigned to JMX enabled pools created with this configuration
+ * Sets the value for the {@code lifo} configuration attribute for pools
+ * created with this configuration instance.
+ *
+ * @param lifo The new setting of {@code lifo}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getLifo()
+ * @see GenericKeyedObjectPool#getLifo()
+ */
+ public void setLifo(final boolean lifo) {
+ this.lifo = lifo;
+ }
+
+ /**
+ * Sets the value for the {@code maxWait} configuration attribute for pools
+ * created with this configuration instance.
+ *
+ * @param maxWaitDuration The new setting of {@code maxWaitDuration}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @since 2.11.0
+ */
+ public void setMaxWait(final Duration maxWaitDuration) {
+ this.maxWaitDuration = PoolImplUtils.nonNull(maxWaitDuration, DEFAULT_MAX_WAIT);
+ }
+
+ /**
+ * Sets the value for the {@code maxWait} configuration attribute for pools
+ * created with this configuration instance.
+ *
+ * @param maxWaitMillis The new setting of {@code maxWaitMillis}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getMaxWaitDuration()
+ * @see GenericKeyedObjectPool#getMaxWaitDuration()
+ * @deprecated Use {@link #setMaxWait(Duration)}.
+ */
+ @Deprecated
+ public void setMaxWaitMillis(final long maxWaitMillis) {
+ setMaxWait(Duration.ofMillis(maxWaitMillis));
+ }
+
+ /**
+ * Sets the value for the {@code minEvictableIdleTime} configuration
+ * attribute for pools created with this configuration instance.
+ *
+ * @param minEvictableIdleTime The new setting of
+ * {@code minEvictableIdleTime} for this configuration instance
+ *
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @since 2.10.0
+ */
+ public void setMinEvictableIdleTime(final Duration minEvictableIdleTime) {
+ this.minEvictableIdleDuration = PoolImplUtils.nonNull(minEvictableIdleTime, DEFAULT_MIN_EVICTABLE_IDLE_TIME);
+ }
+
+ /**
+ * Sets the value for the {@code minEvictableIdleTime} configuration
+ * attribute for pools created with this configuration instance.
+ *
+ * @param minEvictableIdleTimeMillis The new setting of
+ * {@code minEvictableIdleTime} for this configuration instance
+ *
+ * @see GenericObjectPool#getMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getMinEvictableIdleDuration()
+ * @deprecated Use {@link #setMinEvictableIdleTime(Duration)}.
+ */
+ @Deprecated
+ public void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
+ this.minEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis);
+ }
+
+ /**
+ * Sets the value for the {@code numTestsPerEvictionRun} configuration
+ * attribute for pools created with this configuration instance.
+ *
+ * @param numTestsPerEvictionRun The new setting of
+ * {@code numTestsPerEvictionRun} for this configuration instance
+ *
+ * @see GenericObjectPool#getNumTestsPerEvictionRun()
+ * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun()
+ */
+ public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
+ this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ }
+
+ /**
+ * Sets the value for the {@code softMinEvictableIdleTime}
+ * configuration attribute for pools created with this configuration
* instance.
*
- * @return The current setting of {@code jmxNamePrefix} for this
- * configuration instance
+ * @param softMinEvictableIdleTime The new setting of
+ * {@code softMinEvictableIdleTime} for this configuration
+ * instance
+ *
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @since 2.10.0
*/
- public String getJmxNamePrefix() {
- return jmxNamePrefix;
+ public void setSoftMinEvictableIdleTime(final Duration softMinEvictableIdleTime) {
+ this.softMinEvictableIdleDuration = PoolImplUtils.nonNull(softMinEvictableIdleTime, DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME);
}
/**
- * Sets the value of the JMX name prefix that will be used as part of the
- * name assigned to JMX enabled pools created with this configuration
+ * Sets the value for the {@code softMinEvictableIdleTime}
+ * configuration attribute for pools created with this configuration
* instance.
*
- * @param jmxNamePrefix The new setting of {@code jmxNamePrefix}
+ * @param softMinEvictableIdleTimeMillis The new setting of
+ * {@code softMinEvictableIdleTime} for this configuration
+ * instance
+ *
+ * @see GenericObjectPool#getSoftMinEvictableIdleDuration()
+ * @see GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()
+ * @deprecated Use {@link #setSoftMinEvictableIdleTime(Duration)}.
+ */
+ @Deprecated
+ public void setSoftMinEvictableIdleTimeMillis(
+ final long softMinEvictableIdleTimeMillis) {
+ setSoftMinEvictableIdleTime(Duration.ofMillis(softMinEvictableIdleTimeMillis));
+ }
+
+ /**
+ * Sets the value for the {@code testOnBorrow} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param testOnBorrow The new setting of {@code testOnBorrow}
* for this configuration instance
+ *
+ * @see GenericObjectPool#getTestOnBorrow()
+ * @see GenericKeyedObjectPool#getTestOnBorrow()
*/
- public void setJmxNamePrefix(final String jmxNamePrefix) {
- this.jmxNamePrefix = jmxNamePrefix;
+ public void setTestOnBorrow(final boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+
+ /**
+ * Sets the value for the {@code testOnCreate} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param testOnCreate The new setting of {@code testOnCreate}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getTestOnCreate()
+ * @see GenericKeyedObjectPool#getTestOnCreate()
+ *
+ * @since 2.2
+ */
+ public void setTestOnCreate(final boolean testOnCreate) {
+ this.testOnCreate = testOnCreate;
+ }
+
+ /**
+ * Sets the value for the {@code testOnReturn} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param testOnReturn The new setting of {@code testOnReturn}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getTestOnReturn()
+ * @see GenericKeyedObjectPool#getTestOnReturn()
+ */
+ public void setTestOnReturn(final boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
+
+ /**
+ * Sets the value for the {@code testWhileIdle} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param testWhileIdle The new setting of {@code testWhileIdle}
+ * for this configuration instance
+ *
+ * @see GenericObjectPool#getTestWhileIdle()
+ * @see GenericKeyedObjectPool#getTestWhileIdle()
+ */
+ public void setTestWhileIdle(final boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
+
+ /**
+ * Sets the value for the {@code timeBetweenEvictionRuns} configuration
+ * attribute for pools created with this configuration instance.
+ *
+ * @param timeBetweenEvictionRuns The new setting of
+ * {@code timeBetweenEvictionRuns} for this configuration
+ * instance
+ *
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @since 2.10.0
+ */
+ public void setTimeBetweenEvictionRuns(final Duration timeBetweenEvictionRuns) {
+ this.durationBetweenEvictionRuns = PoolImplUtils.nonNull(timeBetweenEvictionRuns, DEFAULT_TIME_BETWEEN_EVICTION_RUNS);
+ }
+
+ /**
+ * Sets the value for the {@code timeBetweenEvictionRuns} configuration
+ * attribute for pools created with this configuration instance.
+ *
+ * @param timeBetweenEvictionRunsMillis The new setting of
+ * {@code timeBetweenEvictionRuns} for this configuration
+ * instance
+ *
+ * @see GenericObjectPool#getDurationBetweenEvictionRuns()
+ * @see GenericKeyedObjectPool#getDurationBetweenEvictionRuns()
+ * @deprecated Use {@link #setTimeBetweenEvictionRuns(Duration)}.
+ */
+ @Deprecated
+ public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+ setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
}
@Override
@@ -718,12 +1054,12 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
builder.append(lifo);
builder.append(", fairness=");
builder.append(fairness);
- builder.append(", maxWaitMillis=");
- builder.append(maxWaitMillis);
- builder.append(", minEvictableIdleTimeMillis=");
- builder.append(minEvictableIdleTimeMillis);
- builder.append(", softMinEvictableIdleTimeMillis=");
- builder.append(softMinEvictableIdleTimeMillis);
+ builder.append(", maxWaitDuration=");
+ builder.append(maxWaitDuration);
+ builder.append(", minEvictableIdleTime=");
+ builder.append(minEvictableIdleDuration);
+ builder.append(", softMinEvictableIdleTime=");
+ builder.append(softMinEvictableIdleDuration);
builder.append(", numTestsPerEvictionRun=");
builder.append(numTestsPerEvictionRun);
builder.append(", evictionPolicyClassName=");
@@ -736,8 +1072,8 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
builder.append(testOnReturn);
builder.append(", testWhileIdle=");
builder.append(testWhileIdle);
- builder.append(", timeBetweenEvictionRunsMillis=");
- builder.append(timeBetweenEvictionRunsMillis);
+ builder.append(", timeBetweenEvictionRuns=");
+ builder.append(durationBetweenEvictionRuns);
builder.append(", blockWhenExhausted=");
builder.append(blockWhenExhausted);
builder.append(", jmxEnabled=");
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java b/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
index fe7aa0d..0f34709 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
@@ -18,10 +18,12 @@ package org.apache.tomcat.dbcp.pool2.impl;
import java.io.PrintWriter;
+import org.apache.tomcat.dbcp.pool2.PooledObject;
+import org.apache.tomcat.dbcp.pool2.UsageTracking;
+
/**
* Strategy for obtaining and printing the current call stack. This is primarily useful for
- * {@link org.apache.tomcat.dbcp.pool2.UsageTracking usage tracking} so
- * that different JVMs and configurations can use more efficient strategies
+ * {@linkplain UsageTracking usage tracking} so that different JVMs and configurations can use more efficient strategies
* for obtaining the current call stack depending on metadata needs.
*
* @see CallStackUtils
@@ -30,13 +32,10 @@ import java.io.PrintWriter;
public interface CallStack {
/**
- * Prints the current stack trace if available to a PrintWriter. The format is undefined and is primarily useful
- * for debugging issues with {@link org.apache.tomcat.dbcp.pool2.PooledObject} usage in user code.
- *
- * @param writer a PrintWriter to write the current stack trace to if available
- * @return true if a stack trace was available to print or false if nothing was printed
+ * Clears the current stack trace snapshot. Subsequent calls to {@link #printStackTrace(PrintWriter)} will be
+ * no-ops until another call to {@link #fillInStackTrace()}.
*/
- boolean printStackTrace(final PrintWriter writer);
+ void clear();
/**
* Takes a snapshot of the current call stack. Subsequent calls to {@link #printStackTrace(PrintWriter)} will print
@@ -45,8 +44,11 @@ public interface CallStack {
void fillInStackTrace();
/**
- * Clears the current stack trace snapshot. Subsequent calls to {@link #printStackTrace(PrintWriter)} will be
- * no-ops until another call to {@link #fillInStackTrace()}.
+ * Prints the current stack trace if available to a PrintWriter. The format is undefined and is primarily useful
+ * for debugging issues with {@link PooledObject} usage in user code.
+ *
+ * @param writer a PrintWriter to write the current stack trace to if available
+ * @return true if a stack trace was available to print or false if nothing was printed
*/
- void clear();
+ boolean printStackTrace(final PrintWriter writer);
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java b/java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
index a5644ad..831343f 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
@@ -26,7 +26,7 @@ import java.security.AccessControlException;
public final class CallStackUtils {
/**
- * Returns whether the caller can create a security manager in the current environment.
+ * Tests whether the caller can create a security manager in the current environment.
*
* @return {@code true} if it is able to create a security manager in the current environment, {@code false}
* otherwise.
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
index fc618a5..3265fd5 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
@@ -19,37 +19,36 @@ package org.apache.tomcat.dbcp.pool2.impl;
import org.apache.tomcat.dbcp.pool2.PooledObject;
/**
- * Provides the default implementation of {@link EvictionPolicy} used by the
- * pools. Objects will be evicted if the following conditions are met:
+ * Provides the default implementation of {@link EvictionPolicy} used by the pools.
+ * <p>
+ * Objects will be evicted if the following conditions are met:
+ * </p>
* <ul>
- * <li>the object has been idle longer than
- * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} /
- * {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()}</li>
- * <li>there are more than {@link GenericObjectPool#getMinIdle()} /
+ * <li>The object has been idle longer than
+ * {@link GenericObjectPool#getMinEvictableIdleDuration()} /
+ * {@link GenericKeyedObjectPool#getMinEvictableIdleDuration()}</li>
+ * <li>There are more than {@link GenericObjectPool#getMinIdle()} /
* {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} idle objects in
* the pool and the object has been idle for longer than
- * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} /
- * {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()}
+ * {@link GenericObjectPool#getSoftMinEvictableIdleDuration()} /
+ * {@link GenericKeyedObjectPool#getSoftMinEvictableIdleDuration()}
* </ul>
* <p>
* This class is immutable and thread-safe.
* </p>
*
- * @param <T> the type of objects in the pool
+ * @param <T> the type of objects in the pool.
*
* @since 2.0
*/
public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {
@Override
- public boolean evict(final EvictionConfig config, final PooledObject<T> underTest,
- final int idleCount) {
-
- if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() &&
+ public boolean evict(final EvictionConfig config, final PooledObject<T> underTest, final int idleCount) {
+ // @formatter:off
+ return (config.getIdleSoftEvictDuration().compareTo(underTest.getIdleDuration()) < 0 &&
config.getMinIdle() < idleCount) ||
- config.getIdleEvictTime() < underTest.getIdleTimeMillis()) {
- return true;
- }
- return false;
+ config.getIdleEvictDuration().compareTo(underTest.getIdleDuration()) < 0;
+ // @formatter:on
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
index 1883041..3894d87 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
@@ -17,6 +17,9 @@
package org.apache.tomcat.dbcp.pool2.impl;
import java.io.PrintWriter;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Deque;
import org.apache.tomcat.dbcp.pool2.PooledObject;
@@ -38,14 +41,16 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
private final T object;
private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid
- private final long createTime = System.currentTimeMillis();
- private volatile long lastBorrowTime = createTime;
- private volatile long lastUseTime = createTime;
- private volatile long lastReturnTime = createTime;
- private volatile boolean logAbandoned = false;
+ private final Clock systemClock = Clock.systemUTC();
+ private final Instant createInstant = now();
+
+ private volatile Instant lastBorrowInstant = createInstant;
+ private volatile Instant lastUseInstant = createInstant;
+ private volatile Instant lastReturnInstant = createInstant;
+ private volatile boolean logAbandoned;
private volatile CallStack borrowedBy = NoOpCallStack.INSTANCE;
private volatile CallStack usedBy = NoOpCallStack.INSTANCE;
- private volatile long borrowedCount = 0;
+ private volatile long borrowedCount;
/**
* Creates a new instance that wraps the provided object so that the pool can
@@ -57,45 +62,85 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
this.object = object;
}
+ /**
+ * Allocates the object.
+ *
+ * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
+ */
@Override
- public T getObject() {
- return object;
+ public synchronized boolean allocate() {
+ if (state == PooledObjectState.IDLE) {
+ state = PooledObjectState.ALLOCATED;
+ lastBorrowInstant = now();
+ lastUseInstant = lastBorrowInstant;
+ borrowedCount++;
+ if (logAbandoned) {
+ borrowedBy.fillInStackTrace();
+ }
+ return true;
+ }
+ if (state == PooledObjectState.EVICTION) {
+ // TODO Allocate anyway and ignore eviction test
+ state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
+ }
+ // TODO if validating and testOnBorrow == true then pre-allocate for
+ // performance
+ return false;
}
@Override
- public long getCreateTime() {
- return createTime;
+ public int compareTo(final PooledObject<T> other) {
+ final int compareTo = getLastReturnInstant().compareTo(other.getLastReturnInstant());
+ if (compareTo == 0) {
+ // Make sure the natural ordering is broadly consistent with equals
+ // although this will break down if distinct objects have the same
+ // identity hash code.
+ // see java.lang.Comparable Javadocs
+ return System.identityHashCode(this) - System.identityHashCode(other);
+ }
+ return compareTo;
}
+ /**
+ * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
+ * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}
+ * or {@link PooledObjectState#RETURNING RETURNING}.
+ *
+ * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
+ * or {@link PooledObjectState#RETURNING RETURNING}.
+ */
@Override
- public long getActiveTimeMillis() {
- // Take copies to avoid threading issues
- final long rTime = lastReturnTime;
- final long bTime = lastBorrowTime;
-
- if (rTime > bTime) {
- return rTime - bTime;
+ public synchronized boolean deallocate() {
+ if (state == PooledObjectState.ALLOCATED || state == PooledObjectState.RETURNING) {
+ state = PooledObjectState.IDLE;
+ lastReturnInstant = now();
+ borrowedBy.clear();
+ return true;
}
- return System.currentTimeMillis() - bTime;
- }
- @Override
- public long getIdleTimeMillis() {
- final long elapsed = System.currentTimeMillis() - lastReturnTime;
- // elapsed may be negative if:
- // - another thread updates lastReturnTime during the calculation window
- // - System.currentTimeMillis() is not monotonic (e.g. system time is set back)
- return elapsed >= 0 ? elapsed : 0;
+ return false;
}
@Override
- public long getLastBorrowTime() {
- return lastBorrowTime;
+ public synchronized boolean endEvictionTest(
+ final Deque<PooledObject<T>> idleQueue) {
+ if (state == PooledObjectState.EVICTION) {
+ state = PooledObjectState.IDLE;
+ return true;
+ }
+ if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) {
+ state = PooledObjectState.IDLE;
+ if (!idleQueue.offerFirst(this)) {
+ // TODO - Should never happen
+ }
+ }
+
+ return false;
}
@Override
- public long getLastReturnTime() {
- return lastReturnTime;
+ public long getActiveTimeMillis() {
+ return getActiveDuration().toMillis();
}
/**
@@ -108,148 +153,93 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
return borrowedCount;
}
- /**
- * Returns an estimate of the last time this object was used. If the class
- * of the pooled object implements {@link TrackedUse}, what is returned is
- * the maximum of {@link TrackedUse#getLastUsed()} and
- * {@link #getLastBorrowTime()}; otherwise this method gives the same
- * value as {@link #getLastBorrowTime()}.
- *
- * @return the last time this object was used
- */
@Override
- public long getLastUsedTime() {
- if (object instanceof TrackedUse) {
- return Math.max(((TrackedUse) object).getLastUsed(), lastUseTime);
- }
- return lastUseTime;
+ public Instant getCreateInstant() {
+ return createInstant;
}
@Override
- public int compareTo(final PooledObject<T> other) {
- final long lastActiveDiff = this.getLastReturnTime() - other.getLastReturnTime();
- if (lastActiveDiff == 0) {
- // Make sure the natural ordering is broadly consistent with equals
- // although this will break down if distinct objects have the same
- // identity hash code.
- // see java.lang.Comparable Javadocs
- return System.identityHashCode(this) - System.identityHashCode(other);
- }
- // handle int overflow
- return (int)Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE);
+ public long getCreateTime() {
+ return createInstant.toEpochMilli();
}
@Override
- public String toString() {
- final StringBuilder result = new StringBuilder();
- result.append("Object: ");
- result.append(object.toString());
- result.append(", State: ");
- synchronized (this) {
- result.append(state.toString());
- }
- return result.toString();
- // TODO add other attributes
+ public Duration getIdleDuration() {
+ // elapsed may be negative if:
+ // - another thread updates lastReturnInstant during the calculation window
+ // - System.currentTimeMillis() is not monotonic (e.g. system time is set back)
+ final Duration elapsed = Duration.between(lastReturnInstant, now());
+ return elapsed.isNegative() ? Duration.ZERO : elapsed;
}
@Override
- public synchronized boolean startEvictionTest() {
- if (state == PooledObjectState.IDLE) {
- state = PooledObjectState.EVICTION;
- return true;
- }
+ public Duration getIdleTime() {
+ return getIdleDuration();
+ }
- return false;
+ @Override
+ public long getIdleTimeMillis() {
+ return getIdleDuration().toMillis();
}
@Override
- public synchronized boolean endEvictionTest(
- final Deque<PooledObject<T>> idleQueue) {
- if (state == PooledObjectState.EVICTION) {
- state = PooledObjectState.IDLE;
- return true;
- } else if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) {
- state = PooledObjectState.IDLE;
- if (!idleQueue.offerFirst(this)) {
- // TODO - Should never happen
- }
- }
+ public Instant getLastBorrowInstant() {
+ return lastBorrowInstant;
+ }
- return false;
+ @Override
+ public long getLastBorrowTime() {
+ return lastBorrowInstant.toEpochMilli();
}
- /**
- * Allocates the object.
- *
- * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
- */
@Override
- public synchronized boolean allocate() {
- if (state == PooledObjectState.IDLE) {
- state = PooledObjectState.ALLOCATED;
- lastBorrowTime = System.currentTimeMillis();
- lastUseTime = lastBorrowTime;
- borrowedCount++;
- if (logAbandoned) {
- borrowedBy.fillInStackTrace();
- }
- return true;
- } else if (state == PooledObjectState.EVICTION) {
- // TODO Allocate anyway and ignore eviction test
- state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
- return false;
- }
- // TODO if validating and testOnBorrow == true then pre-allocate for
- // performance
- return false;
+ public Instant getLastReturnInstant() {
+ return lastReturnInstant;
+ }
+
+ @Override
+ public long getLastReturnTime() {
+ return lastReturnInstant.toEpochMilli();
}
/**
- * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE}
- * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}
- * or {@link PooledObjectState#RETURNING RETURNING}.
+ * Gets an estimate of the last time this object was used. If the class
+ * of the pooled object implements {@link TrackedUse}, what is returned is
+ * the maximum of {@link TrackedUse#getLastUsedInstant()} and
+ * {@link #getLastBorrowTime()}; otherwise this method gives the same
+ * value as {@link #getLastBorrowTime()}.
*
- * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED}
- * or {@link PooledObjectState#RETURNING RETURNING}.
+ * @return the last Instant this object was used.
*/
@Override
- public synchronized boolean deallocate() {
- if (state == PooledObjectState.ALLOCATED ||
- state == PooledObjectState.RETURNING) {
- state = PooledObjectState.IDLE;
- lastReturnTime = System.currentTimeMillis();
- borrowedBy.clear();
- return true;
+ public Instant getLastUsedInstant() {
+ if (object instanceof TrackedUse) {
+ return PoolImplUtils.max(((TrackedUse) object).getLastUsedInstant(), lastUseInstant);
}
-
- return false;
+ return lastUseInstant;
}
/**
- * Sets the state to {@link PooledObjectState#INVALID INVALID}
+ * Gets an estimate of the last time this object was used. If the class
+ * of the pooled object implements {@link TrackedUse}, what is returned is
+ * the maximum of {@link TrackedUse#getLastUsedInstant()} and
+ * {@link #getLastBorrowTime()}; otherwise this method gives the same
+ * value as {@link #getLastBorrowTime()}.
+ *
+ * @return the last time this object was used
*/
@Override
- public synchronized void invalidate() {
- state = PooledObjectState.INVALID;
- }
-
- @Override
- public void use() {
- lastUseTime = System.currentTimeMillis();
- usedBy.fillInStackTrace();
+ public long getLastUsedTime() {
+ return getLastUsedInstant().toEpochMilli();
}
@Override
- public void printStackTrace(final PrintWriter writer) {
- boolean written = borrowedBy.printStackTrace(writer);
- written |= usedBy.printStackTrace(writer);
- if (written) {
- writer.flush();
- }
+ public T getObject() {
+ return object;
}
/**
- * Returns the state of this object.
+ * Gets the state of this object.
* @return state
*/
@Override
@@ -258,7 +248,15 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
}
/**
- * Marks the pooled object as abandoned.
+ * Sets the state to {@link PooledObjectState#INVALID INVALID}.
+ */
+ @Override
+ public synchronized void invalidate() {
+ state = PooledObjectState.INVALID;
+ }
+
+ /**
+ * Marks the pooled object as {@link PooledObjectState#ABANDONED ABANDONED}.
*/
@Override
public synchronized void markAbandoned() {
@@ -266,13 +264,31 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
}
/**
- * Marks the object as returning to the pool.
+ * Marks the pooled object as {@link PooledObjectState#RETURNING RETURNING}.
*/
@Override
public synchronized void markReturning() {
state = PooledObjectState.RETURNING;
}
+ /**
+ * Gets the current instant of the clock.
+ *
+ * @return the current instant of the clock.
+ */
+ private Instant now() {
+ return systemClock.instant();
+ }
+
+ @Override
+ public void printStackTrace(final PrintWriter writer) {
+ boolean written = borrowedBy.printStackTrace(writer);
+ written |= usedBy.printStackTrace(writer);
+ if (written) {
+ writer.flush();
+ }
+ }
+
@Override
public void setLogAbandoned(final boolean logAbandoned) {
this.logAbandoned = logAbandoned;
@@ -297,4 +313,33 @@ public class DefaultPooledObject<T> implements PooledObject<T> {
false, requireFullStackTrace);
}
+ @Override
+ public synchronized boolean startEvictionTest() {
+ if (state == PooledObjectState.IDLE) {
+ state = PooledObjectState.EVICTION;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder result = new StringBuilder();
+ result.append("Object: ");
+ result.append(object.toString());
+ result.append(", State: ");
+ synchronized (this) {
+ result.append(state.toString());
+ }
+ return result.toString();
+ // TODO add other attributes
+ }
+
+ @Override
+ public void use() {
+ lastUseInstant = now();
+ usedBy.fillInStackTrace();
+ }
+
+
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
index 912878b..28f2c10 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
@@ -30,10 +30,12 @@ import org.apache.tomcat.dbcp.pool2.PooledObject;
*/
public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean {
+ private static final String PATTERN = "yyyy-MM-dd HH:mm:ss Z";
+
private final PooledObject<?> pooledObject;
/**
- * Create a new instance for the given pooled object.
+ * Constructs a new instance for the given pooled object.
*
* @param pooledObject The pooled object that this instance will represent
*/
@@ -42,25 +44,29 @@ public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean {
}
@Override
+ public long getBorrowedCount() {
+ return pooledObject.getBorrowedCount();
+ }
+
+ @Override
public long getCreateTime() {
- return pooledObject.getCreateTime();
+ return pooledObject.getCreateInstant().toEpochMilli();
}
@Override
public String getCreateTimeFormatted() {
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
- return sdf.format(Long.valueOf(pooledObject.getCreateTime()));
+ return getTimeMillisFormatted(getCreateTime());
}
@Override
public long getLastBorrowTime() {
- return pooledObject.getLastBorrowTime();
+ return pooledObject.getLastBorrowInstant().toEpochMilli();
}
+
@Override
public String getLastBorrowTimeFormatted() {
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
- return sdf.format(Long.valueOf(pooledObject.getLastBorrowTime()));
+ return getTimeMillisFormatted(getLastBorrowTime());
}
@Override
@@ -72,18 +78,12 @@ public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean {
@Override
public long getLastReturnTime() {
- return pooledObject.getLastReturnTime();
+ return pooledObject.getLastReturnInstant().toEpochMilli();
}
@Override
public String getLastReturnTimeFormatted() {
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
- return sdf.format(Long.valueOf(pooledObject.getLastReturnTime()));
- }
-
- @Override
- public String getPooledObjectType() {
- return pooledObject.getObject().getClass().getName();
+ return getTimeMillisFormatted(getLastReturnTime());
}
@Override
@@ -92,8 +92,12 @@ public class DefaultPooledObjectInfo implements DefaultPooledObjectInfoMBean {
}
@Override
- public long getBorrowedCount() {
- return pooledObject.getBorrowedCount();
+ public String getPooledObjectType() {
+ return pooledObject.getObject().getClass().getName();
+ }
+
+ private String getTimeMillisFormatted(final long millis) {
+ return new SimpleDateFormat(PATTERN).format(Long.valueOf(millis));
}
/**
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
index f4540b6..2d37f4e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
@@ -19,19 +19,28 @@ package org.apache.tomcat.dbcp.pool2.impl;
/**
* The interface that defines the information about pooled objects that will be
* exposed via JMX.
- *
+ * <p>
* NOTE: This interface exists only to define those attributes and methods that
* will be made available via JMX. It must not be implemented by clients
* as it is subject to change between major, minor and patch version
* releases of commons pool. Clients that implement this interface may
* not, therefore, be able to upgrade to a new minor or patch release
* without requiring code changes.
+ * </p>
*
* @since 2.0
*/
public interface DefaultPooledObjectInfoMBean {
+
/**
- * Obtain the time (using the same basis as
+ * Gets the number of times this object has been borrowed.
+ * @return The number of times this object has been borrowed.
+ * @since 2.1
+ */
+ long getBorrowedCount();
+
+ /**
+ * Gets the time (using the same basis as
* {@link System#currentTimeMillis()}) that pooled object was created.
*
* @return The creation time for the pooled object
@@ -39,7 +48,7 @@ public interface DefaultPooledObjectInfoMBean {
long getCreateTime();
/**
- * Obtain the time that pooled object was created.
+ * Gets the time that pooled object was created.
*
* @return The creation time for the pooled object formatted as
* {@code yyyy-MM-dd HH:mm:ss Z}
@@ -47,7 +56,7 @@ public interface DefaultPooledObjectInfoMBean {
String getCreateTimeFormatted();
/**
- * Obtain the time (using the same basis as
+ * Gets the time (using the same basis as
* {@link System#currentTimeMillis()}) the polled object was last borrowed.
*
* @return The time the pooled object was last borrowed
@@ -55,7 +64,7 @@ public interface DefaultPooledObjectInfoMBean {
long getLastBorrowTime();
/**
- * Obtain the time that pooled object was last borrowed.
+ * Gets the time that pooled object was last borrowed.
*
* @return The last borrowed time for the pooled object formatted as
* {@code yyyy-MM-dd HH:mm:ss Z}
@@ -63,16 +72,15 @@ public interface DefaultPooledObjectInfoMBean {
String getLastBorrowTimeFormatted();
/**
- * Obtain the stack trace recorded when the pooled object was last borrowed.
+ * Gets the stack trace recorded when the pooled object was last borrowed.
*
* @return The stack trace showing which code last borrowed the pooled
* object
*/
String getLastBorrowTrace();
-
/**
- * Obtain the time (using the same basis as
+ * Gets the time (using the same basis as
* {@link System#currentTimeMillis()})the wrapped object was last returned.
*
* @return The time the object was last returned
@@ -80,7 +88,7 @@ public interface DefaultPooledObjectInfoMBean {
long getLastReturnTime();
/**
- * Obtain the time that pooled object was last returned.
+ * Gets the time that pooled object was last returned.
*
* @return The last returned time for the pooled object formatted as
* {@code yyyy-MM-dd HH:mm:ss Z}
@@ -88,16 +96,7 @@ public interface DefaultPooledObjectInfoMBean {
String getLastReturnTimeFormatted();
/**
- * Obtain the name of the class of the pooled object.
- *
- * @return The pooled object's class name
- *
- * @see Class#getName()
- */
- String getPooledObjectType();
-
- /**
- * Provides a String form of the wrapper for debug purposes. The format is
+ * Gets a String form of the wrapper for debug purposes. The format is
* not fixed and may change at any time.
*
* @return A string representation of the pooled object
@@ -107,9 +106,11 @@ public interface DefaultPooledObjectInfoMBean {
String getPooledObjectToString();
/**
- * Get the number of times this object has been borrowed.
- * @return The number of times this object has been borrowed.
- * @since 2.1
+ * Gets the name of the class of the pooled object.
+ *
+ * @return The pooled object's class name
+ *
+ * @see Class#getName()
*/
- long getBorrowedCount();
+ String getPooledObjectType();
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
index b124676..b634518 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
@@ -16,6 +16,8 @@
*/
package org.apache.tomcat.dbcp.pool2.impl;
+import java.time.Duration;
+
/**
* This class is used by pool implementations to pass configuration information
* to {@link EvictionPolicy} instances. The {@link EvictionPolicy} may also have
@@ -28,68 +30,149 @@ package org.apache.tomcat.dbcp.pool2.impl;
*/
public class EvictionConfig {
- private final long idleEvictTime;
- private final long idleSoftEvictTime;
+ private static final Duration MAX_DURATION = Duration.ofMillis(Long.MAX_VALUE);
+ private final Duration idleEvictDuration;
+ private final Duration idleSoftEvictDuration;
private final int minIdle;
/**
- * Create a new eviction configuration with the specified parameters.
+ * Creates a new eviction configuration with the specified parameters.
* Instances are immutable.
*
- * @param poolIdleEvictTime Expected to be provided by
- * {@link BaseGenericObjectPool#getMinEvictableIdleTimeMillis()}
- * @param poolIdleSoftEvictTime Expected to be provided by
- * {@link BaseGenericObjectPool#getSoftMinEvictableIdleTimeMillis()}
+ * @param idleEvictDuration Expected to be provided by
+ * {@link BaseGenericObjectPool#getMinEvictableIdleDuration()}
+ * @param idleSoftEvictDuration Expected to be provided by
+ * {@link BaseGenericObjectPool#getSoftMinEvictableIdleDuration()}
* @param minIdle Expected to be provided by
* {@link GenericObjectPool#getMinIdle()} or
* {@link GenericKeyedObjectPool#getMinIdlePerKey()}
+ * @since 2.10.0
*/
- public EvictionConfig(final long poolIdleEvictTime, final long poolIdleSoftEvictTime,
- final int minIdle) {
- if (poolIdleEvictTime > 0) {
- idleEvictTime = poolIdleEvictTime;
- } else {
- idleEvictTime = Long.MAX_VALUE;
- }
- if (poolIdleSoftEvictTime > 0) {
- idleSoftEvictTime = poolIdleSoftEvictTime;
- } else {
- idleSoftEvictTime = Long.MAX_VALUE;
- }
+ public EvictionConfig(final Duration idleEvictDuration, final Duration idleSoftEvictDuration, final int minIdle) {
+ this.idleEvictDuration = PoolImplUtils.isPositive(idleEvictDuration) ? idleEvictDuration : MAX_DURATION;
+ this.idleSoftEvictDuration = PoolImplUtils.isPositive(idleSoftEvictDuration) ? idleSoftEvictDuration : MAX_DURATION;
this.minIdle = minIdle;
}
/**
- * Obtain the {@code idleEvictTime} for this eviction configuration
+ * Creates a new eviction configuration with the specified parameters.
+ * Instances are immutable.
+ *
+ * @param poolIdleEvictMillis Expected to be provided by
+ * {@link BaseGenericObjectPool#getMinEvictableIdleDuration()}
+ * @param poolIdleSoftEvictMillis Expected to be provided by
+ * {@link BaseGenericObjectPool#getSoftMinEvictableIdleDuration()}
+ * @param minIdle Expected to be provided by
+ * {@link GenericObjectPool#getMinIdle()} or
+ * {@link GenericKeyedObjectPool#getMinIdlePerKey()}
+ * @deprecated Use {@link #EvictionConfig(Duration, Duration, int)}.
+ */
+ @Deprecated
+ public EvictionConfig(final long poolIdleEvictMillis, final long poolIdleSoftEvictMillis, final int minIdle) {
+ this(Duration.ofMillis(poolIdleEvictMillis), Duration.ofMillis(poolIdleSoftEvictMillis), minIdle);
+ }
+
+ /**
+ * Gets the {@code idleEvictTime} for this eviction configuration
+ * instance.
+ * <p>
+ * How the evictor behaves based on this value will be determined by the
+ * configured {@link EvictionPolicy}.
+ * </p>
+ *
+ * @return The {@code idleEvictTime}.
+ * @since 2.11.0
+ */
+ public Duration getIdleEvictDuration() {
+ return idleEvictDuration;
+ }
+
+ /**
+ * Gets the {@code idleEvictTime} for this eviction configuration
* instance.
* <p>
* How the evictor behaves based on this value will be determined by the
* configured {@link EvictionPolicy}.
+ * </p>
*
* @return The {@code idleEvictTime} in milliseconds
+ * @deprecated Use {@link #getIdleEvictDuration()}.
*/
+ @Deprecated
public long getIdleEvictTime() {
- return idleEvictTime;
+ return idleEvictDuration.toMillis();
+ }
+
+ /**
+ * Gets the {@code idleEvictTime} for this eviction configuration
+ * instance.
+ * <p>
+ * How the evictor behaves based on this value will be determined by the
+ * configured {@link EvictionPolicy}.
+ * </p>
+ *
+ * @return The {@code idleEvictTime}.
+ * @since 2.10.0
+ * @deprecated Use {@link #getIdleEvictDuration()}.
+ */
+ @Deprecated
+ public Duration getIdleEvictTimeDuration() {
+ return idleEvictDuration;
+ }
+
+ /**
+ * Gets the {@code idleSoftEvictTime} for this eviction configuration
+ * instance.
+ * <p>
+ * How the evictor behaves based on this value will be determined by the
+ * configured {@link EvictionPolicy}.
+ * </p>
+ *
+ * @return The (@code idleSoftEvictTime} in milliseconds
+ * @since 2.11.0
+ */
+ public Duration getIdleSoftEvictDuration() {
+ return idleSoftEvictDuration;
}
/**
- * Obtain the {@code idleSoftEvictTime} for this eviction configuration
+ * Gets the {@code idleSoftEvictTime} for this eviction configuration
* instance.
* <p>
* How the evictor behaves based on this value will be determined by the
* configured {@link EvictionPolicy}.
+ * </p>
*
* @return The (@code idleSoftEvictTime} in milliseconds
+ * @deprecated Use {@link #getIdleSoftEvictDuration()}.
*/
+ @Deprecated
public long getIdleSoftEvictTime() {
- return idleSoftEvictTime;
+ return idleSoftEvictDuration.toMillis();
+ }
+
+ /**
+ * Gets the {@code idleSoftEvictTime} for this eviction configuration
+ * instance.
+ * <p>
+ * How the evictor behaves based on this value will be determined by the
+ * configured {@link EvictionPolicy}.
+ * </p>
+ *
+ * @return The (@code idleSoftEvictTime} in milliseconds
+ * @deprecated Use {@link #getIdleSoftEvictDuration()}.
+ */
+ @Deprecated
+ public Duration getIdleSoftEvictTimeDuration() {
+ return idleSoftEvictDuration;
}
/**
- * Obtain the {@code minIdle} for this eviction configuration instance.
+ * Gets the {@code minIdle} for this eviction configuration instance.
* <p>
* How the evictor behaves based on this value will be determined by the
* configured {@link EvictionPolicy}.
+ * </p>
*
* @return The {@code minIdle}
*/
@@ -103,10 +186,10 @@ public class EvictionConfig {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
- builder.append("EvictionConfig [idleEvictTime=");
- builder.append(idleEvictTime);
- builder.append(", idleSoftEvictTime=");
- builder.append(idleSoftEvictTime);
+ builder.append("EvictionConfig [idleEvictDuration=");
+ builder.append(idleEvictDuration);
+ builder.append(", idleSoftEvictDuration=");
+ builder.append(idleSoftEvictDuration);
builder.append(", minIdle=");
builder.append(minIdle);
builder.append("]");
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
index 0e5759c..8e86e1a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.pool2.impl;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.time.Duration;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
@@ -47,108 +48,6 @@ import java.util.concurrent.TimeUnit;
*/
class EvictionTimer {
- /** Executor instance */
- private static ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class")
-
- /** Keys are weak references to tasks, values are runners managed by executor. */
- private static final HashMap<WeakReference<Runnable>, WeakRunner> taskMap = new HashMap<>(); // @GuardedBy("EvictionTimer.class")
-
- /** Prevents instantiation */
- private EvictionTimer() {
- // Hide the default constructor
- }
-
-
- /**
- * @since 2.4.3
- */
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("EvictionTimer []");
- return builder.toString();
- }
-
- /**
- * Adds the specified eviction task to the timer. Tasks that are added with
- * a call to this method *must* call {@link
- * #cancel(org.apache.tomcat.dbcp.pool2.impl.BaseGenericObjectPool.Evictor, long, TimeUnit, boolean)}
- * to cancel the task to prevent memory and/or thread leaks in application
- * server environments.
- *
- * @param task Task to be scheduled.
- * @param delay Delay in milliseconds before task is executed.
- * @param period Time in milliseconds between executions.
- */
- static synchronized void schedule(
- final BaseGenericObjectPool<?>.Evictor task, final long delay, final long period) {
- if (null == executor) {
- executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
- executor.setRemoveOnCancelPolicy(true);
- executor.scheduleAtFixedRate(new Reaper(), delay, period, TimeUnit.MILLISECONDS);
- }
- final WeakReference<Runnable> ref = new WeakReference<>(task);
- final WeakRunner runner = new WeakRunner(ref);
- final ScheduledFuture<?> scheduledFuture =
- executor.scheduleWithFixedDelay(runner, delay, period, TimeUnit.MILLISECONDS);
- task.setScheduledFuture(scheduledFuture);
- taskMap.put(ref, runner);
- }
-
- /**
- * Removes the specified eviction task from the timer.
- *
- * @param evictor Task to be cancelled.
- * @param timeout If the associated executor is no longer required, how
- * long should this thread wait for the executor to
- * terminate?
- * @param unit The units for the specified timeout.
- * @param restarting The state of the evictor.
- */
- static synchronized void cancel(
- final BaseGenericObjectPool<?>.Evictor evictor, final long timeout, final TimeUnit unit, final boolean restarting) {
- if (evictor != null) {
- evictor.cancel();
- remove(evictor);
- }
- if (!restarting && executor != null) {
- if (taskMap.isEmpty()) {
- executor.shutdown();
- try {
- executor.awaitTermination(timeout, unit);
- } catch (final InterruptedException e) {
- // Swallow
- // Significant API changes would be required to propagate this
- }
- executor.setCorePoolSize(0);
- executor = null;
- }
- }
- }
-
- /**
- * Removes evictor from the task set and executor.
- * Only called when holding the class lock.
- *
- * @param evictor Eviction task to remove
- */
- private static void remove(final BaseGenericObjectPool<?>.Evictor evictor) {
- for (Entry<WeakReference<Runnable>, WeakRunner> entry : taskMap.entrySet()) {
- if (entry.getKey().get() == evictor) {
- executor.remove(entry.getValue());
- taskMap.remove(entry.getKey());
- break;
- }
- }
- }
-
- /**
- * @return the number of eviction tasks under management.
- */
- static synchronized int getNumTasks() {
- return taskMap.size();
- }
-
/**
* Thread factory that creates a daemon thread, with the context class loader from this class.
*/
@@ -156,7 +55,7 @@ class EvictionTimer {
@Override
public Thread newThread(final Runnable runnable) {
- final Thread thread = new Thread(null, runnable, "commons-pool-evictor-thread");
+ final Thread thread = new Thread(null, runnable, "commons-pool-evictor");
thread.setDaemon(true); // POOL-363 - Required for applications using Runtime.addShutdownHook().
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
thread.setContextClassLoader(EvictorThreadFactory.class.getClassLoader());
@@ -175,7 +74,7 @@ class EvictionTimer {
@Override
public void run() {
synchronized (EvictionTimer.class) {
- for (Entry<WeakReference<Runnable>, WeakRunner> entry : taskMap.entrySet()) {
+ for (final Entry<WeakReference<Runnable>, WeakRunner> entry : taskMap.entrySet()) {
if (entry.getKey().get() == null) {
executor.remove(entry.getValue());
taskMap.remove(entry.getKey());
@@ -218,4 +117,103 @@ class EvictionTimer {
}
}
}
+
+
+ /** Executor instance */
+ private static ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class")
+
+ /** Keys are weak references to tasks, values are runners managed by executor. */
+ private static final HashMap<WeakReference<Runnable>, WeakRunner> taskMap = new HashMap<>(); // @GuardedBy("EvictionTimer.class")
+
+ /**
+ * Removes the specified eviction task from the timer.
+ *
+ * @param evictor Task to be cancelled.
+ * @param timeout If the associated executor is no longer required, how
+ * long should this thread wait for the executor to
+ * terminate?
+ * @param restarting The state of the evictor.
+ */
+ static synchronized void cancel(final BaseGenericObjectPool<?>.Evictor evictor, final Duration timeout,
+ final boolean restarting) {
+ if (evictor != null) {
+ evictor.cancel();
+ remove(evictor);
+ }
+ if (!restarting && executor != null && taskMap.isEmpty()) {
+ executor.shutdown();
+ try {
+ executor.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS);
+ } catch (final InterruptedException e) {
+ // Swallow
+ // Significant API changes would be required to propagate this
+ }
+ executor.setCorePoolSize(0);
+ executor = null;
+ }
+ }
+
+ /**
+ * @return the number of eviction tasks under management.
+ */
+ static synchronized int getNumTasks() {
+ return taskMap.size();
+ }
+
+ /**
+ * Removes evictor from the task set and executor.
+ * Only called when holding the class lock.
+ *
+ * @param evictor Eviction task to remove
+ */
+ private static void remove(final BaseGenericObjectPool<?>.Evictor evictor) {
+ for (final Entry<WeakReference<Runnable>, WeakRunner> entry : taskMap.entrySet()) {
+ if (entry.getKey().get() == evictor) {
+ executor.remove(entry.getValue());
+ taskMap.remove(entry.getKey());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds the specified eviction task to the timer. Tasks that are added with
+ * a call to this method *must* call {@link
+ * #cancel(BaseGenericObjectPool.Evictor, Duration, boolean)}
+ * to cancel the task to prevent memory and/or thread leaks in application
+ * server environments.
+ *
+ * @param task Task to be scheduled.
+ * @param delay Delay in milliseconds before task is executed.
+ * @param period Time in milliseconds between executions.
+ */
+ static synchronized void schedule(
+ final BaseGenericObjectPool<?>.Evictor task, final Duration delay, final Duration period) {
+ if (null == executor) {
+ executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
+ executor.setRemoveOnCancelPolicy(true);
+ executor.scheduleAtFixedRate(new Reaper(), delay.toMillis(), period.toMillis(), TimeUnit.MILLISECONDS);
+ }
+ final WeakReference<Runnable> ref = new WeakReference<>(task);
+ final WeakRunner runner = new WeakRunner(ref);
+ final ScheduledFuture<?> scheduledFuture = executor.scheduleWithFixedDelay(runner, delay.toMillis(),
+ period.toMillis(), TimeUnit.MILLISECONDS);
+ task.setScheduledFuture(scheduledFuture);
+ taskMap.put(ref, runner);
+ }
+
+ /** Prevents instantiation */
+ private EvictionTimer() {
+ // Hide the default constructor
+ }
+
+ /**
+ * @since 2.4.3
+ */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("EvictionTimer []");
+ return builder.toString();
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
index ebe4027..0ac5dac 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
@@ -16,6 +16,7 @@
*/
package org.apache.tomcat.dbcp.pool2.impl;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
@@ -24,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -32,6 +34,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
import org.apache.tomcat.dbcp.pool2.DestroyMode;
import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
@@ -39,6 +42,8 @@ import org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory;
import org.apache.tomcat.dbcp.pool2.PoolUtils;
import org.apache.tomcat.dbcp.pool2.PooledObject;
import org.apache.tomcat.dbcp.pool2.PooledObjectState;
+import org.apache.tomcat.dbcp.pool2.SwallowedExceptionListener;
+import org.apache.tomcat.dbcp.pool2.UsageTracking;
/**
* A configurable {@code KeyedObjectPool} implementation.
@@ -83,19 +88,167 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectState;
* @since 2.0
*/
public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
- implements KeyedObjectPool<K, T>, GenericKeyedObjectPoolMXBean<K> {
+ implements KeyedObjectPool<K, T>, GenericKeyedObjectPoolMXBean<K>, UsageTracking<T> {
/**
- * Create a new {@code GenericKeyedObjectPool} using defaults from
+ * Maintains information on the per key queue for a given key.
+ *
+ * @param <S> type of objects in the pool
+ */
+ private class ObjectDeque<S> {
+
+ private final LinkedBlockingDeque<PooledObject<S>> idleObjects;
+
+ /*
+ * Number of instances created - number destroyed.
+ * Invariant: createCount <= maxTotalPerKey
+ */
+ private final AtomicInteger createCount = new AtomicInteger(0);
+
+ private long makeObjectCount;
+ private final Object makeObjectCountLock = new Object();
+
+ /*
+ * The map is keyed on pooled instances, wrapped to ensure that
+ * they work properly as keys.
+ */
+ private final Map<IdentityWrapper<S>, PooledObject<S>> allObjects =
+ new ConcurrentHashMap<>();
+
+ /*
+ * Number of threads with registered interest in this key.
+ * register(K) increments this counter and deRegister(K) decrements it.
+ * Invariant: empty keyed pool will not be dropped unless numInterested
+ * is 0.
+ */
+ private final AtomicLong numInterested = new AtomicLong();
+
+ /**
+ * Constructs a new ObjecDeque with the given fairness policy.
+ * @param fairness true means client threads waiting to borrow / return instances
+ * will be served as if waiting in a FIFO queue.
+ */
+ public ObjectDeque(final boolean fairness) {
+ idleObjects = new LinkedBlockingDeque<>(fairness);
+ }
+
+ /**
+ * Gets all the objects for the current key.
+ *
+ * @return All the objects
+ */
+ public Map<IdentityWrapper<S>, PooledObject<S>> getAllObjects() {
+ return allObjects;
+ }
+
+ /**
+ * Gets the count of the number of objects created for the current
+ * key.
+ *
+ * @return The number of objects created for this key
+ */
+ public AtomicInteger getCreateCount() {
+ return createCount;
+ }
+
+ /**
+ * Gets the idle objects for the current key.
+ *
+ * @return The idle objects
+ */
+ public LinkedBlockingDeque<PooledObject<S>> getIdleObjects() {
+ return idleObjects;
+ }
+
+ /**
+ * Gets the number of threads with an interest registered in this key.
+ *
+ * @return The number of threads with a registered interest in this key
+ */
+ public AtomicLong getNumInterested() {
+ return numInterested;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("ObjectDeque [idleObjects=");
+ builder.append(idleObjects);
+ builder.append(", createCount=");
+ builder.append(createCount);
+ builder.append(", allObjects=");
+ builder.append(allObjects);
+ builder.append(", numInterested=");
+ builder.append(numInterested);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ }
+
+ private static final Integer ZERO = Integer.valueOf(0);
+
+ // JMX specific attributes
+ private static final String ONAME_BASE =
+ "org.apache.commons.pool2:type=GenericKeyedObjectPool,name=";
+
+ //--- configuration attributes ---------------------------------------------
+ private volatile int maxIdlePerKey =
+ GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
+
+ private volatile int minIdlePerKey =
+ GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
+
+
+ private volatile int maxTotalPerKey =
+ GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
+
+ private final KeyedPooledObjectFactory<K, T> factory;
+
+ private final boolean fairness;
+
+ /*
+ * My hash of sub-pools (ObjectQueue). The list of keys <b>must</b> be kept
+ * in step with {@link #poolKeyList} using {@link #keyLock} to ensure any
+ * changes to the list of current keys is made in a thread-safe manner.
+ */
+ private final Map<K, ObjectDeque<T>> poolMap =
+ new ConcurrentHashMap<>(); // @GuardedBy("keyLock") for write access (and some read access)
+
+ /*
+ * List of pool keys - used to control eviction order. The list of keys
+ * <b>must</b> be kept in step with {@link #poolMap} using {@link #keyLock}
+ * to ensure any changes to the list of current keys is made in a
+ * thread-safe manner.
+ */
+ private final List<K> poolKeyList = new ArrayList<>(); // @GuardedBy("keyLock")
+
+ private final ReadWriteLock keyLock = new ReentrantReadWriteLock(true);
+
+ /*
+ * The combined count of the currently active objects for all keys and those
+ * in the process of being created. Under load, it may exceed
+ * {@link #maxTotal} but there will never be more than {@link #maxTotal}
+ * created at any one time.
+ */
+ private final AtomicInteger numTotal = new AtomicInteger(0);
+
+ private Iterator<K> evictionKeyIterator; // @GuardedBy("evictionLock")
+
+
+ private K evictionKey; // @GuardedBy("evictionLock")
+
+ /**
+ * Constructs a new {@code GenericKeyedObjectPool} using defaults from
* {@link GenericKeyedObjectPoolConfig}.
* @param factory the factory to be used to create entries
*/
public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory) {
- this(factory, new GenericKeyedObjectPoolConfig<T>());
+ this(factory, new GenericKeyedObjectPoolConfig<>());
}
/**
- * Create a new {@code GenericKeyedObjectPool} using a specific
+ * Constructs a new {@code GenericKeyedObjectPool} using a specific
* configuration.
*
* @param factory the factory to be used to create entries
@@ -111,7 +264,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
if (factory == null) {
jmxUnregister(); // tidy up
- throw new IllegalArgumentException("factory may not be null");
+ throw new IllegalArgumentException("Factory may not be null");
}
this.factory = factory;
this.fairness = config.getFairness();
@@ -120,156 +273,84 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
/**
- * Returns the limit on the number of object instances allocated by the pool
- * (checked out or idle), per key. When the limit is reached, the sub-pool
- * is said to be exhausted. A negative value indicates no limit.
- *
- * @return the limit on the number of active instances per key
+ * Creates a new {@code GenericKeyedObjectPool} that tracks and destroys
+ * objects that are checked out, but never returned to the pool.
*
- * @see #setMaxTotalPerKey
+ * @param factory The object factory to be used to create object instances
+ * used by this pool
+ * @param config The base pool configuration to use for this pool instance.
+ * The configuration is used by value. Subsequent changes to
+ * the configuration object will not be reflected in the
+ * pool.
+ * @param abandonedConfig Configuration for abandoned object identification
+ * and removal. The configuration is used by value.
+ * @since 2.10.0
*/
- @Override
- public int getMaxTotalPerKey() {
- return maxTotalPerKey;
+ public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory,
+ final GenericKeyedObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
... 7611 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org