    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.pool2.impl;
    018
    019import java.time.Duration;
    020import java.util.ArrayList;
    021import java.util.HashSet;
    022import java.util.Iterator;
    023import java.util.Map;
    024import java.util.NoSuchElementException;
    025import java.util.Set;
    026import java.util.concurrent.ConcurrentHashMap;
    027import java.util.concurrent.atomic.AtomicLong;
    028
    029import org.apache.commons.pool2.DestroyMode;
    030import org.apache.commons.pool2.ObjectPool;
    031import org.apache.commons.pool2.PoolUtils;
    032import org.apache.commons.pool2.PooledObject;
    033import org.apache.commons.pool2.PooledObjectFactory;
    034import org.apache.commons.pool2.PooledObjectState;
    035import org.apache.commons.pool2.SwallowedExceptionListener;
    036import org.apache.commons.pool2.TrackedUse;
    037import org.apache.commons.pool2.UsageTracking;
    038
    039/**
    040 * A configurable {@link ObjectPool} implementation.
    041 * <p>
    042 * When coupled with the appropriate {@link PooledObjectFactory},
    043 * {@code GenericObjectPool} provides robust pooling functionality for
    044 * arbitrary objects.
    045 * </p>
    046 * <p>
    047 * Optionally, one may configure the pool to examine and possibly evict objects
    048 * as they sit idle in the pool and to ensure that a minimum number of idle
    049 * objects are available. This is performed by an "idle object eviction" thread,
    050 * which runs asynchronously. Caution should be used when configuring this
    051 * optional feature. Eviction runs contend with client threads for access to
    052 * objects in the pool, so if they run too frequently performance issues may
    053 * result.
    054 * </p>
    055 * <p>
    056 * The pool can also be configured to detect and remove "abandoned" objects,
    057 * i.e. objects that have been checked out of the pool but neither used nor
    058 * returned before the configured
    059 * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}.
    060 * Abandoned object removal can be configured to happen when
    061 * {@code borrowObject} is invoked and the pool is close to starvation, or
    062 * it can be executed by the idle object evictor, or both. If pooled objects
    063 * implement the {@link TrackedUse} interface, their last use will be queried
    064 * using the {@code getLastUsed} method on that interface; otherwise
    065 * abandonment is determined by how long an object has been checked out from
    066 * the pool.
    067 * </p>
    068 * <p>
    069 * Implementation note: To prevent possible deadlocks, care has been taken to
    070 * ensure that no call to a factory method will occur within a synchronization
    071 * block. See POOL-125 and DBCP-44 for more information.
    072 * </p>
    073 * <p>
    074 * This class is intended to be thread-safe.
    075 * </p>
    076 *
    077 * @see GenericKeyedObjectPool
    078 *
    079 * @param <T> Type of element pooled in this pool.
    080 *
    081 * @since 2.0
    082 */
    083public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
    084        implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
    085
    086    private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(Integer.MAX_VALUE);
    087
    088    // JMX specific attributes
    089    private static final String ONAME_BASE =
    090        "org.apache.commons.pool2:type=GenericObjectPool,name=";
    091
    092    private volatile String factoryType = null;
    093
    094    private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
    095
    096    private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
    097
    098    private final PooledObjectFactory<T> factory;
    099
    100    /*
    101     * All of the objects currently associated with this pool in any state. It
    102     * excludes objects that have been destroyed. The size of
    103     * {@link #allObjects} will always be less than or equal to {@link
    104     * #_maxActive}. Map keys are pooled objects, values are the PooledObject
    105     * wrappers used internally by the pool.
    106     */
    107    private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
    108        new ConcurrentHashMap<>();
    109
    110    /*
    111     * The combined count of the currently created objects and those in the
    112     * process of being created. Under load, it may exceed {@link #_maxActive}
    113     * if multiple threads try and create a new object at the same time but
    114     * {@link #create()} will ensure that there are never more than
    115     * {@link #_maxActive} objects created at any one time.
    116     */
    117    private final AtomicLong createCount = new AtomicLong(0);
    118
    119    private long makeObjectCount;
    120
    121    private final Object makeObjectCountLock = new Object();
    122
    123    private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
    124
    125    // Additional configuration properties for abandoned object tracking
    126    private volatile AbandonedConfig abandonedConfig;
    127
    128    /**
    129     * Creates a new {@code GenericObjectPool} using defaults from
    130     * {@link GenericObjectPoolConfig}.
    131     *
    132     * @param factory The object factory to be used to create object instances
    133     *                used by this pool
    134     */
    135    public GenericObjectPool(final PooledObjectFactory<T> factory) {
    136        this(factory, new GenericObjectPoolConfig<>());
    137    }
    138
    139    /**
    140     * Creates a new {@code GenericObjectPool} using a specific
    141     * configuration.
    142     *
    143     * @param factory   The object factory to be used to create object instances
    144     *                  used by this pool
    145     * @param config    The configuration to use for this pool instance. The
    146     *                  configuration is used by value. Subsequent changes to
    147     *                  the configuration object will not be reflected in the
    148     *                  pool.
    149     */
    150    public GenericObjectPool(final PooledObjectFactory<T> factory,
    151            final GenericObjectPoolConfig<T> config) {
    152
    153        super(config, ONAME_BASE, config.getJmxNamePrefix());
    154
    155        if (factory == null) {
    156            jmxUnregister(); // tidy up
    157            throw new IllegalArgumentException("factory may not be null");
    158        }
    159        this.factory = factory;
    160
    161        idleObjects = new LinkedBlockingDeque<>(config.getFairness());
    162
    163        setConfig(config);
    164    }
    165
    166    /**
    167     * Creates a new {@code GenericObjectPool} that tracks and destroys
    168     * objects that are checked out, but never returned to the pool.
    169     *
    170     * @param factory   The object factory to be used to create object instances
    171     *                  used by this pool
    172     * @param config    The base pool configuration to use for this pool instance.
    173     *                  The configuration is used by value. Subsequent changes to
    174     *                  the configuration object will not be reflected in the
    175     *                  pool.
    176     * @param abandonedConfig  Configuration for abandoned object identification
    177     *                         and removal.  The configuration is used by value.
    178     */
    179    public GenericObjectPool(final PooledObjectFactory<T> factory,
    180            final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
    181        this(factory, config);
    182        setAbandonedConfig(abandonedConfig);
    183    }
    184
    185    /**
    186     * Adds the provided wrapped pooled object to the set of idle objects for
    187     * this pool. The object must already be part of the pool.  If {@code p}
    188     * is null, this is a no-op (no exception, but no impact on the pool).
    189     *
    190     * @param p The object to make idle
    191     *
    192     * @throws Exception If the factory fails to passivate the object
    193     */
    194    private void addIdleObject(final PooledObject<T> p) throws Exception {
    195        if (p != null) {
    196            factory.passivateObject(p);
    197            if (getLifo()) {
    198                idleObjects.addFirst(p);
    199            } else {
    200                idleObjects.addLast(p);
    201            }
    202        }
    203    }
    204
    205    /**
    206     * Creates an object, and place it into the pool. addObject() is useful for
    207     * "pre-loading" a pool with idle objects.
    208     * <p>
    209     * If there is no capacity available to add to the pool, this is a no-op
    210     * (no exception, no impact to the pool). </p>
    211     */
    212    @Override
    213    public void addObject() throws Exception {
    214        assertOpen();
    215        if (factory == null) {
    216            throw new IllegalStateException(
    217                    "Cannot add objects without a factory.");
    218        }
    219        final PooledObject<T> p = create();
    220        addIdleObject(p);
    221    }
    222
    223    /**
    224     * Equivalent to <code>{@link #borrowObject(long)
    225     * borrowObject}({@link #getMaxWaitMillis()})</code>.
    226     * <p>
    227     * {@inheritDoc}
    228     * </p>
    229     */
    230    @Override
    231    public T borrowObject() throws Exception {
    232        return borrowObject(getMaxWaitMillis());
    233    }
    234
    235    /**
    236     * Borrows an object from the pool using the specific waiting time which only
    237     * applies if {@link #getBlockWhenExhausted()} is true.
    238     * <p>
    239     * If there is one or more idle instance available in the pool, then an
    240     * idle instance will be selected based on the value of {@link #getLifo()},
    241     * activated and returned. If activation fails, or {@link #getTestOnBorrow()
    242     * testOnBorrow} is set to {@code true} and validation fails, the
    243     * instance is destroyed and the next available instance is examined. This
    244     * continues until either a valid instance is returned or there are no more
    245     * idle instances available.
    246     * </p>
    247     * <p>
    248     * If there are no idle instances available in the pool, behavior depends on
    249     * the {@link #getMaxTotal() maxTotal}, (if applicable)
    250     * {@link #getBlockWhenExhausted()} and the value passed in to the
    251     * {@code borrowMaxWaitMillis} parameter. If the number of instances
    252     * checked out from the pool is less than {@code maxTotal,} a new
    253     * instance is created, activated and (if applicable) validated and returned
    254     * to the caller. If validation fails, a {@code NoSuchElementException}
    255     * is thrown.
    256     * </p>
    257     * <p>
    258     * If the pool is exhausted (no available idle instances and no capacity to
    259     * create new ones), this method will either block (if
    260     * {@link #getBlockWhenExhausted()} is true) or throw a
    261     * {@code NoSuchElementException} (if
    262     * {@link #getBlockWhenExhausted()} is false). The length of time that this
    263     * method will block when {@link #getBlockWhenExhausted()} is true is
    264     * determined by the value passed in to the {@code borrowMaxWaitMillis}
    265     * parameter.
    266     * </p>
    267     * <p>
    268     * When the pool is exhausted, multiple calling threads may be
    269     * simultaneously blocked waiting for instances to become available. A
    270     * "fairness" algorithm has been implemented to ensure that threads receive
    271     * available instances in request arrival order.
    272     * </p>
    273     *
    274     * @param borrowMaxWait The time to wait for an object
    275     *                            to become available
    276     *
    277     * @return object instance from the pool
    278     *
    279     * @throws NoSuchElementException if an instance cannot be returned
    280     *
    281     * @throws Exception if an object instance cannot be returned due to an
    282     *                   error
    283     * @since 2.10.0
    284     */
    285    public T borrowObject(final Duration borrowMaxWait) throws Exception {
    286        assertOpen();
    287
    288        final AbandonedConfig ac = this.abandonedConfig;
    289        if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) &&
    290                (getNumActive() > getMaxTotal() - 3)) {
    291            removeAbandoned(ac);
    292        }
    293
    294        PooledObject<T> p = null;
    295
    296        // Get local copy of current config so it is consistent for entire
    297        // method execution
    298        final boolean blockWhenExhausted = getBlockWhenExhausted();
    299
    300        boolean create;
    301        final long waitTimeMillis = System.currentTimeMillis();
    302
    303        while (p == null) {
    304            create = false;
    305            p = idleObjects.pollFirst();
    306            if (p == null) {
    307                p = create();
    308                if (p != null) {
    309                    create = true;
    310                }
    311            }
    312            if (blockWhenExhausted) {
    313                if (p == null) {
    314                    if (borrowMaxWait.isNegative()) {
    315                        p = idleObjects.takeFirst();
    316                    } else {
    317                        p = idleObjects.pollFirst(borrowMaxWait);
    318                    }
    319                }
    320                if (p == null) {
    321                    throw new NoSuchElementException("Timeout waiting for idle object");
    322                }
    323            } else if (p == null) {
    324                throw new NoSuchElementException("Pool exhausted");
    325            }
    326            if (!p.allocate()) {
    327                p = null;
    328            }
    329
    330            if (p != null) {
    331                try {
    332                    factory.activateObject(p);
    333                } catch (final Exception e) {
    334                    try {
    335                        destroy(p, DestroyMode.NORMAL);
    336                    } catch (final Exception e1) {
    337                        // Ignore - activation failure is more important
    338                    }
    339                    p = null;
    340                    if (create) {
    341                        final NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");
    342                        nsee.initCause(e);
    343                        throw nsee;
    344                    }
    345                }
    346                if (p != null && getTestOnBorrow()) {
    347                    boolean validate = false;
    348                    Throwable validationThrowable = null;
    349                    try {
    350                        validate = factory.validateObject(p);
    351                    } catch (final Throwable t) {
    352                        PoolUtils.checkRethrow(t);
    353                        validationThrowable = t;
    354                    }
    355                    if (!validate) {
    356                        try {
    357                            destroy(p, DestroyMode.NORMAL);
    358                            destroyedByBorrowValidationCount.incrementAndGet();
    359                        } catch (final Exception e) {
    360                            // Ignore - validation failure is more important
    361                        }
    362                        p = null;
    363                        if (create) {
    364                            final NoSuchElementException nsee = new NoSuchElementException("Unable to validate object");
    365                            nsee.initCause(validationThrowable);
    366                            throw nsee;
    367                        }
    368                    }
    369                }
    370            }
    371        }
    372
    373        updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis));
    374
    375        return p.getObject();
    376    }
    377
    378    /**
    379     * Borrows an object from the pool using the specific waiting time which only
    380     * applies if {@link #getBlockWhenExhausted()} is true.
    381     * <p>
    382     * If there is one or more idle instance available in the pool, then an
    383     * idle instance will be selected based on the value of {@link #getLifo()},
    384     * activated and returned. If activation fails, or {@link #getTestOnBorrow()
    385     * testOnBorrow} is set to {@code true} and validation fails, the
    386     * instance is destroyed and the next available instance is examined. This
    387     * continues until either a valid instance is returned or there are no more
    388     * idle instances available.
    389     * </p>
    390     * <p>
    391     * If there are no idle instances available in the pool, behavior depends on
    392     * the {@link #getMaxTotal() maxTotal}, (if applicable)
    393     * {@link #getBlockWhenExhausted()} and the value passed in to the
    394     * {@code borrowMaxWaitMillis} parameter. If the number of instances
    395     * checked out from the pool is less than {@code maxTotal,} a new
    396     * instance is created, activated and (if applicable) validated and returned
    397     * to the caller. If validation fails, a {@code NoSuchElementException}
    398     * is thrown.
    399     * </p>
    400     * <p>
    401     * If the pool is exhausted (no available idle instances and no capacity to
    402     * create new ones), this method will either block (if
    403     * {@link #getBlockWhenExhausted()} is true) or throw a
    404     * {@code NoSuchElementException} (if
    405     * {@link #getBlockWhenExhausted()} is false). The length of time that this
    406     * method will block when {@link #getBlockWhenExhausted()} is true is
    407     * determined by the value passed in to the {@code borrowMaxWaitMillis}
    408     * parameter.
    409     * </p>
    410     * <p>
    411     * When the pool is exhausted, multiple calling threads may be
    412     * simultaneously blocked waiting for instances to become available. A
    413     * "fairness" algorithm has been implemented to ensure that threads receive
    414     * available instances in request arrival order.
    415     * </p>
    416     *
    417     * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
    418     *                            to become available
    419     *
    420     * @return object instance from the pool
    421     *
    422     * @throws NoSuchElementException if an instance cannot be returned
    423     *
    424     * @throws Exception if an object instance cannot be returned due to an
    425     *                   error
    426     */
    427    public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
    428        return borrowObject(Duration.ofMillis(borrowMaxWaitMillis));
    429    }
    430
    431    /**
    432     * Clears any objects sitting idle in the pool by removing them from the
    433     * idle instance pool and then invoking the configured
    434     * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each
    435     * idle instance.
    436     * <p>
    437     * Implementation notes:
    438     * </p>
    439     * <ul>
    440     * <li>This method does not destroy or effect in any way instances that are
    441     * checked out of the pool when it is invoked.</li>
    442     * <li>Invoking this method does not prevent objects being returned to the
    443     * idle instance pool, even during its execution. Additional instances may
    444     * be returned while removed items are being destroyed.</li>
    445     * <li>Exceptions encountered destroying idle instances are swallowed
    446     * but notified via a {@link SwallowedExceptionListener}.</li>
    447     * </ul>
    448     */
    449    @Override
    450    public void clear() {
    451        PooledObject<T> p = idleObjects.poll();
    452
    453        while (p != null) {
    454            try {
    455                destroy(p, DestroyMode.NORMAL);
    456            } catch (final Exception e) {
    457                swallowException(e);
    458            }
    459            p = idleObjects.poll();
    460        }
    461    }
    462
    463    /**
    464     * Closes the pool. Once the pool is closed, {@link #borrowObject()} will
    465     * fail with IllegalStateException, but {@link #returnObject(Object)} and
    466     * {@link #invalidateObject(Object)} will continue to work, with returned
    467     * objects destroyed on return.
    468     * <p>
    469     * Destroys idle instances in the pool by invoking {@link #clear()}.
    470     * </p>
    471     */
    472    @Override
    473    public void close() {
    474        if (isClosed()) {
    475            return;
    476        }
    477
    478        synchronized (closeLock) {
    479            if (isClosed()) {
    480                return;
    481            }
    482
    483            // Stop the evictor before the pool is closed since evict() calls
    484            // assertOpen()
    485            stopEvictor();
    486
    487            closed = true;
    488            // This clear removes any idle objects
    489            clear();
    490
    491            jmxUnregister();
    492
    493            // Release any threads that were waiting for an object
    494            idleObjects.interuptTakeWaiters();
    495        }
    496    }
    497
    498    /**
    499     * Attempts to create a new wrapped pooled object.
    500     * <p>
    501     * If there are {@link #getMaxTotal()} objects already in circulation
    502     * or in process of being created, this method returns null.
    503     * </p>
    504     *
    505     * @return The new wrapped pooled object
    506     *
    507     * @throws Exception if the object factory's {@code makeObject} fails
    508     */
    509    private PooledObject<T> create() throws Exception {
    510        int localMaxTotal = getMaxTotal();
    511        // This simplifies the code later in this method
    512        if (localMaxTotal < 0) {
    513            localMaxTotal = Integer.MAX_VALUE;
    514        }
    515
    516        final long localStartTimeMillis = System.currentTimeMillis();
    517        final long localMaxWaitTimeMillis = Math.max(getMaxWaitMillis(), 0);
    518
    519        // Flag that indicates if create should:
    520        // - TRUE:  call the factory to create an object
    521        // - FALSE: return null
    522        // - null:  loop and re-test the condition that determines whether to
    523        //          call the factory
    524        Boolean create = null;
    525        while (create == null) {
    526            synchronized (makeObjectCountLock) {
    527                final long newCreateCount = createCount.incrementAndGet();
    528                if (newCreateCount > localMaxTotal) {
    529                    // The pool is currently at capacity or in the process of
    530                    // making enough new objects to take it to capacity.
    531                    createCount.decrementAndGet();
    532                    if (makeObjectCount == 0) {
    533                        // There are no makeObject() calls in progress so the
    534                        // pool is at capacity. Do not attempt to create a new
    535                        // object. Return and wait for an object to be returned
    536                        create = Boolean.FALSE;
    537                    } else {
    538                        // There are makeObject() calls in progress that might
    539                        // bring the pool to capacity. Those calls might also
    540                        // fail so wait until they complete and then re-test if
    541                        // the pool is at capacity or not.
    542                        makeObjectCountLock.wait(localMaxWaitTimeMillis);
    543                    }
    544                } else {
    545                    // The pool is not at capacity. Create a new object.
    546                    makeObjectCount++;
    547                    create = Boolean.TRUE;
    548                }
    549            }
    550
    551            // Do not block more if maxWaitTimeMillis is set.
    552            if (create == null &&
    553                (localMaxWaitTimeMillis > 0 &&
    554                 System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) {
    555                create = Boolean.FALSE;
    556            }
    557        }
    558
    559        if (!create.booleanValue()) {
    560            return null;
    561        }
    562
    563        final PooledObject<T> p;
    564        try {
    565            p = factory.makeObject();
    566            if (getTestOnCreate() && !factory.validateObject(p)) {
    567                createCount.decrementAndGet();
    568                return null;
    569            }
    570        } catch (final Throwable e) {
    571            createCount.decrementAndGet();
    572            throw e;
    573        } finally {
    574            synchronized (makeObjectCountLock) {
    575                makeObjectCount--;
    576                makeObjectCountLock.notifyAll();
    577            }
    578        }
    579
    580        final AbandonedConfig ac = this.abandonedConfig;
    581        if (ac != null && ac.getLogAbandoned()) {
    582            p.setLogAbandoned(true);
    583            p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
    584        }
    585
    586        createdCount.incrementAndGet();
    587        allObjects.put(new IdentityWrapper<>(p.getObject()), p);
    588        return p;
    589    }
    590
    591    /**
    592     * Destroys a wrapped pooled object.
    593     *
    594     * @param toDestroy The wrapped pooled object to destroy
    595     * @param mode DestroyMode context provided to the factory
    596     *
    597     * @throws Exception If the factory fails to destroy the pooled object
    598     *                   cleanly
    599     */
    600    private void destroy(final PooledObject<T> toDestroy, final DestroyMode mode) throws Exception {
    601        toDestroy.invalidate();
    602        idleObjects.remove(toDestroy);
    603        allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
    604        try {
    605            factory.destroyObject(toDestroy, mode);
    606        } finally {
    607            destroyedCount.incrementAndGet();
    608            createCount.decrementAndGet();
    609        }
    610    }
    611
    612    /**
    613     * Tries to ensure that {@code idleCount} idle instances exist in the pool.
    614     * <p>
    615     * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount}
    616     * or the total number of objects (idle, checked out, or being created) reaches
    617     * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless
    618     * there are threads waiting to check out instances from the pool.
    619     * </p>
    620     *
    621     * @param idleCount the number of idle instances desired
    622     * @param always true means create instances even if the pool has no threads waiting
    623     * @throws Exception if the factory's makeObject throws
    624     */
    625    private void ensureIdle(final int idleCount, final boolean always) throws Exception {
    626        if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
    627            return;
    628        }
    629
    630        while (idleObjects.size() < idleCount) {
    631            final PooledObject<T> p = create();
    632            if (p == null) {
    633                // Can't create objects, no reason to think another call to
    634                // create will work. Give up.
    635                break;
    636            }
    637            if (getLifo()) {
    638                idleObjects.addFirst(p);
    639            } else {
    640                idleObjects.addLast(p);
    641            }
    642        }
    643        if (isClosed()) {
    644            // Pool closed while object was being added to idle objects.
    645            // Make sure the returned object is destroyed rather than left
    646            // in the idle object pool (which would effectively be a leak)
    647            clear();
    648        }
    649    }
    650
    651    @Override
    652    void ensureMinIdle() throws Exception {
    653        ensureIdle(getMinIdle(), true);
    654    }
    655
    656    /**
    657     * {@inheritDoc}
    658     * <p>
    659     * Successive activations of this method examine objects in sequence,
    660     * cycling through objects in oldest-to-youngest order.
    661     * </p>
    662     */
    663    @Override
    664    public void evict() throws Exception {
    665        assertOpen();
    666
    667        if (!idleObjects.isEmpty()) {
    668
    669            PooledObject<T> underTest = null;
    670            final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
    671
    672            synchronized (evictionLock) {
    673                final EvictionConfig evictionConfig = new EvictionConfig(
    674                        getMinEvictableIdleTime(),
    675                        getSoftMinEvictableIdleTime(),
    676                        getMinIdle());
    677
    678                final boolean testWhileIdle = getTestWhileIdle();
    679
    680                for (int i = 0, m = getNumTests(); i < m; i++) {
    681                    if (evictionIterator == null || !evictionIterator.hasNext()) {
    682                        evictionIterator = new EvictionIterator(idleObjects);
    683                    }
    684                    if (!evictionIterator.hasNext()) {
    685                        // Pool exhausted, nothing to do here
    686                        return;
    687                    }
    688
    689                    try {
    690                        underTest = evictionIterator.next();
    691                    } catch (final NoSuchElementException nsee) {
    692                        // Object was borrowed in another thread
    693                        // Don't count this as an eviction test so reduce i;
    694                        i--;
    695                        evictionIterator = null;
    696                        continue;
    697                    }
    698
    699                    if (!underTest.startEvictionTest()) {
    700                        // Object was borrowed in another thread
    701                        // Don't count this as an eviction test so reduce i;
    702                        i--;
    703                        continue;
    704                    }
    705
    706                    // User provided eviction policy could throw all sorts of
    707                    // crazy exceptions. Protect against such an exception
    708                    // killing the eviction thread.
    709                    boolean evict;
    710                    try {
    711                        evict = evictionPolicy.evict(evictionConfig, underTest,
    712                                idleObjects.size());
    713                    } catch (final Throwable t) {
    714                        // Slightly convoluted as SwallowedExceptionListener
    715                        // uses Exception rather than Throwable
    716                        PoolUtils.checkRethrow(t);
    717                        swallowException(new Exception(t));
    718                        // Don't evict on error conditions
    719                        evict = false;
    720                    }
    721
    722                    if (evict) {
    723                        destroy(underTest, DestroyMode.NORMAL);
    724                        destroyedByEvictorCount.incrementAndGet();
    725                    } else {
    726                        if (testWhileIdle) {
    727                            boolean active = false;
    728                            try {
    729                                factory.activateObject(underTest);
    730                                active = true;
    731                            } catch (final Exception e) {
    732                                destroy(underTest, DestroyMode.NORMAL);
    733                                destroyedByEvictorCount.incrementAndGet();
    734                            }
    735                            if (active) {
    736                                if (!factory.validateObject(underTest)) {
    737                                    destroy(underTest, DestroyMode.NORMAL);
    738                                    destroyedByEvictorCount.incrementAndGet();
    739                                } else {
    740                                    try {
    741                                        factory.passivateObject(underTest);
    742                                    } catch (final Exception e) {
    743                                        destroy(underTest, DestroyMode.NORMAL);
    744                                        destroyedByEvictorCount.incrementAndGet();
    745                                    }
    746                                }
    747                            }
    748                        }
    749                        if (!underTest.endEvictionTest(idleObjects)) {
    750                            // TODO - May need to add code here once additional
    751                            // states are used
    752                        }
    753                    }
    754                }
    755            }
    756        }
    757        final AbandonedConfig ac = this.abandonedConfig;
    758        if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
    759            removeAbandoned(ac);
    760        }
    761    }
    762
    763    /**
    764     * Gets a reference to the factory used to create, destroy and validate
    765     * the objects used by this pool.
    766     *
    767     * @return the factory
    768     */
    769    public PooledObjectFactory<T> getFactory() {
    770        return factory;
    771    }
    772
    773    /**
    774     * Gets the type - including the specific type rather than the generic -
    775     * of the factory.
    776     *
    777     * @return A string representation of the factory type
    778     */
    779    @Override
    780    public String getFactoryType() {
    781        // Not thread safe. Accept that there may be multiple evaluations.
    782        if (factoryType == null) {
    783            final StringBuilder result = new StringBuilder();
    784            result.append(factory.getClass().getName());
    785            result.append('<');
    786            final Class<?> pooledObjectType =
    787                    PoolImplUtils.getFactoryType(factory.getClass());
    788            result.append(pooledObjectType.getName());
    789            result.append('>');
    790            factoryType = result.toString();
    791        }
    792        return factoryType;
    793    }
    794
    795    /**
    796     * Gets whether this pool identifies and logs any abandoned objects.
    797     *
    798     * @return {@code true} if abandoned object removal is configured for this
    799     *         pool and removal events are to be logged otherwise {@code false}
    800     *
    801     * @see AbandonedConfig#getLogAbandoned()
    802     */
    803    @Override
    804    public boolean getLogAbandoned() {
    805        final AbandonedConfig ac = this.abandonedConfig;
    806        return ac != null && ac.getLogAbandoned();
    807    }
    808
    809    /**
    810     * Gets the cap on the number of "idle" instances in the pool. If maxIdle
    811     * is set too low on heavily loaded systems it is possible you will see
    812     * objects being destroyed and almost immediately new objects being created.
    813     * This is a result of the active threads momentarily returning objects
    814     * faster than they are requesting them, causing the number of idle
    815     * objects to rise above maxIdle. The best value for maxIdle for heavily
    816     * loaded system will vary but the default is a good starting point.
    817     *
    818     * @return the maximum number of "idle" instances that can be held in the
    819     *         pool or a negative value if there is no limit
    820     *
    821     * @see #setMaxIdle
    822     */
    823    @Override
    824    public int getMaxIdle() {
    825        return maxIdle;
    826    }
    827
    828    /**
    829     * Gets the target for the minimum number of idle objects to maintain in
    830     * the pool. This setting only has an effect if it is positive and
    831     * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
    832     * is the case, an attempt is made to ensure that the pool has the required
    833     * minimum number of instances during idle object eviction runs.
    834     * <p>
    835     * If the configured value of minIdle is greater than the configured value
    836     * for maxIdle then the value of maxIdle will be used instead.
    837     * </p>
    838     *
    839     * @return The minimum number of objects.
    840     *
    841     * @see #setMinIdle(int)
    842     * @see #setMaxIdle(int)
    843     * @see #setTimeBetweenEvictionRunsMillis(long)
    844     */
    845    @Override
    846    public int getMinIdle() {
    847        final int maxIdleSave = getMaxIdle();
    848        if (this.minIdle > maxIdleSave) {
    849            return maxIdleSave;
    850        }
    851        return minIdle;
    852    }
    853
    854    @Override
    855    public int getNumActive() {
    856        return allObjects.size() - idleObjects.size();
    857    }
    858
    859    @Override
    860    public int getNumIdle() {
    861        return idleObjects.size();
    862    }
    863
    864    /**
    865     * Calculates the number of objects to test in a run of the idle object
    866     * evictor.
    867     *
    868     * @return The number of objects to test for validity
    869     */
    870    private int getNumTests() {
    871        final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
    872        if (numTestsPerEvictionRun >= 0) {
    873            return Math.min(numTestsPerEvictionRun, idleObjects.size());
    874        }
    875        return (int) (Math.ceil(idleObjects.size() /
    876                Math.abs((double) numTestsPerEvictionRun)));
    877    }
    878
    879    /**
    880     * Gets an estimate of the number of threads currently blocked waiting for
    881     * an object from the pool. This is intended for monitoring only, not for
    882     * synchronization control.
    883     *
    884     * @return The estimate of the number of threads currently blocked waiting
    885     *         for an object from the pool
    886     */
    887    @Override
    888    public int getNumWaiters() {
    889        if (getBlockWhenExhausted()) {
    890            return idleObjects.getTakeQueueLength();
    891        }
    892        return 0;
    893    }
    894
    895    /**
    896     * Gets whether a check is made for abandoned objects when an object is borrowed
    897     * from this pool.
    898     *
    899     * @return {@code true} if abandoned object removal is configured to be
    900     *         activated by borrowObject otherwise {@code false}
    901     *
    902     * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
    903     */
    904    @Override
    905    public boolean getRemoveAbandonedOnBorrow() {
    906        final AbandonedConfig ac = this.abandonedConfig;
    907        return ac != null && ac.getRemoveAbandonedOnBorrow();
    908    }
    909
    910
    911    //--- Usage tracking support -----------------------------------------------
    912
    913    /**
    914     * Gets whether a check is made for abandoned objects when the evictor runs.
    915     *
    916     * @return {@code true} if abandoned object removal is configured to be
    917     *         activated when the evictor runs otherwise {@code false}
    918     *
    919     * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
    920     */
    921    @Override
    922    public boolean getRemoveAbandonedOnMaintenance() {
    923        final AbandonedConfig ac = this.abandonedConfig;
    924        return ac != null && ac.getRemoveAbandonedOnMaintenance();
    925    }
    926
    927
    928    //--- JMX support ----------------------------------------------------------
    929
    930    /**
    931     * Gets the timeout before which an object will be considered to be
    932     * abandoned by this pool.
    933     *
    934     * @return The abandoned object timeout in seconds if abandoned object
    935     *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
    936     *
    937     * @see AbandonedConfig#getRemoveAbandonedTimeout()
    938     * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
    939     * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
    940     */
    941    @Override
    942    @Deprecated
    943    public int getRemoveAbandonedTimeout() {
    944        final AbandonedConfig ac = this.abandonedConfig;
    945        return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
    946    }
    947
    948    /**
    949     * Gets the timeout before which an object will be considered to be
    950     * abandoned by this pool.
    951     *
    952     * @return The abandoned object timeout in seconds if abandoned object
    953     *         removal is configured for this pool; Integer.MAX_VALUE otherwise.
    954     *
    955     * @see AbandonedConfig#getRemoveAbandonedTimeout()
    956     * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration()
    957     */
    958    public Duration getRemoveAbandonedTimeoutDuration() {
    959        final AbandonedConfig ac = this.abandonedConfig;
    960        return ac != null ? ac.getRemoveAbandonedTimeoutDuration() : DEFAULT_REMOVE_ABANDONED_TIMEOUT;
    961    }
    962
    963    /**
    964     * {@inheritDoc}
    965     * <p>
    966     * Activation of this method decrements the active count and attempts to
    967     * destroy the instance, using the default (NORMAL) {@link DestroyMode}.
    968     * </p>
    969     *
    970     * @throws Exception             if an exception occurs destroying the
    971     *                               object
    972     * @throws IllegalStateException if obj does not belong to this pool
    973     */
    974    @Override
    975    public void invalidateObject(final T obj) throws Exception {
    976        invalidateObject(obj, DestroyMode.NORMAL);
    977    }
    978
    979    /**
    980     * {@inheritDoc}
    981     * <p>
    982     * Activation of this method decrements the active count and attempts to
    983     * destroy the instance, using the provided {@link DestroyMode}.
    984     * </p>
    985     *
    986     * @throws Exception             if an exception occurs destroying the
    987     *                               object
    988     * @throws IllegalStateException if obj does not belong to this pool
    989     * @since 2.9.0
    990     */
    991    @Override
    992    public void invalidateObject(final T obj, final DestroyMode mode) throws Exception {
    993        final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
    994        if (p == null) {
    995            if (isAbandonedConfig()) {
    996                return;
    997            }
    998            throw new IllegalStateException(
    999                    "Invalidated object not currently part of this pool");
    1000        }
    1001        synchronized (p) {
    1002            if (p.getState() != PooledObjectState.INVALID) {
    1003                destroy(p, mode);
    1004            }
    1005        }
    1006        ensureIdle(1, false);
    1007    }
    1008
    1009    // --- configuration attributes --------------------------------------------
    1010
    1011    /**
    1012     * Gets whether or not abandoned object removal is configured for this pool.
    1013     *
    1014     * @return true if this pool is configured to detect and remove
    1015     * abandoned objects
    1016     */
    1017    @Override
    1018    public boolean isAbandonedConfig() {
    1019        return abandonedConfig != null;
    1020    }
    1021    /**
    1022     * Provides information on all the objects in the pool, both idle (waiting
    1023     * to be borrowed) and active (currently borrowed).
    1024     * <p>
    1025     * Note: This is named listAllObjects so it is presented as an operation via
    1026     * JMX. That means it won't be invoked unless the explicitly requested
    1027     * whereas all attributes will be automatically requested when viewing the
    1028     * attributes for an object in a tool like JConsole.
    1029     * </p>
    1030     *
    1031     * @return Information grouped on all the objects in the pool
    1032     */
    1033    @Override
    1034    public Set<DefaultPooledObjectInfo> listAllObjects() {
    1035        final Set<DefaultPooledObjectInfo> result =
    1036                new HashSet<>(allObjects.size());
    1037        for (final PooledObject<T> p : allObjects.values()) {
    1038            result.add(new DefaultPooledObjectInfo(p));
    1039        }
    1040        return result;
    1041    }
    1042    /**
    1043     * Tries to ensure that {@link #getMinIdle()} idle instances are available
    1044     * in the pool.
    1045     *
    1046     * @throws Exception If the associated factory throws an exception
    1047     * @since 2.4
    1048     */
    1049    public void preparePool() throws Exception {
    1050        if (getMinIdle() < 1) {
    1051            return;
    1052        }
    1053        ensureMinIdle();
    1054    }
    1055
    1056
    1057    // --- internal attributes -------------------------------------------------
    1058
    1059    /**
    1060     * Recovers abandoned objects which have been checked out but
    1061     * not used since longer than the removeAbandonedTimeout.
    1062     *
    1063     * @param abandonedConfig The configuration to use to identify abandoned objects
    1064     */
    1065    @SuppressWarnings("resource") // PrintWriter is managed elsewhere
    1066    private void removeAbandoned(final AbandonedConfig abandonedConfig) {
    1067        // Generate a list of abandoned objects to remove
    1068        final long nowMillis = System.currentTimeMillis();
    1069        final long timeoutMillis =
    1070                nowMillis - abandonedConfig.getRemoveAbandonedTimeoutDuration().toMillis();
    1071        final ArrayList<PooledObject<T>> remove = new ArrayList<>();
    1072        final Iterator<PooledObject<T>> it = allObjects.values().iterator();
    1073        while (it.hasNext()) {
    1074            final PooledObject<T> pooledObject = it.next();
    1075            synchronized (pooledObject) {
    1076                if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
    1077                        pooledObject.getLastUsedTime() <= timeoutMillis) {
    1078                    pooledObject.markAbandoned();
    1079                    remove.add(pooledObject);
    1080                }
    1081            }
    1082        }
    1083
    1084        // Now remove the abandoned objects
    1085        final Iterator<PooledObject<T>> itr = remove.iterator();
    1086        while (itr.hasNext()) {
    1087            final PooledObject<T> pooledObject = itr.next();
    1088            if (abandonedConfig.getLogAbandoned()) {
    1089                pooledObject.printStackTrace(abandonedConfig.getLogWriter());
    1090            }
    1091            try {
    1092                invalidateObject(pooledObject.getObject(), DestroyMode.ABANDONED);
    1093            } catch (final Exception e) {
    1094                e.printStackTrace();
    1095            }
    1096        }
    1097    }
    1098    /**
    1099     * {@inheritDoc}
    1100     * <p>
    1101     * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
    1102     * number of idle instances has reached this value, the returning instance
    1103     * is destroyed.
    1104     * </p>
    1105     * <p>
    1106     * If {@link #getTestOnReturn() testOnReturn} == true, the returning
    1107     * instance is validated before being returned to the idle instance pool. In
    1108     * this case, if validation fails, the instance is destroyed.
    1109     * </p>
    1110     * <p>
    1111     * Exceptions encountered destroying objects for any reason are swallowed
    1112     * but notified via a {@link SwallowedExceptionListener}.
    1113     * </p>
    1114     */
    1115    @Override
    1116    public void returnObject(final T obj) {
    1117        final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
    1118
    1119        if (p == null) {
    1120            if (!isAbandonedConfig()) {
    1121                throw new IllegalStateException(
    1122                        "Returned object not currently part of this pool");
    1123            }
    1124            return; // Object was abandoned and removed
    1125        }
    1126
    1127        markReturningState(p);
    1128
    1129        final Duration activeTime = p.getActiveTime();
    1130
    1131        if (getTestOnReturn() && !factory.validateObject(p)) {
    1132            try {
    1133                destroy(p, DestroyMode.NORMAL);
    1134            } catch (final Exception e) {
    1135                swallowException(e);
    1136            }
    1137            try {
    1138                ensureIdle(1, false);
    1139            } catch (final Exception e) {
    1140                swallowException(e);
    1141            }
    1142            updateStatsReturn(activeTime);
    1143            return;
    1144        }
    1145
    1146        try {
    1147            factory.passivateObject(p);
    1148        } catch (final Exception e1) {
    1149            swallowException(e1);
    1150            try {
    1151                destroy(p, DestroyMode.NORMAL);
    1152            } catch (final Exception e) {
    1153                swallowException(e);
    1154            }
    1155            try {
    1156                ensureIdle(1, false);
    1157            } catch (final Exception e) {
    1158                swallowException(e);
    1159            }
    1160            updateStatsReturn(activeTime);
    1161            return;
    1162        }
    1163
    1164        if (!p.deallocate()) {
    1165            throw new IllegalStateException(
    1166                    "Object has already been returned to this pool or is invalid");
    1167        }
    1168
    1169        final int maxIdleSave = getMaxIdle();
    1170        if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
    1171            try {
    1172                destroy(p, DestroyMode.NORMAL);
    1173            } catch (final Exception e) {
    1174                swallowException(e);
    1175            }
    1176            try {
    1177                ensureIdle(1, false);
    1178            } catch (final Exception e) {
    1179                swallowException(e);
    1180            }
    1181        } else {
    1182            if (getLifo()) {
    1183                idleObjects.addFirst(p);
    1184            } else {
    1185                idleObjects.addLast(p);
    1186            }
    1187            if (isClosed()) {
    1188                // Pool closed while object was being added to idle objects.
    1189                // Make sure the returned object is destroyed rather than left
    1190                // in the idle object pool (which would effectively be a leak)
    1191                clear();
    1192            }
    1193        }
    1194        updateStatsReturn(activeTime);
    1195    }
    1196    /**
    1197     * Sets the abandoned object removal configuration.
    1198     *
    1199     * @param abandonedConfig the new configuration to use. This is used by value.
    1200     *
    1201     * @see AbandonedConfig
    1202     */
    1203    @SuppressWarnings("resource") // PrintWriter is managed elsewhere
    1204    public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
    1205        if (abandonedConfig == null) {
    1206            this.abandonedConfig = null;
    1207        } else {
    1208            this.abandonedConfig = new AbandonedConfig();
    1209            this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
    1210            this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
    1211            this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
    1212            this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
    1213            this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeoutDuration());
    1214            this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
    1215            this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
    1216        }
    1217    }
    1218    /**
    1219     * Sets the base pool configuration.
    1220     *
    1221     * @param conf the new configuration to use. This is used by value.
    1222     *
    1223     * @see GenericObjectPoolConfig
    1224     */
    1225    public void setConfig(final GenericObjectPoolConfig<T> conf) {
    1226        super.setConfig(conf);
    1227        setMaxIdle(conf.getMaxIdle());
    1228        setMinIdle(conf.getMinIdle());
    1229        setMaxTotal(conf.getMaxTotal());
    1230    }
    1231    /**
    1232     * Sets the cap on the number of "idle" instances in the pool. If maxIdle
    1233     * is set too low on heavily loaded systems it is possible you will see
    1234     * objects being destroyed and almost immediately new objects being created.
    1235     * This is a result of the active threads momentarily returning objects
    1236     * faster than they are requesting them, causing the number of idle
    1237     * objects to rise above maxIdle. The best value for maxIdle for heavily
    1238     * loaded system will vary but the default is a good starting point.
    1239     *
    1240     * @param maxIdle
    1241     *            The cap on the number of "idle" instances in the pool. Use a
    1242     *            negative value to indicate an unlimited number of idle
    1243     *            instances
    1244     *
    1245     * @see #getMaxIdle
    1246     */
    1247    public void setMaxIdle(final int maxIdle) {
    1248        this.maxIdle = maxIdle;
    1249    }
    1250
    1251    /**
    1252     * Sets the target for the minimum number of idle objects to maintain in
    1253     * the pool. This setting only has an effect if it is positive and
    1254     * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
    1255     * is the case, an attempt is made to ensure that the pool has the required
    1256     * minimum number of instances during idle object eviction runs.
    1257     * <p>
    1258     * If the configured value of minIdle is greater than the configured value
    1259     * for maxIdle then the value of maxIdle will be used instead.
    1260     * </p>
    1261     *
    1262     * @param minIdle
    1263     *            The minimum number of objects.
    1264     *
    1265     * @see #getMinIdle()
    1266     * @see #getMaxIdle()
    1267     * @see #getTimeBetweenEvictionRunsMillis()
    1268     */
    1269    public void setMinIdle(final int minIdle) {
    1270        this.minIdle = minIdle;
    1271    }
    1272
    1273    @Override
    1274    protected void toStringAppendFields(final StringBuilder builder) {
    1275        super.toStringAppendFields(builder);
    1276        builder.append(", factoryType=");
    1277        builder.append(factoryType);
    1278        builder.append(", maxIdle=");
    1279        builder.append(maxIdle);
    1280        builder.append(", minIdle=");
    1281        builder.append(minIdle);
    1282        builder.append(", factory=");
    1283        builder.append(factory);
    1284        builder.append(", allObjects=");
    1285        builder.append(allObjects);
    1286        builder.append(", createCount=");
    1287        builder.append(createCount);
    1288        builder.append(", idleObjects=");
    1289        builder.append(idleObjects);
    1290        builder.append(", abandonedConfig=");
    1291        builder.append(abandonedConfig);
    1292    }
    1293
    1294    @Override
    1295    public void use(final T pooledObject) {
    1296        final AbandonedConfig abandonedCfg = this.abandonedConfig;
    1297        if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) {
    1298            final PooledObject<T> wrapper = allObjects.get(new IdentityWrapper<>(pooledObject));
    1299            wrapper.use();
    1300        }
    1301    }
    1302
    1303}