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