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