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