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