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.Deque;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Map.Entry;
27  import java.util.NoSuchElementException;
28  import java.util.Objects;
29  import java.util.TreeMap;
30  import java.util.concurrent.ConcurrentHashMap;
31  import java.util.concurrent.TimeUnit;
32  import java.util.concurrent.atomic.AtomicInteger;
33  import java.util.concurrent.atomic.AtomicLong;
34  import java.util.concurrent.locks.Lock;
35  import java.util.concurrent.locks.ReadWriteLock;
36  import java.util.concurrent.locks.ReentrantReadWriteLock;
37  
38  import org.apache.commons.pool2.DestroyMode;
39  import org.apache.commons.pool2.KeyedObjectPool;
40  import org.apache.commons.pool2.KeyedPooledObjectFactory;
41  import org.apache.commons.pool2.PoolUtils;
42  import org.apache.commons.pool2.PooledObject;
43  import org.apache.commons.pool2.PooledObjectState;
44  import org.apache.commons.pool2.SwallowedExceptionListener;
45  import org.apache.commons.pool2.UsageTracking;
46  
47  /**
48   * A configurable {@code KeyedObjectPool} implementation.
49   * <p>
50   * When coupled with the appropriate {@link KeyedPooledObjectFactory},
51   * {@code GenericKeyedObjectPool} provides robust pooling functionality for
52   * keyed objects. A {@code GenericKeyedObjectPool} can be viewed as a map
53   * of sub-pools, keyed on the (unique) key values provided to the
54   * {@link #preparePool preparePool}, {@link #addObject addObject} or
55   * {@link #borrowObject borrowObject} methods. Each time a new key value is
56   * provided to one of these methods, a sub-new pool is created under the given
57   * key to be managed by the containing {@code GenericKeyedObjectPool.}
58   * </p>
59   * <p>
60   * Note that the current implementation uses a ConcurrentHashMap which uses
61   * equals() to compare keys.
62   * This means that distinct instance keys must be distinguishable using equals.
63   * </p>
64   * <p>
65   * Optionally, one may configure the pool to examine and possibly evict objects
66   * as they sit idle in the pool and to ensure that a minimum number of idle
67   * objects is maintained for each key. This is performed by an "idle object
68   * eviction" thread, which runs asynchronously. Caution should be used when
69   * configuring this optional feature. Eviction runs contend with client threads
70   * for access to objects in the pool, so if they run too frequently performance
71   * issues may result.
72   * </p>
73   * <p>
74   * Implementation note: To prevent possible deadlocks, care has been taken to
75   * ensure that no call to a factory method will occur within a synchronization
76   * block. See POOL-125 and DBCP-44 for more information.
77   * </p>
78   * <p>
79   * This class is intended to be thread-safe.
80   * </p>
81   *
82   * @see GenericObjectPool
83   *
84   * @param <K> The type of keys maintained by this pool.
85   * @param <T> Type of element pooled in this pool.
86   *
87   * @since 2.0
88   */
89  public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
90          implements KeyedObjectPool<K, T>, GenericKeyedObjectPoolMXBean<K>, UsageTracking<T> {
91  
92      /**
93       * Maintains information on the per key queue for a given key.
94       *
95       * @param <S> type of objects in the pool
96       */
97      private class ObjectDeque<S> {
98  
99          private final LinkedBlockingDeque<PooledObject<S>> idleObjects;
100 
101         /*
102          * Number of instances created - number destroyed.
103          * Invariant: createCount <= maxTotalPerKey
104          */
105         private final AtomicInteger createCount = new AtomicInteger(0);
106 
107         private long makeObjectCount = 0;
108         private final Object makeObjectCountLock = new Object();
109 
110         /*
111          * The map is keyed on pooled instances, wrapped to ensure that
112          * they work properly as keys.
113          */
114         private final Map<IdentityWrapper<S>, PooledObject<S>> allObjects =
115                 new ConcurrentHashMap<>();
116 
117         /*
118          * Number of threads with registered interest in this key.
119          * register(K) increments this counter and deRegister(K) decrements it.
120          * Invariant: empty keyed pool will not be dropped unless numInterested
121          *            is 0.
122          */
123         private final AtomicLong numInterested = new AtomicLong(0);
124 
125         /**
126          * Create a new ObjecDeque with the given fairness policy.
127          * @param fairness true means client threads waiting to borrow / return instances
128          * will be served as if waiting in a FIFO queue.
129          */
130         public ObjectDeque(final boolean fairness) {
131             idleObjects = new LinkedBlockingDeque<>(fairness);
132         }
133 
134         /**
135          * Obtain all the objects for the current key.
136          *
137          * @return All the objects
138          */
139         public Map<IdentityWrapper<S>, PooledObject<S>> getAllObjects() {
140             return allObjects;
141         }
142 
143         /**
144          * Obtain the count of the number of objects created for the current
145          * key.
146          *
147          * @return The number of objects created for this key
148          */
149         public AtomicInteger getCreateCount() {
150             return createCount;
151         }
152 
153         /**
154          * Obtain the idle objects for the current key.
155          *
156          * @return The idle objects
157          */
158         public LinkedBlockingDeque<PooledObject<S>> getIdleObjects() {
159             return idleObjects;
160         }
161 
162         /**
163          * Obtain the number of threads with an interest registered in this key.
164          *
165          * @return The number of threads with a registered interest in this key
166          */
167         public AtomicLong getNumInterested() {
168             return numInterested;
169         }
170 
171         @Override
172         public String toString() {
173             final StringBuilder builder = new StringBuilder();
174             builder.append("ObjectDeque [idleObjects=");
175             builder.append(idleObjects);
176             builder.append(", createCount=");
177             builder.append(createCount);
178             builder.append(", allObjects=");
179             builder.append(allObjects);
180             builder.append(", numInterested=");
181             builder.append(numInterested);
182             builder.append("]");
183             return builder.toString();
184         }
185 
186     }
187 
188     private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(Integer.MAX_VALUE);
189 
190     // JMX specific attributes
191     private static final String ONAME_BASE =
192             "org.apache.commons.pool2:type=GenericKeyedObjectPool,name=";
193 
194     //--- configuration attributes ---------------------------------------------
195     private volatile int maxIdlePerKey =
196             GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
197 
198     private volatile int minIdlePerKey =
199             GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
200 
201 
202     private volatile int maxTotalPerKey =
203             GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
204 
205     private final KeyedPooledObjectFactory<K, T> factory;
206 
207     private final boolean fairness;
208 
209     /*
210      * My hash of sub-pools (ObjectQueue). The list of keys <b>must</b> be kept
211      * in step with {@link #poolKeyList} using {@link #keyLock} to ensure any
212      * changes to the list of current keys is made in a thread-safe manner.
213      */
214     private final Map<K, ObjectDeque<T>> poolMap =
215             new ConcurrentHashMap<>(); // @GuardedBy("keyLock") for write access (and some read access)
216 
217     /*
218      * List of pool keys - used to control eviction order. The list of keys
219      * <b>must</b> be kept in step with {@link #poolMap} using {@link #keyLock}
220      * to ensure any changes to the list of current keys is made in a
221      * thread-safe manner.
222      */
223     private final List<K> poolKeyList = new ArrayList<>(); // @GuardedBy("keyLock")
224 
225     private final ReadWriteLock keyLock = new ReentrantReadWriteLock(true);
226 
227     /*
228      * The combined count of the currently active objects for all keys and those
229      * in the process of being created. Under load, it may exceed
230      * {@link #maxTotal} but there will never be more than {@link #maxTotal}
231      * created at any one time.
232      */
233     private final AtomicInteger numTotal = new AtomicInteger(0);
234 
235     private Iterator<K> evictionKeyIterator = null; // @GuardedBy("evictionLock")
236 
237 
238     private K evictionKey = null; // @GuardedBy("evictionLock")
239 
240     // Additional configuration properties for abandoned object tracking
241     private volatile AbandonedConfig abandonedConfig;
242 
243     /**
244      * Create a new {@code GenericKeyedObjectPool} using defaults from
245      * {@link GenericKeyedObjectPoolConfig}.
246      * @param factory the factory to be used to create entries
247      */
248     public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory) {
249         this(factory, new GenericKeyedObjectPoolConfig<>());
250     }
251 
252     /**
253      * Create a new {@code GenericKeyedObjectPool} using a specific
254      * configuration.
255      *
256      * @param factory the factory to be used to create entries
257      * @param config    The configuration to use for this pool instance. The
258      *                  configuration is used by value. Subsequent changes to
259      *                  the configuration object will not be reflected in the
260      *                  pool.
261      */
262     public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory,
263             final GenericKeyedObjectPoolConfig<T> config) {
264 
265         super(config, ONAME_BASE, config.getJmxNamePrefix());
266 
267         if (factory == null) {
268             jmxUnregister(); // tidy up
269             throw new IllegalArgumentException("factory may not be null");
270         }
271         this.factory = factory;
272         this.fairness = config.getFairness();
273 
274         setConfig(config);
275     }
276 
277     /**
278      * Creates a new {@code GenericKeyedObjectPool} that tracks and destroys
279      * objects that are checked out, but never returned to the pool.
280      *
281      * @param factory   The object factory to be used to create object instances
282      *                  used by this pool
283      * @param config    The base pool configuration to use for this pool instance.
284      *                  The configuration is used by value. Subsequent changes to
285      *                  the configuration object will not be reflected in the
286      *                  pool.
287      * @param abandonedConfig  Configuration for abandoned object identification
288      *                         and removal.  The configuration is used by value.
289      * @since 2.10.0
290      */
291     public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory,
292             final GenericKeyedObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
293         this(factory, config);
294         setAbandonedConfig(abandonedConfig);
295     }
296 
297     /**
298      * Add an object to the set of idle objects for a given key.
299      *
300      * @param key The key to associate with the idle object
301      * @param p The wrapped object to add.
302      *
303      * @throws Exception If the associated factory fails to passivate the object
304      */
305     private void addIdleObject(final K key, final PooledObject<T> p) throws Exception {
306 
307         if (p != null) {
308             factory.passivateObject(key, p);
309             final LinkedBlockingDeque<PooledObject<T>> idleObjects =
310                     poolMap.get(key).getIdleObjects();
311             if (getLifo()) {
312                 idleObjects.addFirst(p);
313             } else {
314                 idleObjects.addLast(p);
315             }
316         }
317     }
318 
319 
320     /**
321      * Create an object using the {@link KeyedPooledObjectFactory#makeObject
322      * factory}, passivate it, and then place it in the idle object pool.
323      * {@code addObject} is useful for "pre-loading" a pool with idle
324      * objects.
325      *
326      * @param key the key a new instance should be added to
327      *
328      * @throws Exception when {@link KeyedPooledObjectFactory#makeObject}
329      *                   fails.
330      */
331     @Override
332     public void addObject(final K key) throws Exception {
333         assertOpen();
334         register(key);
335         try {
336             final PooledObject<T> p = create(key);
337             addIdleObject(key, p);
338         } finally {
339             deregister(key);
340         }
341     }
342 
343 
344     /**
345      * Equivalent to <code>{@link #borrowObject(Object, long) borrowObject}(key,
346      * {@link #getMaxWaitMillis()})</code>.
347      * <p>
348      * {@inheritDoc}
349      */
350     @Override
351     public T borrowObject(final K key) throws Exception {
352         return borrowObject(key, getMaxWaitMillis());
353     }
354 
355 
356     /**
357      * Borrows an object from the sub-pool associated with the given key using
358      * the specified waiting time which only applies if
359      * {@link #getBlockWhenExhausted()} is true.
360      * <p>
361      * If there is one or more idle instances available in the sub-pool
362      * associated with the given key, then an idle instance will be selected
363      * based on the value of {@link #getLifo()}, activated and returned.  If
364      * activation fails, or {@link #getTestOnBorrow() testOnBorrow} is set to
365      * {@code true} and validation fails, the instance is destroyed and the
366      * next available instance is examined.  This continues until either a valid
367      * instance is returned or there are no more idle instances available.
368      * <p>
369      * If there are no idle instances available in the sub-pool associated with
370      * the given key, behavior depends on the {@link #getMaxTotalPerKey()
371      * maxTotalPerKey}, {@link #getMaxTotal() maxTotal}, and (if applicable)
372      * {@link #getBlockWhenExhausted()} and the value passed in to the
373      * {@code borrowMaxWaitMillis} parameter. If the number of instances checked
374      * out from the sub-pool under the given key is less than
375      * {@code maxTotalPerKey} and the total number of instances in
376      * circulation (under all keys) is less than {@code maxTotal}, a new
377      * instance is created, activated and (if applicable) validated and returned
378      * to the caller. If validation fails, a {@code NoSuchElementException}
379      * will be thrown.
380      * <p>
381      * If the associated sub-pool is exhausted (no available idle instances and
382      * no capacity to create new ones), this method will either block
383      * ({@link #getBlockWhenExhausted()} is true) or throw a
384      * {@code NoSuchElementException}
385      * ({@link #getBlockWhenExhausted()} is false).
386      * The length of time that this method will block when
387      * {@link #getBlockWhenExhausted()} is true is determined by the value
388      * passed in to the {@code borrowMaxWait} parameter.
389      * <p>
390      * When {@code maxTotal} is set to a positive value and this method is
391      * invoked when at the limit with no idle instances available under the requested
392      * key, an attempt is made to create room by clearing the oldest 15% of the
393      * elements from the keyed sub-pools.
394      * <p>
395      * When the pool is exhausted, multiple calling threads may be
396      * simultaneously blocked waiting for instances to become available. A
397      * "fairness" algorithm has been implemented to ensure that threads receive
398      * available instances in request arrival order.
399      *
400      * @param key pool key
401      * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
402      *                            to become available
403      *
404      * @return object instance from the keyed pool
405      *
406      * @throws NoSuchElementException if a keyed object instance cannot be
407      *                                returned because the pool is exhausted.
408      *
409      * @throws Exception if a keyed object instance cannot be returned due to an
410      *                   error
411      */
412     public T borrowObject(final K key, final long borrowMaxWaitMillis) throws Exception {
413         assertOpen();
414 
415         final AbandonedConfig ac = this.abandonedConfig;
416         if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) &&
417                 (getNumActive() > getMaxTotal() - 3)) {
418             removeAbandoned(ac);
419         }
420 
421         PooledObject<T> p = null;
422 
423         // Get local copy of current config so it is consistent for entire
424         // method execution
425         final boolean blockWhenExhausted = getBlockWhenExhausted();
426 
427         boolean create;
428         final long waitTimeMillis = System.currentTimeMillis();
429         final ObjectDeque<T> objectDeque = register(key);
430 
431         try {
432             while (p == null) {
433                 create = false;
434                 p = objectDeque.getIdleObjects().pollFirst();
435                 if (p == null) {
436                     p = create(key);
437                     if (p != null) {
438                         create = true;
439                     }
440                 }
441                 if (blockWhenExhausted) {
442                     if (p == null) {
443                         if (borrowMaxWaitMillis < 0) {
444                             p = objectDeque.getIdleObjects().takeFirst();
445                         } else {
446                             p = objectDeque.getIdleObjects().pollFirst(
447                                     borrowMaxWaitMillis, TimeUnit.MILLISECONDS);
448                         }
449                     }
450                     if (p == null) {
451                         throw new NoSuchElementException(
452                                 "Timeout waiting for idle object");
453                     }
454                 } else if (p == null) {
455                     throw new NoSuchElementException("Pool exhausted");
456                 }
457                 if (!p.allocate()) {
458                     p = null;
459                 }
460 
461                 if (p != null) {
462                     try {
463                         factory.activateObject(key, p);
464                     } catch (final Exception e) {
465                         try {
466                             destroy(key, p, true, DestroyMode.NORMAL);
467                         } catch (final Exception e1) {
468                             // Ignore - activation failure is more important
469                         }
470                         p = null;
471                         if (create) {
472                             final NoSuchElementException nsee = new NoSuchElementException(
473                                     "Unable to activate object");
474                             nsee.initCause(e);
475                             throw nsee;
476                         }
477                     }
478                     if (p != null && getTestOnBorrow()) {
479                         boolean validate = false;
480                         Throwable validationThrowable = null;
481                         try {
482                             validate = factory.validateObject(key, p);
483                         } catch (final Throwable t) {
484                             PoolUtils.checkRethrow(t);
485                             validationThrowable = t;
486                         }
487                         if (!validate) {
488                             try {
489                                 destroy(key, p, true, DestroyMode.NORMAL);
490                                 destroyedByBorrowValidationCount.incrementAndGet();
491                             } catch (final Exception e) {
492                                 // Ignore - validation failure is more important
493                             }
494                             p = null;
495                             if (create) {
496                                 final NoSuchElementException nsee = new NoSuchElementException(
497                                         "Unable to validate object");
498                                 nsee.initCause(validationThrowable);
499                                 throw nsee;
500                             }
501                         }
502                     }
503                 }
504             }
505         } finally {
506             deregister(key);
507         }
508 
509         updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis));
510 
511         return p.getObject();
512     }
513 
514 
515     /**
516      * Calculate the number of objects that need to be created to attempt to
517      * maintain the minimum number of idle objects while not exceeded the limits
518      * on the maximum number of objects either per key or totally.
519      *
520      * @param objectDeque   The set of objects to check
521      *
522      * @return The number of new objects to create
523      */
524     private int calculateDeficit(final ObjectDeque<T> objectDeque) {
525 
526         if (objectDeque == null) {
527             return getMinIdlePerKey();
528         }
529 
530         // Used more than once so keep a local copy so the value is consistent
531         final int maxTotal = getMaxTotal();
532         final int maxTotalPerKeySave = getMaxTotalPerKey();
533 
534         // Calculate no of objects needed to be created, in order to have
535         // the number of pooled objects < maxTotalPerKey();
536         int objectDefecit = getMinIdlePerKey() - objectDeque.getIdleObjects().size();
537         if (maxTotalPerKeySave > 0) {
538             final int growLimit = Math.max(0,
539                     maxTotalPerKeySave - objectDeque.getIdleObjects().size());
540             objectDefecit = Math.min(objectDefecit, growLimit);
541         }
542 
543         // Take the maxTotal limit into account
544         if (maxTotal > 0) {
545             final int growLimit = Math.max(0, maxTotal - getNumActive() - getNumIdle());
546             objectDefecit = Math.min(objectDefecit, growLimit);
547         }
548 
549         return objectDefecit;
550     }
551 
552 
553     /**
554      * Clears any objects sitting idle in the pool by removing them from the
555      * idle instance sub-pools and then invoking the configured
556      * PoolableObjectFactory's
557      * {@link KeyedPooledObjectFactory#destroyObject(Object, PooledObject)}
558      * method on each idle instance.
559      * <p>
560      * Implementation notes:
561      * <ul>
562      * <li>This method does not destroy or effect in any way instances that are
563      * checked out when it is invoked.</li>
564      * <li>Invoking this method does not prevent objects being returned to the
565      * idle instance pool, even during its execution. Additional instances may
566      * be returned while removed items are being destroyed.</li>
567      * <li>Exceptions encountered destroying idle instances are swallowed
568      * but notified via a {@link SwallowedExceptionListener}.</li>
569      * </ul>
570      */
571     @Override
572     public void clear() {
573         final Iterator<K> iter = poolMap.keySet().iterator();
574 
575         while (iter.hasNext()) {
576             clear(iter.next());
577         }
578     }
579 
580 
581     /**
582      * Clears the specified sub-pool, removing all pooled instances
583      * corresponding to the given {@code key}. Exceptions encountered
584      * destroying idle instances are swallowed but notified via a
585      * {@link SwallowedExceptionListener}.
586      *
587      * @param key the key to clear
588      */
589     @Override
590     public void clear(final K key) {
591 
592         final ObjectDeque<T> objectDeque = register(key);
593 
594         try {
595             final LinkedBlockingDeque<PooledObject<T>> idleObjects =
596                     objectDeque.getIdleObjects();
597 
598             PooledObject<T> p = idleObjects.poll();
599 
600             while (p != null) {
601                 try {
602                     destroy(key, p, true, DestroyMode.NORMAL);
603                 } catch (final Exception e) {
604                     swallowException(e);
605                 }
606                 p = idleObjects.poll();
607             }
608         } finally {
609             deregister(key);
610         }
611     }
612 
613 
614     /**
615      * Clears oldest 15% of objects in pool.  The method sorts the objects into
616      * a TreeMap and then iterates the first 15% for removal.
617      */
618     public void clearOldest() {
619 
620         // build sorted map of idle objects
621         final Map<PooledObject<T>, K> map = new TreeMap<>();
622 
623         for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) {
624             final K k = entry.getKey();
625             final ObjectDeque<T> deque = entry.getValue();
626             // Protect against possible NPE if key has been removed in another
627             // thread. Not worth locking the keys while this loop completes.
628             if (deque != null) {
629                 final LinkedBlockingDeque<PooledObject<T>> idleObjects =
630                         deque.getIdleObjects();
631                 for (final PooledObject<T> p : idleObjects) {
632                     // each item into the map using the PooledObject object as the
633                     // key. It then gets sorted based on the idle time
634                     map.put(p, k);
635                 }
636             }
637         }
638 
639         // Now iterate created map and kill the first 15% plus one to account
640         // for zero
641         int itemsToRemove = ((int) (map.size() * 0.15)) + 1;
642         final Iterator<Map.Entry<PooledObject<T>, K>> iter =
643                 map.entrySet().iterator();
644 
645         while (iter.hasNext() && itemsToRemove > 0) {
646             final Map.Entry<PooledObject<T>, K> entry = iter.next();
647             // kind of backwards on naming.  In the map, each key is the
648             // PooledObject because it has the ordering with the timestamp
649             // value.  Each value that the key references is the key of the
650             // list it belongs to.
651             final K key = entry.getValue();
652             final PooledObject<T> p = entry.getKey();
653             // Assume the destruction succeeds
654             boolean destroyed = true;
655             try {
656                 destroyed = destroy(key, p, false, DestroyMode.NORMAL);
657             } catch (final Exception e) {
658                 swallowException(e);
659             }
660             if (destroyed) {
661                 itemsToRemove--;
662             }
663         }
664     }
665 
666 
667     /**
668      * Closes the keyed object pool. Once the pool is closed,
669      * {@link #borrowObject(Object)} will fail with IllegalStateException, but
670      * {@link #returnObject(Object, Object)} and
671      * {@link #invalidateObject(Object, Object)} will continue to work, with
672      * returned objects destroyed on return.
673      * <p>
674      * Destroys idle instances in the pool by invoking {@link #clear()}.
675      */
676     @Override
677     public void close() {
678         if (isClosed()) {
679             return;
680         }
681 
682         synchronized (closeLock) {
683             if (isClosed()) {
684                 return;
685             }
686 
687             // Stop the evictor before the pool is closed since evict() calls
688             // assertOpen()
689             stopEvictor();
690 
691             closed = true;
692             // This clear removes any idle objects
693             clear();
694 
695             jmxUnregister();
696 
697             // Release any threads that were waiting for an object
698             final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator();
699             while (iter.hasNext()) {
700                 iter.next().getIdleObjects().interuptTakeWaiters();
701             }
702             // This clear cleans up the keys now any waiting threads have been
703             // interrupted
704             clear();
705         }
706     }
707 
708     /**
709      * Create a new pooled object.
710      *
711      * @param key Key associated with new pooled object
712      *
713      * @return The new, wrapped pooled object
714      *
715      * @throws Exception If the objection creation fails
716      */
717     private PooledObject<T> create(final K key) throws Exception {
718         int maxTotalPerKeySave = getMaxTotalPerKey(); // Per key
719         if (maxTotalPerKeySave < 0) {
720             maxTotalPerKeySave = Integer.MAX_VALUE;
721         }
722         final int maxTotal = getMaxTotal();   // All keys
723 
724         final ObjectDeque<T> objectDeque = poolMap.get(key);
725 
726         // Check against the overall limit
727         boolean loop = true;
728 
729         while (loop) {
730             final int newNumTotal = numTotal.incrementAndGet();
731             if (maxTotal > -1 && newNumTotal > maxTotal) {
732                 numTotal.decrementAndGet();
733                 if (getNumIdle() == 0) {
734                     return null;
735                 }
736                 clearOldest();
737             } else {
738                 loop = false;
739             }
740         }
741 
742         // Flag that indicates if create should:
743         // - TRUE:  call the factory to create an object
744         // - FALSE: return null
745         // - null:  loop and re-test the condition that determines whether to
746         //          call the factory
747         Boolean create = null;
748         while (create == null) {
749             synchronized (objectDeque.makeObjectCountLock) {
750                 final long newCreateCount = objectDeque.getCreateCount().incrementAndGet();
751                 // Check against the per key limit
752                 if (newCreateCount > maxTotalPerKeySave) {
753                     // The key is currently at capacity or in the process of
754                     // making enough new objects to take it to capacity.
755                     objectDeque.getCreateCount().decrementAndGet();
756                     if (objectDeque.makeObjectCount == 0) {
757                         // There are no makeObject() calls in progress for this
758                         // key so the key is at capacity. Do not attempt to
759                         // create a new object. Return and wait for an object to
760                         // be returned.
761                         create = Boolean.FALSE;
762                     } else {
763                         // There are makeObject() calls in progress that might
764                         // bring the pool to capacity. Those calls might also
765                         // fail so wait until they complete and then re-test if
766                         // the pool is at capacity or not.
767                         objectDeque.makeObjectCountLock.wait();
768                     }
769                 } else {
770                     // The pool is not at capacity. Create a new object.
771                     objectDeque.makeObjectCount++;
772                     create = Boolean.TRUE;
773                 }
774             }
775         }
776 
777         if (!create.booleanValue()) {
778             numTotal.decrementAndGet();
779             return null;
780         }
781 
782         PooledObject<T> p = null;
783         try {
784             p = factory.makeObject(key);
785             if (getTestOnCreate() && !factory.validateObject(key, p)) {
786                 numTotal.decrementAndGet();
787                 objectDeque.getCreateCount().decrementAndGet();
788                 return null;
789             }
790         } catch (final Exception e) {
791             numTotal.decrementAndGet();
792             objectDeque.getCreateCount().decrementAndGet();
793             throw e;
794         } finally {
795             synchronized (objectDeque.makeObjectCountLock) {
796                 objectDeque.makeObjectCount--;
797                 objectDeque.makeObjectCountLock.notifyAll();
798             }
799         }
800 
801         final AbandonedConfig ac = this.abandonedConfig;
802         if (ac != null && ac.getLogAbandoned()) {
803             p.setLogAbandoned(true);
804             p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
805         }
806 
807         createdCount.incrementAndGet();
808         objectDeque.getAllObjects().put(new IdentityWrapper<>(p.getObject()), p);
809         return p;
810     }
811 
812     /**
813      * De-register the use of a key by an object.
814      * <p>
815      * register() and deregister() must always be used as a pair.
816      *
817      * @param k The key to de-register
818      */
819     private void deregister(final K k) {
820         Lock lock = keyLock.readLock();
821         try {
822             lock.lock();
823             final ObjectDeque<T> objectDeque = poolMap.get(k);
824             final long numInterested = objectDeque.getNumInterested().decrementAndGet();
825             if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) {
826                 // Potential to remove key
827                 // Upgrade to write lock
828                 lock.unlock();
829                 lock = keyLock.writeLock();
830                 lock.lock();
831                 if (objectDeque.getCreateCount().get() == 0 && objectDeque.getNumInterested().get() == 0) {
832                     // NOTE: Keys must always be removed from both poolMap and
833                     //       poolKeyList at the same time while protected by
834                     //       keyLock.writeLock()
835                     poolMap.remove(k);
836                     poolKeyList.remove(k);
837                 }
838             }
839         } finally {
840             lock.unlock();
841         }
842     }
843 
844 
845     /**
846      * Destroy the wrapped, pooled object.
847      *
848      * @param key The key associated with the object to destroy.
849      * @param toDestroy The wrapped object to be destroyed
850      * @param always Should the object be destroyed even if it is not currently
851      *               in the set of idle objects for the given key
852      * @param mode DestroyMode context provided to the factory
853      *
854      * @return {@code true} if the object was destroyed, otherwise {@code false}
855      * @throws Exception If the object destruction failed
856      */
857     private boolean destroy(final K key, final PooledObject<T> toDestroy, final boolean always, final DestroyMode mode)
858             throws Exception {
859 
860         final ObjectDeque<T> objectDeque = register(key);
861 
862         try {
863             boolean isIdle;
864             synchronized(toDestroy) {
865                 // Check idle state directly
866                 isIdle = toDestroy.getState().equals(PooledObjectState.IDLE);
867                 // If idle, not under eviction test, or always is true, remove instance,
868                 // updating isIdle if instance is found in idle objects
869                 if (isIdle || always) {
870                     isIdle = objectDeque.getIdleObjects().remove(toDestroy);
871                 }
872             }
873             if (isIdle || always) {
874                 objectDeque.getAllObjects().remove(new IdentityWrapper<>(toDestroy.getObject()));
875                 toDestroy.invalidate();
876 
877                 try {
878                     factory.destroyObject(key, toDestroy, mode);
879                 } finally {
880                     objectDeque.getCreateCount().decrementAndGet();
881                     destroyedCount.incrementAndGet();
882                     numTotal.decrementAndGet();
883                 }
884                 return true;
885             }
886             return false;
887         } finally {
888             deregister(key);
889         }
890     }
891 
892     @Override
893     void ensureMinIdle() throws Exception {
894         final int minIdlePerKeySave = getMinIdlePerKey();
895         if (minIdlePerKeySave < 1) {
896             return;
897         }
898 
899         for (final K k : poolMap.keySet()) {
900             ensureMinIdle(k);
901         }
902     }
903 
904     /**
905      * Ensure that the configured number of minimum idle objects is available in
906      * the pool for the given key.
907      *
908      * @param key The key to check for idle objects
909      *
910      * @throws Exception If a new object is required and cannot be created
911      */
912     private void ensureMinIdle(final K key) throws Exception {
913         // Calculate current pool objects
914         ObjectDeque<T> objectDeque = poolMap.get(key);
915 
916         // objectDeque == null is OK here. It is handled correctly by both
917         // methods called below.
918 
919         // this method isn't synchronized so the
920         // calculateDeficit is done at the beginning
921         // as a loop limit and a second time inside the loop
922         // to stop when another thread already returned the
923         // needed objects
924         final int deficit = calculateDeficit(objectDeque);
925 
926         for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) {
927             addObject(key);
928             // If objectDeque was null, it won't be any more. Obtain a reference
929             // to it so the deficit can be correctly calculated. It needs to
930             // take account of objects created in other threads.
931             if (objectDeque == null) {
932                 objectDeque = poolMap.get(key);
933             }
934         }
935     }
936 
937 
938     /**
939      * {@inheritDoc}
940      * <p>
941      * Successive activations of this method examine objects in keyed sub-pools
942      * in sequence, cycling through the keys and examining objects in
943      * oldest-to-youngest order within the keyed sub-pools.
944      */
945     @Override
946     public void evict() throws Exception {
947         assertOpen();
948 
949         if (getNumIdle() > 0) {
950 
951             PooledObject<T> underTest = null;
952             final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
953 
954             synchronized (evictionLock) {
955                 final EvictionConfigfig.html#EvictionConfig">EvictionConfig evictionConfig = new EvictionConfig(
956                         getMinEvictableIdleTime(),
957                         getSoftMinEvictableIdleTime(),
958                         getMinIdlePerKey());
959 
960                 final boolean testWhileIdle = getTestWhileIdle();
961 
962                 for (int i = 0, m = getNumTests(); i < m; i++) {
963                     if(evictionIterator == null || !evictionIterator.hasNext()) {
964                         if (evictionKeyIterator == null ||
965                                 !evictionKeyIterator.hasNext()) {
966                             final List<K> keyCopy = new ArrayList<>();
967                             final Lock readLock = keyLock.readLock();
968                             readLock.lock();
969                             try {
970                                 keyCopy.addAll(poolKeyList);
971                             } finally {
972                                 readLock.unlock();
973                             }
974                             evictionKeyIterator = keyCopy.iterator();
975                         }
976                         while (evictionKeyIterator.hasNext()) {
977                             evictionKey = evictionKeyIterator.next();
978                             final ObjectDeque<T> objectDeque = poolMap.get(evictionKey);
979                             if (objectDeque == null) {
980                                 continue;
981                             }
982 
983                             final Deque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects();
984                             evictionIterator = new EvictionIterator(idleObjects);
985                             if (evictionIterator.hasNext()) {
986                                 break;
987                             }
988                             evictionIterator = null;
989                         }
990                     }
991                     if (evictionIterator == null) {
992                         // Pools exhausted
993                         return;
994                     }
995                     final Deque<PooledObject<T>> idleObjects;
996                     try {
997                         underTest = evictionIterator.next();
998                         idleObjects = evictionIterator.getIdleObjects();
999                     } catch (final NoSuchElementException nsee) {
1000                         // Object was borrowed in another thread
1001                         // Don't count this as an eviction test so reduce i;
1002                         i--;
1003                         evictionIterator = null;
1004                         continue;
1005                     }
1006 
1007                     if (!underTest.startEvictionTest()) {
1008                         // Object was borrowed in another thread
1009                         // Don't count this as an eviction test so reduce i;
1010                         i--;
1011                         continue;
1012                     }
1013 
1014                     // User provided eviction policy could throw all sorts of
1015                     // crazy exceptions. Protect against such an exception
1016                     // killing the eviction thread.
1017                     boolean evict;
1018                     try {
1019                         evict = evictionPolicy.evict(evictionConfig, underTest,
1020                                 poolMap.get(evictionKey).getIdleObjects().size());
1021                     } catch (final Throwable t) {
1022                         // Slightly convoluted as SwallowedExceptionListener
1023                         // uses Exception rather than Throwable
1024                         PoolUtils.checkRethrow(t);
1025                         swallowException(new Exception(t));
1026                         // Don't evict on error conditions
1027                         evict = false;
1028                     }
1029 
1030                     if (evict) {
1031                         destroy(evictionKey, underTest, true, DestroyMode.NORMAL);
1032                         destroyedByEvictorCount.incrementAndGet();
1033                     } else {
1034                         if (testWhileIdle) {
1035                             boolean active = false;
1036                             try {
1037                                 factory.activateObject(evictionKey, underTest);
1038                                 active = true;
1039                             } catch (final Exception e) {
1040                                 destroy(evictionKey, underTest, true, DestroyMode.NORMAL);
1041                                 destroyedByEvictorCount.incrementAndGet();
1042                             }
1043                             if (active) {
1044                                 if (!factory.validateObject(evictionKey, underTest)) {
1045                                     destroy(evictionKey, underTest, true, DestroyMode.NORMAL);
1046                                     destroyedByEvictorCount.incrementAndGet();
1047                                 } else {
1048                                     try {
1049                                         factory.passivateObject(evictionKey, underTest);
1050                                     } catch (final Exception e) {
1051                                         destroy(evictionKey, underTest, true, DestroyMode.NORMAL);
1052                                         destroyedByEvictorCount.incrementAndGet();
1053                                     }
1054                                 }
1055                             }
1056                         }
1057                         if (!underTest.endEvictionTest(idleObjects)) {
1058                             // TODO - May need to add code here once additional
1059                             // states are used
1060                         }
1061                     }
1062                 }
1063             }
1064         }
1065         final AbandonedConfig ac = this.abandonedConfig;
1066         if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
1067             removeAbandoned(ac);
1068         }
1069     }
1070 
1071     /**
1072      * Obtain a reference to the factory used to create, destroy and validate
1073      * the objects used by this pool.
1074      *
1075      * @return the factory
1076      */
1077     public KeyedPooledObjectFactory<K, T> getFactory() {
1078         return factory;
1079     }
1080 
1081     /**
1082      * Gets whether this pool identifies and logs any abandoned objects.
1083      *
1084      * @return {@code true} if abandoned object removal is configured for this
1085      *         pool and removal events are to be logged otherwise {@code false}
1086      *
1087      * @see AbandonedConfig#getLogAbandoned()
1088      * @since 2.10.0
1089      */
1090     @Override
1091     public boolean getLogAbandoned() {
1092         final AbandonedConfig ac = this.abandonedConfig;
1093         return ac != null && ac.getLogAbandoned();
1094     }
1095 
1096     /**
1097      * Gets the cap on the number of "idle" instances per key in the pool.
1098      * If maxIdlePerKey is set too low on heavily loaded systems it is possible
1099      * you will see objects being destroyed and almost immediately new objects
1100      * being created. This is a result of the active threads momentarily
1101      * returning objects faster than they are requesting them, causing the
1102      * number of idle objects to rise above maxIdlePerKey. The best value for
1103      * maxIdlePerKey for heavily loaded system will vary but the default is a
1104      * good starting point.
1105      *
1106      * @return the maximum number of "idle" instances that can be held in a
1107      *         given keyed sub-pool or a negative value if there is no limit
1108      *
1109      * @see #setMaxIdlePerKey
1110      */
1111     @Override
1112     public int getMaxIdlePerKey() {
1113         return maxIdlePerKey;
1114     }
1115 
1116     /**
1117      * Gets the limit on the number of object instances allocated by the pool
1118      * (checked out or idle), per key. When the limit is reached, the sub-pool
1119      * is said to be exhausted. A negative value indicates no limit.
1120      *
1121      * @return the limit on the number of active instances per key
1122      *
1123      * @see #setMaxTotalPerKey
1124      */
1125     @Override
1126     public int getMaxTotalPerKey() {
1127         return maxTotalPerKey;
1128     }
1129 
1130     /**
1131      * Gets the target for the minimum number of idle objects to maintain in
1132      * each of the keyed sub-pools. This setting only has an effect if it is
1133      * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than
1134      * zero. If this is the case, an attempt is made to ensure that each
1135      * sub-pool has the required minimum number of instances during idle object
1136      * eviction runs.
1137      * <p>
1138      * If the configured value of minIdlePerKey is greater than the configured
1139      * value for maxIdlePerKey then the value of maxIdlePerKey will be used
1140      * instead.
1141      *
1142      * @return minimum size of the each keyed pool
1143      *
1144      * @see #setTimeBetweenEvictionRunsMillis
1145      */
1146     @Override
1147     public int getMinIdlePerKey() {
1148         final int maxIdlePerKeySave = getMaxIdlePerKey();
1149         if (this.minIdlePerKey > maxIdlePerKeySave) {
1150             return maxIdlePerKeySave;
1151         }
1152         return minIdlePerKey;
1153     }
1154 
1155     @Override
1156     public int getNumActive() {
1157         return numTotal.get() - getNumIdle();
1158     }
1159 
1160     @Override
1161     public int getNumActive(final K key) {
1162         final ObjectDeque<T> objectDeque = poolMap.get(key);
1163         if (objectDeque != null) {
1164             return objectDeque.getAllObjects().size() -
1165                     objectDeque.getIdleObjects().size();
1166         }
1167         return 0;
1168     }
1169 
1170     @Override
1171     public Map<String,Integer> getNumActivePerKey() {
1172         final HashMap<String,Integer> result = new HashMap<>();
1173 
1174         final Iterator<Entry<K,ObjectDeque<T>>> iter = poolMap.entrySet().iterator();
1175         while (iter.hasNext()) {
1176             final Entry<K,ObjectDeque<T>> entry = iter.next();
1177             if (entry != null) {
1178                 final K key = entry.getKey();
1179                 final ObjectDeque<T> objectDequeue = entry.getValue();
1180                 if (key != null && objectDequeue != null) {
1181                     result.put(key.toString(), Integer.valueOf(
1182                             objectDequeue.getAllObjects().size() -
1183                             objectDequeue.getIdleObjects().size()));
1184                 }
1185             }
1186         }
1187         return result;
1188     }
1189 
1190     @Override
1191     public int getNumIdle() {
1192         final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator();
1193         int result = 0;
1194 
1195         while (iter.hasNext()) {
1196             result += iter.next().getIdleObjects().size();
1197         }
1198 
1199         return result;
1200     }
1201 
1202 
1203     //--- JMX support ----------------------------------------------------------
1204 
1205     @Override
1206     public int getNumIdle(final K key) {
1207         final ObjectDeque<T> objectDeque = poolMap.get(key);
1208         return objectDeque != null ? objectDeque.getIdleObjects().size() : 0;
1209     }
1210 
1211     /**
1212      * Calculate the number of objects to test in a run of the idle object
1213      * evictor.
1214      *
1215      * @return The number of objects to test for validity
1216      */
1217     private int getNumTests() {
1218         final int totalIdle = getNumIdle();
1219         final int numTests = getNumTestsPerEvictionRun();
1220         if (numTests >= 0) {
1221             return Math.min(numTests, totalIdle);
1222         }
1223         return(int)(Math.ceil(totalIdle/Math.abs((double)numTests)));
1224     }
1225 
1226     /**
1227      * Return an estimate of the number of threads currently blocked waiting for
1228      * an object from the pool. This is intended for monitoring only, not for
1229      * synchronization control.
1230      *
1231      * @return The estimate of the number of threads currently blocked waiting
1232      *         for an object from the pool
1233      */
1234     @Override
1235     public int getNumWaiters() {
1236         int result = 0;
1237 
1238         if (getBlockWhenExhausted()) {
1239             final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator();
1240 
1241             while (iter.hasNext()) {
1242                 // Assume no overflow
1243                 result += iter.next().getIdleObjects().getTakeQueueLength();
1244             }
1245         }
1246 
1247         return result;
1248     }
1249 
1250     /**
1251      * Return an estimate of the number of threads currently blocked waiting for
1252      * an object from the pool for each key. This is intended for
1253      * monitoring only, not for synchronization control.
1254      *
1255      * @return The estimate of the number of threads currently blocked waiting
1256      *         for an object from the pool for each key
1257      */
1258     @Override
1259     public Map<String,Integer> getNumWaitersByKey() {
1260         final Map<String,Integer> result = new HashMap<>();
1261 
1262         for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) {
1263             final K k = entry.getKey();
1264             final ObjectDeque<T> deque = entry.getValue();
1265             if (deque != null) {
1266                 if (getBlockWhenExhausted()) {
1267                     result.put(k.toString(), Integer.valueOf(
1268                             deque.getIdleObjects().getTakeQueueLength()));
1269                 } else {
1270                     result.put(k.toString(), Integer.valueOf(0));
1271                 }
1272             }
1273         }
1274         return result;
1275     }
1276 
1277     /**
1278      * Gets whether a check is made for abandoned objects when an object is borrowed
1279      * from this pool.
1280      *
1281      * @return {@code true} if abandoned object removal is configured to be
1282      *         activated by borrowObject otherwise {@code false}
1283      *
1284      * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
1285      * @since 2.10.0
1286      */
1287     @Override
1288     public boolean getRemoveAbandonedOnBorrow() {
1289         final AbandonedConfig ac = this.abandonedConfig;
1290         return ac != null && ac.getRemoveAbandonedOnBorrow();
1291     }
1292 
1293     /**
1294      * Gets whether a check is made for abandoned objects when the evictor runs.
1295      *
1296      * @return {@code true} if abandoned object removal is configured to be
1297      *         activated when the evictor runs otherwise {@code false}
1298      *
1299      * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
1300      * @since 2.10.0
1301      */
1302     @Override
1303     public boolean getRemoveAbandonedOnMaintenance() {
1304         final AbandonedConfig ac = this.abandonedConfig;
1305         return ac != null && ac.getRemoveAbandonedOnMaintenance();
1306     }
1307 
1308     /**
1309      * Gets the timeout before which an object will be considered to be
1310      * abandoned by this pool.
1311      *
1312      * @return The abandoned object timeout in seconds if abandoned object
1313      *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
1314      *
1315      * @see AbandonedConfig#getRemoveAbandonedTimeout()
1316      * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
1317      * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
1318      * @since 2.10.0
1319      */
1320     @Override
1321     @Deprecated
1322     public int getRemoveAbandonedTimeout() {
1323         final AbandonedConfig ac = this.abandonedConfig;
1324         return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
1325     }
1326 
1327     /**
1328      * Gets the timeout before which an object will be considered to be
1329      * abandoned by this pool.
1330      *
1331      * @return The abandoned object timeout in seconds if abandoned object
1332      *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
1333      *
1334      * @see AbandonedConfig#getRemoveAbandonedTimeout()
1335      * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
1336      * @since 2.10.0
1337      */
1338     public Duration getRemoveAbandonedTimeoutDuration() {
1339         final AbandonedConfig ac = this.abandonedConfig;
1340         return ac != null ? ac.getRemoveAbandonedTimeoutDuration() : DEFAULT_REMOVE_ABANDONED_TIMEOUT;
1341     }
1342 
1343 
1344     //--- inner classes ----------------------------------------------
1345 
1346     /**
1347      * Checks to see if there are any threads currently waiting to borrow
1348      * objects but are blocked waiting for more objects to become available.
1349      *
1350      * @return {@code true} if there is at least one thread waiting otherwise
1351      *         {@code false}
1352      */
1353     private boolean hasBorrowWaiters() {
1354         for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) {
1355             final ObjectDeque<T> deque = entry.getValue();
1356             if (deque != null) {
1357                 final LinkedBlockingDeque<PooledObject<T>> pool =
1358                         deque.getIdleObjects();
1359                 if(pool.hasTakeWaiters()) {
1360                     return true;
1361                 }
1362             }
1363         }
1364         return false;
1365     }
1366 
1367     /**
1368      * {@inheritDoc}
1369      * <p>
1370      * Activation of this method decrements the active count associated with
1371      * the given keyed pool and attempts to destroy {@code obj.}
1372      *
1373      * @param key pool key
1374      * @param obj instance to invalidate
1375      *
1376      * @throws Exception             if an exception occurs destroying the
1377      *                               object
1378      * @throws IllegalStateException if obj does not belong to the pool
1379      *                               under the given key
1380      */
1381     @Override
1382     public void invalidateObject(final K key, final T obj) throws Exception {
1383         invalidateObject(key, obj, DestroyMode.NORMAL);
1384     }
1385     /**
1386      * {@inheritDoc}
1387      * <p>
1388      * Activation of this method decrements the active count associated with
1389      * the given keyed pool and attempts to destroy {@code obj.}
1390      *
1391      * @param key pool key
1392      * @param obj instance to invalidate
1393      * @param mode DestroyMode context provided to factory
1394      *
1395      * @throws Exception             if an exception occurs destroying the
1396      *                               object
1397      * @throws IllegalStateException if obj does not belong to the pool
1398      *                               under the given key
1399      * @since 2.9.0
1400      */
1401     @Override
1402     public void invalidateObject(final K key, final T obj, final DestroyMode mode) throws Exception {
1403 
1404         final ObjectDeque<T> objectDeque = poolMap.get(key);
1405 
1406         final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj));
1407         if (p == null) {
1408             throw new IllegalStateException(
1409                     "Object not currently part of this pool");
1410         }
1411         synchronized (p) {
1412             if (p.getState() != PooledObjectState.INVALID) {
1413                 destroy(key, p, true, mode);
1414             }
1415         }
1416         if (objectDeque.idleObjects.hasTakeWaiters()) {
1417             addObject(key);
1418         }
1419     }
1420     /**
1421      * Gets whether or not abandoned object removal is configured for this pool.
1422      *
1423      * @return true if this pool is configured to detect and remove
1424      * abandoned objects
1425      * @since 2.10.0
1426      */
1427     @Override
1428     public boolean isAbandonedConfig() {
1429         return abandonedConfig != null;
1430     }
1431     /**
1432      * Provides information on all the objects in the pool, both idle (waiting
1433      * to be borrowed) and active (currently borrowed).
1434      * <p>
1435      * Note: This is named listAllObjects so it is presented as an operation via
1436      * JMX. That means it won't be invoked unless the explicitly requested
1437      * whereas all attributes will be automatically requested when viewing the
1438      * attributes for an object in a tool like JConsole.
1439      *
1440      * @return Information grouped by key on all the objects in the pool
1441      */
1442     @Override
1443     public Map<String,List<DefaultPooledObjectInfo>> listAllObjects() {
1444         final Map<String,List<DefaultPooledObjectInfo>> result =
1445                 new HashMap<>();
1446 
1447         for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) {
1448             final K k = entry.getKey();
1449             final ObjectDeque<T> deque = entry.getValue();
1450             if (deque != null) {
1451                 final List<DefaultPooledObjectInfo> list =
1452                         new ArrayList<>();
1453                 result.put(k.toString(), list);
1454                 for (final PooledObject<T> p : deque.getAllObjects().values()) {
1455                     list.add(new DefaultPooledObjectInfo(p));
1456                 }
1457             }
1458         }
1459         return result;
1460     }
1461     /**
1462      * Registers a key for pool control and ensures that
1463      * {@link #getMinIdlePerKey()} idle instances are created.
1464      *
1465      * @param key - The key to register for pool control.
1466      *
1467      * @throws Exception If the associated factory throws an exception
1468      */
1469     public void preparePool(final K key) throws Exception {
1470         final int minIdlePerKeySave = getMinIdlePerKey();
1471         if (minIdlePerKeySave < 1) {
1472             return;
1473         }
1474         ensureMinIdle(key);
1475     }
1476     /**
1477      * Register the use of a key by an object.
1478      * <p>
1479      * register() and deregister() must always be used as a pair.
1480      *
1481      * @param k The key to register
1482      *
1483      * @return The objects currently associated with the given key. If this
1484      *         method returns without throwing an exception then it will never
1485      *         return null.
1486      */
1487     private ObjectDeque<T> register(final K k) {
1488         Lock lock = keyLock.readLock();
1489         ObjectDeque<T> objectDeque = null;
1490         try {
1491             lock.lock();
1492             objectDeque = poolMap.get(k);
1493             if (objectDeque == null) {
1494                 // Upgrade to write lock
1495                 lock.unlock();
1496                 lock = keyLock.writeLock();
1497                 lock.lock();
1498                 objectDeque = poolMap.get(k);
1499                 if (objectDeque == null) {
1500                     objectDeque = new ObjectDeque<>(fairness);
1501                     objectDeque.getNumInterested().incrementAndGet();
1502                     // NOTE: Keys must always be added to both poolMap and
1503                     //       poolKeyList at the same time while protected by
1504                     //       keyLock.writeLock()
1505                     poolMap.put(k, objectDeque);
1506                     poolKeyList.add(k);
1507                 } else {
1508                     objectDeque.getNumInterested().incrementAndGet();
1509                 }
1510             } else {
1511                 objectDeque.getNumInterested().incrementAndGet();
1512             }
1513         } finally {
1514             lock.unlock();
1515         }
1516         return objectDeque;
1517     }
1518 
1519 
1520     //--- internal attributes --------------------------------------------------
1521 
1522     /**
1523      * Recovers abandoned objects which have been checked out but
1524      * not used since longer than the removeAbandonedTimeout.
1525      *
1526      * @param abandonedConfig The configuration to use to identify abandoned objects
1527      */
1528     @SuppressWarnings("resource") // PrintWriter is managed elsewhere
1529     private void removeAbandoned(final AbandonedConfig abandonedConfig) {
1530         for (final Entry<K, GenericKeyedObjectPool<K, T>.ObjectDeque<T>> pool : poolMap.entrySet()) {
1531             final Map<IdentityWrapper<T>, PooledObject<T>> allObjects = pool.getValue().getAllObjects();
1532 
1533             // Generate a list of abandoned objects to remove
1534             final long nowMillis = System.currentTimeMillis();
1535             final long timeoutMillis =
1536                     nowMillis - abandonedConfig.getRemoveAbandonedTimeoutDuration().toMillis();
1537             final ArrayList<PooledObject<T>> remove = new ArrayList<>();
1538             final Iterator<PooledObject<T>> it = allObjects.values().iterator();
1539             while (it.hasNext()) {
1540                 final PooledObject<T> pooledObject = it.next();
1541                 synchronized (pooledObject) {
1542                     if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
1543                             pooledObject.getLastUsedTime() <= timeoutMillis) {
1544                         pooledObject.markAbandoned();
1545                         remove.add(pooledObject);
1546                     }
1547                 }
1548             }
1549 
1550             // Now remove the abandoned objects
1551             final Iterator<PooledObject<T>> itr = remove.iterator();
1552             while (itr.hasNext()) {
1553                 final PooledObject<T> pooledObject = itr.next();
1554                 if (abandonedConfig.getLogAbandoned()) {
1555                     pooledObject.printStackTrace(abandonedConfig.getLogWriter());
1556                 }
1557                 try {
1558                     invalidateObject(pool.getKey(), pooledObject.getObject(), DestroyMode.ABANDONED);
1559                 } catch (final Exception e) {
1560                     e.printStackTrace();
1561                 }
1562             }
1563         }
1564     }
1565 
1566     /**
1567      * Returns an object to a keyed sub-pool.
1568      * <p>
1569      * If {@link #getMaxIdlePerKey() maxIdle} is set to a positive value and the
1570      * number of idle instances under the given key has reached this value, the
1571      * returning instance is destroyed.
1572      * <p>
1573      * If {@link #getTestOnReturn() testOnReturn} == true, the returning
1574      * instance is validated before being returned to the idle instance sub-pool
1575      * under the given key. In this case, if validation fails, the instance is
1576      * destroyed.
1577      * <p>
1578      * Exceptions encountered destroying objects for any reason are swallowed
1579      * but notified via a {@link SwallowedExceptionListener}.
1580      *
1581      * @param key pool key
1582      * @param obj instance to return to the keyed pool
1583      *
1584      * @throws IllegalStateException if an object is returned to the pool that
1585      *                               was not borrowed from it or if an object is
1586      *                               returned to the pool multiple times
1587      */
1588     @Override
1589     public void returnObject(final K key, final T obj) {
1590 
1591         final ObjectDeque<T> objectDeque = poolMap.get(key);
1592 
1593         if (objectDeque == null) {
1594             throw new IllegalStateException(
1595                     "No keyed pool found under the given key.");
1596         }
1597 
1598         final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj));
1599 
1600         if (p == null) {
1601             throw new IllegalStateException(
1602                     "Returned object not currently part of this pool");
1603         }
1604 
1605         markReturningState(p);
1606 
1607         final Duration activeTime = p.getActiveTime();
1608 
1609         try {
1610             if (getTestOnReturn() && !factory.validateObject(key, p)) {
1611                 try {
1612                     destroy(key, p, true, DestroyMode.NORMAL);
1613                 } catch (final Exception e) {
1614                     swallowException(e);
1615                 }
1616                 whenWaitersAddObject(key, objectDeque.idleObjects);
1617                 return;
1618             }
1619 
1620             try {
1621                 factory.passivateObject(key, p);
1622             } catch (final Exception e1) {
1623                 swallowException(e1);
1624                 try {
1625                     destroy(key, p, true, DestroyMode.NORMAL);
1626                 } catch (final Exception e) {
1627                     swallowException(e);
1628                 }
1629                 whenWaitersAddObject(key, objectDeque.idleObjects);
1630                 return;
1631             }
1632 
1633             if (!p.deallocate()) {
1634                 throw new IllegalStateException(
1635                         "Object has already been returned to this pool");
1636             }
1637 
1638             final int maxIdle = getMaxIdlePerKey();
1639             final LinkedBlockingDeque<PooledObject<T>> idleObjects =
1640                     objectDeque.getIdleObjects();
1641 
1642             if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) {
1643                 try {
1644                     destroy(key, p, true, DestroyMode.NORMAL);
1645                 } catch (final Exception e) {
1646                     swallowException(e);
1647                 }
1648             } else {
1649                 if (getLifo()) {
1650                     idleObjects.addFirst(p);
1651                 } else {
1652                     idleObjects.addLast(p);
1653                 }
1654                 if (isClosed()) {
1655                     // Pool closed while object was being added to idle objects.
1656                     // Make sure the returned object is destroyed rather than left
1657                     // in the idle object pool (which would effectively be a leak)
1658                     clear(key);
1659                 }
1660             }
1661         } finally {
1662             if (hasBorrowWaiters()) {
1663                 reuseCapacity();
1664             }
1665             updateStatsReturn(activeTime);
1666         }
1667     }
1668     /**
1669      * Attempt to create one new instance to serve from the most heavily
1670      * loaded pool that can add a new instance.
1671      *
1672      * This method exists to ensure liveness in the pool when threads are
1673      * parked waiting and capacity to create instances under the requested keys
1674      * subsequently becomes available.
1675      *
1676      * This method is not guaranteed to create an instance and its selection
1677      * of the most loaded pool that can create an instance may not always be
1678      * correct, since it does not lock the pool and instances may be created,
1679      * borrowed, returned or destroyed by other threads while it is executing.
1680      */
1681     private void reuseCapacity() {
1682         final int maxTotalPerKeySave = getMaxTotalPerKey();
1683 
1684         // Find the most loaded pool that could take a new instance
1685         int maxQueueLength = 0;
1686         LinkedBlockingDeque<PooledObject<T>> mostLoaded = null;
1687         K loadedKey = null;
1688         for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) {
1689             final K k = entry.getKey();
1690             final ObjectDeque<T> deque = entry.getValue();
1691             if (deque != null) {
1692                 final LinkedBlockingDeque<PooledObject<T>> pool = deque.getIdleObjects();
1693                 final int queueLength = pool.getTakeQueueLength();
1694                 if (getNumActive(k) < maxTotalPerKeySave && queueLength > maxQueueLength) {
1695                     maxQueueLength = queueLength;
1696                     mostLoaded = pool;
1697                     loadedKey = k;
1698                 }
1699             }
1700         }
1701 
1702         // Attempt to add an instance to the most loaded pool
1703         if (mostLoaded != null) {
1704             register(loadedKey);
1705             try {
1706                 final PooledObject<T> p = create(loadedKey);
1707                 if (p != null) {
1708                     addIdleObject(loadedKey, p);
1709                 }
1710             } catch (final Exception e) {
1711                 swallowException(e);
1712             } finally {
1713                 deregister(loadedKey);
1714             }
1715         }
1716     }
1717     /**
1718      * Sets the abandoned object removal configuration.
1719      *
1720      * @param abandonedConfig the new configuration to use. This is used by value.
1721      *
1722      * @see AbandonedConfig
1723      * @since 2.10.0
1724      */
1725     @SuppressWarnings("resource") // PrintWriter is managed elsewhere
1726     public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
1727         if (abandonedConfig == null) {
1728             this.abandonedConfig = null;
1729         } else {
1730             this.abandonedConfig = new AbandonedConfig();
1731             this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
1732             this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
1733             this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
1734             this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
1735             this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeoutDuration());
1736             this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
1737             this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
1738         }
1739     }
1740     /**
1741      * Sets the configuration.
1742      *
1743      * @param conf the new configuration to use. This is used by value.
1744      *
1745      * @see GenericKeyedObjectPoolConfig
1746      */
1747     public void setConfig(final GenericKeyedObjectPoolConfig<T> conf) {
1748         super.setConfig(conf);
1749         setMaxIdlePerKey(conf.getMaxIdlePerKey());
1750         setMaxTotalPerKey(conf.getMaxTotalPerKey());
1751         setMaxTotal(conf.getMaxTotal());
1752         setMinIdlePerKey(conf.getMinIdlePerKey());
1753     }
1754     /**
1755      * Sets the cap on the number of "idle" instances per key in the pool.
1756      * If maxIdlePerKey is set too low on heavily loaded systems it is possible
1757      * you will see objects being destroyed and almost immediately new objects
1758      * being created. This is a result of the active threads momentarily
1759      * returning objects faster than they are requesting them, causing the
1760      * number of idle objects to rise above maxIdlePerKey. The best value for
1761      * maxIdlePerKey for heavily loaded system will vary but the default is a
1762      * good starting point.
1763      *
1764      * @param maxIdlePerKey the maximum number of "idle" instances that can be
1765      *                      held in a given keyed sub-pool. Use a negative value
1766      *                      for no limit
1767      *
1768      * @see #getMaxIdlePerKey
1769      */
1770     public void setMaxIdlePerKey(final int maxIdlePerKey) {
1771         this.maxIdlePerKey = maxIdlePerKey;
1772     }
1773     /**
1774      * Sets the limit on the number of object instances allocated by the pool
1775      * (checked out or idle), per key. When the limit is reached, the sub-pool
1776      * is said to be exhausted. A negative value indicates no limit.
1777      *
1778      * @param maxTotalPerKey the limit on the number of active instances per key
1779      *
1780      * @see #getMaxTotalPerKey
1781      */
1782     public void setMaxTotalPerKey(final int maxTotalPerKey) {
1783         this.maxTotalPerKey = maxTotalPerKey;
1784     }
1785     /**
1786      * Sets the target for the minimum number of idle objects to maintain in
1787      * each of the keyed sub-pools. This setting only has an effect if it is
1788      * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than
1789      * zero. If this is the case, an attempt is made to ensure that each
1790      * sub-pool has the required minimum number of instances during idle object
1791      * eviction runs.
1792      * <p>
1793      * If the configured value of minIdlePerKey is greater than the configured
1794      * value for maxIdlePerKey then the value of maxIdlePerKey will be used
1795      * instead.
1796      *
1797      * @param minIdlePerKey The minimum size of the each keyed pool
1798      *
1799      * @see #getMinIdlePerKey
1800      * @see #getMaxIdlePerKey()
1801      * @see #setTimeBetweenEvictionRunsMillis
1802      */
1803     public void setMinIdlePerKey(final int minIdlePerKey) {
1804         this.minIdlePerKey = minIdlePerKey;
1805     }
1806 
1807     @Override
1808     protected void toStringAppendFields(final StringBuilder builder) {
1809         super.toStringAppendFields(builder);
1810         builder.append(", maxIdlePerKey=");
1811         builder.append(maxIdlePerKey);
1812         builder.append(", minIdlePerKey=");
1813         builder.append(minIdlePerKey);
1814         builder.append(", maxTotalPerKey=");
1815         builder.append(maxTotalPerKey);
1816         builder.append(", factory=");
1817         builder.append(factory);
1818         builder.append(", fairness=");
1819         builder.append(fairness);
1820         builder.append(", poolMap=");
1821         builder.append(poolMap);
1822         builder.append(", poolKeyList=");
1823         builder.append(poolKeyList);
1824         builder.append(", keyLock=");
1825         builder.append(keyLock);
1826         builder.append(", numTotal=");
1827         builder.append(numTotal);
1828         builder.append(", evictionKeyIterator=");
1829         builder.append(evictionKeyIterator);
1830         builder.append(", evictionKey=");
1831         builder.append(evictionKey);
1832         builder.append(", abandonedConfig=");
1833         builder.append(abandonedConfig);
1834     }
1835 
1836     /**
1837      * Whether there is at least one thread waiting on this deque, add an pool object.
1838      * @param key pool key.
1839      * @param idleObjects list of idle pool objects.
1840      */
1841     private void whenWaitersAddObject(final K key, final LinkedBlockingDeque<PooledObject<T>> idleObjects) {
1842         if (idleObjects.hasTakeWaiters()) {
1843             try {
1844                 addObject(key);
1845             } catch (final Exception e) {
1846                 swallowException(e);
1847             }
1848         }
1849     }
1850 
1851     /**
1852      * @since 2.10.0
1853      */
1854     @Override
1855     public void use(final T pooledObject) {
1856         final AbandonedConfig abandonedCfg = this.abandonedConfig;
1857         if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) {
1858             poolMap.values().stream()
1859                 .map(pool -> pool.getAllObjects().get(new IdentityWrapper<>(pooledObject)))
1860                 .filter(Objects::nonNull)
1861                 .findFirst()
1862                 .ifPresent(PooledObject::use);
1863         }
1864     }
1865 
1866 }