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