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