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