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 * https://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 * @param <T> Type of element pooled in this pool. 078 * @since 2.0 079 */ 080public class GenericObjectPool<T> extends BaseGenericObjectPool<T> 081 implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> { 082 083 // JMX specific attributes 084 private static final String ONAME_BASE = 085 "org.apache.commons.pool2:type=GenericObjectPool,name="; 086 087 private volatile String factoryType; 088 089 private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; 090 091 private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; 092 093 private final PooledObjectFactory<T> factory; 094 095 /* 096 * All of the objects currently associated with this pool in any state. It 097 * excludes objects that have been destroyed. The size of 098 * {@link #allObjects} will always be less than or equal to {@link 099 * #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 216 final int localMaxTotal = getMaxTotal(); 217 final int localMaxIdle = getMaxIdle(); 218 if (getNumIdle() < localMaxIdle && (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.interuptTakeWaiters(); 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}