View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.pool2.impl;
18  
19  import java.time.Duration;
20  import java.util.ArrayList;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.Map;
24  import java.util.NoSuchElementException;
25  import java.util.Set;
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.atomic.AtomicLong;
28  
29  import org.apache.commons.pool2.DestroyMode;
30  import org.apache.commons.pool2.ObjectPool;
31  import org.apache.commons.pool2.PoolUtils;
32  import org.apache.commons.pool2.PooledObject;
33  import org.apache.commons.pool2.PooledObjectFactory;
34  import org.apache.commons.pool2.PooledObjectState;
35  import org.apache.commons.pool2.SwallowedExceptionListener;
36  import org.apache.commons.pool2.TrackedUse;
37  import org.apache.commons.pool2.UsageTracking;
38  
39  /**
40   * A configurable {@link ObjectPool} implementation.
41   * <p>
42   * When coupled with the appropriate {@link PooledObjectFactory},
43   * {@code GenericObjectPool} provides robust pooling functionality for
44   * arbitrary objects.
45   * </p>
46   * <p>
47   * Optionally, one may configure the pool to examine and possibly evict objects
48   * as they sit idle in the pool and to ensure that a minimum number of idle
49   * objects are available. This is performed by an "idle object eviction" thread,
50   * which runs asynchronously. Caution should be used when configuring this
51   * optional feature. Eviction runs contend with client threads for access to
52   * objects in the pool, so if they run too frequently performance issues may
53   * result.
54   * </p>
55   * <p>
56   * The pool can also be configured to detect and remove "abandoned" objects,
57   * i.e. objects that have been checked out of the pool but neither used nor
58   * returned before the configured
59   * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}.
60   * Abandoned object removal can be configured to happen when
61   * {@code borrowObject} is invoked and the pool is close to starvation, or
62   * it can be executed by the idle object evictor, or both. If pooled objects
63   * implement the {@link TrackedUse} interface, their last use will be queried
64   * using the {@code getLastUsed} method on that interface; otherwise
65   * abandonment is determined by how long an object has been checked out from
66   * the pool.
67   * </p>
68   * <p>
69   * Implementation note: To prevent possible deadlocks, care has been taken to
70   * ensure that no call to a factory method will occur within a synchronization
71   * block. See POOL-125 and DBCP-44 for more information.
72   * </p>
73   * <p>
74   * This class is intended to be thread-safe.
75   * </p>
76   *
77   * @see GenericKeyedObjectPool
78   *
79   * @param <T> Type of element pooled in this pool.
80   *
81   * @since 2.0
82   */
83  public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
84          implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
85  
86      private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(Integer.MAX_VALUE);
87  
88      // JMX specific attributes
89      private static final String ONAME_BASE =
90          "org.apache.commons.pool2:type=GenericObjectPool,name=";
91  
92      private volatile String factoryType = null;
93  
94      private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
95  
96      private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
97  
98      private final PooledObjectFactory<T> factory;
99  
100     /*
101      * All of the objects currently associated with this pool in any state. It
102      * excludes objects that have been destroyed. The size of
103      * {@link #allObjects} will always be less than or equal to {@link
104      * #_maxActive}. Map keys are pooled objects, values are the PooledObject
105      * wrappers used internally by the pool.
106      */
107     private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
108         new ConcurrentHashMap<>();
109 
110     /*
111      * The combined count of the currently created objects and those in the
112      * process of being created. Under load, it may exceed {@link #_maxActive}
113      * if multiple threads try and create a new object at the same time but
114      * {@link #create()} will ensure that there are never more than
115      * {@link #_maxActive} objects created at any one time.
116      */
117     private final AtomicLong createCount = new AtomicLong(0);
118 
119     private long makeObjectCount;
120 
121     private final Object makeObjectCountLock = new Object();
122 
123     private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
124 
125     // Additional configuration properties for abandoned object tracking
126     private volatile AbandonedConfig abandonedConfig;
127 
128     /**
129      * Creates a new {@code GenericObjectPool} using defaults from
130      * {@link GenericObjectPoolConfig}.
131      *
132      * @param factory The object factory to be used to create object instances
133      *                used by this pool
134      */
135     public GenericObjectPool(final PooledObjectFactory<T> factory) {
136         this(factory, new GenericObjectPoolConfig<>());
137     }
138 
139     /**
140      * Creates a new {@code GenericObjectPool} using a specific
141      * configuration.
142      *
143      * @param factory   The object factory to be used to create object instances
144      *                  used by this pool
145      * @param config    The configuration to use for this pool instance. The
146      *                  configuration is used by value. Subsequent changes to
147      *                  the configuration object will not be reflected in the
148      *                  pool.
149      */
150     public GenericObjectPool(final PooledObjectFactory<T> factory,
151             final GenericObjectPoolConfig<T> config) {
152 
153         super(config, ONAME_BASE, config.getJmxNamePrefix());
154 
155         if (factory == null) {
156             jmxUnregister(); // tidy up
157             throw new IllegalArgumentException("factory may not be null");
158         }
159         this.factory = factory;
160 
161         idleObjects = new LinkedBlockingDeque<>(config.getFairness());
162 
163         setConfig(config);
164     }
165 
166     /**
167      * Creates a new {@code GenericObjectPool} that tracks and destroys
168      * objects that are checked out, but never returned to the pool.
169      *
170      * @param factory   The object factory to be used to create object instances
171      *                  used by this pool
172      * @param config    The base pool configuration to use for this pool instance.
173      *                  The configuration is used by value. Subsequent changes to
174      *                  the configuration object will not be reflected in the
175      *                  pool.
176      * @param abandonedConfig  Configuration for abandoned object identification
177      *                         and removal.  The configuration is used by value.
178      */
179     public GenericObjectPool(final PooledObjectFactory<T> factory,
180             final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
181         this(factory, config);
182         setAbandonedConfig(abandonedConfig);
183     }
184 
185     /**
186      * Adds the provided wrapped pooled object to the set of idle objects for
187      * this pool. The object must already be part of the pool.  If {@code p}
188      * is null, this is a no-op (no exception, but no impact on the pool).
189      *
190      * @param p The object to make idle
191      *
192      * @throws Exception If the factory fails to passivate the object
193      */
194     private void addIdleObject(final PooledObject<T> p) throws Exception {
195         if (p != null) {
196             factory.passivateObject(p);
197             if (getLifo()) {
198                 idleObjects.addFirst(p);
199             } else {
200                 idleObjects.addLast(p);
201             }
202         }
203     }
204 
205     /**
206      * Creates an object, and place it into the pool. addObject() is useful for
207      * "pre-loading" a pool with idle objects.
208      * <p>
209      * If there is no capacity available to add to the pool, this is a no-op
210      * (no exception, no impact to the pool). </p>
211      */
212     @Override
213     public void addObject() throws Exception {
214         assertOpen();
215         if (factory == null) {
216             throw new IllegalStateException(
217                     "Cannot add objects without a factory.");
218         }
219         final PooledObject<T> p = create();
220         addIdleObject(p);
221     }
222 
223     /**
224      * Equivalent to <code>{@link #borrowObject(long)
225      * borrowObject}({@link #getMaxWaitMillis()})</code>.
226      * <p>
227      * {@inheritDoc}
228      * </p>
229      */
230     @Override
231     public T borrowObject() throws Exception {
232         return borrowObject(getMaxWaitMillis());
233     }
234 
235     /**
236      * Borrows an object from the pool using the specific waiting time which only
237      * applies if {@link #getBlockWhenExhausted()} is true.
238      * <p>
239      * If there is one or more idle instance available in the pool, then an
240      * idle instance will be selected based on the value of {@link #getLifo()},
241      * activated and returned. If activation fails, or {@link #getTestOnBorrow()
242      * testOnBorrow} is set to {@code true} and validation fails, the
243      * instance is destroyed and the next available instance is examined. This
244      * continues until either a valid instance is returned or there are no more
245      * idle instances available.
246      * </p>
247      * <p>
248      * If there are no idle instances available in the pool, behavior depends on
249      * the {@link #getMaxTotal() maxTotal}, (if applicable)
250      * {@link #getBlockWhenExhausted()} and the value passed in to the
251      * {@code borrowMaxWaitMillis} parameter. If the number of instances
252      * checked out from the pool is less than {@code maxTotal,} a new
253      * instance is created, activated and (if applicable) validated and returned
254      * to the caller. If validation fails, a {@code NoSuchElementException}
255      * is thrown.
256      * </p>
257      * <p>
258      * If the pool is exhausted (no available idle instances and no capacity to
259      * create new ones), this method will either block (if
260      * {@link #getBlockWhenExhausted()} is true) or throw a
261      * {@code NoSuchElementException} (if
262      * {@link #getBlockWhenExhausted()} is false). The length of time that this
263      * method will block when {@link #getBlockWhenExhausted()} is true is
264      * determined by the value passed in to the {@code borrowMaxWaitMillis}
265      * parameter.
266      * </p>
267      * <p>
268      * When the pool is exhausted, multiple calling threads may be
269      * simultaneously blocked waiting for instances to become available. A
270      * "fairness" algorithm has been implemented to ensure that threads receive
271      * available instances in request arrival order.
272      * </p>
273      *
274      * @param borrowMaxWait The time to wait for an object
275      *                            to become available
276      *
277      * @return object instance from the pool
278      *
279      * @throws NoSuchElementException if an instance cannot be returned
280      *
281      * @throws Exception if an object instance cannot be returned due to an
282      *                   error
283      * @since 2.10.0
284      */
285     public T borrowObject(final Duration borrowMaxWait) throws Exception {
286         assertOpen();
287 
288         final AbandonedConfig ac = this.abandonedConfig;
289         if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) &&
290                 (getNumActive() > getMaxTotal() - 3)) {
291             removeAbandoned(ac);
292         }
293 
294         PooledObject<T> p = null;
295 
296         // Get local copy of current config so it is consistent for entire
297         // method execution
298         final boolean blockWhenExhausted = getBlockWhenExhausted();
299 
300         boolean create;
301         final long waitTimeMillis = System.currentTimeMillis();
302 
303         while (p == null) {
304             create = false;
305             p = idleObjects.pollFirst();
306             if (p == null) {
307                 p = create();
308                 if (p != null) {
309                     create = true;
310                 }
311             }
312             if (blockWhenExhausted) {
313                 if (p == null) {
314                     if (borrowMaxWait.isNegative()) {
315                         p = idleObjects.takeFirst();
316                     } else {
317                         p = idleObjects.pollFirst(borrowMaxWait);
318                     }
319                 }
320                 if (p == null) {
321                     throw new NoSuchElementException("Timeout waiting for idle object");
322                 }
323             } else if (p == null) {
324                 throw new NoSuchElementException("Pool exhausted");
325             }
326             if (!p.allocate()) {
327                 p = null;
328             }
329 
330             if (p != null) {
331                 try {
332                     factory.activateObject(p);
333                 } catch (final Exception e) {
334                     try {
335                         destroy(p, DestroyMode.NORMAL);
336                     } catch (final Exception e1) {
337                         // Ignore - activation failure is more important
338                     }
339                     p = null;
340                     if (create) {
341                         final NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");
342                         nsee.initCause(e);
343                         throw nsee;
344                     }
345                 }
346                 if (p != null && getTestOnBorrow()) {
347                     boolean validate = false;
348                     Throwable validationThrowable = null;
349                     try {
350                         validate = factory.validateObject(p);
351                     } catch (final Throwable t) {
352                         PoolUtils.checkRethrow(t);
353                         validationThrowable = t;
354                     }
355                     if (!validate) {
356                         try {
357                             destroy(p, DestroyMode.NORMAL);
358                             destroyedByBorrowValidationCount.incrementAndGet();
359                         } catch (final Exception e) {
360                             // Ignore - validation failure is more important
361                         }
362                         p = null;
363                         if (create) {
364                             final NoSuchElementException nsee = new NoSuchElementException("Unable to validate object");
365                             nsee.initCause(validationThrowable);
366                             throw nsee;
367                         }
368                     }
369                 }
370             }
371         }
372 
373         updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis));
374 
375         return p.getObject();
376     }
377 
378     /**
379      * Borrows an object from the pool using the specific waiting time which only
380      * applies if {@link #getBlockWhenExhausted()} is true.
381      * <p>
382      * If there is one or more idle instance available in the pool, then an
383      * idle instance will be selected based on the value of {@link #getLifo()},
384      * activated and returned. If activation fails, or {@link #getTestOnBorrow()
385      * testOnBorrow} is set to {@code true} and validation fails, the
386      * instance is destroyed and the next available instance is examined. This
387      * continues until either a valid instance is returned or there are no more
388      * idle instances available.
389      * </p>
390      * <p>
391      * If there are no idle instances available in the pool, behavior depends on
392      * the {@link #getMaxTotal() maxTotal}, (if applicable)
393      * {@link #getBlockWhenExhausted()} and the value passed in to the
394      * {@code borrowMaxWaitMillis} parameter. If the number of instances
395      * checked out from the pool is less than {@code maxTotal,} a new
396      * instance is created, activated and (if applicable) validated and returned
397      * to the caller. If validation fails, a {@code NoSuchElementException}
398      * is thrown.
399      * </p>
400      * <p>
401      * If the pool is exhausted (no available idle instances and no capacity to
402      * create new ones), this method will either block (if
403      * {@link #getBlockWhenExhausted()} is true) or throw a
404      * {@code NoSuchElementException} (if
405      * {@link #getBlockWhenExhausted()} is false). The length of time that this
406      * method will block when {@link #getBlockWhenExhausted()} is true is
407      * determined by the value passed in to the {@code borrowMaxWaitMillis}
408      * parameter.
409      * </p>
410      * <p>
411      * When the pool is exhausted, multiple calling threads may be
412      * simultaneously blocked waiting for instances to become available. A
413      * "fairness" algorithm has been implemented to ensure that threads receive
414      * available instances in request arrival order.
415      * </p>
416      *
417      * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
418      *                            to become available
419      *
420      * @return object instance from the pool
421      *
422      * @throws NoSuchElementException if an instance cannot be returned
423      *
424      * @throws Exception if an object instance cannot be returned due to an
425      *                   error
426      */
427     public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
428         return borrowObject(Duration.ofMillis(borrowMaxWaitMillis));
429     }
430 
431     /**
432      * Clears any objects sitting idle in the pool by removing them from the
433      * idle instance pool and then invoking the configured
434      * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each
435      * idle instance.
436      * <p>
437      * Implementation notes:
438      * </p>
439      * <ul>
440      * <li>This method does not destroy or effect in any way instances that are
441      * checked out of the pool when it is invoked.</li>
442      * <li>Invoking this method does not prevent objects being returned to the
443      * idle instance pool, even during its execution. Additional instances may
444      * be returned while removed items are being destroyed.</li>
445      * <li>Exceptions encountered destroying idle instances are swallowed
446      * but notified via a {@link SwallowedExceptionListener}.</li>
447      * </ul>
448      */
449     @Override
450     public void clear() {
451         PooledObject<T> p = idleObjects.poll();
452 
453         while (p != null) {
454             try {
455                 destroy(p, DestroyMode.NORMAL);
456             } catch (final Exception e) {
457                 swallowException(e);
458             }
459             p = idleObjects.poll();
460         }
461     }
462 
463     /**
464      * Closes the pool. Once the pool is closed, {@link #borrowObject()} will
465      * fail with IllegalStateException, but {@link #returnObject(Object)} and
466      * {@link #invalidateObject(Object)} will continue to work, with returned
467      * objects destroyed on return.
468      * <p>
469      * Destroys idle instances in the pool by invoking {@link #clear()}.
470      * </p>
471      */
472     @Override
473     public void close() {
474         if (isClosed()) {
475             return;
476         }
477 
478         synchronized (closeLock) {
479             if (isClosed()) {
480                 return;
481             }
482 
483             // Stop the evictor before the pool is closed since evict() calls
484             // assertOpen()
485             stopEvictor();
486 
487             closed = true;
488             // This clear removes any idle objects
489             clear();
490 
491             jmxUnregister();
492 
493             // Release any threads that were waiting for an object
494             idleObjects.interuptTakeWaiters();
495         }
496     }
497 
498     /**
499      * Attempts to create a new wrapped pooled object.
500      * <p>
501      * If there are {@link #getMaxTotal()} objects already in circulation
502      * or in process of being created, this method returns null.
503      * </p>
504      *
505      * @return The new wrapped pooled object
506      *
507      * @throws Exception if the object factory's {@code makeObject} fails
508      */
509     private PooledObject<T> create() throws Exception {
510         int localMaxTotal = getMaxTotal();
511         // This simplifies the code later in this method
512         if (localMaxTotal < 0) {
513             localMaxTotal = Integer.MAX_VALUE;
514         }
515 
516         final long localStartTimeMillis = System.currentTimeMillis();
517         final long localMaxWaitTimeMillis = Math.max(getMaxWaitMillis(), 0);
518 
519         // Flag that indicates if create should:
520         // - TRUE:  call the factory to create an object
521         // - FALSE: return null
522         // - null:  loop and re-test the condition that determines whether to
523         //          call the factory
524         Boolean create = null;
525         while (create == null) {
526             synchronized (makeObjectCountLock) {
527                 final long newCreateCount = createCount.incrementAndGet();
528                 if (newCreateCount > localMaxTotal) {
529                     // The pool is currently at capacity or in the process of
530                     // making enough new objects to take it to capacity.
531                     createCount.decrementAndGet();
532                     if (makeObjectCount == 0) {
533                         // There are no makeObject() calls in progress so the
534                         // pool is at capacity. Do not attempt to create a new
535                         // object. Return and wait for an object to be returned
536                         create = Boolean.FALSE;
537                     } else {
538                         // There are makeObject() calls in progress that might
539                         // bring the pool to capacity. Those calls might also
540                         // fail so wait until they complete and then re-test if
541                         // the pool is at capacity or not.
542                         makeObjectCountLock.wait(localMaxWaitTimeMillis);
543                     }
544                 } else {
545                     // The pool is not at capacity. Create a new object.
546                     makeObjectCount++;
547                     create = Boolean.TRUE;
548                 }
549             }
550 
551             // Do not block more if maxWaitTimeMillis is set.
552             if (create == null &&
553                 (localMaxWaitTimeMillis > 0 &&
554                  System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) {
555                 create = Boolean.FALSE;
556             }
557         }
558 
559         if (!create.booleanValue()) {
560             return null;
561         }
562 
563         final PooledObject<T> p;
564         try {
565             p = factory.makeObject();
566             if (getTestOnCreate() && !factory.validateObject(p)) {
567                 createCount.decrementAndGet();
568                 return null;
569             }
570         } catch (final Throwable e) {
571             createCount.decrementAndGet();
572             throw e;
573         } finally {
574             synchronized (makeObjectCountLock) {
575                 makeObjectCount--;
576                 makeObjectCountLock.notifyAll();
577             }
578         }
579 
580         final AbandonedConfig ac = this.abandonedConfig;
581         if (ac != null && ac.getLogAbandoned()) {
582             p.setLogAbandoned(true);
583             p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
584         }
585 
586         createdCount.incrementAndGet();
587         allObjects.put(new IdentityWrapper<>(p.getObject()), p);
588         return p;
589     }
590 
591     /**
592      * Destroys a wrapped pooled object.
593      *
594      * @param toDestroy The wrapped pooled object to destroy
595      * @param mode DestroyMode context provided to the factory
596      *
597      * @throws Exception If the factory fails to destroy the pooled object
598      *                   cleanly
599      */
600     private void destroy(final PooledObject<T> toDestroy, final DestroyMode mode) throws Exception {
601         toDestroy.invalidate();
602         idleObjects.remove(toDestroy);
603         allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
604         try {
605             factory.destroyObject(toDestroy, mode);
606         } finally {
607             destroyedCount.incrementAndGet();
608             createCount.decrementAndGet();
609         }
610     }
611 
612     /**
613      * Tries to ensure that {@code idleCount} idle instances exist in the pool.
614      * <p>
615      * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount}
616      * or the total number of objects (idle, checked out, or being created) reaches
617      * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless
618      * there are threads waiting to check out instances from the pool.
619      * </p>
620      *
621      * @param idleCount the number of idle instances desired
622      * @param always true means create instances even if the pool has no threads waiting
623      * @throws Exception if the factory's makeObject throws
624      */
625     private void ensureIdle(final int idleCount, final boolean always) throws Exception {
626         if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
627             return;
628         }
629 
630         while (idleObjects.size() < idleCount) {
631             final PooledObject<T> p = create();
632             if (p == null) {
633                 // Can't create objects, no reason to think another call to
634                 // create will work. Give up.
635                 break;
636             }
637             if (getLifo()) {
638                 idleObjects.addFirst(p);
639             } else {
640                 idleObjects.addLast(p);
641             }
642         }
643         if (isClosed()) {
644             // Pool closed while object was being added to idle objects.
645             // Make sure the returned object is destroyed rather than left
646             // in the idle object pool (which would effectively be a leak)
647             clear();
648         }
649     }
650 
651     @Override
652     void ensureMinIdle() throws Exception {
653         ensureIdle(getMinIdle(), true);
654     }
655 
656     /**
657      * {@inheritDoc}
658      * <p>
659      * Successive activations of this method examine objects in sequence,
660      * cycling through objects in oldest-to-youngest order.
661      * </p>
662      */
663     @Override
664     public void evict() throws Exception {
665         assertOpen();
666 
667         if (!idleObjects.isEmpty()) {
668 
669             PooledObject<T> underTest = null;
670             final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
671 
672             synchronized (evictionLock) {
673                 final EvictionConfigfig.html#EvictionConfig">EvictionConfig evictionConfig = new EvictionConfig(
674                         getMinEvictableIdleTime(),
675                         getSoftMinEvictableIdleTime(),
676                         getMinIdle());
677 
678                 final boolean testWhileIdle = getTestWhileIdle();
679 
680                 for (int i = 0, m = getNumTests(); i < m; i++) {
681                     if (evictionIterator == null || !evictionIterator.hasNext()) {
682                         evictionIterator = new EvictionIterator(idleObjects);
683                     }
684                     if (!evictionIterator.hasNext()) {
685                         // Pool exhausted, nothing to do here
686                         return;
687                     }
688 
689                     try {
690                         underTest = evictionIterator.next();
691                     } catch (final NoSuchElementException nsee) {
692                         // Object was borrowed in another thread
693                         // Don't count this as an eviction test so reduce i;
694                         i--;
695                         evictionIterator = null;
696                         continue;
697                     }
698 
699                     if (!underTest.startEvictionTest()) {
700                         // Object was borrowed in another thread
701                         // Don't count this as an eviction test so reduce i;
702                         i--;
703                         continue;
704                     }
705 
706                     // User provided eviction policy could throw all sorts of
707                     // crazy exceptions. Protect against such an exception
708                     // killing the eviction thread.
709                     boolean evict;
710                     try {
711                         evict = evictionPolicy.evict(evictionConfig, underTest,
712                                 idleObjects.size());
713                     } catch (final Throwable t) {
714                         // Slightly convoluted as SwallowedExceptionListener
715                         // uses Exception rather than Throwable
716                         PoolUtils.checkRethrow(t);
717                         swallowException(new Exception(t));
718                         // Don't evict on error conditions
719                         evict = false;
720                     }
721 
722                     if (evict) {
723                         destroy(underTest, DestroyMode.NORMAL);
724                         destroyedByEvictorCount.incrementAndGet();
725                     } else {
726                         if (testWhileIdle) {
727                             boolean active = false;
728                             try {
729                                 factory.activateObject(underTest);
730                                 active = true;
731                             } catch (final Exception e) {
732                                 destroy(underTest, DestroyMode.NORMAL);
733                                 destroyedByEvictorCount.incrementAndGet();
734                             }
735                             if (active) {
736                                 if (!factory.validateObject(underTest)) {
737                                     destroy(underTest, DestroyMode.NORMAL);
738                                     destroyedByEvictorCount.incrementAndGet();
739                                 } else {
740                                     try {
741                                         factory.passivateObject(underTest);
742                                     } catch (final Exception e) {
743                                         destroy(underTest, DestroyMode.NORMAL);
744                                         destroyedByEvictorCount.incrementAndGet();
745                                     }
746                                 }
747                             }
748                         }
749                         if (!underTest.endEvictionTest(idleObjects)) {
750                             // TODO - May need to add code here once additional
751                             // states are used
752                         }
753                     }
754                 }
755             }
756         }
757         final AbandonedConfig ac = this.abandonedConfig;
758         if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
759             removeAbandoned(ac);
760         }
761     }
762 
763     /**
764      * Gets a reference to the factory used to create, destroy and validate
765      * the objects used by this pool.
766      *
767      * @return the factory
768      */
769     public PooledObjectFactory<T> getFactory() {
770         return factory;
771     }
772 
773     /**
774      * Gets the type - including the specific type rather than the generic -
775      * of the factory.
776      *
777      * @return A string representation of the factory type
778      */
779     @Override
780     public String getFactoryType() {
781         // Not thread safe. Accept that there may be multiple evaluations.
782         if (factoryType == null) {
783             final StringBuilder result = new StringBuilder();
784             result.append(factory.getClass().getName());
785             result.append('<');
786             final Class<?> pooledObjectType =
787                     PoolImplUtils.getFactoryType(factory.getClass());
788             result.append(pooledObjectType.getName());
789             result.append('>');
790             factoryType = result.toString();
791         }
792         return factoryType;
793     }
794 
795     /**
796      * Gets whether this pool identifies and logs any abandoned objects.
797      *
798      * @return {@code true} if abandoned object removal is configured for this
799      *         pool and removal events are to be logged otherwise {@code false}
800      *
801      * @see AbandonedConfig#getLogAbandoned()
802      */
803     @Override
804     public boolean getLogAbandoned() {
805         final AbandonedConfig ac = this.abandonedConfig;
806         return ac != null && ac.getLogAbandoned();
807     }
808 
809     /**
810      * Gets the cap on the number of "idle" instances in the pool. If maxIdle
811      * is set too low on heavily loaded systems it is possible you will see
812      * objects being destroyed and almost immediately new objects being created.
813      * This is a result of the active threads momentarily returning objects
814      * faster than they are requesting them, causing the number of idle
815      * objects to rise above maxIdle. The best value for maxIdle for heavily
816      * loaded system will vary but the default is a good starting point.
817      *
818      * @return the maximum number of "idle" instances that can be held in the
819      *         pool or a negative value if there is no limit
820      *
821      * @see #setMaxIdle
822      */
823     @Override
824     public int getMaxIdle() {
825         return maxIdle;
826     }
827 
828     /**
829      * Gets the target for the minimum number of idle objects to maintain in
830      * the pool. This setting only has an effect if it is positive and
831      * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
832      * is the case, an attempt is made to ensure that the pool has the required
833      * minimum number of instances during idle object eviction runs.
834      * <p>
835      * If the configured value of minIdle is greater than the configured value
836      * for maxIdle then the value of maxIdle will be used instead.
837      * </p>
838      *
839      * @return The minimum number of objects.
840      *
841      * @see #setMinIdle(int)
842      * @see #setMaxIdle(int)
843      * @see #setTimeBetweenEvictionRunsMillis(long)
844      */
845     @Override
846     public int getMinIdle() {
847         final int maxIdleSave = getMaxIdle();
848         if (this.minIdle > maxIdleSave) {
849             return maxIdleSave;
850         }
851         return minIdle;
852     }
853 
854     @Override
855     public int getNumActive() {
856         return allObjects.size() - idleObjects.size();
857     }
858 
859     @Override
860     public int getNumIdle() {
861         return idleObjects.size();
862     }
863 
864     /**
865      * Calculates the number of objects to test in a run of the idle object
866      * evictor.
867      *
868      * @return The number of objects to test for validity
869      */
870     private int getNumTests() {
871         final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
872         if (numTestsPerEvictionRun >= 0) {
873             return Math.min(numTestsPerEvictionRun, idleObjects.size());
874         }
875         return (int) (Math.ceil(idleObjects.size() /
876                 Math.abs((double) numTestsPerEvictionRun)));
877     }
878 
879     /**
880      * Gets an estimate of the number of threads currently blocked waiting for
881      * an object from the pool. This is intended for monitoring only, not for
882      * synchronization control.
883      *
884      * @return The estimate of the number of threads currently blocked waiting
885      *         for an object from the pool
886      */
887     @Override
888     public int getNumWaiters() {
889         if (getBlockWhenExhausted()) {
890             return idleObjects.getTakeQueueLength();
891         }
892         return 0;
893     }
894 
895     /**
896      * Gets whether a check is made for abandoned objects when an object is borrowed
897      * from this pool.
898      *
899      * @return {@code true} if abandoned object removal is configured to be
900      *         activated by borrowObject otherwise {@code false}
901      *
902      * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
903      */
904     @Override
905     public boolean getRemoveAbandonedOnBorrow() {
906         final AbandonedConfig ac = this.abandonedConfig;
907         return ac != null && ac.getRemoveAbandonedOnBorrow();
908     }
909 
910 
911     //--- Usage tracking support -----------------------------------------------
912 
913     /**
914      * Gets whether a check is made for abandoned objects when the evictor runs.
915      *
916      * @return {@code true} if abandoned object removal is configured to be
917      *         activated when the evictor runs otherwise {@code false}
918      *
919      * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
920      */
921     @Override
922     public boolean getRemoveAbandonedOnMaintenance() {
923         final AbandonedConfig ac = this.abandonedConfig;
924         return ac != null && ac.getRemoveAbandonedOnMaintenance();
925     }
926 
927 
928     //--- JMX support ----------------------------------------------------------
929 
930     /**
931      * Gets the timeout before which an object will be considered to be
932      * abandoned by this pool.
933      *
934      * @return The abandoned object timeout in seconds if abandoned object
935      *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
936      *
937      * @see AbandonedConfig#getRemoveAbandonedTimeout()
938      * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
939      * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
940      */
941     @Override
942     @Deprecated
943     public int getRemoveAbandonedTimeout() {
944         final AbandonedConfig ac = this.abandonedConfig;
945         return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
946     }
947 
948     /**
949      * Gets the timeout before which an object will be considered to be
950      * abandoned by this pool.
951      *
952      * @return The abandoned object timeout in seconds if abandoned object
953      *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
954      *
955      * @see AbandonedConfig#getRemoveAbandonedTimeout()
956      * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
957      */
958     public Duration getRemoveAbandonedTimeoutDuration() {
959         final AbandonedConfig ac = this.abandonedConfig;
960         return ac != null ? ac.getRemoveAbandonedTimeoutDuration() : DEFAULT_REMOVE_ABANDONED_TIMEOUT;
961     }
962 
963     /**
964      * {@inheritDoc}
965      * <p>
966      * Activation of this method decrements the active count and attempts to
967      * destroy the instance, using the default (NORMAL) {@link DestroyMode}.
968      * </p>
969      *
970      * @throws Exception             if an exception occurs destroying the
971      *                               object
972      * @throws IllegalStateException if obj does not belong to this pool
973      */
974     @Override
975     public void invalidateObject(final T obj) throws Exception {
976         invalidateObject(obj, DestroyMode.NORMAL);
977     }
978 
979     /**
980      * {@inheritDoc}
981      * <p>
982      * Activation of this method decrements the active count and attempts to
983      * destroy the instance, using the provided {@link DestroyMode}.
984      * </p>
985      *
986      * @throws Exception             if an exception occurs destroying the
987      *                               object
988      * @throws IllegalStateException if obj does not belong to this pool
989      * @since 2.9.0
990      */
991     @Override
992     public void invalidateObject(final T obj, final DestroyMode mode) throws Exception {
993         final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
994         if (p == null) {
995             if (isAbandonedConfig()) {
996                 return;
997             }
998             throw new IllegalStateException(
999                     "Invalidated object not currently part of this pool");
1000         }
1001         synchronized (p) {
1002             if (p.getState() != PooledObjectState.INVALID) {
1003                 destroy(p, mode);
1004             }
1005         }
1006         ensureIdle(1, false);
1007     }
1008 
1009     // --- configuration attributes --------------------------------------------
1010 
1011     /**
1012      * Gets whether or not abandoned object removal is configured for this pool.
1013      *
1014      * @return true if this pool is configured to detect and remove
1015      * abandoned objects
1016      */
1017     @Override
1018     public boolean isAbandonedConfig() {
1019         return abandonedConfig != null;
1020     }
1021     /**
1022      * Provides information on all the objects in the pool, both idle (waiting
1023      * to be borrowed) and active (currently borrowed).
1024      * <p>
1025      * Note: This is named listAllObjects so it is presented as an operation via
1026      * JMX. That means it won't be invoked unless the explicitly requested
1027      * whereas all attributes will be automatically requested when viewing the
1028      * attributes for an object in a tool like JConsole.
1029      * </p>
1030      *
1031      * @return Information grouped on all the objects in the pool
1032      */
1033     @Override
1034     public Set<DefaultPooledObjectInfo> listAllObjects() {
1035         final Set<DefaultPooledObjectInfo> result =
1036                 new HashSet<>(allObjects.size());
1037         for (final PooledObject<T> p : allObjects.values()) {
1038             result.add(new DefaultPooledObjectInfo(p));
1039         }
1040         return result;
1041     }
1042     /**
1043      * Tries to ensure that {@link #getMinIdle()} idle instances are available
1044      * in the pool.
1045      *
1046      * @throws Exception If the associated factory throws an exception
1047      * @since 2.4
1048      */
1049     public void preparePool() throws Exception {
1050         if (getMinIdle() < 1) {
1051             return;
1052         }
1053         ensureMinIdle();
1054     }
1055 
1056 
1057     // --- internal attributes -------------------------------------------------
1058 
1059     /**
1060      * Recovers abandoned objects which have been checked out but
1061      * not used since longer than the removeAbandonedTimeout.
1062      *
1063      * @param abandonedConfig The configuration to use to identify abandoned objects
1064      */
1065     @SuppressWarnings("resource") // PrintWriter is managed elsewhere
1066     private void removeAbandoned(final AbandonedConfig abandonedConfig) {
1067         // Generate a list of abandoned objects to remove
1068         final long nowMillis = System.currentTimeMillis();
1069         final long timeoutMillis =
1070                 nowMillis - abandonedConfig.getRemoveAbandonedTimeoutDuration().toMillis();
1071         final ArrayList<PooledObject<T>> remove = new ArrayList<>();
1072         final Iterator<PooledObject<T>> it = allObjects.values().iterator();
1073         while (it.hasNext()) {
1074             final PooledObject<T> pooledObject = it.next();
1075             synchronized (pooledObject) {
1076                 if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
1077                         pooledObject.getLastUsedTime() <= timeoutMillis) {
1078                     pooledObject.markAbandoned();
1079                     remove.add(pooledObject);
1080                 }
1081             }
1082         }
1083 
1084         // Now remove the abandoned objects
1085         final Iterator<PooledObject<T>> itr = remove.iterator();
1086         while (itr.hasNext()) {
1087             final PooledObject<T> pooledObject = itr.next();
1088             if (abandonedConfig.getLogAbandoned()) {
1089                 pooledObject.printStackTrace(abandonedConfig.getLogWriter());
1090             }
1091             try {
1092                 invalidateObject(pooledObject.getObject(), DestroyMode.ABANDONED);
1093             } catch (final Exception e) {
1094                 e.printStackTrace();
1095             }
1096         }
1097     }
1098     /**
1099      * {@inheritDoc}
1100      * <p>
1101      * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
1102      * number of idle instances has reached this value, the returning instance
1103      * is destroyed.
1104      * </p>
1105      * <p>
1106      * If {@link #getTestOnReturn() testOnReturn} == true, the returning
1107      * instance is validated before being returned to the idle instance pool. In
1108      * this case, if validation fails, the instance is destroyed.
1109      * </p>
1110      * <p>
1111      * Exceptions encountered destroying objects for any reason are swallowed
1112      * but notified via a {@link SwallowedExceptionListener}.
1113      * </p>
1114      */
1115     @Override
1116     public void returnObject(final T obj) {
1117         final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
1118 
1119         if (p == null) {
1120             if (!isAbandonedConfig()) {
1121                 throw new IllegalStateException(
1122                         "Returned object not currently part of this pool");
1123             }
1124             return; // Object was abandoned and removed
1125         }
1126 
1127         markReturningState(p);
1128 
1129         final Duration activeTime = p.getActiveTime();
1130 
1131         if (getTestOnReturn() && !factory.validateObject(p)) {
1132             try {
1133                 destroy(p, DestroyMode.NORMAL);
1134             } catch (final Exception e) {
1135                 swallowException(e);
1136             }
1137             try {
1138                 ensureIdle(1, false);
1139             } catch (final Exception e) {
1140                 swallowException(e);
1141             }
1142             updateStatsReturn(activeTime);
1143             return;
1144         }
1145 
1146         try {
1147             factory.passivateObject(p);
1148         } catch (final Exception e1) {
1149             swallowException(e1);
1150             try {
1151                 destroy(p, DestroyMode.NORMAL);
1152             } catch (final Exception e) {
1153                 swallowException(e);
1154             }
1155             try {
1156                 ensureIdle(1, false);
1157             } catch (final Exception e) {
1158                 swallowException(e);
1159             }
1160             updateStatsReturn(activeTime);
1161             return;
1162         }
1163 
1164         if (!p.deallocate()) {
1165             throw new IllegalStateException(
1166                     "Object has already been returned to this pool or is invalid");
1167         }
1168 
1169         final int maxIdleSave = getMaxIdle();
1170         if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
1171             try {
1172                 destroy(p, DestroyMode.NORMAL);
1173             } catch (final Exception e) {
1174                 swallowException(e);
1175             }
1176             try {
1177                 ensureIdle(1, false);
1178             } catch (final Exception e) {
1179                 swallowException(e);
1180             }
1181         } else {
1182             if (getLifo()) {
1183                 idleObjects.addFirst(p);
1184             } else {
1185                 idleObjects.addLast(p);
1186             }
1187             if (isClosed()) {
1188                 // Pool closed while object was being added to idle objects.
1189                 // Make sure the returned object is destroyed rather than left
1190                 // in the idle object pool (which would effectively be a leak)
1191                 clear();
1192             }
1193         }
1194         updateStatsReturn(activeTime);
1195     }
1196     /**
1197      * Sets the abandoned object removal configuration.
1198      *
1199      * @param abandonedConfig the new configuration to use. This is used by value.
1200      *
1201      * @see AbandonedConfig
1202      */
1203     @SuppressWarnings("resource") // PrintWriter is managed elsewhere
1204     public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
1205         if (abandonedConfig == null) {
1206             this.abandonedConfig = null;
1207         } else {
1208             this.abandonedConfig = new AbandonedConfig();
1209             this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
1210             this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
1211             this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
1212             this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
1213             this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeoutDuration());
1214             this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
1215             this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
1216         }
1217     }
1218     /**
1219      * Sets the base pool configuration.
1220      *
1221      * @param conf the new configuration to use. This is used by value.
1222      *
1223      * @see GenericObjectPoolConfig
1224      */
1225     public void setConfig(final GenericObjectPoolConfig<T> conf) {
1226         super.setConfig(conf);
1227         setMaxIdle(conf.getMaxIdle());
1228         setMinIdle(conf.getMinIdle());
1229         setMaxTotal(conf.getMaxTotal());
1230     }
1231     /**
1232      * Sets the cap on the number of "idle" instances in the pool. If maxIdle
1233      * is set too low on heavily loaded systems it is possible you will see
1234      * objects being destroyed and almost immediately new objects being created.
1235      * This is a result of the active threads momentarily returning objects
1236      * faster than they are requesting them, causing the number of idle
1237      * objects to rise above maxIdle. The best value for maxIdle for heavily
1238      * loaded system will vary but the default is a good starting point.
1239      *
1240      * @param maxIdle
1241      *            The cap on the number of "idle" instances in the pool. Use a
1242      *            negative value to indicate an unlimited number of idle
1243      *            instances
1244      *
1245      * @see #getMaxIdle
1246      */
1247     public void setMaxIdle(final int maxIdle) {
1248         this.maxIdle = maxIdle;
1249     }
1250 
1251     /**
1252      * Sets the target for the minimum number of idle objects to maintain in
1253      * the pool. This setting only has an effect if it is positive and
1254      * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
1255      * is the case, an attempt is made to ensure that the pool has the required
1256      * minimum number of instances during idle object eviction runs.
1257      * <p>
1258      * If the configured value of minIdle is greater than the configured value
1259      * for maxIdle then the value of maxIdle will be used instead.
1260      * </p>
1261      *
1262      * @param minIdle
1263      *            The minimum number of objects.
1264      *
1265      * @see #getMinIdle()
1266      * @see #getMaxIdle()
1267      * @see #getTimeBetweenEvictionRunsMillis()
1268      */
1269     public void setMinIdle(final int minIdle) {
1270         this.minIdle = minIdle;
1271     }
1272 
1273     @Override
1274     protected void toStringAppendFields(final StringBuilder builder) {
1275         super.toStringAppendFields(builder);
1276         builder.append(", factoryType=");
1277         builder.append(factoryType);
1278         builder.append(", maxIdle=");
1279         builder.append(maxIdle);
1280         builder.append(", minIdle=");
1281         builder.append(minIdle);
1282         builder.append(", factory=");
1283         builder.append(factory);
1284         builder.append(", allObjects=");
1285         builder.append(allObjects);
1286         builder.append(", createCount=");
1287         builder.append(createCount);
1288         builder.append(", idleObjects=");
1289         builder.append(idleObjects);
1290         builder.append(", abandonedConfig=");
1291         builder.append(abandonedConfig);
1292     }
1293 
1294     @Override
1295     public void use(final T pooledObject) {
1296         final AbandonedConfig abandonedCfg = this.abandonedConfig;
1297         if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) {
1298             final PooledObject<T> wrapper = allObjects.get(new IdentityWrapper<>(pooledObject));
1299             wrapper.use();
1300         }
1301     }
1302 
1303 }