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