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 2017/12/04 13:56:02 UTC

svn commit: r1817092 - /tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/

Author: markt
Date: Mon Dec  4 13:56:01 2017
New Revision: 1817092

URL: http://svn.apache.org/viewvc?rev=1817092&view=rev
Log:
Align packaged renamed Pool2 with original.
Useless (in the context of DBCP) SecurityManager based CallStack implementation excluded.
This updates Pool2 to the point where development switched to git. Another commit will follow shortly with the git updates.

Added:
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java   (with props)
Modified:
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
    tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseGenericObjectPool.java Mon Dec  4 13:56:01 2017
@@ -25,6 +25,7 @@ import java.util.Arrays;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 
 import javax.management.InstanceAlreadyExistsException;
@@ -85,6 +86,8 @@ public abstract class BaseGenericObjectP
     private volatile long softMinEvictableIdleTimeMillis =
             BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
     private volatile EvictionPolicy<T> evictionPolicy;
+    private volatile long evictorShutdownTimeoutMillis =
+            BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
 
 
     // Internal (primarily state) attributes
@@ -611,6 +614,9 @@ public abstract class BaseGenericObjectP
                 final
                 EvictionPolicy<T> evicPolicy = (EvictionPolicy<T>) policy;
                 this.evictionPolicy = evicPolicy;
+            } else {
+                throw new IllegalArgumentException("[" + evictionPolicyClassName +
+                        "] does not implement EvictionPolicy");
             }
         } catch (final ClassNotFoundException e) {
             throw new IllegalArgumentException(
@@ -623,6 +629,31 @@ public abstract class BaseGenericObjectP
         }
     }
 
+    /**
+     * Gets the timeout that will be used when waiting for the Evictor to
+     * shutdown if this pool is closed and it is the only pool still using the
+     * the value for the Evictor.
+     *
+     * @return  The timeout in milliseconds that will be used while waiting for
+     *          the Evictor to shut down.
+     */
+    public final long getEvictorShutdownTimeoutMillis() {
+        return evictorShutdownTimeoutMillis;
+    }
+
+    /**
+     * Sets the timeout that will be used when waiting for the Evictor to
+     * shutdown if this pool is closed and it is the only pool still using the
+     * the value for the Evictor.
+     *
+     * @param evictorShutdownTimeoutMillis  the timeout in milliseconds that
+     *                                      will be used while waiting for the
+     *                                      Evictor to shut down.
+     */
+    public final void setEvictorShutdownTimeoutMillis(
+            final long evictorShutdownTimeoutMillis) {
+        this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
+    }
 
     /**
      * Closes the pool, destroys the remaining idle objects and, if registered
@@ -683,7 +714,7 @@ public abstract class BaseGenericObjectP
     final void startEvictor(final long delay) {
         synchronized (evictionLock) {
             if (null != evictor) {
-                EvictionTimer.cancel(evictor);
+                EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
                 evictor = null;
                 evictionIterator = null;
             }

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/BaseObjectPoolConfig.java Mon Dec  4 13:56:01 2017
@@ -68,6 +68,15 @@ public abstract class BaseObjectPoolConf
     public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
 
     /**
+     * The default value for {@code evictorShutdownTimeoutMillis} configuration
+     * attribute.
+     * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
+     * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+     */
+    public static final long DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS =
+            10L * 1000L;
+
+    /**
      * The default value for the {@code numTestsPerEvictionRun} configuration
      * attribute.
      * @see GenericObjectPool#getNumTestsPerEvictionRun()
@@ -163,8 +172,11 @@ public abstract class BaseObjectPoolConf
     private long minEvictableIdleTimeMillis =
         DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
 
+    private long evictorShutdownTimeoutMillis =
+            DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
+
     private long softMinEvictableIdleTimeMillis =
-            DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+            DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
 
     private int numTestsPerEvictionRun =
         DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
@@ -365,6 +377,36 @@ public abstract class BaseObjectPoolConf
     }
 
     /**
+     * Get the value for the {@code evictorShutdownTimeoutMillis} configuration
+     * attribute for pools created with this configuration instance.
+     *
+     * @return  The current setting of {@code evictorShutdownTimeoutMillis} for
+     *          this configuration instance
+     *
+     * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
+     * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+     */
+    public long getEvictorShutdownTimeoutMillis() {
+        return evictorShutdownTimeoutMillis;
+    }
+
+    /**
+     * Set the value for the {@code evictorShutdownTimeoutMillis} configuration
+     * attribute for pools created with this configuration instance.
+     *
+     * @param evictorShutdownTimeoutMillis The new setting of
+     *        {@code evictorShutdownTimeoutMillis} for this configuration
+     *        instance
+     *
+     * @see GenericObjectPool#getEvictorShutdownTimeoutMillis()
+     * @see GenericKeyedObjectPool#getEvictorShutdownTimeoutMillis()
+     */
+    public void setEvictorShutdownTimeoutMillis(
+            final long evictorShutdownTimeoutMillis) {
+        this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
+    }
+
+    /**
      * Get the value for the {@code testOnCreate} configuration attribute for
      * pools created with this configuration instance.
      *

Added: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java?rev=1817092&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java Mon Dec  4 13:56:01 2017
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.dbcp.pool2.impl;
+
+import java.io.PrintWriter;
+
+/**
+ * Strategy for obtaining and printing the current call stack. This is primarily useful for
+ * {@linkplain UsageTracking usage tracking} so that different JVMs and configurations can use more efficient strategies
+ * for obtaining the current call stack.
+ *
+ * @see CallStackUtils
+ * @since 2.4.3
+ */
+public interface CallStack {
+
+    /**
+     * Prints the current stack trace if available to a PrintWriter. The format is undefined and is primarily useful
+     * for debugging issues with {@link PooledObject} usage in user code.
+     *
+     * @param writer a PrintWriter to write the curren stack trace to if available
+     * @return true if a stack trace was available to print or false if nothing was printed
+     */
+    boolean printStackTrace(final PrintWriter writer);
+
+    /**
+     * Takes a snapshot of the current call stack. Subsequent calls to {@link #printStackTrace(PrintWriter)} will print
+     * out that stack trace until it is {@linkplain #clear() cleared}.
+     */
+    void fillInStackTrace();
+
+    /**
+     * Clears the current stack trace snapshot. Subsequent calls to {@link #printStackTrace(PrintWriter)} will be
+     * no-ops until another call to {@link #fillInStackTrace()}.
+     */
+    void clear();
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/CallStack.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/DefaultPooledObject.java Mon Dec  4 13:56:01 2017
@@ -17,8 +17,6 @@
 package org.apache.tomcat.dbcp.pool2.impl;
 
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.Deque;
 
 import org.apache.tomcat.dbcp.pool2.PooledObject;
@@ -44,8 +42,10 @@ public class DefaultPooledObject<T> impl
     private volatile long lastUseTime = createTime;
     private volatile long lastReturnTime = createTime;
     private volatile boolean logAbandoned = false;
-    private volatile Exception borrowedBy = null;
-    private volatile Exception usedBy = null;
+    private final CallStack borrowedBy = new ThrowableCallStack("'Pooled object created' " +
+        "yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'", true);
+    private final CallStack usedBy = new ThrowableCallStack("The last code to use this object was:",
+        false);
     private volatile long borrowedCount = 0;
 
     /**
@@ -191,7 +191,7 @@ public class DefaultPooledObject<T> impl
             lastUseTime = lastBorrowTime;
             borrowedCount++;
             if (logAbandoned) {
-                borrowedBy = new AbandonedObjectCreatedException();
+                borrowedBy.fillInStackTrace();
             }
             return true;
         } else if (state == PooledObjectState.EVICTION) {
@@ -216,7 +216,7 @@ public class DefaultPooledObject<T> impl
                 state == PooledObjectState.RETURNING) {
             state = PooledObjectState.IDLE;
             lastReturnTime = System.currentTimeMillis();
-            borrowedBy = null;
+            borrowedBy.clear();
             return true;
         }
 
@@ -234,22 +234,13 @@ public class DefaultPooledObject<T> impl
     @Override
     public void use() {
         lastUseTime = System.currentTimeMillis();
-        usedBy = new Exception("The last code to use this object was:");
+        usedBy.fillInStackTrace();
     }
 
     @Override
     public void printStackTrace(final PrintWriter writer) {
-        boolean written = false;
-        final Exception borrowedByCopy = this.borrowedBy;
-        if (borrowedByCopy != null) {
-            borrowedByCopy.printStackTrace(writer);
-            written = true;
-        }
-        final Exception usedByCopy = this.usedBy;
-        if (usedByCopy != null) {
-            usedByCopy.printStackTrace(writer);
-            written = true;
-        }
+        boolean written = borrowedBy.printStackTrace(writer);
+        written |= usedBy.printStackTrace(writer);
         if (written) {
             writer.flush();
         }
@@ -285,42 +276,4 @@ public class DefaultPooledObject<T> impl
         this.logAbandoned = logAbandoned;
     }
 
-    /**
-     * Used to track how an object was obtained from the pool (the stack trace
-     * of the exception will show which code borrowed the object) and when the
-     * object was borrowed.
-     */
-    static class AbandonedObjectCreatedException extends Exception {
-
-        private static final long serialVersionUID = 7398692158058772916L;
-
-        /** Date format */
-        //@GuardedBy("format")
-        private static final SimpleDateFormat format = new SimpleDateFormat
-            ("'Pooled object created' yyyy-MM-dd HH:mm:ss Z " +
-             "'by the following code has not been returned to the pool:'");
-
-        private final long _createdTime;
-
-        /**
-         * Create a new instance.
-         * <p>
-         * @see Exception#Exception()
-         */
-        public AbandonedObjectCreatedException() {
-            super();
-            _createdTime = System.currentTimeMillis();
         }
-
-        // Override getMessage to avoid creating objects and formatting
-        // dates unless the log message will actually be used.
-        @Override
-        public String getMessage() {
-            String msg;
-            synchronized(format) {
-                msg = format.format(new Date(_createdTime));
-            }
-            return msg;
-        }
-    }
-}

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java Mon Dec  4 13:56:01 2017
@@ -18,16 +18,19 @@ package org.apache.tomcat.dbcp.pool2.imp
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Timer;
 import java.util.TimerTask;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 
 /**
- * Provides a shared idle object eviction timer for all pools. This class wraps
- * the standard {@link Timer} and keeps track of how many pools are using it.
- * If no pools are using the timer, it is canceled. This prevents a thread
- * being left running which, in application server environments, can lead to
- * memory leads and/or prevent applications from shutting down or reloading
- * cleanly.
+ * Provides a shared idle object eviction timer for all pools. This class is
+ * currently implemented using {@link ScheduledThreadPoolExecutor}. This
+ * implementation may change in any future release. This class keeps track of
+ * how many pools are using it. If no pools are using the timer, it is canceled.
+ * This prevents a thread being left running which, in application server
+ * environments, can lead to memory leads and/or prevent applications from
+ * shutting down or reloading cleanly.
  * <p>
  * This class has package scope to prevent its inclusion in the pool public API.
  * The class declaration below should *not* be changed to public.
@@ -38,17 +41,29 @@ import java.util.TimerTask;
  */
 class EvictionTimer {
 
-    /** Timer instance */
-    private static Timer _timer; //@GuardedBy("EvictionTimer.class")
+    /** Executor instance */
+    private static ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class")
 
     /** Static usage count tracker */
-    private static int _usageCount; //@GuardedBy("EvictionTimer.class")
+    private static int usageCount; //@GuardedBy("EvictionTimer.class")
 
     /** Prevent instantiation */
     private EvictionTimer() {
         // Hide the default constructor
     }
 
+
+    /**
+     * @since 2.4.3
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("EvictionTimer []");
+        return builder.toString();
+    }
+
+
     /**
      * Add the specified eviction task to the timer. Tasks that are added with a
      * call to this method *must* call {@link #cancel(TimerTask)} to cancel the
@@ -58,112 +73,54 @@ class EvictionTimer {
      * @param delay     Delay in milliseconds before task is executed
      * @param period    Time in milliseconds between executions
      */
-    static synchronized void schedule(final TimerTask task, final long delay, final long period) {
-        if (null == _timer) {
-            // Force the new Timer thread to be created with a context class
-            // loader set to the class loader that loaded this library
-            final ClassLoader ccl = AccessController.doPrivileged(
-                    new PrivilegedGetTccl());
-            try {
-                AccessController.doPrivileged(new PrivilegedSetTccl(
-                        EvictionTimer.class.getClassLoader()));
-                _timer = AccessController.doPrivileged(new PrivilegedNewEvictionTimer());
-            } finally {
-                AccessController.doPrivileged(new PrivilegedSetTccl(ccl));
+    static synchronized void schedule(final Runnable task, final long delay, final long period) {
+        if (null == executor) {
+            executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
             }
+        usageCount++;
+        executor.scheduleWithFixedDelay(task, delay, period, TimeUnit.MILLISECONDS);
         }
-        _usageCount++;
-        _timer.schedule(task, delay, period);
-    }
 
     /**
      * Remove the specified eviction task from the timer.
-     * @param task      Task to be scheduled
+     *
+     * @param task      Task to be cancelled
+     * @param timeout   If the associated executor is no longer required, how
+     *                  long should this thread wait for the executor to
+     *                  terminate?
+     * @param unit      The units for the specified timeout
      */
-    static synchronized void cancel(final TimerTask task) {
+    static synchronized void cancel(final TimerTask task, long timeout, TimeUnit unit) {
         task.cancel();
-        _usageCount--;
-        if (_usageCount == 0) {
-            _timer.cancel();
-            _timer = null;
+        usageCount--;
+        if (usageCount == 0) {
+            executor.shutdown();
+            try {
+                executor.awaitTermination(timeout, unit);
+            } catch (InterruptedException e) {
+                // Swallow
+                // Significant API changes would be required to propagate this
         }
+            executor.setCorePoolSize(0);
+            executor = null;
     }
-
-    /**
-     * {@link PrivilegedAction} used to get the ContextClassLoader
-     */
-    private static class PrivilegedGetTccl implements PrivilegedAction<ClassLoader> {
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public ClassLoader run() {
-            return Thread.currentThread().getContextClassLoader();
-        }
     }
 
-    /**
-     * {@link PrivilegedAction} used to set the ContextClassLoader
-     */
-    private static class PrivilegedSetTccl implements PrivilegedAction<Void> {
-
-        /** ClassLoader */
-        private final ClassLoader classLoader;
+    private static class EvictorThreadFactory implements ThreadFactory {
 
-        /**
-         * Create a new PrivilegedSetTccl using the given classloader
-         * @param classLoader ClassLoader to use
-         */
-        PrivilegedSetTccl(final ClassLoader cl) {
-            this.classLoader = cl;
-        }
+        @Override
+        public Thread newThread(final Runnable r) {
+            final Thread t = new Thread(null, r, "commons-pool-evictor-thread");
 
-        /**
-         * {@inheritDoc}
-         */
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
         @Override
         public Void run() {
-            Thread.currentThread().setContextClassLoader(classLoader);
+                    t.setContextClassLoader(EvictorThreadFactory.class.getClassLoader());
             return null;
         }
+            });
 
-        @Override
-        public String toString() {
-            final StringBuilder builder = new StringBuilder();
-            builder.append("PrivilegedSetTccl [classLoader=");
-            builder.append(classLoader);
-            builder.append("]");
-            return builder.toString();
+            return t;
         }
     }
-
-    /**
-     * {@link PrivilegedAction} used to create a new Timer. Creating the timer
-     * with a privileged action means the associated Thread does not inherit the
-     * current access control context. In a container environment, inheriting
-     * the current access control context is likely to result in retaining a
-     * reference to the thread context class loader which would be a memory
-     * leak.
-     */
-    private static class PrivilegedNewEvictionTimer implements PrivilegedAction<Timer> {
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Timer run() {
-            return new Timer("commons-pool-EvictionTimer", true);
         }
-    }
-
-    /**
-     * @since 2.4.3
-     */
-    @Override
-    public String toString() {
-        final StringBuilder builder = new StringBuilder();
-        builder.append("EvictionTimer []");
-        return builder.toString();
-    }
-}

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java Mon Dec  4 13:56:01 2017
@@ -252,6 +252,7 @@ public class GenericKeyedObjectPool<K,T>
         setTimeBetweenEvictionRunsMillis(
                 conf.getTimeBetweenEvictionRunsMillis());
         setEvictionPolicyClassName(conf.getEvictionPolicyClassName());
+        setEvictorShutdownTimeoutMillis(conf.getEvictorShutdownTimeoutMillis());
     }
 
     /**
@@ -1205,7 +1206,7 @@ public class GenericKeyedObjectPool<K,T>
      */
     private void ensureMinIdle(final K key) throws Exception {
         // Calculate current pool objects
-        final ObjectDeque<T> objectDeque = poolMap.get(key);
+        ObjectDeque<T> objectDeque = poolMap.get(key);
 
         // objectDeque == null is OK here. It is handled correctly by both
         // methods called below.
@@ -1219,8 +1220,14 @@ public class GenericKeyedObjectPool<K,T>
 
         for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) {
             addObject(key);
+            // If objectDeque was null, it won't be any more. Obtain a reference
+            // to it so the deficit can be correctly calculated. It needs to
+            // take account of objects created in other threads.
+            if (objectDeque == null) {
+                objectDeque = poolMap.get(key);
         }
     }
+    }
 
     /**
      * Create an object using the {@link KeyedPooledObjectFactory#makeObject

Modified: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java?rev=1817092&r1=1817091&r2=1817092&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java Mon Dec  4 13:56:01 2017
@@ -315,6 +315,7 @@ public class GenericObjectPool<T> extend
         setSoftMinEvictableIdleTimeMillis(
                 conf.getSoftMinEvictableIdleTimeMillis());
         setEvictionPolicyClassName(conf.getEvictionPolicyClassName());
+        setEvictorShutdownTimeoutMillis(conf.getEvictorShutdownTimeoutMillis());
     }
 
     /**

Added: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java?rev=1817092&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java Mon Dec  4 13:56:01 2017
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.dbcp.pool2.impl;
+
+import java.io.PrintWriter;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
+/**
+ * CallStack strategy that uses the stack trace from a {@link Throwable}.
+ *
+ * @see Throwable#fillInStackTrace()
+ * @since 2.4.3
+ */
+public class ThrowableCallStack implements CallStack {
+
+    private final String messageFormat;
+    //@GuardedBy("dateFormat")
+    private final DateFormat dateFormat;
+
+    private volatile Snapshot snapshot;
+
+    public ThrowableCallStack(final String messageFormat, final boolean useTimestamp) {
+        this.messageFormat = messageFormat;
+        this.dateFormat = useTimestamp ? new SimpleDateFormat(messageFormat) : null;
+    }
+
+    @Override
+    public synchronized boolean printStackTrace(PrintWriter writer) {
+        Snapshot snapshot = this.snapshot;
+        if (snapshot == null) {
+            return false;
+        }
+        final String message;
+        if (dateFormat == null) {
+            message = messageFormat;
+        } else {
+            synchronized (dateFormat) {
+                message = dateFormat.format(Long.valueOf(snapshot.timestamp));
+            }
+        }
+        writer.println(message);
+        snapshot.printStackTrace(writer);
+        return true;
+    }
+
+    @Override
+    public void fillInStackTrace() {
+        snapshot = new Snapshot();
+    }
+
+    @Override
+    public void clear() {
+        snapshot = null;
+    }
+
+    private static class Snapshot extends Throwable {
+        private static final long serialVersionUID = -7871548158947014789L;
+        private final long timestamp = System.currentTimeMillis();
+    }
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/dbcp/pool2/impl/ThrowableCallStack.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org