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