001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.pool2.impl; 018 019import java.time.Duration; 020import java.util.ArrayList; 021import java.util.Deque; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Map.Entry; 027import java.util.NoSuchElementException; 028import java.util.Objects; 029import java.util.TreeMap; 030import java.util.concurrent.ConcurrentHashMap; 031import java.util.concurrent.TimeUnit; 032import java.util.concurrent.atomic.AtomicInteger; 033import java.util.concurrent.atomic.AtomicLong; 034import java.util.concurrent.locks.Lock; 035import java.util.concurrent.locks.ReadWriteLock; 036import java.util.concurrent.locks.ReentrantReadWriteLock; 037 038import org.apache.commons.pool2.DestroyMode; 039import org.apache.commons.pool2.KeyedObjectPool; 040import org.apache.commons.pool2.KeyedPooledObjectFactory; 041import org.apache.commons.pool2.PoolUtils; 042import org.apache.commons.pool2.PooledObject; 043import org.apache.commons.pool2.PooledObjectState; 044import org.apache.commons.pool2.SwallowedExceptionListener; 045import org.apache.commons.pool2.UsageTracking; 046 047/** 048 * A configurable {@code KeyedObjectPool} implementation. 049 * <p> 050 * When coupled with the appropriate {@link KeyedPooledObjectFactory}, 051 * {@code GenericKeyedObjectPool} provides robust pooling functionality for 052 * keyed objects. A {@code GenericKeyedObjectPool} can be viewed as a map 053 * of sub-pools, keyed on the (unique) key values provided to the 054 * {@link #preparePool preparePool}, {@link #addObject addObject} or 055 * {@link #borrowObject borrowObject} methods. Each time a new key value is 056 * provided to one of these methods, a sub-new pool is created under the given 057 * key to be managed by the containing {@code GenericKeyedObjectPool.} 058 * </p> 059 * <p> 060 * Note that the current implementation uses a ConcurrentHashMap which uses 061 * equals() to compare keys. 062 * This means that distinct instance keys must be distinguishable using equals. 063 * </p> 064 * <p> 065 * Optionally, one may configure the pool to examine and possibly evict objects 066 * as they sit idle in the pool and to ensure that a minimum number of idle 067 * objects is maintained for each key. This is performed by an "idle object 068 * eviction" thread, which runs asynchronously. Caution should be used when 069 * configuring this optional feature. Eviction runs contend with client threads 070 * for access to objects in the pool, so if they run too frequently performance 071 * issues may result. 072 * </p> 073 * <p> 074 * Implementation note: To prevent possible deadlocks, care has been taken to 075 * ensure that no call to a factory method will occur within a synchronization 076 * block. See POOL-125 and DBCP-44 for more information. 077 * </p> 078 * <p> 079 * This class is intended to be thread-safe. 080 * </p> 081 * 082 * @see GenericObjectPool 083 * 084 * @param <K> The type of keys maintained by this pool. 085 * @param <T> Type of element pooled in this pool. 086 * 087 * @since 2.0 088 */ 089public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T> 090 implements KeyedObjectPool<K, T>, GenericKeyedObjectPoolMXBean<K>, UsageTracking<T> { 091 092 /** 093 * Maintains information on the per key queue for a given key. 094 * 095 * @param <S> type of objects in the pool 096 */ 097 private class ObjectDeque<S> { 098 099 private final LinkedBlockingDeque<PooledObject<S>> idleObjects; 100 101 /* 102 * Number of instances created - number destroyed. 103 * Invariant: createCount <= maxTotalPerKey 104 */ 105 private final AtomicInteger createCount = new AtomicInteger(0); 106 107 private long makeObjectCount = 0; 108 private final Object makeObjectCountLock = new Object(); 109 110 /* 111 * The map is keyed on pooled instances, wrapped to ensure that 112 * they work properly as keys. 113 */ 114 private final Map<IdentityWrapper<S>, PooledObject<S>> allObjects = 115 new ConcurrentHashMap<>(); 116 117 /* 118 * Number of threads with registered interest in this key. 119 * register(K) increments this counter and deRegister(K) decrements it. 120 * Invariant: empty keyed pool will not be dropped unless numInterested 121 * is 0. 122 */ 123 private final AtomicLong numInterested = new AtomicLong(0); 124 125 /** 126 * Create a new ObjecDeque with the given fairness policy. 127 * @param fairness true means client threads waiting to borrow / return instances 128 * will be served as if waiting in a FIFO queue. 129 */ 130 public ObjectDeque(final boolean fairness) { 131 idleObjects = new LinkedBlockingDeque<>(fairness); 132 } 133 134 /** 135 * Obtain all the objects for the current key. 136 * 137 * @return All the objects 138 */ 139 public Map<IdentityWrapper<S>, PooledObject<S>> getAllObjects() { 140 return allObjects; 141 } 142 143 /** 144 * Obtain the count of the number of objects created for the current 145 * key. 146 * 147 * @return The number of objects created for this key 148 */ 149 public AtomicInteger getCreateCount() { 150 return createCount; 151 } 152 153 /** 154 * Obtain the idle objects for the current key. 155 * 156 * @return The idle objects 157 */ 158 public LinkedBlockingDeque<PooledObject<S>> getIdleObjects() { 159 return idleObjects; 160 } 161 162 /** 163 * Obtain the number of threads with an interest registered in this key. 164 * 165 * @return The number of threads with a registered interest in this key 166 */ 167 public AtomicLong getNumInterested() { 168 return numInterested; 169 } 170 171 @Override 172 public String toString() { 173 final StringBuilder builder = new StringBuilder(); 174 builder.append("ObjectDeque [idleObjects="); 175 builder.append(idleObjects); 176 builder.append(", createCount="); 177 builder.append(createCount); 178 builder.append(", allObjects="); 179 builder.append(allObjects); 180 builder.append(", numInterested="); 181 builder.append(numInterested); 182 builder.append("]"); 183 return builder.toString(); 184 } 185 186 } 187 188 private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(Integer.MAX_VALUE); 189 190 // JMX specific attributes 191 private static final String ONAME_BASE = 192 "org.apache.commons.pool2:type=GenericKeyedObjectPool,name="; 193 194 //--- configuration attributes --------------------------------------------- 195 private volatile int maxIdlePerKey = 196 GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; 197 198 private volatile int minIdlePerKey = 199 GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; 200 201 202 private volatile int maxTotalPerKey = 203 GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; 204 205 private final KeyedPooledObjectFactory<K, T> factory; 206 207 private final boolean fairness; 208 209 /* 210 * My hash of sub-pools (ObjectQueue). The list of keys <b>must</b> be kept 211 * in step with {@link #poolKeyList} using {@link #keyLock} to ensure any 212 * changes to the list of current keys is made in a thread-safe manner. 213 */ 214 private final Map<K, ObjectDeque<T>> poolMap = 215 new ConcurrentHashMap<>(); // @GuardedBy("keyLock") for write access (and some read access) 216 217 /* 218 * List of pool keys - used to control eviction order. The list of keys 219 * <b>must</b> be kept in step with {@link #poolMap} using {@link #keyLock} 220 * to ensure any changes to the list of current keys is made in a 221 * thread-safe manner. 222 */ 223 private final List<K> poolKeyList = new ArrayList<>(); // @GuardedBy("keyLock") 224 225 private final ReadWriteLock keyLock = new ReentrantReadWriteLock(true); 226 227 /* 228 * The combined count of the currently active objects for all keys and those 229 * in the process of being created. Under load, it may exceed 230 * {@link #maxTotal} but there will never be more than {@link #maxTotal} 231 * created at any one time. 232 */ 233 private final AtomicInteger numTotal = new AtomicInteger(0); 234 235 private Iterator<K> evictionKeyIterator = null; // @GuardedBy("evictionLock") 236 237 238 private K evictionKey = null; // @GuardedBy("evictionLock") 239 240 // Additional configuration properties for abandoned object tracking 241 private volatile AbandonedConfig abandonedConfig; 242 243 /** 244 * Create a new {@code GenericKeyedObjectPool} using defaults from 245 * {@link GenericKeyedObjectPoolConfig}. 246 * @param factory the factory to be used to create entries 247 */ 248 public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory) { 249 this(factory, new GenericKeyedObjectPoolConfig<>()); 250 } 251 252 /** 253 * Create a new {@code GenericKeyedObjectPool} using a specific 254 * configuration. 255 * 256 * @param factory the factory to be used to create entries 257 * @param config The configuration to use for this pool instance. The 258 * configuration is used by value. Subsequent changes to 259 * the configuration object will not be reflected in the 260 * pool. 261 */ 262 public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory, 263 final GenericKeyedObjectPoolConfig<T> config) { 264 265 super(config, ONAME_BASE, config.getJmxNamePrefix()); 266 267 if (factory == null) { 268 jmxUnregister(); // tidy up 269 throw new IllegalArgumentException("factory may not be null"); 270 } 271 this.factory = factory; 272 this.fairness = config.getFairness(); 273 274 setConfig(config); 275 } 276 277 /** 278 * Creates a new {@code GenericKeyedObjectPool} that tracks and destroys 279 * objects that are checked out, but never returned to the pool. 280 * 281 * @param factory The object factory to be used to create object instances 282 * used by this pool 283 * @param config The base pool configuration to use for this pool instance. 284 * The configuration is used by value. Subsequent changes to 285 * the configuration object will not be reflected in the 286 * pool. 287 * @param abandonedConfig Configuration for abandoned object identification 288 * and removal. The configuration is used by value. 289 * @since 2.10.0 290 */ 291 public GenericKeyedObjectPool(final KeyedPooledObjectFactory<K, T> factory, 292 final GenericKeyedObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) { 293 this(factory, config); 294 setAbandonedConfig(abandonedConfig); 295 } 296 297 /** 298 * Add an object to the set of idle objects for a given key. 299 * 300 * @param key The key to associate with the idle object 301 * @param p The wrapped object to add. 302 * 303 * @throws Exception If the associated factory fails to passivate the object 304 */ 305 private void addIdleObject(final K key, final PooledObject<T> p) throws Exception { 306 307 if (p != null) { 308 factory.passivateObject(key, p); 309 final LinkedBlockingDeque<PooledObject<T>> idleObjects = 310 poolMap.get(key).getIdleObjects(); 311 if (getLifo()) { 312 idleObjects.addFirst(p); 313 } else { 314 idleObjects.addLast(p); 315 } 316 } 317 } 318 319 320 /** 321 * Create an object using the {@link KeyedPooledObjectFactory#makeObject 322 * factory}, passivate it, and then place it in the idle object pool. 323 * {@code addObject} is useful for "pre-loading" a pool with idle 324 * objects. 325 * 326 * @param key the key a new instance should be added to 327 * 328 * @throws Exception when {@link KeyedPooledObjectFactory#makeObject} 329 * fails. 330 */ 331 @Override 332 public void addObject(final K key) throws Exception { 333 assertOpen(); 334 register(key); 335 try { 336 final PooledObject<T> p = create(key); 337 addIdleObject(key, p); 338 } finally { 339 deregister(key); 340 } 341 } 342 343 344 /** 345 * Equivalent to <code>{@link #borrowObject(Object, long) borrowObject}(key, 346 * {@link #getMaxWaitMillis()})</code>. 347 * <p> 348 * {@inheritDoc} 349 */ 350 @Override 351 public T borrowObject(final K key) throws Exception { 352 return borrowObject(key, getMaxWaitMillis()); 353 } 354 355 356 /** 357 * Borrows an object from the sub-pool associated with the given key using 358 * the specified waiting time which only applies if 359 * {@link #getBlockWhenExhausted()} is true. 360 * <p> 361 * If there is one or more idle instances available in the sub-pool 362 * associated with the given key, then an idle instance will be selected 363 * based on the value of {@link #getLifo()}, activated and returned. If 364 * activation fails, or {@link #getTestOnBorrow() testOnBorrow} is set to 365 * {@code true} and validation fails, the instance is destroyed and the 366 * next available instance is examined. This continues until either a valid 367 * instance is returned or there are no more idle instances available. 368 * <p> 369 * If there are no idle instances available in the sub-pool associated with 370 * the given key, behavior depends on the {@link #getMaxTotalPerKey() 371 * maxTotalPerKey}, {@link #getMaxTotal() maxTotal}, and (if applicable) 372 * {@link #getBlockWhenExhausted()} and the value passed in to the 373 * {@code borrowMaxWaitMillis} parameter. If the number of instances checked 374 * out from the sub-pool under the given key is less than 375 * {@code maxTotalPerKey} and the total number of instances in 376 * circulation (under all keys) is less than {@code maxTotal}, a new 377 * instance is created, activated and (if applicable) validated and returned 378 * to the caller. If validation fails, a {@code NoSuchElementException} 379 * will be thrown. 380 * <p> 381 * If the associated sub-pool is exhausted (no available idle instances and 382 * no capacity to create new ones), this method will either block 383 * ({@link #getBlockWhenExhausted()} is true) or throw a 384 * {@code NoSuchElementException} 385 * ({@link #getBlockWhenExhausted()} is false). 386 * The length of time that this method will block when 387 * {@link #getBlockWhenExhausted()} is true is determined by the value 388 * passed in to the {@code borrowMaxWait} parameter. 389 * <p> 390 * When {@code maxTotal} is set to a positive value and this method is 391 * invoked when at the limit with no idle instances available under the requested 392 * key, an attempt is made to create room by clearing the oldest 15% of the 393 * elements from the keyed sub-pools. 394 * <p> 395 * When the pool is exhausted, multiple calling threads may be 396 * simultaneously blocked waiting for instances to become available. A 397 * "fairness" algorithm has been implemented to ensure that threads receive 398 * available instances in request arrival order. 399 * 400 * @param key pool key 401 * @param borrowMaxWaitMillis The time to wait in milliseconds for an object 402 * to become available 403 * 404 * @return object instance from the keyed pool 405 * 406 * @throws NoSuchElementException if a keyed object instance cannot be 407 * returned because the pool is exhausted. 408 * 409 * @throws Exception if a keyed object instance cannot be returned due to an 410 * error 411 */ 412 public T borrowObject(final K key, final long borrowMaxWaitMillis) throws Exception { 413 assertOpen(); 414 415 final AbandonedConfig ac = this.abandonedConfig; 416 if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) && 417 (getNumActive() > getMaxTotal() - 3)) { 418 removeAbandoned(ac); 419 } 420 421 PooledObject<T> p = null; 422 423 // Get local copy of current config so it is consistent for entire 424 // method execution 425 final boolean blockWhenExhausted = getBlockWhenExhausted(); 426 427 boolean create; 428 final long waitTimeMillis = System.currentTimeMillis(); 429 final ObjectDeque<T> objectDeque = register(key); 430 431 try { 432 while (p == null) { 433 create = false; 434 p = objectDeque.getIdleObjects().pollFirst(); 435 if (p == null) { 436 p = create(key); 437 if (p != null) { 438 create = true; 439 } 440 } 441 if (blockWhenExhausted) { 442 if (p == null) { 443 if (borrowMaxWaitMillis < 0) { 444 p = objectDeque.getIdleObjects().takeFirst(); 445 } else { 446 p = objectDeque.getIdleObjects().pollFirst( 447 borrowMaxWaitMillis, TimeUnit.MILLISECONDS); 448 } 449 } 450 if (p == null) { 451 throw new NoSuchElementException( 452 "Timeout waiting for idle object"); 453 } 454 } else if (p == null) { 455 throw new NoSuchElementException("Pool exhausted"); 456 } 457 if (!p.allocate()) { 458 p = null; 459 } 460 461 if (p != null) { 462 try { 463 factory.activateObject(key, p); 464 } catch (final Exception e) { 465 try { 466 destroy(key, p, true, DestroyMode.NORMAL); 467 } catch (final Exception e1) { 468 // Ignore - activation failure is more important 469 } 470 p = null; 471 if (create) { 472 final NoSuchElementException nsee = new NoSuchElementException( 473 "Unable to activate object"); 474 nsee.initCause(e); 475 throw nsee; 476 } 477 } 478 if (p != null && getTestOnBorrow()) { 479 boolean validate = false; 480 Throwable validationThrowable = null; 481 try { 482 validate = factory.validateObject(key, p); 483 } catch (final Throwable t) { 484 PoolUtils.checkRethrow(t); 485 validationThrowable = t; 486 } 487 if (!validate) { 488 try { 489 destroy(key, p, true, DestroyMode.NORMAL); 490 destroyedByBorrowValidationCount.incrementAndGet(); 491 } catch (final Exception e) { 492 // Ignore - validation failure is more important 493 } 494 p = null; 495 if (create) { 496 final NoSuchElementException nsee = new NoSuchElementException( 497 "Unable to validate object"); 498 nsee.initCause(validationThrowable); 499 throw nsee; 500 } 501 } 502 } 503 } 504 } 505 } finally { 506 deregister(key); 507 } 508 509 updateStatsBorrow(p, Duration.ofMillis(System.currentTimeMillis() - waitTimeMillis)); 510 511 return p.getObject(); 512 } 513 514 515 /** 516 * Calculate the number of objects that need to be created to attempt to 517 * maintain the minimum number of idle objects while not exceeded the limits 518 * on the maximum number of objects either per key or totally. 519 * 520 * @param objectDeque The set of objects to check 521 * 522 * @return The number of new objects to create 523 */ 524 private int calculateDeficit(final ObjectDeque<T> objectDeque) { 525 526 if (objectDeque == null) { 527 return getMinIdlePerKey(); 528 } 529 530 // Used more than once so keep a local copy so the value is consistent 531 final int maxTotal = getMaxTotal(); 532 final int maxTotalPerKeySave = getMaxTotalPerKey(); 533 534 // Calculate no of objects needed to be created, in order to have 535 // the number of pooled objects < maxTotalPerKey(); 536 int objectDefecit = getMinIdlePerKey() - objectDeque.getIdleObjects().size(); 537 if (maxTotalPerKeySave > 0) { 538 final int growLimit = Math.max(0, 539 maxTotalPerKeySave - objectDeque.getIdleObjects().size()); 540 objectDefecit = Math.min(objectDefecit, growLimit); 541 } 542 543 // Take the maxTotal limit into account 544 if (maxTotal > 0) { 545 final int growLimit = Math.max(0, maxTotal - getNumActive() - getNumIdle()); 546 objectDefecit = Math.min(objectDefecit, growLimit); 547 } 548 549 return objectDefecit; 550 } 551 552 553 /** 554 * Clears any objects sitting idle in the pool by removing them from the 555 * idle instance sub-pools and then invoking the configured 556 * PoolableObjectFactory's 557 * {@link KeyedPooledObjectFactory#destroyObject(Object, PooledObject)} 558 * method on each idle instance. 559 * <p> 560 * Implementation notes: 561 * <ul> 562 * <li>This method does not destroy or effect in any way instances that are 563 * checked out when it is invoked.</li> 564 * <li>Invoking this method does not prevent objects being returned to the 565 * idle instance pool, even during its execution. Additional instances may 566 * be returned while removed items are being destroyed.</li> 567 * <li>Exceptions encountered destroying idle instances are swallowed 568 * but notified via a {@link SwallowedExceptionListener}.</li> 569 * </ul> 570 */ 571 @Override 572 public void clear() { 573 final Iterator<K> iter = poolMap.keySet().iterator(); 574 575 while (iter.hasNext()) { 576 clear(iter.next()); 577 } 578 } 579 580 581 /** 582 * Clears the specified sub-pool, removing all pooled instances 583 * corresponding to the given {@code key}. Exceptions encountered 584 * destroying idle instances are swallowed but notified via a 585 * {@link SwallowedExceptionListener}. 586 * 587 * @param key the key to clear 588 */ 589 @Override 590 public void clear(final K key) { 591 592 final ObjectDeque<T> objectDeque = register(key); 593 594 try { 595 final LinkedBlockingDeque<PooledObject<T>> idleObjects = 596 objectDeque.getIdleObjects(); 597 598 PooledObject<T> p = idleObjects.poll(); 599 600 while (p != null) { 601 try { 602 destroy(key, p, true, DestroyMode.NORMAL); 603 } catch (final Exception e) { 604 swallowException(e); 605 } 606 p = idleObjects.poll(); 607 } 608 } finally { 609 deregister(key); 610 } 611 } 612 613 614 /** 615 * Clears oldest 15% of objects in pool. The method sorts the objects into 616 * a TreeMap and then iterates the first 15% for removal. 617 */ 618 public void clearOldest() { 619 620 // build sorted map of idle objects 621 final Map<PooledObject<T>, K> map = new TreeMap<>(); 622 623 for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) { 624 final K k = entry.getKey(); 625 final ObjectDeque<T> deque = entry.getValue(); 626 // Protect against possible NPE if key has been removed in another 627 // thread. Not worth locking the keys while this loop completes. 628 if (deque != null) { 629 final LinkedBlockingDeque<PooledObject<T>> idleObjects = 630 deque.getIdleObjects(); 631 for (final PooledObject<T> p : idleObjects) { 632 // each item into the map using the PooledObject object as the 633 // key. It then gets sorted based on the idle time 634 map.put(p, k); 635 } 636 } 637 } 638 639 // Now iterate created map and kill the first 15% plus one to account 640 // for zero 641 int itemsToRemove = ((int) (map.size() * 0.15)) + 1; 642 final Iterator<Map.Entry<PooledObject<T>, K>> iter = 643 map.entrySet().iterator(); 644 645 while (iter.hasNext() && itemsToRemove > 0) { 646 final Map.Entry<PooledObject<T>, K> entry = iter.next(); 647 // kind of backwards on naming. In the map, each key is the 648 // PooledObject because it has the ordering with the timestamp 649 // value. Each value that the key references is the key of the 650 // list it belongs to. 651 final K key = entry.getValue(); 652 final PooledObject<T> p = entry.getKey(); 653 // Assume the destruction succeeds 654 boolean destroyed = true; 655 try { 656 destroyed = destroy(key, p, false, DestroyMode.NORMAL); 657 } catch (final Exception e) { 658 swallowException(e); 659 } 660 if (destroyed) { 661 itemsToRemove--; 662 } 663 } 664 } 665 666 667 /** 668 * Closes the keyed object pool. Once the pool is closed, 669 * {@link #borrowObject(Object)} will fail with IllegalStateException, but 670 * {@link #returnObject(Object, Object)} and 671 * {@link #invalidateObject(Object, Object)} will continue to work, with 672 * returned objects destroyed on return. 673 * <p> 674 * Destroys idle instances in the pool by invoking {@link #clear()}. 675 */ 676 @Override 677 public void close() { 678 if (isClosed()) { 679 return; 680 } 681 682 synchronized (closeLock) { 683 if (isClosed()) { 684 return; 685 } 686 687 // Stop the evictor before the pool is closed since evict() calls 688 // assertOpen() 689 stopEvictor(); 690 691 closed = true; 692 // This clear removes any idle objects 693 clear(); 694 695 jmxUnregister(); 696 697 // Release any threads that were waiting for an object 698 final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator(); 699 while (iter.hasNext()) { 700 iter.next().getIdleObjects().interuptTakeWaiters(); 701 } 702 // This clear cleans up the keys now any waiting threads have been 703 // interrupted 704 clear(); 705 } 706 } 707 708 /** 709 * Create a new pooled object. 710 * 711 * @param key Key associated with new pooled object 712 * 713 * @return The new, wrapped pooled object 714 * 715 * @throws Exception If the objection creation fails 716 */ 717 private PooledObject<T> create(final K key) throws Exception { 718 int maxTotalPerKeySave = getMaxTotalPerKey(); // Per key 719 if (maxTotalPerKeySave < 0) { 720 maxTotalPerKeySave = Integer.MAX_VALUE; 721 } 722 final int maxTotal = getMaxTotal(); // All keys 723 724 final ObjectDeque<T> objectDeque = poolMap.get(key); 725 726 // Check against the overall limit 727 boolean loop = true; 728 729 while (loop) { 730 final int newNumTotal = numTotal.incrementAndGet(); 731 if (maxTotal > -1 && newNumTotal > maxTotal) { 732 numTotal.decrementAndGet(); 733 if (getNumIdle() == 0) { 734 return null; 735 } 736 clearOldest(); 737 } else { 738 loop = false; 739 } 740 } 741 742 // Flag that indicates if create should: 743 // - TRUE: call the factory to create an object 744 // - FALSE: return null 745 // - null: loop and re-test the condition that determines whether to 746 // call the factory 747 Boolean create = null; 748 while (create == null) { 749 synchronized (objectDeque.makeObjectCountLock) { 750 final long newCreateCount = objectDeque.getCreateCount().incrementAndGet(); 751 // Check against the per key limit 752 if (newCreateCount > maxTotalPerKeySave) { 753 // The key is currently at capacity or in the process of 754 // making enough new objects to take it to capacity. 755 objectDeque.getCreateCount().decrementAndGet(); 756 if (objectDeque.makeObjectCount == 0) { 757 // There are no makeObject() calls in progress for this 758 // key so the key is at capacity. Do not attempt to 759 // create a new object. Return and wait for an object to 760 // be returned. 761 create = Boolean.FALSE; 762 } else { 763 // There are makeObject() calls in progress that might 764 // bring the pool to capacity. Those calls might also 765 // fail so wait until they complete and then re-test if 766 // the pool is at capacity or not. 767 objectDeque.makeObjectCountLock.wait(); 768 } 769 } else { 770 // The pool is not at capacity. Create a new object. 771 objectDeque.makeObjectCount++; 772 create = Boolean.TRUE; 773 } 774 } 775 } 776 777 if (!create.booleanValue()) { 778 numTotal.decrementAndGet(); 779 return null; 780 } 781 782 PooledObject<T> p = null; 783 try { 784 p = factory.makeObject(key); 785 if (getTestOnCreate() && !factory.validateObject(key, p)) { 786 numTotal.decrementAndGet(); 787 objectDeque.getCreateCount().decrementAndGet(); 788 return null; 789 } 790 } catch (final Exception e) { 791 numTotal.decrementAndGet(); 792 objectDeque.getCreateCount().decrementAndGet(); 793 throw e; 794 } finally { 795 synchronized (objectDeque.makeObjectCountLock) { 796 objectDeque.makeObjectCount--; 797 objectDeque.makeObjectCountLock.notifyAll(); 798 } 799 } 800 801 final AbandonedConfig ac = this.abandonedConfig; 802 if (ac != null && ac.getLogAbandoned()) { 803 p.setLogAbandoned(true); 804 p.setRequireFullStackTrace(ac.getRequireFullStackTrace()); 805 } 806 807 createdCount.incrementAndGet(); 808 objectDeque.getAllObjects().put(new IdentityWrapper<>(p.getObject()), p); 809 return p; 810 } 811 812 /** 813 * De-register the use of a key by an object. 814 * <p> 815 * register() and deregister() must always be used as a pair. 816 * 817 * @param k The key to de-register 818 */ 819 private void deregister(final K k) { 820 Lock lock = keyLock.readLock(); 821 try { 822 lock.lock(); 823 final ObjectDeque<T> objectDeque = poolMap.get(k); 824 final long numInterested = objectDeque.getNumInterested().decrementAndGet(); 825 if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) { 826 // Potential to remove key 827 // Upgrade to write lock 828 lock.unlock(); 829 lock = keyLock.writeLock(); 830 lock.lock(); 831 if (objectDeque.getCreateCount().get() == 0 && objectDeque.getNumInterested().get() == 0) { 832 // NOTE: Keys must always be removed from both poolMap and 833 // poolKeyList at the same time while protected by 834 // keyLock.writeLock() 835 poolMap.remove(k); 836 poolKeyList.remove(k); 837 } 838 } 839 } finally { 840 lock.unlock(); 841 } 842 } 843 844 845 /** 846 * Destroy the wrapped, pooled object. 847 * 848 * @param key The key associated with the object to destroy. 849 * @param toDestroy The wrapped object to be destroyed 850 * @param always Should the object be destroyed even if it is not currently 851 * in the set of idle objects for the given key 852 * @param mode DestroyMode context provided to the factory 853 * 854 * @return {@code true} if the object was destroyed, otherwise {@code false} 855 * @throws Exception If the object destruction failed 856 */ 857 private boolean destroy(final K key, final PooledObject<T> toDestroy, final boolean always, final DestroyMode mode) 858 throws Exception { 859 860 final ObjectDeque<T> objectDeque = register(key); 861 862 try { 863 boolean isIdle; 864 synchronized(toDestroy) { 865 // Check idle state directly 866 isIdle = toDestroy.getState().equals(PooledObjectState.IDLE); 867 // If idle, not under eviction test, or always is true, remove instance, 868 // updating isIdle if instance is found in idle objects 869 if (isIdle || always) { 870 isIdle = objectDeque.getIdleObjects().remove(toDestroy); 871 } 872 } 873 if (isIdle || always) { 874 objectDeque.getAllObjects().remove(new IdentityWrapper<>(toDestroy.getObject())); 875 toDestroy.invalidate(); 876 877 try { 878 factory.destroyObject(key, toDestroy, mode); 879 } finally { 880 objectDeque.getCreateCount().decrementAndGet(); 881 destroyedCount.incrementAndGet(); 882 numTotal.decrementAndGet(); 883 } 884 return true; 885 } 886 return false; 887 } finally { 888 deregister(key); 889 } 890 } 891 892 @Override 893 void ensureMinIdle() throws Exception { 894 final int minIdlePerKeySave = getMinIdlePerKey(); 895 if (minIdlePerKeySave < 1) { 896 return; 897 } 898 899 for (final K k : poolMap.keySet()) { 900 ensureMinIdle(k); 901 } 902 } 903 904 /** 905 * Ensure that the configured number of minimum idle objects is available in 906 * the pool for the given key. 907 * 908 * @param key The key to check for idle objects 909 * 910 * @throws Exception If a new object is required and cannot be created 911 */ 912 private void ensureMinIdle(final K key) throws Exception { 913 // Calculate current pool objects 914 ObjectDeque<T> objectDeque = poolMap.get(key); 915 916 // objectDeque == null is OK here. It is handled correctly by both 917 // methods called below. 918 919 // this method isn't synchronized so the 920 // calculateDeficit is done at the beginning 921 // as a loop limit and a second time inside the loop 922 // to stop when another thread already returned the 923 // needed objects 924 final int deficit = calculateDeficit(objectDeque); 925 926 for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) { 927 addObject(key); 928 // If objectDeque was null, it won't be any more. Obtain a reference 929 // to it so the deficit can be correctly calculated. It needs to 930 // take account of objects created in other threads. 931 if (objectDeque == null) { 932 objectDeque = poolMap.get(key); 933 } 934 } 935 } 936 937 938 /** 939 * {@inheritDoc} 940 * <p> 941 * Successive activations of this method examine objects in keyed sub-pools 942 * in sequence, cycling through the keys and examining objects in 943 * oldest-to-youngest order within the keyed sub-pools. 944 */ 945 @Override 946 public void evict() throws Exception { 947 assertOpen(); 948 949 if (getNumIdle() > 0) { 950 951 PooledObject<T> underTest = null; 952 final EvictionPolicy<T> evictionPolicy = getEvictionPolicy(); 953 954 synchronized (evictionLock) { 955 final EvictionConfig evictionConfig = new EvictionConfig( 956 getMinEvictableIdleTime(), 957 getSoftMinEvictableIdleTime(), 958 getMinIdlePerKey()); 959 960 final boolean testWhileIdle = getTestWhileIdle(); 961 962 for (int i = 0, m = getNumTests(); i < m; i++) { 963 if(evictionIterator == null || !evictionIterator.hasNext()) { 964 if (evictionKeyIterator == null || 965 !evictionKeyIterator.hasNext()) { 966 final List<K> keyCopy = new ArrayList<>(); 967 final Lock readLock = keyLock.readLock(); 968 readLock.lock(); 969 try { 970 keyCopy.addAll(poolKeyList); 971 } finally { 972 readLock.unlock(); 973 } 974 evictionKeyIterator = keyCopy.iterator(); 975 } 976 while (evictionKeyIterator.hasNext()) { 977 evictionKey = evictionKeyIterator.next(); 978 final ObjectDeque<T> objectDeque = poolMap.get(evictionKey); 979 if (objectDeque == null) { 980 continue; 981 } 982 983 final Deque<PooledObject<T>> idleObjects = objectDeque.getIdleObjects(); 984 evictionIterator = new EvictionIterator(idleObjects); 985 if (evictionIterator.hasNext()) { 986 break; 987 } 988 evictionIterator = null; 989 } 990 } 991 if (evictionIterator == null) { 992 // Pools exhausted 993 return; 994 } 995 final Deque<PooledObject<T>> idleObjects; 996 try { 997 underTest = evictionIterator.next(); 998 idleObjects = evictionIterator.getIdleObjects(); 999 } catch (final NoSuchElementException nsee) { 1000 // Object was borrowed in another thread 1001 // Don't count this as an eviction test so reduce i; 1002 i--; 1003 evictionIterator = null; 1004 continue; 1005 } 1006 1007 if (!underTest.startEvictionTest()) { 1008 // Object was borrowed in another thread 1009 // Don't count this as an eviction test so reduce i; 1010 i--; 1011 continue; 1012 } 1013 1014 // User provided eviction policy could throw all sorts of 1015 // crazy exceptions. Protect against such an exception 1016 // killing the eviction thread. 1017 boolean evict; 1018 try { 1019 evict = evictionPolicy.evict(evictionConfig, underTest, 1020 poolMap.get(evictionKey).getIdleObjects().size()); 1021 } catch (final Throwable t) { 1022 // Slightly convoluted as SwallowedExceptionListener 1023 // uses Exception rather than Throwable 1024 PoolUtils.checkRethrow(t); 1025 swallowException(new Exception(t)); 1026 // Don't evict on error conditions 1027 evict = false; 1028 } 1029 1030 if (evict) { 1031 destroy(evictionKey, underTest, true, DestroyMode.NORMAL); 1032 destroyedByEvictorCount.incrementAndGet(); 1033 } else { 1034 if (testWhileIdle) { 1035 boolean active = false; 1036 try { 1037 factory.activateObject(evictionKey, underTest); 1038 active = true; 1039 } catch (final Exception e) { 1040 destroy(evictionKey, underTest, true, DestroyMode.NORMAL); 1041 destroyedByEvictorCount.incrementAndGet(); 1042 } 1043 if (active) { 1044 if (!factory.validateObject(evictionKey, underTest)) { 1045 destroy(evictionKey, underTest, true, DestroyMode.NORMAL); 1046 destroyedByEvictorCount.incrementAndGet(); 1047 } else { 1048 try { 1049 factory.passivateObject(evictionKey, underTest); 1050 } catch (final Exception e) { 1051 destroy(evictionKey, underTest, true, DestroyMode.NORMAL); 1052 destroyedByEvictorCount.incrementAndGet(); 1053 } 1054 } 1055 } 1056 } 1057 if (!underTest.endEvictionTest(idleObjects)) { 1058 // TODO - May need to add code here once additional 1059 // states are used 1060 } 1061 } 1062 } 1063 } 1064 } 1065 final AbandonedConfig ac = this.abandonedConfig; 1066 if (ac != null && ac.getRemoveAbandonedOnMaintenance()) { 1067 removeAbandoned(ac); 1068 } 1069 } 1070 1071 /** 1072 * Obtain a reference to the factory used to create, destroy and validate 1073 * the objects used by this pool. 1074 * 1075 * @return the factory 1076 */ 1077 public KeyedPooledObjectFactory<K, T> getFactory() { 1078 return factory; 1079 } 1080 1081 /** 1082 * Gets whether this pool identifies and logs any abandoned objects. 1083 * 1084 * @return {@code true} if abandoned object removal is configured for this 1085 * pool and removal events are to be logged otherwise {@code false} 1086 * 1087 * @see AbandonedConfig#getLogAbandoned() 1088 * @since 2.10.0 1089 */ 1090 @Override 1091 public boolean getLogAbandoned() { 1092 final AbandonedConfig ac = this.abandonedConfig; 1093 return ac != null && ac.getLogAbandoned(); 1094 } 1095 1096 /** 1097 * Gets the cap on the number of "idle" instances per key in the pool. 1098 * If maxIdlePerKey is set too low on heavily loaded systems it is possible 1099 * you will see objects being destroyed and almost immediately new objects 1100 * being created. This is a result of the active threads momentarily 1101 * returning objects faster than they are requesting them, causing the 1102 * number of idle objects to rise above maxIdlePerKey. The best value for 1103 * maxIdlePerKey for heavily loaded system will vary but the default is a 1104 * good starting point. 1105 * 1106 * @return the maximum number of "idle" instances that can be held in a 1107 * given keyed sub-pool or a negative value if there is no limit 1108 * 1109 * @see #setMaxIdlePerKey 1110 */ 1111 @Override 1112 public int getMaxIdlePerKey() { 1113 return maxIdlePerKey; 1114 } 1115 1116 /** 1117 * Gets the limit on the number of object instances allocated by the pool 1118 * (checked out or idle), per key. When the limit is reached, the sub-pool 1119 * is said to be exhausted. A negative value indicates no limit. 1120 * 1121 * @return the limit on the number of active instances per key 1122 * 1123 * @see #setMaxTotalPerKey 1124 */ 1125 @Override 1126 public int getMaxTotalPerKey() { 1127 return maxTotalPerKey; 1128 } 1129 1130 /** 1131 * Gets the target for the minimum number of idle objects to maintain in 1132 * each of the keyed sub-pools. This setting only has an effect if it is 1133 * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than 1134 * zero. If this is the case, an attempt is made to ensure that each 1135 * sub-pool has the required minimum number of instances during idle object 1136 * eviction runs. 1137 * <p> 1138 * If the configured value of minIdlePerKey is greater than the configured 1139 * value for maxIdlePerKey then the value of maxIdlePerKey will be used 1140 * instead. 1141 * 1142 * @return minimum size of the each keyed pool 1143 * 1144 * @see #setTimeBetweenEvictionRunsMillis 1145 */ 1146 @Override 1147 public int getMinIdlePerKey() { 1148 final int maxIdlePerKeySave = getMaxIdlePerKey(); 1149 if (this.minIdlePerKey > maxIdlePerKeySave) { 1150 return maxIdlePerKeySave; 1151 } 1152 return minIdlePerKey; 1153 } 1154 1155 @Override 1156 public int getNumActive() { 1157 return numTotal.get() - getNumIdle(); 1158 } 1159 1160 @Override 1161 public int getNumActive(final K key) { 1162 final ObjectDeque<T> objectDeque = poolMap.get(key); 1163 if (objectDeque != null) { 1164 return objectDeque.getAllObjects().size() - 1165 objectDeque.getIdleObjects().size(); 1166 } 1167 return 0; 1168 } 1169 1170 @Override 1171 public Map<String,Integer> getNumActivePerKey() { 1172 final HashMap<String,Integer> result = new HashMap<>(); 1173 1174 final Iterator<Entry<K,ObjectDeque<T>>> iter = poolMap.entrySet().iterator(); 1175 while (iter.hasNext()) { 1176 final Entry<K,ObjectDeque<T>> entry = iter.next(); 1177 if (entry != null) { 1178 final K key = entry.getKey(); 1179 final ObjectDeque<T> objectDequeue = entry.getValue(); 1180 if (key != null && objectDequeue != null) { 1181 result.put(key.toString(), Integer.valueOf( 1182 objectDequeue.getAllObjects().size() - 1183 objectDequeue.getIdleObjects().size())); 1184 } 1185 } 1186 } 1187 return result; 1188 } 1189 1190 @Override 1191 public int getNumIdle() { 1192 final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator(); 1193 int result = 0; 1194 1195 while (iter.hasNext()) { 1196 result += iter.next().getIdleObjects().size(); 1197 } 1198 1199 return result; 1200 } 1201 1202 1203 //--- JMX support ---------------------------------------------------------- 1204 1205 @Override 1206 public int getNumIdle(final K key) { 1207 final ObjectDeque<T> objectDeque = poolMap.get(key); 1208 return objectDeque != null ? objectDeque.getIdleObjects().size() : 0; 1209 } 1210 1211 /** 1212 * Calculate the number of objects to test in a run of the idle object 1213 * evictor. 1214 * 1215 * @return The number of objects to test for validity 1216 */ 1217 private int getNumTests() { 1218 final int totalIdle = getNumIdle(); 1219 final int numTests = getNumTestsPerEvictionRun(); 1220 if (numTests >= 0) { 1221 return Math.min(numTests, totalIdle); 1222 } 1223 return(int)(Math.ceil(totalIdle/Math.abs((double)numTests))); 1224 } 1225 1226 /** 1227 * Return an estimate of the number of threads currently blocked waiting for 1228 * an object from the pool. This is intended for monitoring only, not for 1229 * synchronization control. 1230 * 1231 * @return The estimate of the number of threads currently blocked waiting 1232 * for an object from the pool 1233 */ 1234 @Override 1235 public int getNumWaiters() { 1236 int result = 0; 1237 1238 if (getBlockWhenExhausted()) { 1239 final Iterator<ObjectDeque<T>> iter = poolMap.values().iterator(); 1240 1241 while (iter.hasNext()) { 1242 // Assume no overflow 1243 result += iter.next().getIdleObjects().getTakeQueueLength(); 1244 } 1245 } 1246 1247 return result; 1248 } 1249 1250 /** 1251 * Return an estimate of the number of threads currently blocked waiting for 1252 * an object from the pool for each key. This is intended for 1253 * monitoring only, not for synchronization control. 1254 * 1255 * @return The estimate of the number of threads currently blocked waiting 1256 * for an object from the pool for each key 1257 */ 1258 @Override 1259 public Map<String,Integer> getNumWaitersByKey() { 1260 final Map<String,Integer> result = new HashMap<>(); 1261 1262 for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) { 1263 final K k = entry.getKey(); 1264 final ObjectDeque<T> deque = entry.getValue(); 1265 if (deque != null) { 1266 if (getBlockWhenExhausted()) { 1267 result.put(k.toString(), Integer.valueOf( 1268 deque.getIdleObjects().getTakeQueueLength())); 1269 } else { 1270 result.put(k.toString(), Integer.valueOf(0)); 1271 } 1272 } 1273 } 1274 return result; 1275 } 1276 1277 /** 1278 * Gets whether a check is made for abandoned objects when an object is borrowed 1279 * from this pool. 1280 * 1281 * @return {@code true} if abandoned object removal is configured to be 1282 * activated by borrowObject otherwise {@code false} 1283 * 1284 * @see AbandonedConfig#getRemoveAbandonedOnBorrow() 1285 * @since 2.10.0 1286 */ 1287 @Override 1288 public boolean getRemoveAbandonedOnBorrow() { 1289 final AbandonedConfig ac = this.abandonedConfig; 1290 return ac != null && ac.getRemoveAbandonedOnBorrow(); 1291 } 1292 1293 /** 1294 * Gets whether a check is made for abandoned objects when the evictor runs. 1295 * 1296 * @return {@code true} if abandoned object removal is configured to be 1297 * activated when the evictor runs otherwise {@code false} 1298 * 1299 * @see AbandonedConfig#getRemoveAbandonedOnMaintenance() 1300 * @since 2.10.0 1301 */ 1302 @Override 1303 public boolean getRemoveAbandonedOnMaintenance() { 1304 final AbandonedConfig ac = this.abandonedConfig; 1305 return ac != null && ac.getRemoveAbandonedOnMaintenance(); 1306 } 1307 1308 /** 1309 * Gets the timeout before which an object will be considered to be 1310 * abandoned by this pool. 1311 * 1312 * @return The abandoned object timeout in seconds if abandoned object 1313 * removal is configured for this pool; Integer.MAX_VALUE otherwise. 1314 * 1315 * @see AbandonedConfig#getRemoveAbandonedTimeout() 1316 * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration() 1317 * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}. 1318 * @since 2.10.0 1319 */ 1320 @Override 1321 @Deprecated 1322 public int getRemoveAbandonedTimeout() { 1323 final AbandonedConfig ac = this.abandonedConfig; 1324 return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE; 1325 } 1326 1327 /** 1328 * Gets the timeout before which an object will be considered to be 1329 * abandoned by this pool. 1330 * 1331 * @return The abandoned object timeout in seconds if abandoned object 1332 * removal is configured for this pool; Integer.MAX_VALUE otherwise. 1333 * 1334 * @see AbandonedConfig#getRemoveAbandonedTimeout() 1335 * @see AbandonedConfig#getRemoveAbandonedTimeoutDuration() 1336 * @since 2.10.0 1337 */ 1338 public Duration getRemoveAbandonedTimeoutDuration() { 1339 final AbandonedConfig ac = this.abandonedConfig; 1340 return ac != null ? ac.getRemoveAbandonedTimeoutDuration() : DEFAULT_REMOVE_ABANDONED_TIMEOUT; 1341 } 1342 1343 1344 //--- inner classes ---------------------------------------------- 1345 1346 /** 1347 * Checks to see if there are any threads currently waiting to borrow 1348 * objects but are blocked waiting for more objects to become available. 1349 * 1350 * @return {@code true} if there is at least one thread waiting otherwise 1351 * {@code false} 1352 */ 1353 private boolean hasBorrowWaiters() { 1354 for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) { 1355 final ObjectDeque<T> deque = entry.getValue(); 1356 if (deque != null) { 1357 final LinkedBlockingDeque<PooledObject<T>> pool = 1358 deque.getIdleObjects(); 1359 if(pool.hasTakeWaiters()) { 1360 return true; 1361 } 1362 } 1363 } 1364 return false; 1365 } 1366 1367 /** 1368 * {@inheritDoc} 1369 * <p> 1370 * Activation of this method decrements the active count associated with 1371 * the given keyed pool and attempts to destroy {@code obj.} 1372 * 1373 * @param key pool key 1374 * @param obj instance to invalidate 1375 * 1376 * @throws Exception if an exception occurs destroying the 1377 * object 1378 * @throws IllegalStateException if obj does not belong to the pool 1379 * under the given key 1380 */ 1381 @Override 1382 public void invalidateObject(final K key, final T obj) throws Exception { 1383 invalidateObject(key, obj, DestroyMode.NORMAL); 1384 } 1385 /** 1386 * {@inheritDoc} 1387 * <p> 1388 * Activation of this method decrements the active count associated with 1389 * the given keyed pool and attempts to destroy {@code obj.} 1390 * 1391 * @param key pool key 1392 * @param obj instance to invalidate 1393 * @param mode DestroyMode context provided to factory 1394 * 1395 * @throws Exception if an exception occurs destroying the 1396 * object 1397 * @throws IllegalStateException if obj does not belong to the pool 1398 * under the given key 1399 * @since 2.9.0 1400 */ 1401 @Override 1402 public void invalidateObject(final K key, final T obj, final DestroyMode mode) throws Exception { 1403 1404 final ObjectDeque<T> objectDeque = poolMap.get(key); 1405 1406 final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj)); 1407 if (p == null) { 1408 throw new IllegalStateException( 1409 "Object not currently part of this pool"); 1410 } 1411 synchronized (p) { 1412 if (p.getState() != PooledObjectState.INVALID) { 1413 destroy(key, p, true, mode); 1414 } 1415 } 1416 if (objectDeque.idleObjects.hasTakeWaiters()) { 1417 addObject(key); 1418 } 1419 } 1420 /** 1421 * Gets whether or not abandoned object removal is configured for this pool. 1422 * 1423 * @return true if this pool is configured to detect and remove 1424 * abandoned objects 1425 * @since 2.10.0 1426 */ 1427 @Override 1428 public boolean isAbandonedConfig() { 1429 return abandonedConfig != null; 1430 } 1431 /** 1432 * Provides information on all the objects in the pool, both idle (waiting 1433 * to be borrowed) and active (currently borrowed). 1434 * <p> 1435 * Note: This is named listAllObjects so it is presented as an operation via 1436 * JMX. That means it won't be invoked unless the explicitly requested 1437 * whereas all attributes will be automatically requested when viewing the 1438 * attributes for an object in a tool like JConsole. 1439 * 1440 * @return Information grouped by key on all the objects in the pool 1441 */ 1442 @Override 1443 public Map<String,List<DefaultPooledObjectInfo>> listAllObjects() { 1444 final Map<String,List<DefaultPooledObjectInfo>> result = 1445 new HashMap<>(); 1446 1447 for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) { 1448 final K k = entry.getKey(); 1449 final ObjectDeque<T> deque = entry.getValue(); 1450 if (deque != null) { 1451 final List<DefaultPooledObjectInfo> list = 1452 new ArrayList<>(); 1453 result.put(k.toString(), list); 1454 for (final PooledObject<T> p : deque.getAllObjects().values()) { 1455 list.add(new DefaultPooledObjectInfo(p)); 1456 } 1457 } 1458 } 1459 return result; 1460 } 1461 /** 1462 * Registers a key for pool control and ensures that 1463 * {@link #getMinIdlePerKey()} idle instances are created. 1464 * 1465 * @param key - The key to register for pool control. 1466 * 1467 * @throws Exception If the associated factory throws an exception 1468 */ 1469 public void preparePool(final K key) throws Exception { 1470 final int minIdlePerKeySave = getMinIdlePerKey(); 1471 if (minIdlePerKeySave < 1) { 1472 return; 1473 } 1474 ensureMinIdle(key); 1475 } 1476 /** 1477 * Register the use of a key by an object. 1478 * <p> 1479 * register() and deregister() must always be used as a pair. 1480 * 1481 * @param k The key to register 1482 * 1483 * @return The objects currently associated with the given key. If this 1484 * method returns without throwing an exception then it will never 1485 * return null. 1486 */ 1487 private ObjectDeque<T> register(final K k) { 1488 Lock lock = keyLock.readLock(); 1489 ObjectDeque<T> objectDeque = null; 1490 try { 1491 lock.lock(); 1492 objectDeque = poolMap.get(k); 1493 if (objectDeque == null) { 1494 // Upgrade to write lock 1495 lock.unlock(); 1496 lock = keyLock.writeLock(); 1497 lock.lock(); 1498 objectDeque = poolMap.get(k); 1499 if (objectDeque == null) { 1500 objectDeque = new ObjectDeque<>(fairness); 1501 objectDeque.getNumInterested().incrementAndGet(); 1502 // NOTE: Keys must always be added to both poolMap and 1503 // poolKeyList at the same time while protected by 1504 // keyLock.writeLock() 1505 poolMap.put(k, objectDeque); 1506 poolKeyList.add(k); 1507 } else { 1508 objectDeque.getNumInterested().incrementAndGet(); 1509 } 1510 } else { 1511 objectDeque.getNumInterested().incrementAndGet(); 1512 } 1513 } finally { 1514 lock.unlock(); 1515 } 1516 return objectDeque; 1517 } 1518 1519 1520 //--- internal attributes -------------------------------------------------- 1521 1522 /** 1523 * Recovers abandoned objects which have been checked out but 1524 * not used since longer than the removeAbandonedTimeout. 1525 * 1526 * @param abandonedConfig The configuration to use to identify abandoned objects 1527 */ 1528 @SuppressWarnings("resource") // PrintWriter is managed elsewhere 1529 private void removeAbandoned(final AbandonedConfig abandonedConfig) { 1530 for (final Entry<K, GenericKeyedObjectPool<K, T>.ObjectDeque<T>> pool : poolMap.entrySet()) { 1531 final Map<IdentityWrapper<T>, PooledObject<T>> allObjects = pool.getValue().getAllObjects(); 1532 1533 // Generate a list of abandoned objects to remove 1534 final long nowMillis = System.currentTimeMillis(); 1535 final long timeoutMillis = 1536 nowMillis - abandonedConfig.getRemoveAbandonedTimeoutDuration().toMillis(); 1537 final ArrayList<PooledObject<T>> remove = new ArrayList<>(); 1538 final Iterator<PooledObject<T>> it = allObjects.values().iterator(); 1539 while (it.hasNext()) { 1540 final PooledObject<T> pooledObject = it.next(); 1541 synchronized (pooledObject) { 1542 if (pooledObject.getState() == PooledObjectState.ALLOCATED && 1543 pooledObject.getLastUsedTime() <= timeoutMillis) { 1544 pooledObject.markAbandoned(); 1545 remove.add(pooledObject); 1546 } 1547 } 1548 } 1549 1550 // Now remove the abandoned objects 1551 final Iterator<PooledObject<T>> itr = remove.iterator(); 1552 while (itr.hasNext()) { 1553 final PooledObject<T> pooledObject = itr.next(); 1554 if (abandonedConfig.getLogAbandoned()) { 1555 pooledObject.printStackTrace(abandonedConfig.getLogWriter()); 1556 } 1557 try { 1558 invalidateObject(pool.getKey(), pooledObject.getObject(), DestroyMode.ABANDONED); 1559 } catch (final Exception e) { 1560 e.printStackTrace(); 1561 } 1562 } 1563 } 1564 } 1565 1566 /** 1567 * Returns an object to a keyed sub-pool. 1568 * <p> 1569 * If {@link #getMaxIdlePerKey() maxIdle} is set to a positive value and the 1570 * number of idle instances under the given key has reached this value, the 1571 * returning instance is destroyed. 1572 * <p> 1573 * If {@link #getTestOnReturn() testOnReturn} == true, the returning 1574 * instance is validated before being returned to the idle instance sub-pool 1575 * under the given key. In this case, if validation fails, the instance is 1576 * destroyed. 1577 * <p> 1578 * Exceptions encountered destroying objects for any reason are swallowed 1579 * but notified via a {@link SwallowedExceptionListener}. 1580 * 1581 * @param key pool key 1582 * @param obj instance to return to the keyed pool 1583 * 1584 * @throws IllegalStateException if an object is returned to the pool that 1585 * was not borrowed from it or if an object is 1586 * returned to the pool multiple times 1587 */ 1588 @Override 1589 public void returnObject(final K key, final T obj) { 1590 1591 final ObjectDeque<T> objectDeque = poolMap.get(key); 1592 1593 if (objectDeque == null) { 1594 throw new IllegalStateException( 1595 "No keyed pool found under the given key."); 1596 } 1597 1598 final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj)); 1599 1600 if (p == null) { 1601 throw new IllegalStateException( 1602 "Returned object not currently part of this pool"); 1603 } 1604 1605 markReturningState(p); 1606 1607 final Duration activeTime = p.getActiveTime(); 1608 1609 try { 1610 if (getTestOnReturn() && !factory.validateObject(key, p)) { 1611 try { 1612 destroy(key, p, true, DestroyMode.NORMAL); 1613 } catch (final Exception e) { 1614 swallowException(e); 1615 } 1616 whenWaitersAddObject(key, objectDeque.idleObjects); 1617 return; 1618 } 1619 1620 try { 1621 factory.passivateObject(key, p); 1622 } catch (final Exception e1) { 1623 swallowException(e1); 1624 try { 1625 destroy(key, p, true, DestroyMode.NORMAL); 1626 } catch (final Exception e) { 1627 swallowException(e); 1628 } 1629 whenWaitersAddObject(key, objectDeque.idleObjects); 1630 return; 1631 } 1632 1633 if (!p.deallocate()) { 1634 throw new IllegalStateException( 1635 "Object has already been returned to this pool"); 1636 } 1637 1638 final int maxIdle = getMaxIdlePerKey(); 1639 final LinkedBlockingDeque<PooledObject<T>> idleObjects = 1640 objectDeque.getIdleObjects(); 1641 1642 if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { 1643 try { 1644 destroy(key, p, true, DestroyMode.NORMAL); 1645 } catch (final Exception e) { 1646 swallowException(e); 1647 } 1648 } else { 1649 if (getLifo()) { 1650 idleObjects.addFirst(p); 1651 } else { 1652 idleObjects.addLast(p); 1653 } 1654 if (isClosed()) { 1655 // Pool closed while object was being added to idle objects. 1656 // Make sure the returned object is destroyed rather than left 1657 // in the idle object pool (which would effectively be a leak) 1658 clear(key); 1659 } 1660 } 1661 } finally { 1662 if (hasBorrowWaiters()) { 1663 reuseCapacity(); 1664 } 1665 updateStatsReturn(activeTime); 1666 } 1667 } 1668 /** 1669 * Attempt to create one new instance to serve from the most heavily 1670 * loaded pool that can add a new instance. 1671 * 1672 * This method exists to ensure liveness in the pool when threads are 1673 * parked waiting and capacity to create instances under the requested keys 1674 * subsequently becomes available. 1675 * 1676 * This method is not guaranteed to create an instance and its selection 1677 * of the most loaded pool that can create an instance may not always be 1678 * correct, since it does not lock the pool and instances may be created, 1679 * borrowed, returned or destroyed by other threads while it is executing. 1680 */ 1681 private void reuseCapacity() { 1682 final int maxTotalPerKeySave = getMaxTotalPerKey(); 1683 1684 // Find the most loaded pool that could take a new instance 1685 int maxQueueLength = 0; 1686 LinkedBlockingDeque<PooledObject<T>> mostLoaded = null; 1687 K loadedKey = null; 1688 for (final Map.Entry<K, ObjectDeque<T>> entry : poolMap.entrySet()) { 1689 final K k = entry.getKey(); 1690 final ObjectDeque<T> deque = entry.getValue(); 1691 if (deque != null) { 1692 final LinkedBlockingDeque<PooledObject<T>> pool = deque.getIdleObjects(); 1693 final int queueLength = pool.getTakeQueueLength(); 1694 if (getNumActive(k) < maxTotalPerKeySave && queueLength > maxQueueLength) { 1695 maxQueueLength = queueLength; 1696 mostLoaded = pool; 1697 loadedKey = k; 1698 } 1699 } 1700 } 1701 1702 // Attempt to add an instance to the most loaded pool 1703 if (mostLoaded != null) { 1704 register(loadedKey); 1705 try { 1706 final PooledObject<T> p = create(loadedKey); 1707 if (p != null) { 1708 addIdleObject(loadedKey, p); 1709 } 1710 } catch (final Exception e) { 1711 swallowException(e); 1712 } finally { 1713 deregister(loadedKey); 1714 } 1715 } 1716 } 1717 /** 1718 * Sets the abandoned object removal configuration. 1719 * 1720 * @param abandonedConfig the new configuration to use. This is used by value. 1721 * 1722 * @see AbandonedConfig 1723 * @since 2.10.0 1724 */ 1725 @SuppressWarnings("resource") // PrintWriter is managed elsewhere 1726 public void setAbandonedConfig(final AbandonedConfig abandonedConfig) { 1727 if (abandonedConfig == null) { 1728 this.abandonedConfig = null; 1729 } else { 1730 this.abandonedConfig = new AbandonedConfig(); 1731 this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned()); 1732 this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter()); 1733 this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow()); 1734 this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance()); 1735 this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeoutDuration()); 1736 this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking()); 1737 this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace()); 1738 } 1739 } 1740 /** 1741 * Sets the configuration. 1742 * 1743 * @param conf the new configuration to use. This is used by value. 1744 * 1745 * @see GenericKeyedObjectPoolConfig 1746 */ 1747 public void setConfig(final GenericKeyedObjectPoolConfig<T> conf) { 1748 super.setConfig(conf); 1749 setMaxIdlePerKey(conf.getMaxIdlePerKey()); 1750 setMaxTotalPerKey(conf.getMaxTotalPerKey()); 1751 setMaxTotal(conf.getMaxTotal()); 1752 setMinIdlePerKey(conf.getMinIdlePerKey()); 1753 } 1754 /** 1755 * Sets the cap on the number of "idle" instances per key in the pool. 1756 * If maxIdlePerKey is set too low on heavily loaded systems it is possible 1757 * you will see objects being destroyed and almost immediately new objects 1758 * being created. This is a result of the active threads momentarily 1759 * returning objects faster than they are requesting them, causing the 1760 * number of idle objects to rise above maxIdlePerKey. The best value for 1761 * maxIdlePerKey for heavily loaded system will vary but the default is a 1762 * good starting point. 1763 * 1764 * @param maxIdlePerKey the maximum number of "idle" instances that can be 1765 * held in a given keyed sub-pool. Use a negative value 1766 * for no limit 1767 * 1768 * @see #getMaxIdlePerKey 1769 */ 1770 public void setMaxIdlePerKey(final int maxIdlePerKey) { 1771 this.maxIdlePerKey = maxIdlePerKey; 1772 } 1773 /** 1774 * Sets the limit on the number of object instances allocated by the pool 1775 * (checked out or idle), per key. When the limit is reached, the sub-pool 1776 * is said to be exhausted. A negative value indicates no limit. 1777 * 1778 * @param maxTotalPerKey the limit on the number of active instances per key 1779 * 1780 * @see #getMaxTotalPerKey 1781 */ 1782 public void setMaxTotalPerKey(final int maxTotalPerKey) { 1783 this.maxTotalPerKey = maxTotalPerKey; 1784 } 1785 /** 1786 * Sets the target for the minimum number of idle objects to maintain in 1787 * each of the keyed sub-pools. This setting only has an effect if it is 1788 * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than 1789 * zero. If this is the case, an attempt is made to ensure that each 1790 * sub-pool has the required minimum number of instances during idle object 1791 * eviction runs. 1792 * <p> 1793 * If the configured value of minIdlePerKey is greater than the configured 1794 * value for maxIdlePerKey then the value of maxIdlePerKey will be used 1795 * instead. 1796 * 1797 * @param minIdlePerKey The minimum size of the each keyed pool 1798 * 1799 * @see #getMinIdlePerKey 1800 * @see #getMaxIdlePerKey() 1801 * @see #setTimeBetweenEvictionRunsMillis 1802 */ 1803 public void setMinIdlePerKey(final int minIdlePerKey) { 1804 this.minIdlePerKey = minIdlePerKey; 1805 } 1806 1807 @Override 1808 protected void toStringAppendFields(final StringBuilder builder) { 1809 super.toStringAppendFields(builder); 1810 builder.append(", maxIdlePerKey="); 1811 builder.append(maxIdlePerKey); 1812 builder.append(", minIdlePerKey="); 1813 builder.append(minIdlePerKey); 1814 builder.append(", maxTotalPerKey="); 1815 builder.append(maxTotalPerKey); 1816 builder.append(", factory="); 1817 builder.append(factory); 1818 builder.append(", fairness="); 1819 builder.append(fairness); 1820 builder.append(", poolMap="); 1821 builder.append(poolMap); 1822 builder.append(", poolKeyList="); 1823 builder.append(poolKeyList); 1824 builder.append(", keyLock="); 1825 builder.append(keyLock); 1826 builder.append(", numTotal="); 1827 builder.append(numTotal); 1828 builder.append(", evictionKeyIterator="); 1829 builder.append(evictionKeyIterator); 1830 builder.append(", evictionKey="); 1831 builder.append(evictionKey); 1832 builder.append(", abandonedConfig="); 1833 builder.append(abandonedConfig); 1834 } 1835 1836 /** 1837 * Whether there is at least one thread waiting on this deque, add an pool object. 1838 * @param key pool key. 1839 * @param idleObjects list of idle pool objects. 1840 */ 1841 private void whenWaitersAddObject(final K key, final LinkedBlockingDeque<PooledObject<T>> idleObjects) { 1842 if (idleObjects.hasTakeWaiters()) { 1843 try { 1844 addObject(key); 1845 } catch (final Exception e) { 1846 swallowException(e); 1847 } 1848 } 1849 } 1850 1851 /** 1852 * @since 2.10.0 1853 */ 1854 @Override 1855 public void use(final T pooledObject) { 1856 final AbandonedConfig abandonedCfg = this.abandonedConfig; 1857 if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) { 1858 poolMap.values().stream() 1859 .map(pool -> pool.getAllObjects().get(new IdentityWrapper<>(pooledObject))) 1860 .filter(Objects::nonNull) 1861 .findFirst() 1862 .ifPresent(PooledObject::use); 1863 } 1864 } 1865 1866}