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