    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}