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 * @param <T> Type of element pooled in this pool. 078 * @since 2.0 079 */ 080public class GenericObjectPool<T> extends BaseGenericObjectPool<T> 081 implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> { 082 083 // JMX specific attributes 084 private static final String ONAME_BASE = 085 "org.apache.commons.pool2:type=GenericObjectPool,name="; 086 087 private static void wait(final Object obj, final Duration duration) throws InterruptedException { 088 if (!duration.isNegative()) { 089 obj.wait(duration.toMillis(), duration.getNano() % 1_000_000); 090 } 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 * @throws Exception If the factory fails to passivate the object 189 */ 190 private void addIdleObject(final PooledObject<T> p) throws Exception { 191 if (!PooledObject.isNull(p)) { 192 factory.passivateObject(p); 193 if (getLifo()) { 194 idleObjects.addFirst(p); 195 } else { 196 idleObjects.addLast(p); 197 } 198 } 199 } 200 201 /** 202 * Creates an object, and place it into the pool. addObject() is useful for 203 * "pre-loading" a pool with idle objects. 204 * <p> 205 * If there is no capacity available to add to the pool, this is a no-op 206 * (no exception, no impact to the pool). 207 * </p> 208 * <p> 209 * If the factory returns null when creating an object, a {@code NullPointerException} 210 * is thrown. If there is no factory set (factory == null), an {@code IllegalStateException} 211 * is thrown. 212 * </p> 213 */ 214 @Override 215 public void addObject() throws Exception { 216 assertOpen(); 217 if (factory == null) { 218 throw new IllegalStateException("Cannot add objects without a factory."); 219 } 220 addIdleObject(create(getMaxWaitDuration())); 221 } 222 223 /** 224 * Equivalent to <code>{@link #borrowObject(long) 225 * borrowObject}({@link #getMaxWaitDuration()})</code>. 226 * 227 * {@inheritDoc} 228 */ 229 @Override 230 public T borrowObject() throws Exception { 231 return borrowObject(getMaxWaitDuration()); 232 } 233 234 /** 235 * Borrows an object from the pool using the specific waiting time which only 236 * applies if {@link #getBlockWhenExhausted()} is true. 237 * <p> 238 * If there is one or more idle instance available in the pool, then an 239 * idle instance will be selected based on the value of {@link #getLifo()}, 240 * activated and returned. If activation fails, or {@link #getTestOnBorrow() 241 * testOnBorrow} is set to {@code true} and validation fails, the 242 * instance is destroyed and the next available instance is examined. This 243 * continues until either a valid instance is returned or there are no more 244 * idle instances available. 245 * </p> 246 * <p> 247 * If there are no idle instances available in the pool, behavior depends on 248 * the {@link #getMaxTotal() maxTotal}, (if applicable) 249 * {@link #getBlockWhenExhausted()} and the value passed in to the 250 * {@code borrowMaxWaitMillis} parameter. If the number of instances 251 * checked out from the pool is less than {@code maxTotal,} a new 252 * instance is created, activated and (if applicable) validated and returned 253 * to the caller. If validation fails, a {@code NoSuchElementException} 254 * is thrown. If the factory returns null when creating an instance, 255 * a {@code NullPointerException} is thrown. 256 * </p> 257 * <p> 258 * If the pool is exhausted (no available idle instances and no capacity to 259 * create new ones), this method will either block (if 260 * {@link #getBlockWhenExhausted()} is true) or throw a 261 * {@code NoSuchElementException} (if 262 * {@link #getBlockWhenExhausted()} is false). The length of time that this 263 * method will block when {@link #getBlockWhenExhausted()} is true is 264 * determined by the value passed in to the {@code borrowMaxWaitMillis} 265 * parameter. 266 * </p> 267 * <p> 268 * When the pool is exhausted, multiple calling threads may be 269 * simultaneously blocked waiting for instances to become available. A 270 * "fairness" algorithm has been implemented to ensure that threads receive 271 * available instances in request arrival order. 272 * </p> 273 * 274 * @param borrowMaxWaitDuration The time to wait for an object to become available, not null. 275 * @return object instance from the pool 276 * @throws NoSuchElementException if an instance cannot be returned 277 * @throws Exception if an object instance cannot be returned due to an error 278 * @since 2.10.0 279 */ 280 public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception { 281 assertOpen(); 282 final Instant startInstant = Instant.now(); 283 final boolean negativeDuration = borrowMaxWaitDuration.isNegative(); 284 Duration remainingWaitDuration = borrowMaxWaitDuration; 285 final AbandonedConfig ac = this.abandonedConfig; 286 if (ac != null && ac.getRemoveAbandonedOnBorrow() && getNumIdle() < 2 && getNumActive() > getMaxTotal() - 3) { 287 removeAbandoned(ac); 288 } 289 PooledObject<T> p = null; 290 // Get local copy of current config so it is consistent for entire 291 // method execution 292 final boolean blockWhenExhausted = getBlockWhenExhausted(); 293 boolean create; 294 while (p == null) { 295 remainingWaitDuration = remainingWaitDuration.minus(durationSince(startInstant)); 296 create = false; 297 p = idleObjects.pollFirst(); 298 if (p == null) { 299 p = create(remainingWaitDuration); 300 if (!PooledObject.isNull(p)) { 301 create = true; 302 } 303 } 304 if (blockWhenExhausted) { 305 if (PooledObject.isNull(p)) { 306 p = negativeDuration ? idleObjects.takeFirst() : idleObjects.pollFirst(remainingWaitDuration); 307 } 308 if (PooledObject.isNull(p)) { 309 throw new NoSuchElementException(appendStats( 310 "Timeout waiting for idle object, borrowMaxWaitDuration=" + remainingWaitDuration)); 311 } 312 } else if (PooledObject.isNull(p)) { 313 throw new NoSuchElementException(appendStats("Pool exhausted")); 314 } 315 if (!p.allocate()) { 316 p = null; 317 } 318 if (!PooledObject.isNull(p)) { 319 try { 320 factory.activateObject(p); 321 } catch (final Exception e) { 322 try { 323 destroy(p, DestroyMode.NORMAL); 324 } catch (final Exception ignored) { 325 // ignored - activation failure is more important 326 } 327 p = null; 328 if (create) { 329 final NoSuchElementException nsee = new NoSuchElementException( 330 appendStats("Unable to activate object")); 331 nsee.initCause(e); 332 throw nsee; 333 } 334 } 335 if (!PooledObject.isNull(p) && getTestOnBorrow()) { 336 boolean validate = false; 337 Throwable validationThrowable = null; 338 try { 339 validate = factory.validateObject(p); 340 } catch (final Throwable t) { 341 PoolUtils.checkRethrow(t); 342 validationThrowable = t; 343 } 344 if (!validate) { 345 try { 346 destroy(p, DestroyMode.NORMAL); 347 destroyedByBorrowValidationCount.incrementAndGet(); 348 } catch (final Exception ignored) { 349 // ignored - validation failure is more important 350 } 351 p = null; 352 if (create) { 353 final NoSuchElementException nsee = new NoSuchElementException( 354 appendStats("Unable to validate object")); 355 nsee.initCause(validationThrowable); 356 throw nsee; 357 } 358 } 359 } 360 } 361 } 362 updateStatsBorrow(p, durationSince(startInstant)); 363 return p.getObject(); 364 } 365 366 private Duration durationSince(final Instant startInstant) { 367 return Duration.between(startInstant, Instant.now()); 368 } 369 370 /** 371 * Borrows an object from the pool using the specific waiting time which only 372 * applies if {@link #getBlockWhenExhausted()} is true. 373 * <p> 374 * If there is one or more idle instance available in the pool, then an 375 * idle instance will be selected based on the value of {@link #getLifo()}, 376 * activated and returned. If activation fails, or {@link #getTestOnBorrow() 377 * testOnBorrow} is set to {@code true} and validation fails, the 378 * instance is destroyed and the next available instance is examined. This 379 * continues until either a valid instance is returned or there are no more 380 * idle instances available. 381 * </p> 382 * <p> 383 * If there are no idle instances available in the pool, behavior depends on 384 * the {@link #getMaxTotal() maxTotal}, (if applicable) 385 * {@link #getBlockWhenExhausted()} and the value passed in to the 386 * {@code borrowMaxWaitMillis} parameter. If the number of instances 387 * checked out from the pool is less than {@code maxTotal,} a new 388 * instance is created, activated and (if applicable) validated and returned 389 * to the caller. If validation fails, a {@code NoSuchElementException} 390 * is thrown. If the factory returns null when creating an instance, 391 * a {@code NullPointerException} is thrown. 392 * </p> 393 * <p> 394 * If the pool is exhausted (no available idle instances and no capacity to 395 * create new ones), this method will either block (if 396 * {@link #getBlockWhenExhausted()} is true) or throw a 397 * {@code NoSuchElementException} (if 398 * {@link #getBlockWhenExhausted()} is false). The length of time that this 399 * method will block when {@link #getBlockWhenExhausted()} is true is 400 * determined by the value passed in to the {@code borrowMaxWaitMillis} 401 * parameter. 402 * </p> 403 * <p> 404 * When the pool is exhausted, multiple calling threads may be 405 * simultaneously blocked waiting for instances to become available. A 406 * "fairness" algorithm has been implemented to ensure that threads receive 407 * available instances in request arrival order. 408 * </p> 409 * 410 * @param borrowMaxWaitMillis The time to wait in milliseconds for an object 411 * to become available 412 * @return object instance from the pool 413 * @throws NoSuchElementException if an instance cannot be returned 414 * @throws Exception if an object instance cannot be returned due to an 415 * error 416 */ 417 public T borrowObject(final long borrowMaxWaitMillis) throws Exception { 418 return borrowObject(Duration.ofMillis(borrowMaxWaitMillis)); 419 } 420 421 /** 422 * Clears any objects sitting idle in the pool by removing them from the 423 * idle instance pool and then invoking the configured 424 * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each 425 * idle instance. 426 * <p> 427 * Implementation notes: 428 * </p> 429 * <ul> 430 * <li>This method does not destroy or effect in any way instances that are 431 * checked out of the pool when it is invoked.</li> 432 * <li>Invoking this method does not prevent objects being returned to the 433 * idle instance pool, even during its execution. Additional instances may 434 * be returned while removed items are being destroyed.</li> 435 * <li>Exceptions encountered destroying idle instances are swallowed 436 * but notified via a {@link SwallowedExceptionListener}.</li> 437 * </ul> 438 */ 439 @Override 440 public void clear() { 441 PooledObject<T> p = idleObjects.poll(); 442 443 while (p != null) { 444 try { 445 destroy(p, DestroyMode.NORMAL); 446 } catch (final Exception e) { 447 swallowException(e); 448 } 449 p = idleObjects.poll(); 450 } 451 } 452 453 /** 454 * Closes the pool. Once the pool is closed, {@link #borrowObject()} will 455 * fail with IllegalStateException, but {@link #returnObject(Object)} and 456 * {@link #invalidateObject(Object)} will continue to work, with returned 457 * objects destroyed on return. 458 * <p> 459 * Destroys idle instances in the pool by invoking {@link #clear()}. 460 * </p> 461 */ 462 @Override 463 public void close() { 464 if (isClosed()) { 465 return; 466 } 467 468 synchronized (closeLock) { 469 if (isClosed()) { 470 return; 471 } 472 473 // Stop the evictor before the pool is closed since evict() calls 474 // assertOpen() 475 stopEvictor(); 476 477 closed = true; 478 // This clear removes any idle objects 479 clear(); 480 481 jmxUnregister(); 482 483 // Release any threads that were waiting for an object 484 idleObjects.interuptTakeWaiters(); 485 } 486 } 487 488 /** 489 * Attempts to create a new wrapped pooled object. 490 * <p> 491 * If there are {@link #getMaxTotal()} objects already in circulation or in process of being created, this method 492 * returns null. 493 * </p> 494 * <p> 495 * If the factory makeObject returns null, this method throws a NullPointerException. 496 * </p> 497 * 498 * @param maxWaitDuration The time to wait for an object to become available. 499 * @return The new wrapped pooled object or null. 500 * @throws Exception if the object factory's {@code makeObject} fails 501 */ 502 private PooledObject<T> create(final Duration maxWaitDuration) throws Exception { 503 final Instant startInstant = Instant.now(); 504 Duration remainingWaitDuration = maxWaitDuration.isNegative() ? Duration.ZERO : maxWaitDuration; 505 int localMaxTotal = getMaxTotal(); 506 // This simplifies the code later in this method 507 if (localMaxTotal < 0) { 508 localMaxTotal = Integer.MAX_VALUE; 509 } 510 final Instant localStartInstant = Instant.now(); 511 // Flag that indicates if create should: 512 // - TRUE: call the factory to create an object 513 // - FALSE: return null 514 // - null: loop and re-test the condition that determines whether to 515 // call the factory 516 Boolean create = null; 517 while (create == null) { 518 // remainingWaitDuration handles spurious wakeup from wait(). 519 remainingWaitDuration = remainingWaitDuration.minus(durationSince(startInstant)); 520 synchronized (makeObjectCountLock) { 521 final long newCreateCount = createCount.incrementAndGet(); 522 if (newCreateCount > localMaxTotal) { 523 // The pool is currently at capacity or in the process of 524 // making enough new objects to take it to capacity. 525 createCount.decrementAndGet(); 526 if (makeObjectCount == 0) { 527 // There are no makeObject() calls in progress so the 528 // pool is at capacity. Do not attempt to create a new 529 // object. Return and wait for an object to be returned 530 create = Boolean.FALSE; 531 } else { 532 // There are makeObject() calls in progress that might 533 // bring the pool to capacity. Those calls might also 534 // fail so wait until they complete and then re-test if 535 // the pool is at capacity or not. 536 wait(makeObjectCountLock, remainingWaitDuration); 537 } 538 } else { 539 // The pool is not at capacity. Create a new object. 540 makeObjectCount++; 541 create = Boolean.TRUE; 542 } 543 } 544 // Do not block more if remainingWaitDuration > 0. 545 if (create == null && remainingWaitDuration.compareTo(Duration.ZERO) > 0 && 546 durationSince(localStartInstant).compareTo(remainingWaitDuration) >= 0) { 547 create = Boolean.FALSE; 548 } 549 } 550 551 if (!create.booleanValue()) { 552 return null; 553 } 554 555 final PooledObject<T> p; 556 try { 557 p = factory.makeObject(); 558 if (PooledObject.isNull(p)) { 559 createCount.decrementAndGet(); 560 throw new NullPointerException(String.format("%s.makeObject() = null", factory.getClass().getSimpleName())); 561 } 562 if (getTestOnCreate() && !factory.validateObject(p)) { 563 createCount.decrementAndGet(); 564 return null; 565 } 566 } catch (final Throwable e) { 567 createCount.decrementAndGet(); 568 throw e; 569 } finally { 570 synchronized (makeObjectCountLock) { 571 makeObjectCount--; 572 makeObjectCountLock.notifyAll(); 573 } 574 } 575 576 final AbandonedConfig ac = this.abandonedConfig; 577 if (ac != null && ac.getLogAbandoned()) { 578 p.setLogAbandoned(true); 579 p.setRequireFullStackTrace(ac.getRequireFullStackTrace()); 580 } 581 582 createdCount.incrementAndGet(); 583 allObjects.put(new IdentityWrapper<>(p.getObject()), p); 584 return p; 585 } 586 587 /** 588 * Destroys a wrapped pooled object. 589 * 590 * @param toDestroy The wrapped pooled object to destroy 591 * @param destroyMode DestroyMode context provided to the factory 592 * @throws Exception If the factory fails to destroy the pooled object 593 * cleanly 594 */ 595 private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception { 596 toDestroy.invalidate(); 597 idleObjects.remove(toDestroy); 598 allObjects.remove(new IdentityWrapper<>(toDestroy.getObject())); 599 try { 600 factory.destroyObject(toDestroy, destroyMode); 601 } finally { 602 destroyedCount.incrementAndGet(); 603 createCount.decrementAndGet(); 604 } 605 } 606 607 /** 608 * Tries to ensure that {@code idleCount} idle instances exist in the pool. 609 * <p> 610 * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount} 611 * or the total number of objects (idle, checked out, or being created) reaches 612 * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless 613 * there are threads waiting to check out instances from the pool. 614 * </p> 615 * <p> 616 * If the factory returns null when creating an instance, a {@code NullPointerException} 617 * is thrown. 618 * </p> 619 * 620 * @param idleCount the number of idle instances desired 621 * @param always true means create instances even if the pool has no threads waiting 622 * @throws Exception if the factory's makeObject throws 623 */ 624 private void ensureIdle(final int idleCount, final boolean always) throws Exception { 625 if (idleCount < 1 || isClosed() || !always && !idleObjects.hasTakeWaiters()) { 626 return; 627 } 628 629 while (idleObjects.size() < idleCount) { 630 final PooledObject<T> p = create(getMaxWaitDuration()); 631 if (PooledObject.isNull(p)) { 632 // Can't create objects, no reason to think another call to 633 // create will work. Give up. 634 break; 635 } 636 if (getLifo()) { 637 idleObjects.addFirst(p); 638 } else { 639 idleObjects.addLast(p); 640 } 641 } 642 if (isClosed()) { 643 // Pool closed while object was being added to idle objects. 644 // Make sure the returned object is destroyed rather than left 645 // in the idle object pool (which would effectively be a leak) 646 clear(); 647 } 648 } 649 650 @Override 651 void ensureMinIdle() throws Exception { 652 ensureIdle(getMinIdle(), true); 653 } 654 655 /** 656 * {@inheritDoc} 657 * <p> 658 * Successive activations of this method examine objects in sequence, 659 * cycling through objects in oldest-to-youngest order. 660 * </p> 661 */ 662 @Override 663 public void evict() throws Exception { 664 assertOpen(); 665 666 if (!idleObjects.isEmpty()) { 667 668 PooledObject<T> underTest = null; 669 final EvictionPolicy<T> evictionPolicy = getEvictionPolicy(); 670 671 synchronized (evictionLock) { 672 final EvictionConfig evictionConfig = new EvictionConfig( 673 getMinEvictableIdleDuration(), 674 getSoftMinEvictableIdleDuration(), 675 getMinIdle()); 676 677 final boolean testWhileIdle = getTestWhileIdle(); 678 679 for (int i = 0, m = getNumTests(); i < m; i++) { 680 if (evictionIterator == null || !evictionIterator.hasNext()) { 681 evictionIterator = new EvictionIterator(idleObjects); 682 } 683 if (!evictionIterator.hasNext()) { 684 // Pool exhausted, nothing to do here 685 return; 686 } 687 688 try { 689 underTest = evictionIterator.next(); 690 } catch (final NoSuchElementException nsee) { 691 // Object was borrowed in another thread 692 // Don't count this as an eviction test so reduce i; 693 i--; 694 evictionIterator = null; 695 continue; 696 } 697 698 if (!underTest.startEvictionTest()) { 699 // Object was borrowed in another thread 700 // Don't count this as an eviction test so reduce i; 701 i--; 702 continue; 703 } 704 705 // User provided eviction policy could throw all sorts of 706 // crazy exceptions. Protect against such an exception 707 // killing the eviction thread. 708 boolean evict; 709 try { 710 evict = evictionPolicy.evict(evictionConfig, underTest, 711 idleObjects.size()); 712 } catch (final Throwable t) { 713 // Slightly convoluted as SwallowedExceptionListener 714 // uses Exception rather than Throwable 715 PoolUtils.checkRethrow(t); 716 swallowException(new Exception(t)); 717 // Don't evict on error conditions 718 evict = false; 719 } 720 721 if (evict) { 722 destroy(underTest, DestroyMode.NORMAL); 723 destroyedByEvictorCount.incrementAndGet(); 724 } else { 725 if (testWhileIdle) { 726 boolean active = false; 727 try { 728 factory.activateObject(underTest); 729 active = true; 730 } catch (final Exception e) { 731 destroy(underTest, DestroyMode.NORMAL); 732 destroyedByEvictorCount.incrementAndGet(); 733 } 734 if (active) { 735 boolean validate = false; 736 Throwable validationThrowable = null; 737 try { 738 validate = factory.validateObject(underTest); 739 } catch (final Throwable t) { 740 PoolUtils.checkRethrow(t); 741 validationThrowable = t; 742 } 743 if (!validate) { 744 destroy(underTest, DestroyMode.NORMAL); 745 destroyedByEvictorCount.incrementAndGet(); 746 if (validationThrowable != null) { 747 if (validationThrowable instanceof RuntimeException) { 748 throw (RuntimeException) validationThrowable; 749 } 750 throw (Error) validationThrowable; 751 } 752 } else { 753 try { 754 factory.passivateObject(underTest); 755 } catch (final Exception e) { 756 destroy(underTest, DestroyMode.NORMAL); 757 destroyedByEvictorCount.incrementAndGet(); 758 } 759 } 760 } 761 } 762 underTest.endEvictionTest(idleObjects); 763 // TODO - May need to add code here once additional 764 // states are used 765 } 766 } 767 } 768 } 769 final AbandonedConfig ac = this.abandonedConfig; 770 if (ac != null && ac.getRemoveAbandonedOnMaintenance()) { 771 removeAbandoned(ac); 772 } 773 } 774 775 /** 776 * Gets a reference to the factory used to create, destroy and validate 777 * the objects used by this pool. 778 * 779 * @return the factory 780 */ 781 public PooledObjectFactory<T> getFactory() { 782 return factory; 783 } 784 785 /** 786 * Gets the type - including the specific type rather than the generic - 787 * of the factory. 788 * 789 * @return A string representation of the factory type 790 */ 791 @Override 792 public String getFactoryType() { 793 // Not thread safe. Accept that there may be multiple evaluations. 794 if (factoryType == null) { 795 final StringBuilder result = new StringBuilder(); 796 result.append(factory.getClass().getName()); 797 result.append('<'); 798 final Class<?> pooledObjectType = 799 PoolImplUtils.getFactoryType(factory.getClass()); 800 result.append(pooledObjectType.getName()); 801 result.append('>'); 802 factoryType = result.toString(); 803 } 804 return factoryType; 805 } 806 807 /** 808 * Gets the cap on the number of "idle" instances in the pool. If maxIdle 809 * is set too low on heavily loaded systems it is possible you will see 810 * objects being destroyed and almost immediately new objects being created. 811 * This is a result of the active threads momentarily returning objects 812 * faster than they are requesting them, causing the number of idle 813 * objects to rise above maxIdle. The best value for maxIdle for heavily 814 * loaded system will vary but the default is a good starting point. 815 * 816 * @return the maximum number of "idle" instances that can be held in the 817 * pool or a negative value if there is no limit 818 * @see #setMaxIdle 819 */ 820 @Override 821 public int getMaxIdle() { 822 return maxIdle; 823 } 824 825 /** 826 * Gets the target for the minimum number of idle objects to maintain in 827 * the pool. This setting only has an effect if it is positive and 828 * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this 829 * is the case, an attempt is made to ensure that the pool has the required 830 * minimum number of instances during idle object eviction runs. 831 * <p> 832 * If the configured value of minIdle is greater than the configured value 833 * for maxIdle then the value of maxIdle will be used instead. 834 * </p> 835 * 836 * @return The minimum number of objects. 837 * @see #setMinIdle(int) 838 * @see #setMaxIdle(int) 839 * @see #setDurationBetweenEvictionRuns(Duration) 840 */ 841 @Override 842 public int getMinIdle() { 843 final int maxIdleSave = getMaxIdle(); 844 return Math.min(this.minIdle, maxIdleSave); 845 } 846 847 @Override 848 public int getNumActive() { 849 return allObjects.size() - idleObjects.size(); 850 } 851 852 @Override 853 public int getNumIdle() { 854 return idleObjects.size(); 855 } 856 857 /** 858 * Calculates the number of objects to test in a run of the idle object 859 * evictor. 860 * 861 * @return The number of objects to test for validity 862 */ 863 private int getNumTests() { 864 final int numTestsPerEvictionRun = getNumTestsPerEvictionRun(); 865 if (numTestsPerEvictionRun >= 0) { 866 return Math.min(numTestsPerEvictionRun, idleObjects.size()); 867 } 868 return (int) Math.ceil(idleObjects.size() / 869 Math.abs((double) numTestsPerEvictionRun)); 870 } 871 872 /** 873 * Gets an estimate of the number of threads currently blocked waiting for 874 * an object from the pool. This is intended for monitoring only, not for 875 * synchronization control. 876 * 877 * @return The estimate of the number of threads currently blocked waiting 878 * for an object from the pool 879 */ 880 @Override 881 public int getNumWaiters() { 882 if (getBlockWhenExhausted()) { 883 return idleObjects.getTakeQueueLength(); 884 } 885 return 0; 886 } 887 888 PooledObject<T> getPooledObject(final T obj) { 889 return allObjects.get(new IdentityWrapper<>(obj)); 890 } 891 892 @Override 893 String getStatsString() { 894 // Simply listed in AB order. 895 return super.getStatsString() + 896 String.format(", createdCount=%,d, makeObjectCount=%,d, maxIdle=%,d, minIdle=%,d", 897 createdCount.get(), makeObjectCount, maxIdle, minIdle); 898 } 899 900 /** 901 * {@inheritDoc} 902 * <p> 903 * Activation of this method decrements the active count and attempts to destroy the instance, using the default 904 * (NORMAL) {@link DestroyMode}. 905 * </p> 906 * 907 * @throws Exception if an exception occurs destroying the 908 * @throws IllegalStateException if obj does not belong to this pool 909 */ 910 @Override 911 public void invalidateObject(final T obj) throws Exception { 912 invalidateObject(obj, DestroyMode.NORMAL); 913 } 914 915 /** 916 * {@inheritDoc} 917 * <p> 918 * Activation of this method decrements the active count and attempts to destroy the instance, using the provided 919 * {@link DestroyMode}. 920 * </p> 921 * 922 * @throws Exception if an exception occurs destroying the object 923 * @throws IllegalStateException if obj does not belong to this pool 924 * @since 2.9.0 925 */ 926 @Override 927 public void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception { 928 final PooledObject<T> p = getPooledObject(obj); 929 if (p == null) { 930 if (isAbandonedConfig()) { 931 return; 932 } 933 throw new IllegalStateException("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 = getPooledObject(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 * @see GenericObjectPoolConfig 1100 */ 1101 public void setConfig(final GenericObjectPoolConfig<T> conf) { 1102 super.setConfig(conf); 1103 setMaxIdle(conf.getMaxIdle()); 1104 setMinIdle(conf.getMinIdle()); 1105 setMaxTotal(conf.getMaxTotal()); 1106 } 1107 1108 /** 1109 * Sets the cap on the number of "idle" instances in the pool. If maxIdle 1110 * is set too low on heavily loaded systems it is possible you will see 1111 * objects being destroyed and almost immediately new objects being created. 1112 * This is a result of the active threads momentarily returning objects 1113 * faster than they are requesting them, causing the number of idle 1114 * objects to rise above maxIdle. The best value for maxIdle for heavily 1115 * loaded system will vary but the default is a good starting point. 1116 * 1117 * @param maxIdle 1118 * The cap on the number of "idle" instances in the pool. Use a 1119 * negative value to indicate an unlimited number of idle 1120 * instances 1121 * @see #getMaxIdle 1122 */ 1123 public void setMaxIdle(final int maxIdle) { 1124 this.maxIdle = maxIdle; 1125 } 1126 1127 /** 1128 * Sets the target for the minimum number of idle objects to maintain in 1129 * the pool. This setting only has an effect if it is positive and 1130 * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this 1131 * is the case, an attempt is made to ensure that the pool has the required 1132 * minimum number of instances during idle object eviction runs. 1133 * <p> 1134 * If the configured value of minIdle is greater than the configured value 1135 * for maxIdle then the value of maxIdle will be used instead. 1136 * </p> 1137 * 1138 * @param minIdle 1139 * The minimum number of objects. 1140 * @see #getMinIdle() 1141 * @see #getMaxIdle() 1142 * @see #getDurationBetweenEvictionRuns() 1143 */ 1144 public void setMinIdle(final int minIdle) { 1145 this.minIdle = minIdle; 1146 } 1147 1148 @Override 1149 protected void toStringAppendFields(final StringBuilder builder) { 1150 super.toStringAppendFields(builder); 1151 builder.append(", factoryType="); 1152 builder.append(factoryType); 1153 builder.append(", maxIdle="); 1154 builder.append(maxIdle); 1155 builder.append(", minIdle="); 1156 builder.append(minIdle); 1157 builder.append(", factory="); 1158 builder.append(factory); 1159 builder.append(", allObjects="); 1160 builder.append(allObjects); 1161 builder.append(", createCount="); 1162 builder.append(createCount); 1163 builder.append(", idleObjects="); 1164 builder.append(idleObjects); 1165 builder.append(", abandonedConfig="); 1166 builder.append(abandonedConfig); 1167 } 1168 1169 @Override 1170 public void use(final T pooledObject) { 1171 final AbandonedConfig abandonedCfg = this.abandonedConfig; 1172 if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) { 1173 final PooledObject<T> po = getPooledObject(pooledObject); 1174 if (po != null) { 1175 po.use(); 1176 } 1177 } 1178 } 1179 1180}