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