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