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, borrowMaxWaitMillis=" + 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 @Override 373 String getStatsString() { 374 // Simply listed in AB order. 375 return super.getStatsString() + 376 String.format(", createdCount=%,d, makeObjectCount=%,d, maxIdle=%,d, minIdle=%,d", 377 createdCount.get(), makeObjectCount, maxIdle, minIdle); 378 } 379 380 /** 381 * Borrows an object from the pool using the specific waiting time which only 382 * applies if {@link #getBlockWhenExhausted()} is true. 383 * <p> 384 * If there is one or more idle instance available in the pool, then an 385 * idle instance will be selected based on the value of {@link #getLifo()}, 386 * activated and returned. If activation fails, or {@link #getTestOnBorrow() 387 * testOnBorrow} is set to {@code true} and validation fails, the 388 * instance is destroyed and the next available instance is examined. This 389 * continues until either a valid instance is returned or there are no more 390 * idle instances available. 391 * </p> 392 * <p> 393 * If there are no idle instances available in the pool, behavior depends on 394 * the {@link #getMaxTotal() maxTotal}, (if applicable) 395 * {@link #getBlockWhenExhausted()} and the value passed in to the 396 * {@code borrowMaxWaitMillis} parameter. If the number of instances 397 * checked out from the pool is less than {@code maxTotal,} a new 398 * instance is created, activated and (if applicable) validated and returned 399 * to the caller. If validation fails, a {@code NoSuchElementException} 400 * is thrown. 401 * </p> 402 * <p> 403 * If the pool is exhausted (no available idle instances and no capacity to 404 * create new ones), this method will either block (if 405 * {@link #getBlockWhenExhausted()} is true) or throw a 406 * {@code NoSuchElementException} (if 407 * {@link #getBlockWhenExhausted()} is false). The length of time that this 408 * method will block when {@link #getBlockWhenExhausted()} is true is 409 * determined by the value passed in to the {@code borrowMaxWaitMillis} 410 * parameter. 411 * </p> 412 * <p> 413 * When the pool is exhausted, multiple calling threads may be 414 * simultaneously blocked waiting for instances to become available. A 415 * "fairness" algorithm has been implemented to ensure that threads receive 416 * available instances in request arrival order. 417 * </p> 418 * 419 * @param borrowMaxWaitMillis The time to wait in milliseconds for an object 420 * to become available 421 * 422 * @return object instance from the pool 423 * 424 * @throws NoSuchElementException if an instance cannot be returned 425 * 426 * @throws Exception if an object instance cannot be returned due to an 427 * error 428 */ 429 public T borrowObject(final long borrowMaxWaitMillis) throws Exception { 430 return borrowObject(Duration.ofMillis(borrowMaxWaitMillis)); 431 } 432 433 /** 434 * Clears any objects sitting idle in the pool by removing them from the 435 * idle instance pool and then invoking the configured 436 * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each 437 * idle instance. 438 * <p> 439 * Implementation notes: 440 * </p> 441 * <ul> 442 * <li>This method does not destroy or effect in any way instances that are 443 * checked out of the pool when it is invoked.</li> 444 * <li>Invoking this method does not prevent objects being returned to the 445 * idle instance pool, even during its execution. Additional instances may 446 * be returned while removed items are being destroyed.</li> 447 * <li>Exceptions encountered destroying idle instances are swallowed 448 * but notified via a {@link SwallowedExceptionListener}.</li> 449 * </ul> 450 */ 451 @Override 452 public void clear() { 453 PooledObject<T> p = idleObjects.poll(); 454 455 while (p != null) { 456 try { 457 destroy(p, DestroyMode.NORMAL); 458 } catch (final Exception e) { 459 swallowException(e); 460 } 461 p = idleObjects.poll(); 462 } 463 } 464 465 /** 466 * Closes the pool. Once the pool is closed, {@link #borrowObject()} will 467 * fail with IllegalStateException, but {@link #returnObject(Object)} and 468 * {@link #invalidateObject(Object)} will continue to work, with returned 469 * objects destroyed on return. 470 * <p> 471 * Destroys idle instances in the pool by invoking {@link #clear()}. 472 * </p> 473 */ 474 @Override 475 public void close() { 476 if (isClosed()) { 477 return; 478 } 479 480 synchronized (closeLock) { 481 if (isClosed()) { 482 return; 483 } 484 485 // Stop the evictor before the pool is closed since evict() calls 486 // assertOpen() 487 stopEvictor(); 488 489 closed = true; 490 // This clear removes any idle objects 491 clear(); 492 493 jmxUnregister(); 494 495 // Release any threads that were waiting for an object 496 idleObjects.interuptTakeWaiters(); 497 } 498 } 499 500 /** 501 * Attempts to create a new wrapped pooled object. 502 * <p> 503 * If there are {@link #getMaxTotal()} objects already in circulation 504 * or in process of being created, this method returns null. 505 * </p> 506 * 507 * @return The new wrapped pooled object 508 * 509 * @throws Exception if the object factory's {@code makeObject} fails 510 */ 511 private PooledObject<T> create() throws Exception { 512 int localMaxTotal = getMaxTotal(); 513 // This simplifies the code later in this method 514 if (localMaxTotal < 0) { 515 localMaxTotal = Integer.MAX_VALUE; 516 } 517 518 final long localStartTimeMillis = System.currentTimeMillis(); 519 final long localMaxWaitTimeMillis = Math.max(getMaxWaitDuration().toMillis(), 0); 520 521 // Flag that indicates if create should: 522 // - TRUE: call the factory to create an object 523 // - FALSE: return null 524 // - null: loop and re-test the condition that determines whether to 525 // call the factory 526 Boolean create = null; 527 while (create == null) { 528 synchronized (makeObjectCountLock) { 529 final long newCreateCount = createCount.incrementAndGet(); 530 if (newCreateCount > localMaxTotal) { 531 // The pool is currently at capacity or in the process of 532 // making enough new objects to take it to capacity. 533 createCount.decrementAndGet(); 534 if (makeObjectCount == 0) { 535 // There are no makeObject() calls in progress so the 536 // pool is at capacity. Do not attempt to create a new 537 // object. Return and wait for an object to be returned 538 create = Boolean.FALSE; 539 } else { 540 // There are makeObject() calls in progress that might 541 // bring the pool to capacity. Those calls might also 542 // fail so wait until they complete and then re-test if 543 // the pool is at capacity or not. 544 makeObjectCountLock.wait(localMaxWaitTimeMillis); 545 } 546 } else { 547 // The pool is not at capacity. Create a new object. 548 makeObjectCount++; 549 create = Boolean.TRUE; 550 } 551 } 552 553 // Do not block more if maxWaitTimeMillis is set. 554 if (create == null && 555 (localMaxWaitTimeMillis > 0 && 556 System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) { 557 create = Boolean.FALSE; 558 } 559 } 560 561 if (!create.booleanValue()) { 562 return null; 563 } 564 565 final PooledObject<T> p; 566 try { 567 p = factory.makeObject(); 568 if (getTestOnCreate() && !factory.validateObject(p)) { 569 createCount.decrementAndGet(); 570 return null; 571 } 572 } catch (final Throwable e) { 573 createCount.decrementAndGet(); 574 throw e; 575 } finally { 576 synchronized (makeObjectCountLock) { 577 makeObjectCount--; 578 makeObjectCountLock.notifyAll(); 579 } 580 } 581 582 final AbandonedConfig ac = this.abandonedConfig; 583 if (ac != null && ac.getLogAbandoned()) { 584 p.setLogAbandoned(true); 585 p.setRequireFullStackTrace(ac.getRequireFullStackTrace()); 586 } 587 588 createdCount.incrementAndGet(); 589 allObjects.put(new IdentityWrapper<>(p.getObject()), p); 590 return p; 591 } 592 593 /** 594 * Destroys a wrapped pooled object. 595 * 596 * @param toDestroy The wrapped pooled object to destroy 597 * @param destroyMode DestroyMode context provided to the factory 598 * 599 * @throws Exception If the factory fails to destroy the pooled object 600 * cleanly 601 */ 602 private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception { 603 toDestroy.invalidate(); 604 idleObjects.remove(toDestroy); 605 allObjects.remove(new IdentityWrapper<>(toDestroy.getObject())); 606 try { 607 factory.destroyObject(toDestroy, destroyMode); 608 } finally { 609 destroyedCount.incrementAndGet(); 610 createCount.decrementAndGet(); 611 } 612 } 613 614 /** 615 * Tries to ensure that {@code idleCount} idle instances exist in the pool. 616 * <p> 617 * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount} 618 * or the total number of objects (idle, checked out, or being created) reaches 619 * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless 620 * there are threads waiting to check out instances from the pool. 621 * </p> 622 * 623 * @param idleCount the number of idle instances desired 624 * @param always true means create instances even if the pool has no threads waiting 625 * @throws Exception if the factory's makeObject throws 626 */ 627 private void ensureIdle(final int idleCount, final boolean always) throws Exception { 628 if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) { 629 return; 630 } 631 632 while (idleObjects.size() < idleCount) { 633 final PooledObject<T> p = create(); 634 if (p == null) { 635 // Can't create objects, no reason to think another call to 636 // create will work. Give up. 637 break; 638 } 639 if (getLifo()) { 640 idleObjects.addFirst(p); 641 } else { 642 idleObjects.addLast(p); 643 } 644 } 645 if (isClosed()) { 646 // Pool closed while object was being added to idle objects. 647 // Make sure the returned object is destroyed rather than left 648 // in the idle object pool (which would effectively be a leak) 649 clear(); 650 } 651 } 652 653 @Override 654 void ensureMinIdle() throws Exception { 655 ensureIdle(getMinIdle(), true); 656 } 657 658 /** 659 * {@inheritDoc} 660 * <p> 661 * Successive activations of this method examine objects in sequence, 662 * cycling through objects in oldest-to-youngest order. 663 * </p> 664 */ 665 @Override 666 public void evict() throws Exception { 667 assertOpen(); 668 669 if (!idleObjects.isEmpty()) { 670 671 PooledObject<T> underTest = null; 672 final EvictionPolicy<T> evictionPolicy = getEvictionPolicy(); 673 674 synchronized (evictionLock) { 675 final EvictionConfig evictionConfig = new EvictionConfig( 676 getMinEvictableIdleDuration(), 677 getSoftMinEvictableIdleDuration(), 678 getMinIdle()); 679 680 final boolean testWhileIdle = getTestWhileIdle(); 681 682 for (int i = 0, m = getNumTests(); i < m; i++) { 683 if (evictionIterator == null || !evictionIterator.hasNext()) { 684 evictionIterator = new EvictionIterator(idleObjects); 685 } 686 if (!evictionIterator.hasNext()) { 687 // Pool exhausted, nothing to do here 688 return; 689 } 690 691 try { 692 underTest = evictionIterator.next(); 693 } catch (final NoSuchElementException nsee) { 694 // Object was borrowed in another thread 695 // Don't count this as an eviction test so reduce i; 696 i--; 697 evictionIterator = null; 698 continue; 699 } 700 701 if (!underTest.startEvictionTest()) { 702 // Object was borrowed in another thread 703 // Don't count this as an eviction test so reduce i; 704 i--; 705 continue; 706 } 707 708 // User provided eviction policy could throw all sorts of 709 // crazy exceptions. Protect against such an exception 710 // killing the eviction thread. 711 boolean evict; 712 try { 713 evict = evictionPolicy.evict(evictionConfig, underTest, 714 idleObjects.size()); 715 } catch (final Throwable t) { 716 // Slightly convoluted as SwallowedExceptionListener 717 // uses Exception rather than Throwable 718 PoolUtils.checkRethrow(t); 719 swallowException(new Exception(t)); 720 // Don't evict on error conditions 721 evict = false; 722 } 723 724 if (evict) { 725 destroy(underTest, DestroyMode.NORMAL); 726 destroyedByEvictorCount.incrementAndGet(); 727 } else { 728 if (testWhileIdle) { 729 boolean active = false; 730 try { 731 factory.activateObject(underTest); 732 active = true; 733 } catch (final Exception e) { 734 destroy(underTest, DestroyMode.NORMAL); 735 destroyedByEvictorCount.incrementAndGet(); 736 } 737 if (active) { 738 boolean validate = false; 739 Throwable validationThrowable = null; 740 try { 741 validate = factory.validateObject(underTest); 742 } catch (final Throwable t) { 743 PoolUtils.checkRethrow(t); 744 validationThrowable = t; 745 } 746 if (!validate) { 747 destroy(underTest, DestroyMode.NORMAL); 748 destroyedByEvictorCount.incrementAndGet(); 749 if (validationThrowable != null) { 750 if (validationThrowable instanceof RuntimeException) { 751 throw (RuntimeException) validationThrowable; 752 } 753 throw (Error) validationThrowable; 754 } 755 } else { 756 try { 757 factory.passivateObject(underTest); 758 } catch (final Exception e) { 759 destroy(underTest, DestroyMode.NORMAL); 760 destroyedByEvictorCount.incrementAndGet(); 761 } 762 } 763 } 764 } 765 if (!underTest.endEvictionTest(idleObjects)) { 766 // TODO - May need to add code here once additional 767 // states are used 768 } 769 } 770 } 771 } 772 } 773 final AbandonedConfig ac = this.abandonedConfig; 774 if (ac != null && ac.getRemoveAbandonedOnMaintenance()) { 775 removeAbandoned(ac); 776 } 777 } 778 779 /** 780 * Gets a reference to the factory used to create, destroy and validate 781 * the objects used by this pool. 782 * 783 * @return the factory 784 */ 785 public PooledObjectFactory<T> getFactory() { 786 return factory; 787 } 788 789 /** 790 * Gets the type - including the specific type rather than the generic - 791 * of the factory. 792 * 793 * @return A string representation of the factory type 794 */ 795 @Override 796 public String getFactoryType() { 797 // Not thread safe. Accept that there may be multiple evaluations. 798 if (factoryType == null) { 799 final StringBuilder result = new StringBuilder(); 800 result.append(factory.getClass().getName()); 801 result.append('<'); 802 final Class<?> pooledObjectType = 803 PoolImplUtils.getFactoryType(factory.getClass()); 804 result.append(pooledObjectType.getName()); 805 result.append('>'); 806 factoryType = result.toString(); 807 } 808 return factoryType; 809 } 810 811 /** 812 * Gets the cap on the number of "idle" instances in the pool. If maxIdle 813 * is set too low on heavily loaded systems it is possible you will see 814 * objects being destroyed and almost immediately new objects being created. 815 * This is a result of the active threads momentarily returning objects 816 * faster than they are requesting them, causing the number of idle 817 * objects to rise above maxIdle. The best value for maxIdle for heavily 818 * loaded system will vary but the default is a good starting point. 819 * 820 * @return the maximum number of "idle" instances that can be held in the 821 * pool or a negative value if there is no limit 822 * 823 * @see #setMaxIdle 824 */ 825 @Override 826 public int getMaxIdle() { 827 return maxIdle; 828 } 829 830 /** 831 * Gets the target for the minimum number of idle objects to maintain in 832 * the pool. This setting only has an effect if it is positive and 833 * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this 834 * is the case, an attempt is made to ensure that the pool has the required 835 * minimum number of instances during idle object eviction runs. 836 * <p> 837 * If the configured value of minIdle is greater than the configured value 838 * for maxIdle then the value of maxIdle will be used instead. 839 * </p> 840 * 841 * @return The minimum number of objects. 842 * 843 * @see #setMinIdle(int) 844 * @see #setMaxIdle(int) 845 * @see #setTimeBetweenEvictionRuns(Duration) 846 */ 847 @Override 848 public int getMinIdle() { 849 final int maxIdleSave = getMaxIdle(); 850 if (this.minIdle > maxIdleSave) { 851 return maxIdleSave; 852 } 853 return minIdle; 854 } 855 856 @Override 857 public int getNumActive() { 858 return allObjects.size() - idleObjects.size(); 859 } 860 861 @Override 862 public int getNumIdle() { 863 return idleObjects.size(); 864 } 865 866 /** 867 * Calculates the number of objects to test in a run of the idle object 868 * evictor. 869 * 870 * @return The number of objects to test for validity 871 */ 872 private int getNumTests() { 873 final int numTestsPerEvictionRun = getNumTestsPerEvictionRun(); 874 if (numTestsPerEvictionRun >= 0) { 875 return Math.min(numTestsPerEvictionRun, idleObjects.size()); 876 } 877 return (int) (Math.ceil(idleObjects.size() / 878 Math.abs((double) numTestsPerEvictionRun))); 879 } 880 881 /** 882 * Gets an estimate of the number of threads currently blocked waiting for 883 * an object from the pool. This is intended for monitoring only, not for 884 * synchronization control. 885 * 886 * @return The estimate of the number of threads currently blocked waiting 887 * for an object from the pool 888 */ 889 @Override 890 public int getNumWaiters() { 891 if (getBlockWhenExhausted()) { 892 return idleObjects.getTakeQueueLength(); 893 } 894 return 0; 895 } 896 897 /** 898 * {@inheritDoc} 899 * <p> 900 * Activation of this method decrements the active count and attempts to 901 * destroy the instance, using the default (NORMAL) {@link DestroyMode}. 902 * </p> 903 * 904 * @throws Exception if an exception occurs destroying the 905 * object 906 * @throws IllegalStateException if obj does not belong to this pool 907 */ 908 @Override 909 public void invalidateObject(final T obj) throws Exception { 910 invalidateObject(obj, DestroyMode.NORMAL); 911 } 912 913 /** 914 * {@inheritDoc} 915 * <p> 916 * Activation of this method decrements the active count and attempts to 917 * destroy the instance, using the provided {@link DestroyMode}. 918 * </p> 919 * 920 * @throws Exception if an exception occurs destroying the 921 * object 922 * @throws IllegalStateException if obj does not belong to this pool 923 * @since 2.9.0 924 */ 925 @Override 926 public void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception { 927 final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj)); 928 if (p == null) { 929 if (isAbandonedConfig()) { 930 return; 931 } 932 throw new IllegalStateException( 933 "Invalidated object not currently part of this pool"); 934 } 935 synchronized (p) { 936 if (p.getState() != PooledObjectState.INVALID) { 937 destroy(p, destroyMode); 938 } 939 } 940 ensureIdle(1, false); 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 * Tries to ensure that {@link #getMinIdle()} idle instances are available 961 * in the pool. 962 * 963 * @throws Exception If the associated factory throws an exception 964 * @since 2.4 965 */ 966 public void preparePool() throws Exception { 967 if (getMinIdle() < 1) { 968 return; 969 } 970 ensureMinIdle(); 971 } 972 973 /** 974 * Recovers abandoned objects which have been checked out but 975 * not used since longer than the removeAbandonedTimeout. 976 * 977 * @param abandonedConfig The configuration to use to identify abandoned objects 978 */ 979 @SuppressWarnings("resource") // PrintWriter is managed elsewhere 980 private void removeAbandoned(final AbandonedConfig abandonedConfig) { 981 // Generate a list of abandoned objects to remove 982 final ArrayList<PooledObject<T>> remove = createRemoveList(abandonedConfig, allObjects); 983 // Now remove the abandoned objects 984 remove.forEach(pooledObject -> { 985 if (abandonedConfig.getLogAbandoned()) { 986 pooledObject.printStackTrace(abandonedConfig.getLogWriter()); 987 } 988 try { 989 invalidateObject(pooledObject.getObject(), DestroyMode.ABANDONED); 990 } catch (final Exception e) { 991 swallowException(e); 992 } 993 }); 994 } 995 996 /** 997 * {@inheritDoc} 998 * <p> 999 * If {@link #getMaxIdle() maxIdle} is set to a positive value and the 1000 * number of idle instances has reached this value, the returning instance 1001 * is destroyed. 1002 * </p> 1003 * <p> 1004 * If {@link #getTestOnReturn() testOnReturn} == true, the returning 1005 * instance is validated before being returned to the idle instance pool. In 1006 * this case, if validation fails, the instance is destroyed. 1007 * </p> 1008 * <p> 1009 * Exceptions encountered destroying objects for any reason are swallowed 1010 * but notified via a {@link SwallowedExceptionListener}. 1011 * </p> 1012 */ 1013 @Override 1014 public void returnObject(final T obj) { 1015 final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj)); 1016 1017 if (p == null) { 1018 if (!isAbandonedConfig()) { 1019 throw new IllegalStateException( 1020 "Returned object not currently part of this pool"); 1021 } 1022 return; // Object was abandoned and removed 1023 } 1024 1025 markReturningState(p); 1026 1027 final Duration activeTime = p.getActiveDuration(); 1028 1029 if (getTestOnReturn() && !factory.validateObject(p)) { 1030 try { 1031 destroy(p, DestroyMode.NORMAL); 1032 } catch (final Exception e) { 1033 swallowException(e); 1034 } 1035 try { 1036 ensureIdle(1, false); 1037 } catch (final Exception e) { 1038 swallowException(e); 1039 } 1040 updateStatsReturn(activeTime); 1041 return; 1042 } 1043 1044 try { 1045 factory.passivateObject(p); 1046 } catch (final Exception e1) { 1047 swallowException(e1); 1048 try { 1049 destroy(p, DestroyMode.NORMAL); 1050 } catch (final Exception e) { 1051 swallowException(e); 1052 } 1053 try { 1054 ensureIdle(1, false); 1055 } catch (final Exception e) { 1056 swallowException(e); 1057 } 1058 updateStatsReturn(activeTime); 1059 return; 1060 } 1061 1062 if (!p.deallocate()) { 1063 throw new IllegalStateException( 1064 "Object has already been returned to this pool or is invalid"); 1065 } 1066 1067 final int maxIdleSave = getMaxIdle(); 1068 if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) { 1069 try { 1070 destroy(p, DestroyMode.NORMAL); 1071 } catch (final Exception e) { 1072 swallowException(e); 1073 } 1074 try { 1075 ensureIdle(1, false); 1076 } catch (final Exception e) { 1077 swallowException(e); 1078 } 1079 } else { 1080 if (getLifo()) { 1081 idleObjects.addFirst(p); 1082 } else { 1083 idleObjects.addLast(p); 1084 } 1085 if (isClosed()) { 1086 // Pool closed while object was being added to idle objects. 1087 // Make sure the returned object is destroyed rather than left 1088 // in the idle object pool (which would effectively be a leak) 1089 clear(); 1090 } 1091 } 1092 updateStatsReturn(activeTime); 1093 } 1094 1095 /** 1096 * Sets the base pool configuration. 1097 * 1098 * @param conf the new configuration to use. This is used by value. 1099 * 1100 * @see GenericObjectPoolConfig 1101 */ 1102 public void setConfig(final GenericObjectPoolConfig<T> conf) { 1103 super.setConfig(conf); 1104 setMaxIdle(conf.getMaxIdle()); 1105 setMinIdle(conf.getMinIdle()); 1106 setMaxTotal(conf.getMaxTotal()); 1107 } 1108 1109 /** 1110 * Sets the cap on the number of "idle" instances in the pool. If maxIdle 1111 * is set too low on heavily loaded systems it is possible you will see 1112 * objects being destroyed and almost immediately new objects being created. 1113 * This is a result of the active threads momentarily returning objects 1114 * faster than they are requesting them, causing the number of idle 1115 * objects to rise above maxIdle. The best value for maxIdle for heavily 1116 * loaded system will vary but the default is a good starting point. 1117 * 1118 * @param maxIdle 1119 * The cap on the number of "idle" instances in the pool. Use a 1120 * negative value to indicate an unlimited number of idle 1121 * instances 1122 * 1123 * @see #getMaxIdle 1124 */ 1125 public void setMaxIdle(final int maxIdle) { 1126 this.maxIdle = maxIdle; 1127 } 1128 1129 /** 1130 * Sets the target for the minimum number of idle objects to maintain in 1131 * the pool. This setting only has an effect if it is positive and 1132 * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this 1133 * is the case, an attempt is made to ensure that the pool has the required 1134 * minimum number of instances during idle object eviction runs. 1135 * <p> 1136 * If the configured value of minIdle is greater than the configured value 1137 * for maxIdle then the value of maxIdle will be used instead. 1138 * </p> 1139 * 1140 * @param minIdle 1141 * The minimum number of objects. 1142 * 1143 * @see #getMinIdle() 1144 * @see #getMaxIdle() 1145 * @see #getDurationBetweenEvictionRuns() 1146 */ 1147 public void setMinIdle(final int minIdle) { 1148 this.minIdle = minIdle; 1149 } 1150 1151 @Override 1152 protected void toStringAppendFields(final StringBuilder builder) { 1153 super.toStringAppendFields(builder); 1154 builder.append(", factoryType="); 1155 builder.append(factoryType); 1156 builder.append(", maxIdle="); 1157 builder.append(maxIdle); 1158 builder.append(", minIdle="); 1159 builder.append(minIdle); 1160 builder.append(", factory="); 1161 builder.append(factory); 1162 builder.append(", allObjects="); 1163 builder.append(allObjects); 1164 builder.append(", createCount="); 1165 builder.append(createCount); 1166 builder.append(", idleObjects="); 1167 builder.append(idleObjects); 1168 builder.append(", abandonedConfig="); 1169 builder.append(abandonedConfig); 1170 } 1171 1172 @Override 1173 public void use(final T pooledObject) { 1174 final AbandonedConfig abandonedCfg = this.abandonedConfig; 1175 if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) { 1176 allObjects.get(new IdentityWrapper<>(pooledObject)).use(); 1177 } 1178 } 1179 1180}