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 2025/12/12 11:55:45 UTC
(tomcat) 05/05: Update the internal fork of Commons Pool to 2.13.0.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit ae8cd099e93febd67b3ccf9348dfed0cee2ada3c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 12 11:18:35 2025 +0000
Update the internal fork of Commons Pool to 2.13.0.
---
java/org/apache/tomcat/dbcp/pool2/BaseObject.java | 9 +-
.../apache/tomcat/dbcp/pool2/BaseObjectPool.java | 9 +-
java/org/apache/tomcat/dbcp/pool2/DestroyMode.java | 2 +-
.../apache/tomcat/dbcp/pool2/KeyedObjectPool.java | 2 +-
.../dbcp/pool2/KeyedPooledObjectFactory.java | 2 +-
java/org/apache/tomcat/dbcp/pool2/ObjectPool.java | 2 +-
java/org/apache/tomcat/dbcp/pool2/PoolUtils.java | 48 ++--
.../org/apache/tomcat/dbcp/pool2/PooledObject.java | 33 ++-
.../tomcat/dbcp/pool2/PooledObjectFactory.java | 2 +-
.../tomcat/dbcp/pool2/PooledObjectState.java | 2 +-
.../dbcp/pool2/SwallowedExceptionListener.java | 2 +-
java/org/apache/tomcat/dbcp/pool2/TrackedUse.java | 2 +-
.../apache/tomcat/dbcp/pool2/UsageTracking.java | 2 +-
.../tomcat/dbcp/pool2/impl/AbandonedConfig.java | 2 +-
.../dbcp/pool2/impl/BaseGenericObjectPool.java | 125 ++++++++---
.../dbcp/pool2/impl/BaseObjectPoolConfig.java | 62 +++++-
.../apache/tomcat/dbcp/pool2/impl/CallStack.java | 2 +-
.../dbcp/pool2/impl/DefaultEvictionPolicy.java | 9 +-
.../dbcp/pool2/impl/DefaultPooledObject.java | 2 +-
.../dbcp/pool2/impl/DefaultPooledObjectInfo.java | 2 +-
.../pool2/impl/DefaultPooledObjectInfoMBean.java | 2 +-
.../tomcat/dbcp/pool2/impl/EvictionConfig.java | 2 +-
.../tomcat/dbcp/pool2/impl/EvictionPolicy.java | 4 +-
.../tomcat/dbcp/pool2/impl/EvictionTimer.java | 25 ++-
.../dbcp/pool2/impl/GenericKeyedObjectPool.java | 248 +++++++++++++++++----
.../pool2/impl/GenericKeyedObjectPoolConfig.java | 82 ++++++-
.../pool2/impl/GenericKeyedObjectPoolMXBean.java | 2 +-
.../tomcat/dbcp/pool2/impl/GenericObjectPool.java | 229 +++++++++----------
.../dbcp/pool2/impl/GenericObjectPoolConfig.java | 9 +-
.../dbcp/pool2/impl/GenericObjectPoolMXBean.java | 2 +-
.../pool2/impl/InterruptibleReentrantLock.java | 8 +-
.../dbcp/pool2/impl/LinkedBlockingDeque.java | 66 ++++--
.../tomcat/dbcp/pool2/impl/NoOpCallStack.java | 4 +-
.../tomcat/dbcp/pool2/impl/PoolImplUtils.java | 2 +-
.../dbcp/pool2/impl/PooledSoftReference.java | 2 +-
.../dbcp/pool2/impl/SoftReferenceObjectPool.java | 8 +-
.../tomcat/dbcp/pool2/impl/ThrowableCallStack.java | 4 +-
res/checkstyle/header-al2.txt | 2 +-
webapps/docs/changelog.xml | 3 +
39 files changed, 745 insertions(+), 280 deletions(-)
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseObject.java b/java/org/apache/tomcat/dbcp/pool2/BaseObject.java
index 87c6cce6a3..47e2fe1b68 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseObject.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,6 +23,13 @@ package org.apache.tomcat.dbcp.pool2;
*/
public abstract class BaseObject {
+ /**
+ * Constructs a new instance.
+ */
+ public BaseObject() {
+ // empty
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
index 94ed157997..dbca4addf7 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,6 +32,13 @@ public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool
private volatile boolean closed;
+ /**
+ * Constructs a new instance.
+ */
+ public BaseObjectPool() {
+ // empty
+ }
+
/**
* Not supported in this base implementation. Subclasses should override
* this behavior.
diff --git a/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java b/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
index 2b8b6833a0..bc073cb19b 100644
--- a/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
+++ b/java/org/apache/tomcat/dbcp/pool2/DestroyMode.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
index 6d1ba97f45..c9ed7da6a8 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
index 9c0a71c5a9..d93008dcfa 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedPooledObjectFactory.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
index 848957f0f0..b93a19cd52 100644
--- a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
index 73bb4851b5..554f6c479c 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -46,6 +47,9 @@ public final class PoolUtils {
* frequently.
*/
private static final class ErodingFactor {
+
+ private static final float MAX_INTERVAL = 15f;
+
/** Determines frequency of "erosion" events */
private final float factor;
@@ -53,7 +57,9 @@ public final class PoolUtils {
private transient volatile long nextShrinkMillis;
/** High water mark - largest numIdle encountered */
- private transient volatile int idleHighWaterMark;
+ private transient volatile int idleHighWaterMark = 1;
+
+ private final ReentrantLock lock = new ReentrantLock();
/**
* Creates a new ErodingFactor with the given erosion factor.
@@ -61,10 +67,9 @@ public final class PoolUtils {
* @param factor
* erosion factor
*/
- ErodingFactor(final float factor) {
+ private ErodingFactor(final float factor) {
this.factor = factor;
- nextShrinkMillis = System.currentTimeMillis() + (long) (900000 * factor); // now + 15 min * factor
- idleHighWaterMark = 1;
+ nextShrinkMillis = System.currentTimeMillis() + (long) (900_000 * factor); // now + 15 min * factor
}
/**
@@ -72,7 +77,7 @@ public final class PoolUtils {
*
* @return next shrink time
*/
- public long getNextShrink() {
+ private long getNextShrink() {
return nextShrinkMillis;
}
@@ -81,7 +86,7 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- return "ErodingFactor{" + "factor=" + factor +
+ return "ErodingFactor{factor=" + factor +
", idleHighWaterMark=" + idleHighWaterMark + '}';
}
@@ -95,11 +100,14 @@ public final class PoolUtils {
*/
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);
+ lock.lock();
+ try {
+ idleHighWaterMark = Math.max(idle, idleHighWaterMark);
+ final float minutes = MAX_INTERVAL + (1f - MAX_INTERVAL) / idleHighWaterMark * idle;
+ nextShrinkMillis = nowMillis + (long) (minutes * 60000f * factor);
+ } finally {
+ lock.unlock();
+ }
}
}
/**
@@ -129,7 +137,7 @@ public final class PoolUtils {
* events
* @see #erodingFactor
*/
- protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
+ private ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
final ErodingFactor erodingFactor) {
if (keyedPool == null) {
throw new IllegalArgumentException(
@@ -150,7 +158,7 @@ public final class PoolUtils {
* events
* @see #erodingFactor
*/
- ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
+ private ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
final float factor) {
this(keyedPool, new ErodingFactor(factor));
}
@@ -315,7 +323,7 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- return "ErodingKeyedObjectPool{" + "factor=" +
+ return "ErodingKeyedObjectPool{factor=" +
erodingFactor + ", keyedPool=" + keyedPool + '}';
}
}
@@ -346,7 +354,7 @@ public final class PoolUtils {
* events
* @see #factor
*/
- ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
+ private ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
this.pool = pool;
this.factor = new ErodingFactor(factor);
}
@@ -355,7 +363,7 @@ public final class PoolUtils {
* {@inheritDoc}
*/
@Override
- public void addObject() throws Exception{
+ public void addObject() throws Exception {
pool.addObject();
}
@@ -457,7 +465,7 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
+ return "ErodingObjectPool{factor=" + factor + ", pool=" +
pool + '}';
}
}
@@ -486,7 +494,7 @@ public final class PoolUtils {
* @param factor
* erosion factor
*/
- ErodingPerKeyKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final float factor) {
+ private ErodingPerKeyKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final float factor) {
super(keyedPool, null);
this.factor = factor;
}
@@ -506,7 +514,7 @@ public final class PoolUtils {
*/
@Override
public String toString() {
- return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
+ return "ErodingPerKeyKeyedObjectPool{factor=" + factor +
", keyedPool=" + getKeyedPool() + '}';
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
index 75bbc941ad..65497d5e9d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -34,14 +34,37 @@ import java.util.Deque;
public interface PooledObject<T> extends Comparable<PooledObject<T>> {
/**
- * Tests whether the given PooledObject is null <em>or</em> contains a null.
+ * Gets the wrapped object or null.
*
- * @param pooledObject the PooledObject to test.
- * @return whether the given PooledObject is null <em>or</em> contains a null.
+ * @param <T> the type of object in the pool.
+ * @param pooledObject the PooledObject to unwrap, may be null.
+ * @return the wrapped object or null.
+ * @since 2.13.0
+ */
+ static <T> T getObject(final PooledObject<T> pooledObject) {
+ return pooledObject != null ? pooledObject.getObject() : null;
+ }
+
+ /**
+ * Tests whether the given PooledObject is null <em>or</em> wraps a null.
+ *
+ * @param pooledObject the PooledObject to test, may be null.
+ * @return whether the given PooledObject is null <em>or</em> wraps a null.
* @since 2.12.0
*/
static boolean isNull(final PooledObject<?> pooledObject) {
- return pooledObject == null || pooledObject.getObject() == null;
+ return getObject(pooledObject) == null;
+ }
+
+ /**
+ * Tests whether the given PooledObject isn't null <em>and</em> doesn't wraps a null.
+ *
+ * @param pooledObject the PooledObject to test, may be null.
+ * @return whether the given PooledObject isn't null <em>and</em> doesn't wraps a null.
+ * @since 2.13.0
+ */
+ static boolean nonNull(final PooledObject<?> pooledObject) {
+ return getObject(pooledObject) != null;
}
/**
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
index 5c5a662039..03463455c7 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObjectFactory.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java b/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
index b405f94711..9ff127581b 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObjectState.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java b/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
index c80b05b6a5..7e45d84887 100644
--- a/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
+++ b/java/org/apache/tomcat/dbcp/pool2/SwallowedExceptionListener.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java b/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
index cac0ce2da6..4c22ddff5d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
+++ b/java/org/apache/tomcat/dbcp/pool2/TrackedUse.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java b/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
index 6b86754d98..4de577d064 100644
--- a/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
+++ b/java/org/apache/tomcat/dbcp/pool2/UsageTracking.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
index 92797c8b45..38178c7d00 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/AbandonedConfig.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
index 9b410772c0..92e314dff3 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -205,41 +205,53 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
* @param <T> type of objects in the pool
*/
static class IdentityWrapper<T> {
+
+ /**
+ * Creates a new instance for the object inside a {@link PooledObject}.
+ *
+ * @param <T> The type of the object in the {@link PooledObject}.
+ * @param p The {@link PooledObject}.
+ * @return a new instance.
+ */
+ static <T> IdentityWrapper<T> unwrap(final PooledObject<T> p) {
+ return new IdentityWrapper<>(p.getObject());
+ }
+
/** Wrapped object */
- private final T instance;
+ private final T object;
/**
* Constructs a wrapper for an instance.
*
- * @param instance object to wrap
+ * @param object object to wrap
*/
- IdentityWrapper(final T instance) {
- this.instance = instance;
+ IdentityWrapper(final T object) {
+ this.object = object;
}
@Override
@SuppressWarnings("rawtypes")
public boolean equals(final Object other) {
- return other instanceof IdentityWrapper && ((IdentityWrapper) other).instance == instance;
+ return other instanceof IdentityWrapper && ((IdentityWrapper) other).object == object;
}
/**
* @return the wrapped object
*/
- public T getObject() {
- return instance;
+ T getObject() {
+ return object;
}
@Override
public int hashCode() {
- return System.identityHashCode(instance);
+ return System.identityHashCode(object);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("IdentityWrapper [instance=");
- builder.append(instance);
+ builder.append(object);
builder.append("]");
return builder.toString();
}
@@ -395,6 +407,7 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
private volatile SwallowedExceptionListener swallowedExceptionListener;
private volatile boolean messageStatistics;
+ private volatile boolean collectDetailedStatistics = BaseObjectPoolConfig.DEFAULT_COLLECT_DETAILED_STATISTICS;
/** Additional configuration properties for abandoned object tracking. */
protected volatile AbandonedConfig abandonedConfig;
@@ -482,6 +495,16 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
return remove;
}
+ /**
+ * Returns the duration since the given start time.
+ *
+ * @param startInstant the start time
+ * @return the duration since the given start time
+ */
+ final Duration durationSince(final Instant startInstant) {
+ return Duration.between(startInstant, Instant.now());
+ }
+
/**
* Tries to ensure that the configured minimum number of idle instances are
* available in the pool.
@@ -524,6 +547,20 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
return borrowedCount.get();
}
+ /**
+ * Gets whether detailed timing statistics collection is enabled.
+ * When {@code false}, the pool will not collect detailed timing statistics for
+ * mean active time, mean idle time, and mean borrow wait time,
+ * improving performance under high load.
+ *
+ * @return {@code true} if detailed statistics collection is enabled,
+ * {@code false} if disabled for improved performance.
+ * @since 2.13.0
+ */
+ public boolean getCollectDetailedStatistics() {
+ return collectDetailedStatistics;
+ }
+
/**
* Gets the total number of objects created for this pool over the lifetime of
* the pool.
@@ -1225,8 +1262,9 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
}
/**
- * Tests whether this pool instance been closed.
- * @return {@code true} when this pool has been closed.
+ * Tests whether this pool instance is closed.
+ *
+ * @return {@code true} when this pool is closed.
*/
public final boolean isClosed() {
return closed;
@@ -1257,7 +1295,7 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
}
while (!registered) {
try {
- ObjectName objName;
+ final ObjectName objName;
// Skip the numeric suffix for the first pool in case there is
// only one so the names are cleaner.
if (i == 1) {
@@ -1347,6 +1385,21 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
this.blockWhenExhausted = blockWhenExhausted;
}
+ /**
+ * Sets whether detailed timing statistics collection is enabled.
+ * When {@code false}, the pool will not collect detailed timing statistics,
+ * improving performance under high load at the cost of reduced monitoring capabilities.
+ * <p>
+ * This setting affects data collection for mean active time, mean idle time, and mean borrow wait time.
+ * </p>
+ *
+ * @param collectDetailedStatistics whether to collect detailed statistics.
+ * @since 2.13.0
+ */
+ public void setCollectDetailedStatistics(final boolean collectDetailedStatistics) {
+ this.collectDetailedStatistics = collectDetailedStatistics;
+ }
+
/**
* Sets the receiver with the given configuration.
*
@@ -1373,6 +1426,7 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
setEvictionPolicy(policy);
}
setEvictorShutdownTimeout(config.getEvictorShutdownTimeoutDuration());
+ setCollectDetailedStatistics(config.getCollectDetailedStatistics());
}
/**
@@ -1944,6 +1998,7 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
startEvictor(Duration.ofMillis(-1L));
}
+
/**
* Swallows an exception and notifies the configured listener for swallowed
* exceptions queue.
@@ -2044,17 +2099,19 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
*/
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.compareTo(waitDuration) >= 0) {
- break;
- }
- } while (!maxBorrowWaitDuration.compareAndSet(currentMaxDuration, waitDuration));
+ // Only collect detailed statistics if enabled
+ if (collectDetailedStatistics) {
+ idleTimes.add(p.getIdleDuration());
+ waitTimes.add(waitDuration);
+ // lock-free optimistic-locking maximum
+ Duration currentMaxDuration;
+ do {
+ currentMaxDuration = maxBorrowWaitDuration.get();
+ if (currentMaxDuration.compareTo(waitDuration) >= 0) {
+ break;
+ }
+ } while (!maxBorrowWaitDuration.compareAndSet(currentMaxDuration, waitDuration));
+ }
}
/**
@@ -2065,7 +2122,25 @@ public abstract class BaseGenericObjectPool<T> extends BaseObject implements Aut
*/
final void updateStatsReturn(final Duration activeTime) {
returnedCount.incrementAndGet();
- activeTimes.add(activeTime);
+ // Only collect detailed statistics if enabled
+ if (collectDetailedStatistics) {
+ activeTimes.add(activeTime);
+ }
+ }
+
+ /**
+ * Waits for notification on the given object for the specified duration.
+ * Duration.ZERO causes the thread to wait indefinitely.
+ *
+ * @param obj the object to wait on
+ * @param duration the duration to wait
+ * @throws InterruptedException if interrupted while waiting
+ * @throws IllegalArgumentException if the duration is negative
+ */
+ final void wait(final Object obj, final Duration duration) throws InterruptedException {
+ if (!duration.isNegative()) {
+ obj.wait(duration.toMillis(), duration.getNano() % 1_000_000);
+ }
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
index 38d7aa523e..8c278022c7 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -254,6 +254,19 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
*/
public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = DefaultEvictionPolicy.class.getName();
+ /**
+ * The default value for the {@code collectDetailedStatistics} configuration
+ * attribute. When {@code true}, the pool will collect detailed timing statistics
+ * for monitoring purposes. When {@code false}, detailed statistics collection
+ * is disabled, improving performance under high load.
+ * <p>
+ * This setting affects data collection for mean active time, mean idle time, and mean borrow wait time.
+ * </p>
+ *
+ * @since 2.13.0
+ */
+ public static final boolean DEFAULT_COLLECT_DETAILED_STATISTICS = true;
+
private boolean lifo = DEFAULT_LIFO;
private boolean fairness = DEFAULT_FAIRNESS;
@@ -291,6 +304,15 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
private String jmxNameBase = DEFAULT_JMX_NAME_BASE;
+ private boolean collectDetailedStatistics = DEFAULT_COLLECT_DETAILED_STATISTICS;
+
+ /**
+ * Constructs a new instance.
+ */
+ public BaseObjectPoolConfig() {
+ // empty
+ }
+
/**
* Gets the value for the {@code blockWhenExhausted} configuration attribute for pools created with this configuration instance.
*
@@ -302,6 +324,23 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
return blockWhenExhausted;
}
+ /**
+ * Gets the value for the {@code collectDetailedStatistics} configuration attribute
+ * for pools created with this configuration instance.
+ * <p>
+ * This setting affects data collection for mean active time, mean idle time, and mean borrow wait time.
+ * </p>
+ *
+ * @return {@code true} if detailed statistics collection is enabled,
+ * {@code false} if disabled for improved performance.
+ * @see GenericObjectPool#getCollectDetailedStatistics()
+ * @see GenericKeyedObjectPool#getCollectDetailedStatistics()
+ * @since 2.13.0
+ */
+ public boolean getCollectDetailedStatistics() {
+ return collectDetailedStatistics;
+ }
+
/**
* Gets the value for the {@code timeBetweenEvictionRuns} configuration attribute for pools created with this configuration instance.
*
@@ -623,6 +662,25 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
this.blockWhenExhausted = blockWhenExhausted;
}
+ /**
+ * Sets the value for the {@code collectDetailedStatistics} configuration attribute
+ * for pools created with this configuration instance. When {@code false}, the pool
+ * will not collect detailed timing statistics, improving performance under high load
+ * at the cost of reduced monitoring capabilities.
+ * <p>
+ * This setting affects data collection for mean active time, mean idle time, and mean borrow wait time.
+ * </p>
+ *
+ * @param collectDetailedStatistics The new setting of {@code collectDetailedStatistics}
+ * for this configuration instance.
+ * @see GenericObjectPool#getCollectDetailedStatistics()
+ * @see GenericKeyedObjectPool#getCollectDetailedStatistics()
+ * @since 2.13.0
+ */
+ public void setCollectDetailedStatistics(final boolean collectDetailedStatistics) {
+ this.collectDetailedStatistics = collectDetailedStatistics;
+ }
+
/**
* Sets the value for the {@code evictionPolicyClass} configuration attribute for pools created with this configuration instance.
*
@@ -953,5 +1011,7 @@ public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Clon
builder.append(jmxNamePrefix);
builder.append(", jmxNameBase=");
builder.append(jmxNameBase);
+ builder.append(", collectDetailedStatistics=");
+ builder.append(collectDetailedStatistics);
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java b/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
index 9320fe42a7..58b0e66793 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
index ffe607242e..e04145c90e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -42,6 +42,13 @@ import org.apache.tomcat.dbcp.pool2.PooledObject;
*/
public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {
+ /**
+ * Constructs a new instance.
+ */
+ public DefaultEvictionPolicy() {
+ // empty
+ }
+
@Override
public boolean evict(final EvictionConfig config, final PooledObject<T> underTest, final int idleCount) {
// @formatter:off
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
index a03f2762e5..e7a239414f 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
index 30854e2fad..40efe6c109 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfo.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
index 3e8ad6ea04..7d6d49c3b5 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObjectInfoMBean.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
index b6345187bd..5e23a2bca4 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionPolicy.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionPolicy.java
index 281ca367bd..28ee6c595e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionPolicy.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionPolicy.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,7 +23,7 @@ import org.apache.tomcat.dbcp.pool2.PooledObject;
* DefaultEvictionPolicy} for a pool, users must provide an implementation of
* this interface that provides the required eviction policy.
*
- * @param <T> the type of objects in the pool
+ * @param <T> the type of objects in the pool.
* @since 2.0
*/
public interface EvictionPolicy<T> {
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
index fadc5159b9..dcfe6004e3 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.pool2.impl;
import java.lang.ref.WeakReference;
import java.time.Duration;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -67,11 +68,17 @@ final class EvictionTimer {
@Override
public void run() {
synchronized (EvictionTimer.class) {
- for (final Entry<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>> entry : TASK_MAP
- .entrySet()) {
+ /*
+ * Need to use iterator over TASK_MAP so entries can be removed when iterating without triggering a
+ * ConcurrentModificationException.
+ */
+ final Iterator<Entry<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>>> iterator =
+ TASK_MAP.entrySet().iterator();
+ while (iterator.hasNext()) {
+ final Entry<WeakReference<BaseGenericObjectPool<?>.Evictor>, WeakRunner<BaseGenericObjectPool<?>.Evictor>> entry = iterator.next();
if (entry.getKey().get() == null) {
executor.remove(entry.getValue());
- TASK_MAP.remove(entry.getKey());
+ iterator.remove();
}
}
if (TASK_MAP.isEmpty() && executor != null) {
@@ -107,8 +114,10 @@ final class EvictionTimer {
if (task != null) {
task.run();
} else {
- executor.remove(this);
- TASK_MAP.remove(ref);
+ synchronized (EvictionTimer.class) {
+ executor.remove(this);
+ TASK_MAP.remove(ref);
+ }
}
}
}
@@ -189,8 +198,8 @@ final class EvictionTimer {
* server environments.
*
* @param task Task to be scheduled.
- * @param delay Delay in milliseconds before task is executed.
- * @param period Time in milliseconds between executions.
+ * @param delay Duration before task is executed.
+ * @param period Duration between executions.
*/
static synchronized void schedule(
final BaseGenericObjectPool<?>.Evictor task, final Duration delay, final Duration period) {
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
index 07e89b6690..763ba12e71 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,8 +28,8 @@ import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.TreeMap;
+import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -128,16 +128,16 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* @param fairness true means client threads waiting to borrow / return instances
* will be served as if waiting in a FIFO queue.
*/
- ObjectDeque(final boolean fairness) {
+ private ObjectDeque(final boolean fairness) {
idleObjects = new LinkedBlockingDeque<>(fairness);
}
/**
* Gets all the objects for the current key.
*
- * @return All the objects
+ * @return All the objects,
*/
- public Map<IdentityWrapper<S>, PooledObject<S>> getAllObjects() {
+ Map<IdentityWrapper<S>, PooledObject<S>> getAllObjects() {
return allObjects;
}
@@ -145,27 +145,27 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* Gets the number of instances created - number destroyed.
* Should always be less than or equal to maxTotalPerKey.
*
- * @return The net instance addition count for this deque
+ * @return The net instance addition count for this deque.
*/
- public AtomicInteger getCreateCount() {
+ AtomicInteger getCreateCount() {
return createCount;
}
/**
* Gets the idle objects for the current key.
*
- * @return The idle objects
+ * @return The idle objects.
*/
- public LinkedBlockingDeque<PooledObject<S>> getIdleObjects() {
+ 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
+ * @return The number of threads with a registered interest in this key.
*/
- public AtomicLong getNumInterested() {
+ AtomicLong getNumInterested() {
return numInterested;
}
@@ -201,6 +201,12 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
private volatile int maxTotalPerKey =
GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
+ private volatile boolean reuseCapacityOnReturn =
+ GenericKeyedObjectPoolConfig.DEFAULT_REUSE_CAPACITY_ON_RETURN;
+
+ private volatile boolean reuseCapacityOnMaintenance =
+ GenericKeyedObjectPoolConfig.DEFAULT_REUSE_CAPACITY_ON_MAINTENANCE;
+
private final KeyedPooledObjectFactory<K, T> factory;
private final boolean fairness;
@@ -298,9 +304,9 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* @throws Exception If the associated factory fails to passivate the object
*/
private void addIdleObject(final K key, final PooledObject<T> p) throws Exception {
- if (!PooledObject.isNull(p)) {
+ if (PooledObject.nonNull(p)) {
factory.passivateObject(key, p);
- final LinkedBlockingDeque<PooledObject<T>> idleObjects = poolMap.get(key).getIdleObjects();
+ final BlockingDeque<PooledObject<T>> idleObjects = poolMap.get(key).getIdleObjects();
if (getLifo()) {
idleObjects.addFirst(p);
} else {
@@ -330,9 +336,18 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
@Override
public void addObject(final K key) throws Exception {
assertOpen();
- register(key);
+ final ObjectDeque<T> objectDeque = register(key);
try {
- addIdleObject(key, create(key));
+ // Attempt create and add only if there is capacity to add
+ // > to the overall instance count
+ // > to the pool under the key
+ final int maxtTotalPerKey = getMaxTotalPerKey();
+ final int maxTotal = getMaxTotal();
+ if ((maxTotal < 0 || getNumActive() + getNumIdle() < maxTotal)
+ && (maxtTotalPerKey < 0 || objectDeque.allObjects.size() < maxtTotalPerKey)) {
+ // Attempt to create and add a new instance under key
+ addIdleObject(key, create(key, getMaxWaitDuration()));
+ }
} finally {
deregister(key);
}
@@ -400,8 +415,8 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* </p>
*
* @param key pool key
- * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
- * to become available
+ * @param maxWaitDuration The time to wait for an object to become
+ * available
*
* @return object instance from the keyed pool
* @throws NoSuchElementException if a keyed object instance cannot be
@@ -409,10 +424,12 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
*
* @throws Exception if a keyed object instance cannot be returned due to an
* error
+ * @since 2.12.2
*/
- public T borrowObject(final K key, final long borrowMaxWaitMillis) throws Exception {
+ public T borrowObject(final K key, final Duration maxWaitDuration) throws Exception {
assertOpen();
-
+ final Instant startInstant = Instant.now();
+ Duration remainingWaitDuration = maxWaitDuration;
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnBorrow() && getNumIdle() < 2 &&
getNumActive() > getMaxTotal() - 3) {
@@ -426,27 +443,28 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
final boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
- final Instant waitTime = Instant.now();
final ObjectDeque<T> objectDeque = register(key);
try {
while (p == null) {
+ remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
create = false;
p = objectDeque.getIdleObjects().pollFirst();
if (p == null) {
- p = create(key);
- if (!PooledObject.isNull(p)) {
+ p = create(key, remainingWaitDuration);
+ if (PooledObject.nonNull(p)) {
create = true;
}
+ remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
}
if (blockWhenExhausted) {
if (PooledObject.isNull(p)) {
- p = borrowMaxWaitMillis < 0 ? objectDeque.getIdleObjects().takeFirst():
- objectDeque.getIdleObjects().pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
+ p = maxWaitDuration.isNegative() ? objectDeque.getIdleObjects().takeFirst()
+ : objectDeque.getIdleObjects().pollFirst(remainingWaitDuration);
}
if (PooledObject.isNull(p)) {
throw new NoSuchElementException(appendStats(
- "Timeout waiting for idle object, borrowMaxWaitMillis=" + borrowMaxWaitMillis));
+ "Timeout waiting for idle object, borrowMaxWaitMillis=" + maxWaitDuration.toMillis()));
}
} else if (PooledObject.isNull(p)) {
throw new NoSuchElementException(appendStats("Pool exhausted"));
@@ -455,7 +473,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
p = null;
}
- if (!PooledObject.isNull(p)) {
+ if (PooledObject.nonNull(p)) {
try {
factory.activateObject(key, p);
} catch (final Exception e) {
@@ -466,12 +484,13 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
p = null;
if (create) {
- final NoSuchElementException nsee = new NoSuchElementException(appendStats("Unable to activate object"));
+ final NoSuchElementException nsee = new NoSuchElementException(
+ appendStats("Unable to activate object"));
nsee.initCause(e);
throw nsee;
}
}
- if (!PooledObject.isNull(p) && getTestOnBorrow()) {
+ if (PooledObject.nonNull(p) && getTestOnBorrow()) {
boolean validate = false;
Throwable validationThrowable = null;
try {
@@ -502,11 +521,78 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
deregister(key);
}
- updateStatsBorrow(p, Duration.between(waitTime, Instant.now()));
+ updateStatsBorrow(p, Duration.between(startInstant, Instant.now()));
return p.getObject();
}
+
+ /**
+ * Borrows an object from the sub-pool associated with the given key using
+ * the specified waiting time which only applies if
+ * {@link #getBlockWhenExhausted()} is true.
+ * <p>
+ * If there is one or more idle instances available in the sub-pool
+ * associated with the given key, then an idle instance will be selected
+ * based on the value of {@link #getLifo()}, activated and returned. If
+ * activation fails, or {@link #getTestOnBorrow() testOnBorrow} is set to
+ * {@code true} and validation fails, the instance is destroyed and the
+ * next available instance is examined. This continues until either a valid
+ * instance is returned or there are no more idle instances available.
+ * </p>
+ * <p>
+ * If there are no idle instances available in the sub-pool associated with
+ * the given key, behavior depends on the {@link #getMaxTotalPerKey()
+ * maxTotalPerKey}, {@link #getMaxTotal() maxTotal}, and (if applicable)
+ * {@link #getBlockWhenExhausted()} and the value passed in to the
+ * {@code borrowMaxWaitMillis} parameter. If the number of instances checked
+ * out from the sub-pool under the given key is less than
+ * {@code maxTotalPerKey} and the total number of instances in
+ * circulation (under all keys) is less than {@code maxTotal}, a new
+ * instance is created, activated and (if applicable) validated and returned
+ * to the caller. If validation fails, a {@code NoSuchElementException}
+ * will be thrown. If the factory returns null when creating an instance,
+ * a {@code NullPointerException} is thrown.
+ * </p>
+ * <p>
+ * If the associated sub-pool is exhausted (no available idle instances and
+ * no capacity to create new ones), this method will either block
+ * ({@link #getBlockWhenExhausted()} is true) or throw a
+ * {@code NoSuchElementException}
+ * ({@link #getBlockWhenExhausted()} is false).
+ * The length of time that this method will block when
+ * {@link #getBlockWhenExhausted()} is true is determined by the value
+ * passed in to the {@code borrowMaxWait} parameter.
+ * </p>
+ * <p>
+ * When {@code maxTotal} is set to a positive value and this method is
+ * invoked when at the limit with no idle instances available under the requested
+ * key, an attempt is made to create room by clearing the oldest 15% of the
+ * elements from the keyed sub-pools.
+ * </p>
+ * <p>
+ * When the pool is exhausted, multiple calling threads may be
+ * simultaneously blocked waiting for instances to become available. A
+ * "fairness" algorithm has been implemented to ensure that threads receive
+ * available instances in request arrival order.
+ * </p>
+ *
+ * @param key pool key
+ * @param maxWaitMillis The time to wait in milliseconds for an object to become
+ * available
+ *
+ * @return object instance from the keyed pool
+ * @throws NoSuchElementException if a keyed object instance cannot be
+ * returned because the pool is exhausted.
+ *
+ * @throws Exception if a keyed object instance cannot be returned due to an
+ * error
+ */
+
+ public T borrowObject(final K key, final long maxWaitMillis) throws Exception {
+ return borrowObject(key, Duration.ofMillis(maxWaitMillis));
+ }
+
/**
* Calculate the number of objects that need to be created to attempt to
* maintain the minimum number of idle objects while not exceeded the limits
@@ -607,7 +693,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
final ObjectDeque<T> objectDeque = register(key);
int freedCapacity = 0;
try {
- final LinkedBlockingDeque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects();
+ final BlockingDeque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects();
PooledObject<T> p = idleObjects.poll();
while (p != null) {
try {
@@ -708,11 +794,16 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
/**
* Creates a new pooled object or null.
*
- * @param key Key associated with new pooled object.
+ * @param key Key associated with new pooled object.
+ * @param maxWaitDuration The time to wait in this method. If negative or ZERO,
+ * this method may wait indefinitely.
* @return The new, wrapped pooled object. May return null.
* @throws Exception If the objection creation fails.
*/
- private PooledObject<T> create(final K key) throws Exception {
+ private PooledObject<T> create(final K key, final Duration maxWaitDuration) throws Exception {
+ final Instant startInstant = Instant.now();
+ Duration remainingWaitDuration = maxWaitDuration.isNegative() ? Duration.ZERO : maxWaitDuration;
+
int maxTotalPerKeySave = getMaxTotalPerKey(); // Per key
if (maxTotalPerKeySave < 0) {
maxTotalPerKeySave = Integer.MAX_VALUE;
@@ -744,6 +835,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
// call the factory
Boolean create = null;
while (create == null) {
+ remainingWaitDuration = maxWaitDuration.isNegative() ? Duration.ZERO : maxWaitDuration.minus(durationSince(startInstant));
synchronized (objectDeque.makeObjectCountLock) {
final long newCreateCount = objectDeque.getCreateCount().incrementAndGet();
// Check against the per key limit
@@ -757,12 +849,13 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
// create a new object. Return and wait for an object to
// be returned.
create = Boolean.FALSE;
- } else {
+ } else if (!remainingWaitDuration.isNegative()) {
// There are makeObject() calls in progress that might
// bring the pool to capacity. Those calls might also
// fail so wait until they complete and then re-test if
// the pool is at capacity or not.
- objectDeque.makeObjectCountLock.wait();
+ objectDeque.makeObjectCountLock.wait(remainingWaitDuration.toMillis(),
+ remainingWaitDuration.getNano() % 1_000_000);
}
} else {
// The pool is not at capacity. Create a new object.
@@ -808,7 +901,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
createdCount.incrementAndGet();
- objectDeque.getAllObjects().put(new IdentityWrapper<>(p.getObject()), p);
+ objectDeque.getAllObjects().put(IdentityWrapper.unwrap(p), p);
return p;
}
@@ -857,13 +950,13 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
/**
* Destroy the wrapped, pooled object.
*
- * @param key The key associated with the object to destroy.
+ * @param key The key associated with the object to destroy
* @param toDestroy The wrapped object to be destroyed
* @param always Should the object be destroyed even if it is not currently
* in the set of idle objects for the given key
- * @param destroyMode DestroyMode context provided to the factory
+ * @param destroyMode {@link DestroyMode} context provided to the factory
* @return {@code true} if the object was destroyed, otherwise {@code false}
- * @throws Exception If the object destruction failed
+ * @throws Exception If the factory throws an exception during destruction
*/
private boolean destroy(final K key, final PooledObject<T> toDestroy, final boolean always, final DestroyMode destroyMode) throws Exception {
@@ -881,7 +974,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
}
if (isIdle || always) {
- objectDeque.getAllObjects().remove(new IdentityWrapper<>(toDestroy.getObject()));
+ objectDeque.getAllObjects().remove(IdentityWrapper.unwrap(toDestroy));
toDestroy.invalidate();
try {
@@ -1086,8 +1179,6 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
}
underTest.endEvictionTest(idleObjects);
- // TODO - May need to add code here once additional
- // states are used
}
}
}
@@ -1096,6 +1187,9 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
removeAbandoned(ac);
}
+ if (reuseCapacityOnMaintenance) {
+ reuseCapacity();
+ }
}
/**
@@ -1258,6 +1352,32 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
return result;
}
+ /**
+ * Gets whether to call {@link #reuseCapacity()} during pool maintenance (eviction).
+ * When true, the pool will attempt to reuse freed capacity at the end of each
+ * eviction run.
+ *
+ * @return {@code true} if capacity reuse is enabled during maintenance, {@code false} otherwise
+ * @see #setReuseCapacityOnMaintenance(boolean)
+ * @since 2.13.0
+ */
+ public boolean getReuseCapacityOnMaintenance() {
+ return reuseCapacityOnMaintenance;
+ }
+
+ /**
+ * Gets whether to call {@link #reuseCapacity()} when returning objects to the pool.
+ * When true, the pool will check if there are threads waiting to borrow objects
+ * and attempt to reuse the capacity freed by the return operation.
+ *
+ * @return {@code true} if capacity reuse is enabled on return, {@code false} otherwise
+ * @see #setReuseCapacityOnReturn(boolean)
+ * @since 2.13.0
+ */
+ public boolean getReuseCapacityOnReturn() {
+ return reuseCapacityOnReturn;
+ }
+
@SuppressWarnings("boxing") // Commons Pool uses auto-boxing
@Override
String getStatsString() {
@@ -1333,7 +1453,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* to be borrowed) and active (currently borrowed).
* <p>
* Note: This is named listAllObjects so it is presented as an operation via
- * JMX. That means it won't be invoked unless the explicitly requested
+ * JMX. That means it won't be invoked unless explicitly requested
* whereas all attributes will be automatically requested when viewing the
* attributes for an object in a tool like JConsole.
* </p>
@@ -1505,7 +1625,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
final int maxIdle = getMaxIdlePerKey();
- final LinkedBlockingDeque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects();
+ final BlockingDeque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects();
if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) {
try {
@@ -1527,7 +1647,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
}
}
} finally {
- if (hasBorrowWaiters()) {
+ if (reuseCapacityOnReturn && hasBorrowWaiters()) {
reuseCapacity();
}
updateStatsReturn(activeTime);
@@ -1550,7 +1670,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
private void reuseCapacity() {
final int maxTotalPerKeySave = getMaxTotalPerKey();
int maxQueueLength = 0;
- LinkedBlockingDeque<PooledObject<T>> mostLoadedPool = null;
+ BlockingDeque<PooledObject<T>> mostLoadedPool = null;
K mostLoadedKey = null;
// Find the most loaded pool that could take a new instance
@@ -1571,7 +1691,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
try {
// If there is no capacity to add, create will return null
// and addIdleObject will no-op.
- addIdleObject(mostLoadedKey, create(mostLoadedKey));
+ addIdleObject(mostLoadedKey, create(mostLoadedKey, Duration.ZERO));
} catch (final Exception e) {
swallowException(e);
} finally {
@@ -1585,7 +1705,7 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
* <p>
* Always activates {@link #reuseCapacity()} at least once.
*
- * @param newCapacity number of new instances to attempt to create.
+ * @param newCapacity number of times to call {@link #reuseCapacity()}
*/
private void reuseCapacity(final int newCapacity) {
final int bound = newCapacity < 1 ? 1 : newCapacity;
@@ -1606,6 +1726,8 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
setMaxTotalPerKey(conf.getMaxTotalPerKey());
setMaxTotal(conf.getMaxTotal());
setMinIdlePerKey(conf.getMinIdlePerKey());
+ setReuseCapacityOnReturn(conf.getReuseCapacityOnReturn());
+ setReuseCapacityOnMaintenance(conf.getReuseCapacityOnMaintenance());
}
/**
@@ -1662,6 +1784,34 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
this.minIdlePerKey = minIdlePerKey;
}
+ /**
+ * Sets whether to call {@link #reuseCapacity()} during pool maintenance (eviction).
+ * When enabled, the pool will attempt to reuse capacity at the end of each
+ * eviction run.
+ *
+ * @param reuseCapacityOnMaintenance {@code true} to enable capacity reuse during
+ * maintenance, {@code false} to disable
+ * @see #getReuseCapacityOnMaintenance()
+ * @since 2.13.0
+ */
+ public void setReuseCapacityOnMaintenance(final boolean reuseCapacityOnMaintenance) {
+ this.reuseCapacityOnMaintenance = reuseCapacityOnMaintenance;
+ }
+
+ /**
+ * Sets whether to call {@link #reuseCapacity()} when returning objects to the pool.
+ * When enabled, the pool will check if there are threads waiting to borrow objects
+ * and attempt to reuse capacity (across pools) on return.
+ *
+ * @param reuseCapacityOnReturn {@code true} to enable capacity reuse on return,
+ * {@code false} to disable
+ * @see #getReuseCapacityOnReturn()
+ * @since 2.13.0
+ */
+ public void setReuseCapacityOnReturn(final boolean reuseCapacityOnReturn) {
+ this.reuseCapacityOnReturn = reuseCapacityOnReturn;
+ }
+
@Override
protected void toStringAppendFields(final StringBuilder builder) {
super.toStringAppendFields(builder);
@@ -1689,6 +1839,10 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
builder.append(evictionKey);
builder.append(", abandonedConfig=");
builder.append(abandonedConfig);
+ builder.append(", reuseCapacityOnReturn=");
+ builder.append(reuseCapacityOnReturn);
+ builder.append(", reuseCapacityOnMaintenance=");
+ builder.append(reuseCapacityOnMaintenance);
}
/**
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolConfig.java
index 14fe7b139c..97c45449e0 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolConfig.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -58,6 +58,22 @@ public class GenericKeyedObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
*/
public static final int DEFAULT_MAX_IDLE_PER_KEY = 8;
+ /**
+ * The default value for the {@code reuseCapacityOnReturn} configuration attribute: {@value}.
+ *
+ * @see GenericKeyedObjectPool#getReuseCapacityOnReturn()
+ * @since 2.13.0
+ */
+ public static final boolean DEFAULT_REUSE_CAPACITY_ON_RETURN = true;
+
+ /**
+ * The default value for the {@code reuseCapacityOnMaintenance} configuration attribute: {@value}.
+ *
+ * @see GenericKeyedObjectPool#getReuseCapacityOnMaintenance()
+ * @since 2.13.0
+ */
+ public static final boolean DEFAULT_REUSE_CAPACITY_ON_MAINTENANCE = false;
+
private int minIdlePerKey = DEFAULT_MIN_IDLE_PER_KEY;
private int maxIdlePerKey = DEFAULT_MAX_IDLE_PER_KEY;
@@ -66,6 +82,10 @@ public class GenericKeyedObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
private int maxTotal = DEFAULT_MAX_TOTAL;
+ private boolean reuseCapacityOnReturn = DEFAULT_REUSE_CAPACITY_ON_RETURN;
+
+ private boolean reuseCapacityOnMaintenance = DEFAULT_REUSE_CAPACITY_ON_MAINTENANCE;
+
/**
* Constructs a new configuration with default settings.
*/
@@ -134,6 +154,34 @@ public class GenericKeyedObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
return minIdlePerKey;
}
+ /**
+ * Gets the value for the {@code reuseCapacityOnMaintenance} configuration attribute
+ * for pools created with this configuration instance.
+ *
+ * @return The current setting of {@code reuseCapacityOnMaintenance} for this
+ * configuration instance
+ *
+ * @see GenericKeyedObjectPool#getReuseCapacityOnMaintenance()
+ * @since 2.13.0
+ */
+ public boolean getReuseCapacityOnMaintenance() {
+ return reuseCapacityOnMaintenance;
+ }
+
+ /**
+ * Gets the value for the {@code reuseCapacityOnReturn} configuration attribute
+ * for pools created with this configuration instance.
+ *
+ * @return The current setting of {@code reuseCapacityOnReturn} for this
+ * configuration instance
+ *
+ * @see GenericKeyedObjectPool#getReuseCapacityOnReturn()
+ * @since 2.13.0
+ */
+ public boolean getReuseCapacityOnReturn() {
+ return reuseCapacityOnReturn;
+ }
+
/**
* Sets the value for the {@code maxIdlePerKey} configuration attribute for
* pools created with this configuration instance.
@@ -186,6 +234,34 @@ public class GenericKeyedObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
this.minIdlePerKey = minIdlePerKey;
}
+ /**
+ * Sets the value for the {@code reuseCapacityOnMaintenance} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param reuseCapacityOnMaintenance The new setting of {@code reuseCapacityOnMaintenance}
+ * for this configuration instance
+ *
+ * @see GenericKeyedObjectPool#setReuseCapacityOnMaintenance(boolean)
+ * @since 2.13.0
+ */
+ public void setReuseCapacityOnMaintenance(final boolean reuseCapacityOnMaintenance) {
+ this.reuseCapacityOnMaintenance = reuseCapacityOnMaintenance;
+ }
+
+ /**
+ * Sets the value for the {@code reuseCapacityOnReturn} configuration attribute for
+ * pools created with this configuration instance.
+ *
+ * @param reuseCapacityOnReturn The new setting of {@code reuseCapacityOnReturn}
+ * for this configuration instance
+ *
+ * @see GenericKeyedObjectPool#setReuseCapacityOnReturn(boolean)
+ * @since 2.13.0
+ */
+ public void setReuseCapacityOnReturn(final boolean reuseCapacityOnReturn) {
+ this.reuseCapacityOnReturn = reuseCapacityOnReturn;
+ }
+
@Override
protected void toStringAppendFields(final StringBuilder builder) {
super.toStringAppendFields(builder);
@@ -197,5 +273,9 @@ public class GenericKeyedObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
builder.append(maxTotalPerKey);
builder.append(", maxTotal=");
builder.append(maxTotal);
+ builder.append(", reuseCapacityOnReturn=");
+ builder.append(reuseCapacityOnReturn);
+ builder.append(", reuseCapacityOnMaintenance=");
+ builder.append(reuseCapacityOnMaintenance);
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolMXBean.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolMXBean.java
index 076e888662..6e267bd73c 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolMXBean.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPoolMXBean.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
index 98f9819cc0..20398ff9e2 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -84,12 +84,6 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
private static final String ONAME_BASE =
"org.apache.commons.pool2:type=GenericObjectPool,name=";
- private static void wait(final Object obj, final Duration duration) throws InterruptedException {
- if (!duration.isNegative()) {
- obj.wait(duration.toMillis(), duration.getNano() % 1_000_000);
- }
- }
-
private volatile String factoryType;
private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
@@ -102,17 +96,17 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* All of the objects currently associated with this pool in any state. It
* excludes objects that have been destroyed. The size of
* {@link #allObjects} will always be less than or equal to {@link
- * #_maxActive}. Map keys are pooled objects, values are the PooledObject
+ * #getMaxTotal()}. Map keys are pooled objects, values are the PooledObject
* wrappers used internally by the pool.
*/
private final ConcurrentHashMap<IdentityWrapper<T>, PooledObject<T>> allObjects = new ConcurrentHashMap<>();
/*
* The combined count of the currently created objects and those in the
- * process of being created. Under load, it may exceed {@link #_maxActive}
+ * process of being created. Under load, it may exceed {@link #getMaxTotal()}
* if multiple threads try and create a new object at the same time but
* {@link #create()} will ensure that there are never more than
- * {@link #_maxActive} objects created at any one time.
+ * {@link #getMaxTotal()} objects created at any one time.
*/
private final AtomicLong createCount = new AtomicLong();
@@ -188,7 +182,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* @throws Exception If the factory fails to passivate the object
*/
private void addIdleObject(final PooledObject<T> p) throws Exception {
- if (!PooledObject.isNull(p)) {
+ if (PooledObject.nonNull(p)) {
factory.passivateObject(p);
if (getLifo()) {
idleObjects.addFirst(p);
@@ -199,10 +193,11 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
/**
- * Creates an object, and place it into the pool. addObject() is useful for
+ * Creates an object, and places it into the pool. addObject() is useful for
* "pre-loading" a pool with idle objects.
* <p>
- * If there is no capacity available to add to the pool, this is a no-op
+ * If there is no capacity available to add to the pool, or there are already
+ * {@link #getMaxIdle()} idle instances in the pool, this is a no-op
* (no exception, no impact to the pool).
* </p>
* <p>
@@ -217,11 +212,16 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
if (factory == null) {
throw new IllegalStateException("Cannot add objects without a factory.");
}
- addIdleObject(create(getMaxWaitDuration()));
+
+ final int localMaxTotal = getMaxTotal();
+ final int localMaxIdle = getMaxIdle();
+ if (getNumIdle() < localMaxIdle && (localMaxTotal < 0 || createCount.get() < localMaxTotal)) {
+ addIdleObject(create(getMaxWaitDuration()));
+ }
}
/**
- * Equivalent to <code>{@link #borrowObject(long)
+ * Equivalent to <code>{@link #borrowObject(Duration)
* borrowObject}({@link #getMaxWaitDuration()})</code>.
*
* {@inheritDoc}
@@ -246,8 +246,8 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* <p>
* If there are no idle instances available in the pool, behavior depends on
* the {@link #getMaxTotal() maxTotal}, (if applicable)
- * {@link #getBlockWhenExhausted()} and the value passed in to the
- * {@code borrowMaxWaitMillis} parameter. If the number of instances
+ * {@link #getBlockWhenExhausted()} and the value passed in the
+ * {@code maxWaitDuration} parameter. If the number of instances
* checked out from the pool is less than {@code maxTotal,} a new
* instance is created, activated and (if applicable) validated and returned
* to the caller. If validation fails, a {@code NoSuchElementException}
@@ -261,8 +261,9 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* {@code NoSuchElementException} (if
* {@link #getBlockWhenExhausted()} is false). The length of time that this
* method will block when {@link #getBlockWhenExhausted()} is true is
- * determined by the value passed in to the {@code borrowMaxWaitMillis}
- * parameter.
+ * determined by the value passed in to the {@code maxWaitDuration}
+ * parameter. Passing a negative duration will cause this method to block
+ * indefinitely until an object becomes available.
* </p>
* <p>
* When the pool is exhausted, multiple calling threads may be
@@ -271,17 +272,17 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* available instances in request arrival order.
* </p>
*
- * @param borrowMaxWaitDuration The time to wait for an object to become available, not null.
+ * @param maxWaitDuration The time to wait for an object to become available, not null.
* @return object instance from the pool
* @throws NoSuchElementException if an instance cannot be returned
* @throws Exception if an object instance cannot be returned due to an error
* @since 2.10.0
*/
- public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception {
+ public T borrowObject(final Duration maxWaitDuration) throws Exception {
assertOpen();
final Instant startInstant = Instant.now();
- final boolean negativeDuration = borrowMaxWaitDuration.isNegative();
- Duration remainingWaitDuration = borrowMaxWaitDuration;
+ final boolean negativeDuration = maxWaitDuration.isNegative();
+ Duration remainingWaitDuration = maxWaitDuration;
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnBorrow() && getNumIdle() < 2 && getNumActive() > getMaxTotal() - 3) {
removeAbandoned(ac);
@@ -292,22 +293,22 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
final boolean blockWhenExhausted = getBlockWhenExhausted();
boolean create;
while (p == null) {
- remainingWaitDuration = remainingWaitDuration.minus(durationSince(startInstant));
+ remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
create = false;
p = idleObjects.pollFirst();
if (p == null) {
p = create(remainingWaitDuration);
- if (!PooledObject.isNull(p)) {
+ if (PooledObject.nonNull(p)) {
create = true;
}
}
if (blockWhenExhausted) {
if (PooledObject.isNull(p)) {
+ remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
p = negativeDuration ? idleObjects.takeFirst() : idleObjects.pollFirst(remainingWaitDuration);
}
if (PooledObject.isNull(p)) {
- throw new NoSuchElementException(appendStats(
- "Timeout waiting for idle object, borrowMaxWaitDuration=" + remainingWaitDuration));
+ throw new NoSuchElementException(appendStats("Timeout waiting for idle object, maxWaitDuration=" + remainingWaitDuration));
}
} else if (PooledObject.isNull(p)) {
throw new NoSuchElementException(appendStats("Pool exhausted"));
@@ -326,8 +327,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
p = null;
if (create) {
- final NoSuchElementException nsee = new NoSuchElementException(
- appendStats("Unable to activate object"));
+ final NoSuchElementException nsee = new NoSuchElementException(appendStats("Unable to activate object"));
nsee.initCause(e);
throw nsee;
}
@@ -350,8 +350,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
p = null;
if (create) {
- final NoSuchElementException nsee = new NoSuchElementException(
- appendStats("Unable to validate object"));
+ final NoSuchElementException nsee = new NoSuchElementException(appendStats("Unable to validate object"));
nsee.initCause(validationThrowable);
throw nsee;
}
@@ -363,10 +362,6 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
return p.getObject();
}
- private Duration durationSince(final Instant startInstant) {
- return Duration.between(startInstant, Instant.now());
- }
-
/**
* Borrows an object from the pool using the specific waiting time which only
* applies if {@link #getBlockWhenExhausted()} is true.
@@ -383,7 +378,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* If there are no idle instances available in the pool, behavior depends on
* the {@link #getMaxTotal() maxTotal}, (if applicable)
* {@link #getBlockWhenExhausted()} and the value passed in to the
- * {@code borrowMaxWaitMillis} parameter. If the number of instances
+ * {@code maxWaitMillis} parameter. If the number of instances
* checked out from the pool is less than {@code maxTotal,} a new
* instance is created, activated and (if applicable) validated and returned
* to the caller. If validation fails, a {@code NoSuchElementException}
@@ -397,8 +392,9 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* {@code NoSuchElementException} (if
* {@link #getBlockWhenExhausted()} is false). The length of time that this
* method will block when {@link #getBlockWhenExhausted()} is true is
- * determined by the value passed in to the {@code borrowMaxWaitMillis}
- * parameter.
+ * determined by the value passed in to the {@code maxWaitMillis}
+ * parameter. Passing a negative duration will cause this method to block
+ * indefinitely until an object becomes available.
* </p>
* <p>
* When the pool is exhausted, multiple calling threads may be
@@ -407,15 +403,17 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* available instances in request arrival order.
* </p>
*
- * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
+ * @param maxWaitMillis The time to wait in milliseconds for an object
* to become available
* @return object instance from the pool
* @throws NoSuchElementException if an instance cannot be returned
* @throws Exception if an object instance cannot be returned due to an
* error
+ * @deprecated Use {@link #borrowObject(Duration)}.
*/
- public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
- return borrowObject(Duration.ofMillis(borrowMaxWaitMillis));
+ @Deprecated
+ public T borrowObject(final long maxWaitMillis) throws Exception {
+ return borrowObject(Duration.ofMillis(maxWaitMillis));
}
/**
@@ -495,13 +493,13 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* If the factory makeObject returns null, this method throws a NullPointerException.
* </p>
*
- * @param maxWaitDuration The time to wait for an object to become available.
+ * @param maxWaitDurationRequest The time to wait for capacity to create.
* @return The new wrapped pooled object or null.
- * @throws Exception if the object factory's {@code makeObject} fails
+ * @throws Exception if the object factory's {@code makeObject} fails.
*/
- private PooledObject<T> create(final Duration maxWaitDuration) throws Exception {
+ private PooledObject<T> create(final Duration maxWaitDurationRequest) throws Exception {
final Instant startInstant = Instant.now();
- Duration remainingWaitDuration = maxWaitDuration.isNegative() ? Duration.ZERO : maxWaitDuration;
+ final Duration maxWaitDuration = maxWaitDurationRequest.isNegative() ? Duration.ZERO : maxWaitDurationRequest;
int localMaxTotal = getMaxTotal();
// This simplifies the code later in this method
if (localMaxTotal < 0) {
@@ -516,7 +514,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
Boolean create = null;
while (create == null) {
// remainingWaitDuration handles spurious wakeup from wait().
- remainingWaitDuration = remainingWaitDuration.minus(durationSince(startInstant));
+ final Duration remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
synchronized (makeObjectCountLock) {
final long newCreateCount = createCount.incrementAndGet();
if (newCreateCount > localMaxTotal) {
@@ -580,7 +578,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
createdCount.incrementAndGet();
- allObjects.put(new IdentityWrapper<>(p.getObject()), p);
+ allObjects.put(IdentityWrapper.unwrap(p), p);
return p;
}
@@ -595,7 +593,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception {
toDestroy.invalidate();
idleObjects.remove(toDestroy);
- allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
+ allObjects.remove(IdentityWrapper.unwrap(toDestroy));
try {
factory.destroyObject(toDestroy, destroyMode);
} finally {
@@ -604,6 +602,7 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
}
+
/**
* Tries to ensure that {@code idleCount} idle instances exist in the pool.
* <p>
@@ -760,8 +759,6 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
}
underTest.endEvictionTest(idleObjects);
- // TODO - May need to add code here once additional
- // states are used
}
}
}
@@ -917,7 +914,8 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
* {@inheritDoc}
* <p>
* Activation of this method decrements the active count and attempts to destroy the instance, using the provided
- * {@link DestroyMode}.
+ * {@link DestroyMode}. To ensure liveness of the pool, {@link #addObject()} is called to replace the invalidated
+ * instance.
* </p>
*
* @throws Exception if an exception occurs destroying the object
@@ -938,7 +936,9 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
destroy(p, destroyMode);
}
}
- ensureIdle(1, false);
+ if (!isClosed()) {
+ addObject();
+ }
}
/**
@@ -957,11 +957,12 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
public Set<DefaultPooledObjectInfo> listAllObjects() {
return allObjects.values().stream().map(DefaultPooledObjectInfo::new).collect(Collectors.toSet());
}
+
/**
* Tries to ensure that {@link #getMinIdle()} idle instances are available
* in the pool.
*
- * @throws Exception If the associated factory throws an exception
+ * @throws Exception If the associated factory throws an exception.
* @since 2.4
*/
public void preparePool() throws Exception {
@@ -973,7 +974,10 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
/**
* Recovers abandoned objects which have been checked out but
- * not used since longer than the removeAbandonedTimeout.
+ * not used since longer than the removeAbandonedTimeout. For each object
+ * deemed abandoned, {@link #invalidateObject(Object)} is called. This
+ * results in the object being destroyed and then {@link #addObject()} is
+ * called to try to replace it.
*
* @param abandonedConfig The configuration to use to identify abandoned objects
*/
@@ -1021,75 +1025,76 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
}
return; // Object was abandoned and removed
}
+ synchronized (p) {
+ markReturningState(p);
- markReturningState(p);
-
- final Duration activeTime = p.getActiveDuration();
+ final Duration activeTime = p.getActiveDuration();
- if (getTestOnReturn() && !factory.validateObject(p)) {
- try {
- destroy(p, DestroyMode.NORMAL);
- } catch (final Exception e) {
- swallowException(e);
- }
- try {
- ensureIdle(1, false);
- } catch (final Exception e) {
- swallowException(e);
+ if (getTestOnReturn() && !factory.validateObject(p)) {
+ try {
+ destroy(p, DestroyMode.NORMAL);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ try {
+ ensureIdle(1, false);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ updateStatsReturn(activeTime);
+ return;
}
- updateStatsReturn(activeTime);
- return;
- }
- try {
- factory.passivateObject(p);
- } catch (final Exception e1) {
- swallowException(e1);
try {
- destroy(p, DestroyMode.NORMAL);
- } catch (final Exception e) {
- swallowException(e);
- }
- try {
- ensureIdle(1, false);
- } catch (final Exception e) {
- swallowException(e);
+ factory.passivateObject(p);
+ } catch (final Exception e1) {
+ swallowException(e1);
+ try {
+ destroy(p, DestroyMode.NORMAL);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ try {
+ ensureIdle(1, false);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ updateStatsReturn(activeTime);
+ return;
}
- updateStatsReturn(activeTime);
- return;
- }
-
- if (!p.deallocate()) {
- throw new IllegalStateException(
- "Object has already been returned to this pool or is invalid");
- }
- final int maxIdleSave = getMaxIdle();
- if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
- try {
- destroy(p, DestroyMode.NORMAL);
- } catch (final Exception e) {
- swallowException(e);
- }
- try {
- ensureIdle(1, false);
- } catch (final Exception e) {
- swallowException(e);
+ if (!p.deallocate()) {
+ throw new IllegalStateException(
+ "Object has already been returned to this pool or is invalid");
}
- } else {
- if (getLifo()) {
- idleObjects.addFirst(p);
+
+ final int maxIdleSave = getMaxIdle();
+ if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
+ try {
+ destroy(p, DestroyMode.NORMAL);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ try {
+ ensureIdle(1, false);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
} else {
- idleObjects.addLast(p);
- }
- if (isClosed()) {
- // Pool closed while object was being added to idle objects.
- // Make sure the returned object is destroyed rather than left
- // in the idle object pool (which would effectively be a leak)
- clear();
+ if (getLifo()) {
+ idleObjects.addFirst(p);
+ } else {
+ idleObjects.addLast(p);
+ }
+ if (isClosed()) {
+ // Pool closed while object was being added to idle objects.
+ // Make sure the returned object is destroyed rather than left
+ // in the idle object pool (which would effectively be a leak)
+ clear();
+ }
}
+ updateStatsReturn(activeTime);
}
- updateStatsReturn(activeTime);
}
/**
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolConfig.java
index ec3271e879..157037ca13 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolConfig.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -57,6 +57,13 @@ public class GenericObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
private int minIdle = DEFAULT_MIN_IDLE;
+ /**
+ * Constructs a new instance.
+ */
+ public GenericObjectPoolConfig() {
+ // empty
+ }
+
@SuppressWarnings("unchecked")
@Override
public GenericObjectPoolConfig<T> clone() {
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolMXBean.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolMXBean.java
index f17aa3ff6c..48a9a1ef89 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolMXBean.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPoolMXBean.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
index 63be6e1678..227f5686cd 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -37,18 +37,18 @@ final class InterruptibleReentrantLock extends ReentrantLock {
* Constructs a new InterruptibleReentrantLock with the given fairness policy.
*
* @param fairness true means threads should acquire contended locks as if
- * waiting in a FIFO queue
+ * waiting in a FIFO queue.
*/
InterruptibleReentrantLock(final boolean fairness) {
super(fairness);
}
/**
- * Interrupts the threads that are waiting on a specific condition
+ * Interrupts the threads that are waiting on a specific condition.
*
* @param condition the condition on which the threads are waiting.
*/
- public void interruptWaiters(final Condition condition) {
+ void interruptWaiters(final Condition condition) {
getWaitingThreads(condition).forEach(Thread::interrupt);
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
index 7edd10f64e..441f203b9e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -22,10 +22,10 @@ import java.io.Serializable;
import java.time.Duration;
import java.util.AbstractQueue;
import java.util.Collection;
-import java.util.Deque;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.concurrent.BlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@@ -66,7 +66,7 @@ import java.util.concurrent.locks.Condition;
* @since 2.0
*/
final class LinkedBlockingDeque<E> extends AbstractQueue<E>
- implements Deque<E>, Serializable {
+ implements BlockingDeque<E>, Serializable {
/*
* Implemented as a simple doubly-linked list protected by a
@@ -223,18 +223,26 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
/** Descending iterator */
private final class DescendingItr extends AbstractItr {
@Override
- Node<E> firstNode() { return last; }
+ Node<E> firstNode() {
+ return last;
+ }
@Override
- Node<E> nextNode(final Node<E> n) { return n.prev; }
+ Node<E> nextNode(final Node<E> n) {
+ return n.prev;
+ }
}
/** Forward iterator */
private final class Itr extends AbstractItr {
@Override
- Node<E> firstNode() { return first; }
+ Node<E> firstNode() {
+ return first;
+ }
@Override
- Node<E> nextNode(final Node<E> n) { return n.next; }
+ Node<E> nextNode(final Node<E> n) {
+ return n.next;
}
+ }
/**
* Doubly-linked list node class.
@@ -471,6 +479,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws NullPointerException if c is null
* @throws IllegalArgumentException if c is this instance
*/
+ @Override
public int drainTo(final Collection<? super E> c) {
return drainTo(c, Integer.MAX_VALUE);
}
@@ -490,6 +499,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws NullPointerException if c is null
* @throws IllegalArgumentException if c is this instance
*/
+ @Override
public int drainTo(final Collection<? super E> collection, final int maxElements) {
Objects.requireNonNull(collection, "collection");
if (collection == this) {
@@ -547,7 +557,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
*
* @return number of threads waiting on this deque's notEmpty condition.
*/
- public int getTakeQueueLength() {
+ int getTakeQueueLength() {
lock.lock();
try {
return lock.getWaitQueueLength(notEmpty);
@@ -562,7 +572,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
*
* @return true if there is at least one thread waiting on this deque's notEmpty condition.
*/
- public boolean hasTakeWaiters() {
+ boolean hasTakeWaiters() {
lock.lock();
try {
return lock.hasWaiters(notEmpty);
@@ -575,7 +585,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* Interrupts the threads currently waiting to take an object from the pool. See disclaimer on accuracy in
* {@link java.util.concurrent.locks.ReentrantLock#getWaitingThreads(Condition)}.
*/
- public void interuptTakeWaiters() {
+ void interuptTakeWaiters() {
lock.lock();
try {
lock.interruptWaiters(notEmpty);
@@ -685,6 +695,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
+ @Override
public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
return offerLast(e, timeout, unit);
}
@@ -711,7 +722,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
- public boolean offerFirst(final E e, final Duration timeout) throws InterruptedException {
+ boolean offerFirst(final E e, final Duration timeout) throws InterruptedException {
Objects.requireNonNull(e, "e");
long nanos = timeout.toNanos();
lock.lockInterruptibly();
@@ -740,6 +751,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
+ @Override
public boolean offerFirst(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
return offerFirst(e, PoolImplUtils.toDuration(timeout, unit));
}
@@ -795,6 +807,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whist waiting
* for space
*/
+ @Override
public boolean offerLast(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
return offerLast(e, PoolImplUtils.toDuration(timeout, unit));
}
@@ -856,6 +869,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E poll(final long timeout, final TimeUnit unit) throws InterruptedException {
return pollFirst(timeout, unit);
}
@@ -904,6 +918,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E pollFirst(final long timeout, final TimeUnit unit) throws InterruptedException {
return pollFirst(PoolImplUtils.toDuration(timeout, unit));
}
@@ -926,7 +941,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
- public E pollLast(final Duration timeout)
+ E pollLast(final Duration timeout)
throws InterruptedException {
long nanos = timeout.toNanos();
lock.lockInterruptibly();
@@ -953,6 +968,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E pollLast(final long timeout, final TimeUnit unit)
throws InterruptedException {
return pollLast(PoolImplUtils.toDuration(timeout, unit));
@@ -981,6 +997,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
+ @Override
public void put(final E e) throws InterruptedException {
putLast(e);
}
@@ -994,6 +1011,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
+ @Override
public void putFirst(final E e) throws InterruptedException {
Objects.requireNonNull(e, "e");
lock.lock();
@@ -1015,6 +1033,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @throws InterruptedException if the thread is interrupted whilst waiting
* for space
*/
+ @Override
public void putLast(final E e) throws InterruptedException {
Objects.requireNonNull(e, "e");
lock.lock();
@@ -1030,12 +1049,11 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
// Stack methods
/**
- * Reconstitutes this deque from a stream (that is,
- * deserialize it).
+ * Reconstitutes this deque from a stream (that is, deserialize it).
+ *
* @param s the stream
*/
- private void readObject(final ObjectInputStream s)
- throws IOException, ClassNotFoundException {
+ private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
count = 0;
first = null;
@@ -1043,7 +1061,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
// Read in all elements and place in queue
for (;;) {
@SuppressWarnings("unchecked")
- final E item = (E)s.readObject();
+ final E item = (E) s.readObject();
if (item == null) {
break;
}
@@ -1066,6 +1084,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
*
* @return The number of additional elements the queue is able to accept
*/
+ @Override
public int remainingCapacity() {
lock.lock();
try {
@@ -1238,6 +1257,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E take() throws InterruptedException {
return takeFirst();
}
@@ -1249,6 +1269,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E takeFirst() throws InterruptedException {
lock.lock();
try {
@@ -1269,6 +1290,7 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
* @return the unlinked element
* @throws InterruptedException if the current thread is interrupted
*/
+ @Override
public E takeLast() throws InterruptedException {
lock.lock();
try {
@@ -1319,12 +1341,11 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
lock.lock();
try {
if (a.length < count) {
- a = (T[])java.lang.reflect.Array.newInstance
- (a.getClass().getComponentType(), count);
+ a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), count);
}
int k = 0;
for (Node<E> p = first; p != null; p = p.next) {
- a[k++] = (T)p.item;
+ a[k++] = (T) p.item;
}
if (a.length > k) {
a[k] = null;
@@ -1362,9 +1383,8 @@ final class LinkedBlockingDeque<E> extends AbstractQueue<E>
p.next = n;
n.prev = p;
x.item = null;
- // Don't mess with x's links. They may still be in use by
- // an iterator.
- --count;
+ // Don't mess with x's links. They may still be in use by an iterator.
+ --count;
notFull.signal();
}
}
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/NoOpCallStack.java b/java/org/apache/tomcat/dbcp/pool2/impl/NoOpCallStack.java
index 24dcac6ca9..172c3550ab 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/NoOpCallStack.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/NoOpCallStack.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -27,7 +27,7 @@ import java.io.PrintWriter;
public class NoOpCallStack implements CallStack {
/**
- * Singleton instance.
+ * The singleton instance.
*/
public static final CallStack INSTANCE = new NoOpCallStack();
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/PoolImplUtils.java b/java/org/apache/tomcat/dbcp/pool2/impl/PoolImplUtils.java
index f552f38bc9..a36a22c7e1 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/PoolImplUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/PoolImplUtils.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/PooledSoftReference.java b/java/org/apache/tomcat/dbcp/pool2/impl/PooledSoftReference.java
index 68f2fcacca..31282bb193 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/PooledSoftReference.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/PooledSoftReference.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
index c39b105e9b..ebb34b8435 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Optional;
+import java.util.concurrent.BlockingDeque;
import org.apache.tomcat.dbcp.pool2.BaseObjectPool;
import org.apache.tomcat.dbcp.pool2.ObjectPool;
@@ -62,8 +63,7 @@ public class SoftReferenceObjectPool<T> extends BaseObjectPool<T> {
private long createCount; // @GuardedBy("this")
/** Idle references - waiting to be borrowed */
- private final LinkedBlockingDeque<PooledSoftReference<T>> idleReferences =
- new LinkedBlockingDeque<>();
+ private final BlockingDeque<PooledSoftReference<T>> idleReferences = new LinkedBlockingDeque<>();
/** All references - checked out or waiting to be borrowed. */
private final ArrayList<PooledSoftReference<T>> allReferences =
@@ -262,7 +262,7 @@ public class SoftReferenceObjectPool<T> extends BaseObjectPool<T> {
}
/**
- * Destroys a {@code PooledSoftReference} and removes it from the idle and all
+ * Destroys a {@link PooledSoftReference} and removes it from the idle and all
* references pools.
*
* @param toDestroy PooledSoftReference to destroy
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java b/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java
index 18592b2050..616a035360 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -42,7 +42,7 @@ public class ThrowableCallStack implements CallStack {
/**
* Constructs a new instance with its message set to the now instant.
*/
- Snapshot() {
+ private Snapshot() {
this(Instant.now());
}
diff --git a/res/checkstyle/header-al2.txt b/res/checkstyle/header-al2.txt
index 723479356f..0619032075 100644
--- a/res/checkstyle/header-al2.txt
+++ b/res/checkstyle/header-al2.txt
@@ -9,7 +9,7 @@
^(rem)?\W*\(the "License"\); you may not use this file except in compliance with$
^(rem)?\W*the License\. You may obtain a copy of the License at$
^(rem)?\W*$
-^(rem)?\W*http://www.apache.org/licenses/LICENSE-2\.0$
+^(rem)?\W*http(s)?://www.apache.org/licenses/LICENSE-2\.0$
^(rem)?\W*$
^(rem)?\W*Unless required by applicable law or agreed to in writing, software$
^(rem)?\W*distributed under the License is distributed on an "AS IS" BASIS,$
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 8555c7939d..037475dd0a 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -112,6 +112,9 @@
during test execution. Useful for cleaner console output when running
tests with multiple threads. (csutherl)
</add>
+ <update>
+ Update the internal fork of Commons Pool to 2.13.0. (markt)
+ </update>
</changelog>
</subsection>
</section>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org