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