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