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