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