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