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