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 * https://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; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Timer; 025import java.util.TimerTask; 026import java.util.concurrent.locks.ReentrantLock; 027import java.util.concurrent.locks.ReentrantReadWriteLock; 028import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; 029import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; 030 031/** 032 * This class consists exclusively of static methods that operate on or return 033 * ObjectPool or KeyedObjectPool related interfaces. 034 * 035 * @since 2.0 036 */ 037public final class PoolUtils { 038 039 /** 040 * Encapsulate the logic for when the next poolable object should be 041 * discarded. Each time update is called, the next time to shrink is 042 * recomputed, based on the float factor, number of idle instances in the 043 * pool and high water mark. Float factor is assumed to be between 0 and 1. 044 * Values closer to 1 cause less frequent erosion events. Erosion event 045 * timing also depends on numIdle. When this value is relatively high (close 046 * to previously established high water mark), erosion occurs more 047 * frequently. 048 */ 049 private static final class ErodingFactor { 050 051 private static final float MAX_INTERVAL = 15f; 052 053 /** Determines frequency of "erosion" events */ 054 private final float factor; 055 056 /** Time of next shrink event */ 057 private transient volatile long nextShrinkMillis; 058 059 /** High water mark - largest numIdle encountered */ 060 private transient volatile int idleHighWaterMark = 1; 061 062 private final ReentrantLock lock = new ReentrantLock(); 063 064 /** 065 * Creates a new ErodingFactor with the given erosion factor. 066 * 067 * @param factor 068 * erosion factor 069 */ 070 private ErodingFactor(final float factor) { 071 this.factor = factor; 072 nextShrinkMillis = System.currentTimeMillis() + (long) (90_0000 * factor); // now + 15 min * factor 073 } 074 075 /** 076 * Gets the time of the next erosion event. 077 * 078 * @return next shrink time 079 */ 080 private long getNextShrink() { 081 return nextShrinkMillis; 082 } 083 084 /** 085 * {@inheritDoc} 086 */ 087 @Override 088 public String toString() { 089 return "ErodingFactor{factor=" + factor + 090 ", idleHighWaterMark=" + idleHighWaterMark + '}'; 091 } 092 093 /** 094 * Updates internal state using the supplied time and numIdle. 095 * 096 * @param nowMillis 097 * current time 098 * @param numIdle 099 * number of idle elements in the pool 100 */ 101 public void update(final long nowMillis, final int numIdle) { 102 final int idle = Math.max(0, numIdle); 103 lock.lock(); 104 try { 105 idleHighWaterMark = Math.max(idle, idleHighWaterMark); 106 final float minutes = MAX_INTERVAL + (1f - MAX_INTERVAL) / idleHighWaterMark * idle; 107 nextShrinkMillis = nowMillis + (long) (minutes * 60000f * factor); 108 } finally { 109 lock.unlock(); 110 } 111 } 112 } 113 /** 114 * Decorates a keyed object pool, adding "eroding" behavior. Based on the 115 * configured erosion factor, objects returning to the pool 116 * may be invalidated instead of being added to idle capacity. 117 * 118 * @param <K> object pool key type 119 * @param <V> object pool value type 120 */ 121 private static class ErodingKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 122 123 /** Underlying pool */ 124 private final KeyedObjectPool<K, V> keyedPool; 125 126 /** Erosion factor */ 127 private final ErodingFactor erodingFactor; 128 129 /** 130 * Creates an ErodingObjectPool wrapping the given pool using the 131 * specified erosion factor. 132 * 133 * @param keyedPool 134 * underlying pool - must not be null 135 * @param erodingFactor 136 * erosion factor - determines the frequency of erosion 137 * events 138 * @see #erodingFactor 139 */ 140 private ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, 141 final ErodingFactor erodingFactor) { 142 if (keyedPool == null) { 143 throw new IllegalArgumentException( 144 MSG_NULL_KEYED_POOL); 145 } 146 this.keyedPool = keyedPool; 147 this.erodingFactor = erodingFactor; 148 } 149 150 /** 151 * Creates an ErodingObjectPool wrapping the given pool using the 152 * specified erosion factor. 153 * 154 * @param keyedPool 155 * underlying pool 156 * @param factor 157 * erosion factor - determines the frequency of erosion 158 * events 159 * @see #erodingFactor 160 */ 161 private ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, 162 final float factor) { 163 this(keyedPool, new ErodingFactor(factor)); 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 @Override 170 public void addObject(final K key) throws Exception { 171 keyedPool.addObject(key); 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public V borrowObject(final K key) throws Exception { 179 return keyedPool.borrowObject(key); 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void clear() throws Exception { 187 keyedPool.clear(); 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override 194 public void clear(final K key) throws Exception { 195 keyedPool.clear(key); 196 } 197 198 /** 199 * {@inheritDoc} 200 */ 201 @Override 202 public void close() { 203 try { 204 keyedPool.close(); 205 } catch (final Exception ignored) { 206 // ignored 207 } 208 } 209 210 /** 211 * Gets the eroding factor for the given key 212 * 213 * @param key 214 * key 215 * @return eroding factor for the given keyed pool 216 */ 217 protected ErodingFactor getErodingFactor(final K key) { 218 return erodingFactor; 219 } 220 221 /** 222 * Gets the underlying pool 223 * 224 * @return the keyed pool that this ErodingKeyedObjectPool wraps 225 */ 226 protected KeyedObjectPool<K, V> getKeyedPool() { 227 return keyedPool; 228 } 229 230 /** 231 * {@inheritDoc} 232 */ 233 @Override 234 public List<K> getKeys() { 235 return keyedPool.getKeys(); 236 } 237 238 /** 239 * {@inheritDoc} 240 */ 241 @Override 242 public int getNumActive() { 243 return keyedPool.getNumActive(); 244 } 245 246 /** 247 * {@inheritDoc} 248 */ 249 @Override 250 public int getNumActive(final K key) { 251 return keyedPool.getNumActive(key); 252 } 253 254 /** 255 * {@inheritDoc} 256 */ 257 @Override 258 public int getNumIdle() { 259 return keyedPool.getNumIdle(); 260 } 261 262 /** 263 * {@inheritDoc} 264 */ 265 @Override 266 public int getNumIdle(final K key) { 267 return keyedPool.getNumIdle(key); 268 } 269 270 /** 271 * {@inheritDoc} 272 */ 273 @Override 274 public void invalidateObject(final K key, final V obj) { 275 try { 276 keyedPool.invalidateObject(key, obj); 277 } catch (final Exception ignored) { 278 // ignored 279 } 280 } 281 282 /** 283 * Returns obj to the pool, unless erosion is triggered, in which case 284 * obj is invalidated. Erosion is triggered when there are idle 285 * instances in the pool associated with the given key and more than the 286 * configured {@link #erodingFactor erosion factor} time has elapsed 287 * since the last returnObject activation. 288 * 289 * @param obj 290 * object to return or invalidate 291 * @param key 292 * key 293 * @see #erodingFactor 294 */ 295 @Override 296 public void returnObject(final K key, final V obj) throws Exception { 297 boolean discard = false; 298 final long nowMillis = System.currentTimeMillis(); 299 final ErodingFactor factor = getErodingFactor(key); 300 synchronized (keyedPool) { 301 if (factor.getNextShrink() < nowMillis) { 302 final int numIdle = getNumIdle(key); 303 if (numIdle > 0) { 304 discard = true; 305 } 306 307 factor.update(nowMillis, numIdle); 308 } 309 } 310 try { 311 if (discard) { 312 keyedPool.invalidateObject(key, obj); 313 } else { 314 keyedPool.returnObject(key, obj); 315 } 316 } catch (final Exception ignored) { 317 // ignored 318 } 319 } 320 321 /** 322 * {@inheritDoc} 323 */ 324 @Override 325 public String toString() { 326 return "ErodingKeyedObjectPool{factor=" + 327 erodingFactor + ", keyedPool=" + keyedPool + '}'; 328 } 329 } 330 331 /** 332 * Decorates an object pool, adding "eroding" behavior. Based on the 333 * configured {@link #factor erosion factor}, objects returning to the pool 334 * may be invalidated instead of being added to idle capacity. 335 * 336 * @param <T> type of objects in the pool 337 */ 338 private static final class ErodingObjectPool<T> implements ObjectPool<T> { 339 340 /** Underlying object pool */ 341 private final ObjectPool<T> pool; 342 343 /** Erosion factor */ 344 private final ErodingFactor factor; 345 346 /** 347 * Creates an ErodingObjectPool wrapping the given pool using the 348 * specified erosion factor. 349 * 350 * @param pool 351 * underlying pool 352 * @param factor 353 * erosion factor - determines the frequency of erosion 354 * events 355 * @see #factor 356 */ 357 private ErodingObjectPool(final ObjectPool<T> pool, final float factor) { 358 this.pool = pool; 359 this.factor = new ErodingFactor(factor); 360 } 361 362 /** 363 * {@inheritDoc} 364 */ 365 @Override 366 public void addObject() throws Exception { 367 pool.addObject(); 368 } 369 370 /** 371 * {@inheritDoc} 372 */ 373 @Override 374 public T borrowObject() throws Exception { 375 return pool.borrowObject(); 376 } 377 378 /** 379 * {@inheritDoc} 380 */ 381 @Override 382 public void clear() throws Exception { 383 pool.clear(); 384 } 385 386 /** 387 * {@inheritDoc} 388 */ 389 @Override 390 public void close() { 391 try { 392 pool.close(); 393 } catch (final Exception ignored) { 394 // ignored 395 } 396 } 397 398 /** 399 * {@inheritDoc} 400 */ 401 @Override 402 public int getNumActive() { 403 return pool.getNumActive(); 404 } 405 406 /** 407 * {@inheritDoc} 408 */ 409 @Override 410 public int getNumIdle() { 411 return pool.getNumIdle(); 412 } 413 414 /** 415 * {@inheritDoc} 416 */ 417 @Override 418 public void invalidateObject(final T obj) { 419 try { 420 pool.invalidateObject(obj); 421 } catch (final Exception ignored) { 422 // ignored 423 } 424 } 425 426 /** 427 * Returns * Gets obj to the pool, unless erosion is triggered, in which case 428 * obj is invalidated. Erosion is triggered when there are idle 429 * instances in the pool and more than the {@link #factor erosion 430 * factor}-determined time has elapsed since the last returnObject 431 * activation. 432 * 433 * @param obj 434 * object to return or invalidate 435 * @see #factor 436 */ 437 @Override 438 public void returnObject(final T obj) { 439 boolean discard = false; 440 final long nowMillis = System.currentTimeMillis(); 441 synchronized (pool) { 442 if (factor.getNextShrink() < nowMillis) { // XXX: Pool 3: move test 443 // out of sync block 444 final int numIdle = pool.getNumIdle(); 445 if (numIdle > 0) { 446 discard = true; 447 } 448 449 factor.update(nowMillis, numIdle); 450 } 451 } 452 try { 453 if (discard) { 454 pool.invalidateObject(obj); 455 } else { 456 pool.returnObject(obj); 457 } 458 } catch (final Exception ignored) { 459 // ignored 460 } 461 } 462 463 /** 464 * {@inheritDoc} 465 */ 466 @Override 467 public String toString() { 468 return "ErodingObjectPool{factor=" + factor + ", pool=" + 469 pool + '}'; 470 } 471 } 472 /** 473 * Extends ErodingKeyedObjectPool to allow erosion to take place on a 474 * per-key basis. Timing of erosion events is tracked separately for 475 * separate keyed pools. 476 * 477 * @param <K> object pool key type 478 * @param <V> object pool value type 479 */ 480 private static final class ErodingPerKeyKeyedObjectPool<K, V> extends ErodingKeyedObjectPool<K, V> { 481 482 /** Erosion factor - same for all pools */ 483 private final float factor; 484 485 /** Map of ErodingFactor instances keyed on pool keys */ 486 private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<>()); 487 488 /** 489 * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed 490 * pool with the specified erosion factor. 491 * 492 * @param keyedPool 493 * underlying keyed pool 494 * @param factor 495 * erosion factor 496 */ 497 private ErodingPerKeyKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final float factor) { 498 super(keyedPool, null); 499 this.factor = factor; 500 } 501 502 /** 503 * {@inheritDoc} 504 */ 505 @Override 506 protected ErodingFactor getErodingFactor(final K key) { 507 // This may result in two ErodingFactors being created for a key 508 // since they are small and cheap this is okay. 509 return factors.computeIfAbsent(key, k -> new ErodingFactor(this.factor)); 510 } 511 512 /** 513 * {@inheritDoc} 514 */ 515 @SuppressWarnings("resource") // getKeyedPool(): ivar access 516 @Override 517 public String toString() { 518 return "ErodingPerKeyKeyedObjectPool{factor=" + factor + 519 ", keyedPool=" + getKeyedPool() + '}'; 520 } 521 } 522 /** 523 * Timer task that adds objects to the pool until the number of idle 524 * instances for the given key reaches the configured minIdle. Note that 525 * this is not the same as the pool's minIdle setting. 526 * 527 * @param <K> object pool key type 528 * @param <V> object pool value type 529 */ 530 private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends TimerTask { 531 532 /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ 533 private final int minIdle; 534 535 /** Key to ensure minIdle for */ 536 private final K key; 537 538 /** Keyed object pool */ 539 private final KeyedObjectPool<K, V> keyedPool; 540 541 /** 542 * Creates a new KeyedObjecPoolMinIdleTimerTask. 543 * 544 * @param keyedPool 545 * keyed object pool 546 * @param key 547 * key to ensure minimum number of idle instances 548 * @param minIdle 549 * minimum number of idle instances 550 * @throws IllegalArgumentException 551 * if the key is null 552 */ 553 KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool<K, V> keyedPool, 554 final K key, final int minIdle) throws IllegalArgumentException { 555 if (keyedPool == null) { 556 throw new IllegalArgumentException( 557 MSG_NULL_KEYED_POOL); 558 } 559 this.keyedPool = keyedPool; 560 this.key = key; 561 this.minIdle = minIdle; 562 } 563 564 /** 565 * {@inheritDoc} 566 */ 567 @Override 568 public void run() { 569 boolean success = false; 570 try { 571 if (keyedPool.getNumIdle(key) < minIdle) { 572 keyedPool.addObject(key); 573 } 574 success = true; 575 576 } catch (final Exception e) { 577 cancel(); 578 579 } finally { 580 // detect other types of Throwable and cancel this Timer 581 if (!success) { 582 cancel(); 583 } 584 } 585 } 586 587 /** 588 * {@inheritDoc} 589 */ 590 @Override 591 public String toString() { 592 final StringBuilder sb = new StringBuilder(); 593 sb.append("KeyedObjectPoolMinIdleTimerTask"); 594 sb.append("{minIdle=").append(minIdle); 595 sb.append(", key=").append(key); 596 sb.append(", keyedPool=").append(keyedPool); 597 sb.append('}'); 598 return sb.toString(); 599 } 600 } 601 /** 602 * Timer task that adds objects to the pool until the number of idle 603 * instances reaches the configured minIdle. Note that this is not the same 604 * as the pool's minIdle setting. 605 * 606 * @param <T> type of objects in the pool 607 */ 608 private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask { 609 610 /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ 611 private final int minIdle; 612 613 /** Object pool */ 614 private final ObjectPool<T> pool; 615 616 /** 617 * Constructs a new ObjectPoolMinIdleTimerTask for the given pool with the 618 * given minIdle setting. 619 * 620 * @param pool 621 * object pool 622 * @param minIdle 623 * number of idle instances to maintain 624 * @throws IllegalArgumentException 625 * if the pool is null 626 */ 627 ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle) 628 throws IllegalArgumentException { 629 if (pool == null) { 630 throw new IllegalArgumentException(MSG_NULL_POOL); 631 } 632 this.pool = pool; 633 this.minIdle = minIdle; 634 } 635 636 /** 637 * {@inheritDoc} 638 */ 639 @Override 640 public void run() { 641 boolean success = false; 642 try { 643 if (pool.getNumIdle() < minIdle) { 644 pool.addObject(); 645 } 646 success = true; 647 648 } catch (final Exception e) { 649 cancel(); 650 } finally { 651 // detect other types of Throwable and cancel this Timer 652 if (!success) { 653 cancel(); 654 } 655 } 656 } 657 658 /** 659 * {@inheritDoc} 660 */ 661 @Override 662 public String toString() { 663 final StringBuilder sb = new StringBuilder(); 664 sb.append("ObjectPoolMinIdleTimerTask"); 665 sb.append("{minIdle=").append(minIdle); 666 sb.append(", pool=").append(pool); 667 sb.append('}'); 668 return sb.toString(); 669 } 670 } 671 672 /** 673 * A synchronized (thread-safe) KeyedObjectPool backed by the specified 674 * KeyedObjectPool. 675 * <p> 676 * <strong>Note:</strong> This should not be used on pool implementations that already 677 * provide proper synchronization such as the pools provided in the Commons 678 * Pool library. Wrapping a pool that {@link #wait() waits} for poolable 679 * objects to be returned before allowing another one to be borrowed with 680 * another layer of synchronization will cause liveliness issues or a 681 * deadlock. 682 * </p> 683 * 684 * @param <K> object pool key type 685 * @param <V> object pool value type 686 */ 687 static final class SynchronizedKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 688 689 /** 690 * Object whose monitor is used to synchronize methods on the wrapped 691 * pool. 692 */ 693 private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 694 695 /** Underlying object pool */ 696 private final KeyedObjectPool<K, V> keyedPool; 697 698 /** 699 * Creates a new SynchronizedKeyedObjectPool wrapping the given pool 700 * 701 * @param keyedPool 702 * KeyedObjectPool to wrap 703 * @throws IllegalArgumentException 704 * if keyedPool is null 705 */ 706 SynchronizedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool) 707 throws IllegalArgumentException { 708 if (keyedPool == null) { 709 throw new IllegalArgumentException( 710 MSG_NULL_KEYED_POOL); 711 } 712 this.keyedPool = keyedPool; 713 } 714 715 /** 716 * {@inheritDoc} 717 */ 718 @Override 719 public void addObject(final K key) throws Exception { 720 final WriteLock writeLock = readWriteLock.writeLock(); 721 writeLock.lock(); 722 try { 723 keyedPool.addObject(key); 724 } finally { 725 writeLock.unlock(); 726 } 727 } 728 729 /** 730 * {@inheritDoc} 731 */ 732 @Override 733 public V borrowObject(final K key) throws Exception { 734 final WriteLock writeLock = readWriteLock.writeLock(); 735 writeLock.lock(); 736 try { 737 return keyedPool.borrowObject(key); 738 } finally { 739 writeLock.unlock(); 740 } 741 } 742 743 /** 744 * {@inheritDoc} 745 */ 746 @Override 747 public void clear() throws Exception { 748 final WriteLock writeLock = readWriteLock.writeLock(); 749 writeLock.lock(); 750 try { 751 keyedPool.clear(); 752 } finally { 753 writeLock.unlock(); 754 } 755 } 756 757 /** 758 * {@inheritDoc} 759 */ 760 @Override 761 public void clear(final K key) throws Exception { 762 final WriteLock writeLock = readWriteLock.writeLock(); 763 writeLock.lock(); 764 try { 765 keyedPool.clear(key); 766 } finally { 767 writeLock.unlock(); 768 } 769 } 770 771 /** 772 * {@inheritDoc} 773 */ 774 @Override 775 public void close() { 776 final WriteLock writeLock = readWriteLock.writeLock(); 777 writeLock.lock(); 778 try { 779 keyedPool.close(); 780 } catch (final Exception ignored) { 781 // ignored as of Pool 2 782 } finally { 783 writeLock.unlock(); 784 } 785 } 786 787 /** 788 * {@inheritDoc} 789 */ 790 @Override 791 public List<K> getKeys() { 792 final ReadLock readLock = readWriteLock.readLock(); 793 readLock.lock(); 794 try { 795 return keyedPool.getKeys(); 796 } finally { 797 readLock.unlock(); 798 } 799 } 800 801 /** 802 * {@inheritDoc} 803 */ 804 @Override 805 public int getNumActive() { 806 final ReadLock readLock = readWriteLock.readLock(); 807 readLock.lock(); 808 try { 809 return keyedPool.getNumActive(); 810 } finally { 811 readLock.unlock(); 812 } 813 } 814 815 /** 816 * {@inheritDoc} 817 */ 818 @Override 819 public int getNumActive(final K key) { 820 final ReadLock readLock = readWriteLock.readLock(); 821 readLock.lock(); 822 try { 823 return keyedPool.getNumActive(key); 824 } finally { 825 readLock.unlock(); 826 } 827 } 828 829 /** 830 * {@inheritDoc} 831 */ 832 @Override 833 public int getNumIdle() { 834 final ReadLock readLock = readWriteLock.readLock(); 835 readLock.lock(); 836 try { 837 return keyedPool.getNumIdle(); 838 } finally { 839 readLock.unlock(); 840 } 841 } 842 843 /** 844 * {@inheritDoc} 845 */ 846 @Override 847 public int getNumIdle(final K key) { 848 final ReadLock readLock = readWriteLock.readLock(); 849 readLock.lock(); 850 try { 851 return keyedPool.getNumIdle(key); 852 } finally { 853 readLock.unlock(); 854 } 855 } 856 857 /** 858 * {@inheritDoc} 859 */ 860 @Override 861 public void invalidateObject(final K key, final V obj) { 862 final WriteLock writeLock = readWriteLock.writeLock(); 863 writeLock.lock(); 864 try { 865 keyedPool.invalidateObject(key, obj); 866 } catch (final Exception ignored) { 867 // ignored as of Pool 2 868 } finally { 869 writeLock.unlock(); 870 } 871 } 872 873 /** 874 * {@inheritDoc} 875 */ 876 @Override 877 public void returnObject(final K key, final V obj) { 878 final WriteLock writeLock = readWriteLock.writeLock(); 879 writeLock.lock(); 880 try { 881 keyedPool.returnObject(key, obj); 882 } catch (final Exception ignored) { 883 // ignored 884 } finally { 885 writeLock.unlock(); 886 } 887 } 888 889 /** 890 * {@inheritDoc} 891 */ 892 @Override 893 public String toString() { 894 final StringBuilder sb = new StringBuilder(); 895 sb.append("SynchronizedKeyedObjectPool"); 896 sb.append("{keyedPool=").append(keyedPool); 897 sb.append('}'); 898 return sb.toString(); 899 } 900 } 901 902 /** 903 * A fully synchronized KeyedPooledObjectFactory that wraps a 904 * KeyedPooledObjectFactory and synchronizes access to the wrapped factory 905 * methods. 906 * <p> 907 * <strong>Note:</strong> This should not be used on pool implementations that already 908 * provide proper synchronization such as the pools provided in the Commons 909 * Pool library. 910 * </p> 911 * 912 * @param <K> pooled object factory key type 913 * @param <V> pooled object factory value type 914 */ 915 private static final class SynchronizedKeyedPooledObjectFactory<K, V> implements KeyedPooledObjectFactory<K, V> { 916 917 /** Synchronization lock */ 918 private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); 919 920 /** Wrapped factory */ 921 private final KeyedPooledObjectFactory<K, V> keyedFactory; 922 923 /** 924 * Creates a SynchronizedKeyedPooledObjectFactory wrapping the given 925 * factory. 926 * 927 * @param keyedFactory 928 * underlying factory to wrap 929 * @throws IllegalArgumentException 930 * if the factory is null 931 */ 932 SynchronizedKeyedPooledObjectFactory(final KeyedPooledObjectFactory<K, V> keyedFactory) throws IllegalArgumentException { 933 if (keyedFactory == null) { 934 throw new IllegalArgumentException( 935 "keyedFactory must not be null."); 936 } 937 this.keyedFactory = keyedFactory; 938 } 939 940 /** 941 * {@inheritDoc} 942 */ 943 @Override 944 public void activateObject(final K key, final PooledObject<V> p) throws Exception { 945 writeLock.lock(); 946 try { 947 keyedFactory.activateObject(key, p); 948 } finally { 949 writeLock.unlock(); 950 } 951 } 952 953 /** 954 * {@inheritDoc} 955 */ 956 @Override 957 public void destroyObject(final K key, final PooledObject<V> p) throws Exception { 958 writeLock.lock(); 959 try { 960 keyedFactory.destroyObject(key, p); 961 } finally { 962 writeLock.unlock(); 963 } 964 } 965 966 /** 967 * {@inheritDoc} 968 */ 969 @Override 970 public PooledObject<V> makeObject(final K key) throws Exception { 971 writeLock.lock(); 972 try { 973 return keyedFactory.makeObject(key); 974 } finally { 975 writeLock.unlock(); 976 } 977 } 978 979 /** 980 * {@inheritDoc} 981 */ 982 @Override 983 public void passivateObject(final K key, final PooledObject<V> p) throws Exception { 984 writeLock.lock(); 985 try { 986 keyedFactory.passivateObject(key, p); 987 } finally { 988 writeLock.unlock(); 989 } 990 } 991 992 /** 993 * {@inheritDoc} 994 */ 995 @Override 996 public String toString() { 997 final StringBuilder sb = new StringBuilder(); 998 sb.append("SynchronizedKeyedPooledObjectFactory"); 999 sb.append("{keyedFactory=").append(keyedFactory); 1000 sb.append('}'); 1001 return sb.toString(); 1002 } 1003 1004 /** 1005 * {@inheritDoc} 1006 */ 1007 @Override 1008 public boolean validateObject(final K key, final PooledObject<V> p) { 1009 writeLock.lock(); 1010 try { 1011 return keyedFactory.validateObject(key, p); 1012 } finally { 1013 writeLock.unlock(); 1014 } 1015 } 1016 } 1017 1018 /** 1019 * A synchronized (thread-safe) ObjectPool backed by the specified 1020 * ObjectPool. 1021 * <p> 1022 * <strong>Note:</strong> This should not be used on pool implementations that already 1023 * provide proper synchronization such as the pools provided in the Commons 1024 * Pool library. Wrapping a pool that {@link #wait() waits} for poolable 1025 * objects to be returned before allowing another one to be borrowed with 1026 * another layer of synchronization will cause liveliness issues or a 1027 * deadlock. 1028 * </p> 1029 * 1030 * @param <T> type of objects in the pool 1031 */ 1032 private static final class SynchronizedObjectPool<T> implements ObjectPool<T> { 1033 1034 /** 1035 * Object whose monitor is used to synchronize methods on the wrapped 1036 * pool. 1037 */ 1038 private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 1039 1040 /** The underlying object pool */ 1041 private final ObjectPool<T> pool; 1042 1043 /** 1044 * Creates a new SynchronizedObjectPool wrapping the given pool. 1045 * 1046 * @param pool 1047 * the ObjectPool to be "wrapped" in a synchronized 1048 * ObjectPool. 1049 * @throws IllegalArgumentException 1050 * if the pool is null 1051 */ 1052 SynchronizedObjectPool(final ObjectPool<T> pool) 1053 throws IllegalArgumentException { 1054 if (pool == null) { 1055 throw new IllegalArgumentException(MSG_NULL_POOL); 1056 } 1057 this.pool = pool; 1058 } 1059 1060 /** 1061 * {@inheritDoc} 1062 */ 1063 @Override 1064 public void addObject() throws Exception { 1065 final WriteLock writeLock = readWriteLock.writeLock(); 1066 writeLock.lock(); 1067 try { 1068 pool.addObject(); 1069 } finally { 1070 writeLock.unlock(); 1071 } 1072 } 1073 1074 /** 1075 * {@inheritDoc} 1076 */ 1077 @Override 1078 public T borrowObject() throws Exception { 1079 final WriteLock writeLock = readWriteLock.writeLock(); 1080 writeLock.lock(); 1081 try { 1082 return pool.borrowObject(); 1083 } finally { 1084 writeLock.unlock(); 1085 } 1086 } 1087 1088 /** 1089 * {@inheritDoc} 1090 */ 1091 @Override 1092 public void clear() throws Exception { 1093 final WriteLock writeLock = readWriteLock.writeLock(); 1094 writeLock.lock(); 1095 try { 1096 pool.clear(); 1097 } finally { 1098 writeLock.unlock(); 1099 } 1100 } 1101 1102 /** 1103 * {@inheritDoc} 1104 */ 1105 @Override 1106 public void close() { 1107 final WriteLock writeLock = readWriteLock.writeLock(); 1108 writeLock.lock(); 1109 try { 1110 pool.close(); 1111 } catch (final Exception ignored) { 1112 // ignored as of Pool 2 1113 } finally { 1114 writeLock.unlock(); 1115 } 1116 } 1117 1118 /** 1119 * {@inheritDoc} 1120 */ 1121 @Override 1122 public int getNumActive() { 1123 final ReadLock readLock = readWriteLock.readLock(); 1124 readLock.lock(); 1125 try { 1126 return pool.getNumActive(); 1127 } finally { 1128 readLock.unlock(); 1129 } 1130 } 1131 1132 /** 1133 * {@inheritDoc} 1134 */ 1135 @Override 1136 public int getNumIdle() { 1137 final ReadLock readLock = readWriteLock.readLock(); 1138 readLock.lock(); 1139 try { 1140 return pool.getNumIdle(); 1141 } finally { 1142 readLock.unlock(); 1143 } 1144 } 1145 1146 /** 1147 * {@inheritDoc} 1148 */ 1149 @Override 1150 public void invalidateObject(final T obj) { 1151 final WriteLock writeLock = readWriteLock.writeLock(); 1152 writeLock.lock(); 1153 try { 1154 pool.invalidateObject(obj); 1155 } catch (final Exception ignored) { 1156 // ignored as of Pool 2 1157 } finally { 1158 writeLock.unlock(); 1159 } 1160 } 1161 1162 /** 1163 * {@inheritDoc} 1164 */ 1165 @Override 1166 public void returnObject(final T obj) { 1167 final WriteLock writeLock = readWriteLock.writeLock(); 1168 writeLock.lock(); 1169 try { 1170 pool.returnObject(obj); 1171 } catch (final Exception ignored) { 1172 // ignored as of Pool 2 1173 } finally { 1174 writeLock.unlock(); 1175 } 1176 } 1177 1178 /** 1179 * {@inheritDoc} 1180 */ 1181 @Override 1182 public String toString() { 1183 final StringBuilder sb = new StringBuilder(); 1184 sb.append("SynchronizedObjectPool"); 1185 sb.append("{pool=").append(pool); 1186 sb.append('}'); 1187 return sb.toString(); 1188 } 1189 } 1190 1191 /** 1192 * A fully synchronized PooledObjectFactory that wraps a 1193 * PooledObjectFactory and synchronizes access to the wrapped factory 1194 * methods. 1195 * <p> 1196 * <strong>Note:</strong> This should not be used on pool implementations that already 1197 * provide proper synchronization such as the pools provided in the Commons 1198 * Pool library. 1199 * </p> 1200 * 1201 * @param <T> pooled object factory type 1202 */ 1203 private static final class SynchronizedPooledObjectFactory<T> implements 1204 PooledObjectFactory<T> { 1205 1206 /** Synchronization lock */ 1207 private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); 1208 1209 /** Wrapped factory */ 1210 private final PooledObjectFactory<T> factory; 1211 1212 /** 1213 * Creates a SynchronizedPoolableObjectFactory wrapping the given 1214 * factory. 1215 * 1216 * @param factory 1217 * underlying factory to wrap 1218 * @throws IllegalArgumentException 1219 * if the factory is null 1220 */ 1221 SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory) 1222 throws IllegalArgumentException { 1223 if (factory == null) { 1224 throw new IllegalArgumentException("factory must not be null."); 1225 } 1226 this.factory = factory; 1227 } 1228 1229 /** 1230 * {@inheritDoc} 1231 */ 1232 @Override 1233 public void activateObject(final PooledObject<T> p) throws Exception { 1234 writeLock.lock(); 1235 try { 1236 factory.activateObject(p); 1237 } finally { 1238 writeLock.unlock(); 1239 } 1240 } 1241 1242 /** 1243 * {@inheritDoc} 1244 */ 1245 @Override 1246 public void destroyObject(final PooledObject<T> p) throws Exception { 1247 writeLock.lock(); 1248 try { 1249 factory.destroyObject(p); 1250 } finally { 1251 writeLock.unlock(); 1252 } 1253 } 1254 1255 /** 1256 * {@inheritDoc} 1257 */ 1258 @Override 1259 public PooledObject<T> makeObject() throws Exception { 1260 writeLock.lock(); 1261 try { 1262 return factory.makeObject(); 1263 } finally { 1264 writeLock.unlock(); 1265 } 1266 } 1267 1268 /** 1269 * {@inheritDoc} 1270 */ 1271 @Override 1272 public void passivateObject(final PooledObject<T> p) throws Exception { 1273 writeLock.lock(); 1274 try { 1275 factory.passivateObject(p); 1276 } finally { 1277 writeLock.unlock(); 1278 } 1279 } 1280 1281 /** 1282 * {@inheritDoc} 1283 */ 1284 @Override 1285 public String toString() { 1286 final StringBuilder sb = new StringBuilder(); 1287 sb.append("SynchronizedPoolableObjectFactory"); 1288 sb.append("{factory=").append(factory); 1289 sb.append('}'); 1290 return sb.toString(); 1291 } 1292 1293 /** 1294 * {@inheritDoc} 1295 */ 1296 @Override 1297 public boolean validateObject(final PooledObject<T> p) { 1298 writeLock.lock(); 1299 try { 1300 return factory.validateObject(p); 1301 } finally { 1302 writeLock.unlock(); 1303 } 1304 } 1305 } 1306 1307 /** 1308 * Timer used to periodically check pools idle object count. Because a 1309 * {@link Timer} creates a {@link Thread}, an IODH is used. 1310 */ 1311 static class TimerHolder { 1312 static final Timer MIN_IDLE_TIMER = new Timer(true); 1313 } 1314 1315 private static final String MSG_FACTOR_NEGATIVE = "factor must be positive."; 1316 1317 private static final String MSG_MIN_IDLE = "minIdle must be non-negative."; 1318 1319 static final String MSG_NULL_KEY = "key must not be null."; 1320 1321 private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null."; 1322 1323 static final String MSG_NULL_KEYS = "keys must not be null."; 1324 1325 private static final String MSG_NULL_POOL = "pool must not be null."; 1326 1327 /** 1328 * Periodically check the idle object count for each key in the 1329 * {@code Collection keys} in the keyedPool. At most one idle object will be 1330 * added per period. 1331 * 1332 * @param keyedPool 1333 * the keyedPool to check periodically. 1334 * @param keys 1335 * a collection of keys to check the idle object count. 1336 * @param minIdle 1337 * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than 1338 * this then add an idle object. 1339 * @param periodMillis 1340 * the frequency in milliseconds to check the number of idle objects in a 1341 * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. 1342 * @param <K> the type of the pool key 1343 * @param <V> the type of pool entries 1344 * @return a {@link Map} of key and {@link TimerTask} pairs that will 1345 * periodically check the pools idle object count. 1346 * @throws IllegalArgumentException 1347 * when {@code keyedPool}, {@code keys}, or any of the values in 1348 * the collection is {@code null} or when {@code minIdle} is 1349 * negative or when {@code period} isn't valid for 1350 * {@link Timer#schedule(TimerTask, long, long)}. 1351 * @see #checkMinIdle(KeyedObjectPool, Object, int, long) 1352 */ 1353 public static <K, V> Map<K, TimerTask> checkMinIdle( 1354 final KeyedObjectPool<K, V> keyedPool, final Collection<K> keys, 1355 final int minIdle, final long periodMillis) 1356 throws IllegalArgumentException { 1357 if (keys == null) { 1358 throw new IllegalArgumentException(MSG_NULL_KEYS); 1359 } 1360 final Map<K, TimerTask> tasks = new HashMap<>(keys.size()); 1361 keys.forEach(key -> tasks.put(key, checkMinIdle(keyedPool, key, minIdle, periodMillis))); 1362 return tasks; 1363 } 1364 1365 /** 1366 * Periodically check the idle object count for the key in the keyedPool. At 1367 * most one idle object will be added per period. If there is an exception 1368 * when calling {@link KeyedObjectPool#addObject(Object)} then no more 1369 * checks for that key will be performed. 1370 * 1371 * @param keyedPool 1372 * the keyedPool to check periodically. 1373 * @param key 1374 * the key to check the idle count of. 1375 * @param minIdle 1376 * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than 1377 * this then add an idle object. 1378 * @param periodMillis 1379 * the frequency in milliseconds to check the number of idle objects in a 1380 * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. 1381 * @param <K> the type of the pool key 1382 * @param <V> the type of pool entries 1383 * @return the {@link TimerTask} that will periodically check the pools idle 1384 * object count. 1385 * @throws IllegalArgumentException 1386 * when {@code keyedPool}, {@code key} is {@code null} or 1387 * when {@code minIdle} is negative or when {@code period} isn't 1388 * valid for {@link Timer#schedule(TimerTask, long, long)}. 1389 */ 1390 public static <K, V> TimerTask checkMinIdle( 1391 final KeyedObjectPool<K, V> keyedPool, final K key, 1392 final int minIdle, final long periodMillis) 1393 throws IllegalArgumentException { 1394 if (keyedPool == null) { 1395 throw new IllegalArgumentException(MSG_NULL_KEYED_POOL); 1396 } 1397 if (key == null) { 1398 throw new IllegalArgumentException(MSG_NULL_KEY); 1399 } 1400 if (minIdle < 0) { 1401 throw new IllegalArgumentException(MSG_MIN_IDLE); 1402 } 1403 final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>( 1404 keyedPool, key, minIdle); 1405 getMinIdleTimer().schedule(task, 0L, periodMillis); 1406 return task; 1407 } 1408 1409 /** 1410 * Periodically check the idle object count for the pool. At most one idle 1411 * object will be added per period. If there is an exception when calling 1412 * {@link ObjectPool#addObject()} then no more checks will be performed. 1413 * 1414 * @param pool 1415 * the pool to check periodically. 1416 * @param minIdle 1417 * if the {@link ObjectPool#getNumIdle()} is less than this then 1418 * add an idle object. 1419 * @param periodMillis 1420 * the frequency in milliseconds to check the number of idle objects in a pool, 1421 * see {@link Timer#schedule(TimerTask, long, long)}. 1422 * @param <T> the type of objects in the pool 1423 * @return the {@link TimerTask} that will periodically check the pools idle 1424 * object count. 1425 * @throws IllegalArgumentException 1426 * when {@code pool} is {@code null} or when {@code minIdle} is 1427 * negative or when {@code period} isn't valid for 1428 * {@link Timer#schedule(TimerTask, long, long)} 1429 */ 1430 public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool, 1431 final int minIdle, final long periodMillis) 1432 throws IllegalArgumentException { 1433 if (pool == null) { 1434 throw new IllegalArgumentException(MSG_NULL_KEYED_POOL); 1435 } 1436 if (minIdle < 0) { 1437 throw new IllegalArgumentException(MSG_MIN_IDLE); 1438 } 1439 final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle); 1440 getMinIdleTimer().schedule(task, 0L, periodMillis); 1441 return task; 1442 } 1443 1444 /** 1445 * Should the supplied Throwable be re-thrown (eg if it is an instance of 1446 * one of the Throwables that should never be swallowed). Used by the pool 1447 * error handling for operations that throw exceptions that normally need to 1448 * be ignored. 1449 * 1450 * @param t 1451 * The Throwable to check 1452 * @throws ThreadDeath 1453 * if that is passed in 1454 * @throws VirtualMachineError 1455 * if that is passed in 1456 */ 1457 public static void checkRethrow(final Throwable t) { 1458 if (t instanceof ThreadDeath) { 1459 throw (ThreadDeath) t; 1460 } 1461 if (t instanceof VirtualMachineError) { 1462 throw (VirtualMachineError) t; 1463 } 1464 // All other instances of Throwable will be silently swallowed 1465 } 1466 1467 /** 1468 * Returns a pool that adaptively decreases its size when idle objects are 1469 * no longer needed. This is intended as an always thread-safe alternative 1470 * to using an idle object evictor provided by many pool implementations. 1471 * This is also an effective way to shrink FIFO ordered pools that 1472 * experience load spikes. 1473 * 1474 * @param keyedPool 1475 * the KeyedObjectPool to be decorated so it shrinks its idle 1476 * count when possible. 1477 * @param <K> the type of the pool key 1478 * @param <V> the type of pool entries 1479 * @throws IllegalArgumentException 1480 * when {@code keyedPool} is {@code null}. 1481 * @return a pool that adaptively decreases its size when idle objects are 1482 * no longer needed. 1483 * @see #erodingPool(KeyedObjectPool, float) 1484 * @see #erodingPool(KeyedObjectPool, float, boolean) 1485 */ 1486 public static <K, V> KeyedObjectPool<K, V> erodingPool(final KeyedObjectPool<K, V> keyedPool) { 1487 return erodingPool(keyedPool, 1f); 1488 } 1489 1490 /** 1491 * Returns a pool that adaptively decreases its size when idle objects are 1492 * no longer needed. This is intended as an always thread-safe alternative 1493 * to using an idle object evictor provided by many pool implementations. 1494 * This is also an effective way to shrink FIFO ordered pools that 1495 * experience load spikes. 1496 * <p> 1497 * The factor parameter provides a mechanism to tweak the rate at which the 1498 * pool tries to shrink its size. Values between 0 and 1 cause the pool to 1499 * try to shrink its size more often. Values greater than 1 cause the pool 1500 * to less frequently try to shrink its size. 1501 * </p> 1502 * 1503 * @param keyedPool 1504 * the KeyedObjectPool to be decorated so it shrinks its idle 1505 * count when possible. 1506 * @param factor 1507 * a positive value to scale the rate at which the pool tries to 1508 * reduce its size. If 0 < factor < 1 then the pool 1509 * shrinks more aggressively. If 1 < factor then the pool 1510 * shrinks less aggressively. 1511 * @param <K> the type of the pool key 1512 * @param <V> the type of pool entries 1513 * @throws IllegalArgumentException 1514 * when {@code keyedPool} is {@code null} or when {@code factor} 1515 * is not positive. 1516 * @return a pool that adaptively decreases its size when idle objects are 1517 * no longer needed. 1518 * @see #erodingPool(KeyedObjectPool, float, boolean) 1519 */ 1520 public static <K, V> KeyedObjectPool<K, V> erodingPool(final KeyedObjectPool<K, V> keyedPool, final float factor) { 1521 return erodingPool(keyedPool, factor, false); 1522 } 1523 1524 /** 1525 * Returns a pool that adaptively decreases its size when idle objects are 1526 * no longer needed. This is intended as an always thread-safe alternative 1527 * to using an idle object evictor provided by many pool implementations. 1528 * This is also an effective way to shrink FIFO ordered pools that 1529 * experience load spikes. 1530 * <p> 1531 * The factor parameter provides a mechanism to tweak the rate at which the 1532 * pool tries to shrink its size. Values between 0 and 1 cause the pool to 1533 * try to shrink its size more often. Values greater than 1 cause the pool 1534 * to less frequently try to shrink its size. 1535 * </p> 1536 * <p> 1537 * The perKey parameter determines if the pool shrinks on a whole pool basis 1538 * or a per key basis. When perKey is false, the keys do not have an effect 1539 * on the rate at which the pool tries to shrink its size. When perKey is 1540 * true, each key is shrunk independently. 1541 * </p> 1542 * 1543 * @param keyedPool 1544 * the KeyedObjectPool to be decorated so it shrinks its idle 1545 * count when possible. 1546 * @param factor 1547 * a positive value to scale the rate at which the pool tries to 1548 * reduce its size. If 0 < factor < 1 then the pool 1549 * shrinks more aggressively. If 1 < factor then the pool 1550 * shrinks less aggressively. 1551 * @param perKey 1552 * when true, each key is treated independently. 1553 * @param <K> the type of the pool key 1554 * @param <V> the type of pool entries 1555 * @throws IllegalArgumentException 1556 * when {@code keyedPool} is {@code null} or when {@code factor} 1557 * is not positive. 1558 * @return a pool that adaptively decreases its size when idle objects are 1559 * no longer needed. 1560 * @see #erodingPool(KeyedObjectPool) 1561 * @see #erodingPool(KeyedObjectPool, float) 1562 */ 1563 public static <K, V> KeyedObjectPool<K, V> erodingPool( 1564 final KeyedObjectPool<K, V> keyedPool, final float factor, 1565 final boolean perKey) { 1566 if (keyedPool == null) { 1567 throw new IllegalArgumentException(MSG_NULL_KEYED_POOL); 1568 } 1569 if (factor <= 0f) { 1570 throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE); 1571 } 1572 if (perKey) { 1573 return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor); 1574 } 1575 return new ErodingKeyedObjectPool<>(keyedPool, factor); 1576 } 1577 1578 /** 1579 * Returns a pool that adaptively decreases its size when idle objects are 1580 * no longer needed. This is intended as an always thread-safe alternative 1581 * to using an idle object evictor provided by many pool implementations. 1582 * This is also an effective way to shrink FIFO ordered pools that 1583 * experience load spikes. 1584 * 1585 * @param pool 1586 * the ObjectPool to be decorated so it shrinks its idle count 1587 * when possible. 1588 * @param <T> the type of objects in the pool 1589 * @throws IllegalArgumentException 1590 * when {@code pool} is {@code null}. 1591 * @return a pool that adaptively decreases its size when idle objects are 1592 * no longer needed. 1593 * @see #erodingPool(ObjectPool, float) 1594 */ 1595 public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) { 1596 return erodingPool(pool, 1f); 1597 } 1598 1599 /** 1600 * Returns a pool that adaptively decreases its size when idle objects are 1601 * no longer needed. This is intended as an always thread-safe alternative 1602 * to using an idle object evictor provided by many pool implementations. 1603 * This is also an effective way to shrink FIFO ordered pools that 1604 * experience load spikes. 1605 * <p> 1606 * The factor parameter provides a mechanism to tweak the rate at which the 1607 * pool tries to shrink its size. Values between 0 and 1 cause the pool to 1608 * try to shrink its size more often. Values greater than 1 cause the pool 1609 * to less frequently try to shrink its size. 1610 * </p> 1611 * 1612 * @param pool 1613 * the ObjectPool to be decorated so it shrinks its idle count 1614 * when possible. 1615 * @param factor 1616 * a positive value to scale the rate at which the pool tries to 1617 * reduce its size. If 0 < factor < 1 then the pool 1618 * shrinks more aggressively. If 1 < factor then the pool 1619 * shrinks less aggressively. 1620 * @param <T> the type of objects in the pool 1621 * @throws IllegalArgumentException 1622 * when {@code pool} is {@code null} or when {@code factor} is 1623 * not positive. 1624 * @return a pool that adaptively decreases its size when idle objects are 1625 * no longer needed. 1626 * @see #erodingPool(ObjectPool) 1627 */ 1628 public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool, final float factor) { 1629 if (pool == null) { 1630 throw new IllegalArgumentException(MSG_NULL_POOL); 1631 } 1632 if (factor <= 0f) { 1633 throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE); 1634 } 1635 return new ErodingObjectPool<>(pool, factor); 1636 } 1637 1638 /** 1639 * Gets the {@code Timer} for checking keyedPool's idle count. 1640 * 1641 * @return the {@link Timer} for checking keyedPool's idle count. 1642 */ 1643 private static Timer getMinIdleTimer() { 1644 return TimerHolder.MIN_IDLE_TIMER; 1645 } 1646 1647 /** 1648 * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with 1649 * each key in {@code keys} for {@code count} number of times. This has 1650 * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)} 1651 * for each key in the {@code keys} collection. 1652 * 1653 * @param keyedPool 1654 * the keyedPool to prefill. 1655 * @param keys 1656 * {@link Collection} of keys to add objects for. 1657 * @param count 1658 * the number of idle objects to add for each {@code key}. 1659 * @param <K> the type of the pool key 1660 * @param <V> the type of pool entries 1661 * @throws Exception 1662 * when {@link KeyedObjectPool#addObject(Object)} fails. 1663 * @throws IllegalArgumentException 1664 * when {@code keyedPool}, {@code keys}, or any value in 1665 * {@code keys} is {@code null}. 1666 * @see #prefill(KeyedObjectPool, Object, int) 1667 * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}. 1668 */ 1669 @Deprecated 1670 public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, 1671 final Collection<K> keys, final int count) throws Exception, 1672 IllegalArgumentException { 1673 if (keys == null) { 1674 throw new IllegalArgumentException(MSG_NULL_KEYS); 1675 } 1676 keyedPool.addObjects(keys, count); 1677 } 1678 1679 /** 1680 * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with 1681 * {@code key} {@code count} number of times. 1682 * 1683 * @param keyedPool 1684 * the keyedPool to prefill. 1685 * @param key 1686 * the key to add objects for. 1687 * @param count 1688 * the number of idle objects to add for {@code key}. 1689 * @param <K> the type of the pool key 1690 * @param <V> the type of pool entries 1691 * @throws Exception 1692 * when {@link KeyedObjectPool#addObject(Object)} fails. 1693 * @throws IllegalArgumentException 1694 * when {@code keyedPool} or {@code key} is {@code null}. 1695 * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}. 1696 */ 1697 @Deprecated 1698 public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, 1699 final K key, final int count) throws Exception, 1700 IllegalArgumentException { 1701 if (keyedPool == null) { 1702 throw new IllegalArgumentException(MSG_NULL_KEYED_POOL); 1703 } 1704 keyedPool.addObjects(key, count); 1705 } 1706 1707 /** 1708 * Calls {@link ObjectPool#addObject()} on {@code pool} {@code count} number 1709 * of times. 1710 * 1711 * @param pool 1712 * the pool to prefill. 1713 * @param count 1714 * the number of idle objects to add. 1715 * @param <T> the type of objects in the pool 1716 * @throws Exception 1717 * when {@link ObjectPool#addObject()} fails. 1718 * @throws IllegalArgumentException 1719 * when {@code pool} is {@code null}. 1720 * @deprecated Use {@link ObjectPool#addObjects(int)}. 1721 */ 1722 @Deprecated 1723 public static <T> void prefill(final ObjectPool<T> pool, final int count) 1724 throws Exception { 1725 if (pool == null) { 1726 throw new IllegalArgumentException(MSG_NULL_POOL); 1727 } 1728 pool.addObjects(count); 1729 } 1730 1731 /** 1732 * Returns a synchronized (thread-safe) KeyedPooledObjectFactory backed by 1733 * the specified KeyedPooledObjectFactory. 1734 * 1735 * @param keyedFactory 1736 * the KeyedPooledObjectFactory to be "wrapped" in a 1737 * synchronized KeyedPooledObjectFactory. 1738 * @param <K> the type of the pool key 1739 * @param <V> the type of pool entries 1740 * @return a synchronized view of the specified KeyedPooledObjectFactory. 1741 */ 1742 public static <K, V> KeyedPooledObjectFactory<K, V> synchronizedKeyedPooledFactory( 1743 final KeyedPooledObjectFactory<K, V> keyedFactory) { 1744 return new SynchronizedKeyedPooledObjectFactory<>(keyedFactory); 1745 } 1746 1747 /** 1748 * Returns a synchronized (thread-safe) KeyedObjectPool backed by the 1749 * specified KeyedObjectPool. 1750 * <p> 1751 * <strong>Note:</strong> This should not be used on pool implementations that already 1752 * provide proper synchronization such as the pools provided in the Commons 1753 * Pool library. Wrapping a pool that {@link #wait() waits} for poolable 1754 * objects to be returned before allowing another one to be borrowed with 1755 * another layer of synchronization will cause liveliness issues or a 1756 * deadlock. 1757 * </p> 1758 * 1759 * @param keyedPool 1760 * the KeyedObjectPool to be "wrapped" in a synchronized 1761 * KeyedObjectPool. 1762 * @param <K> the type of the pool key 1763 * @param <V> the type of pool entries 1764 * @return a synchronized view of the specified KeyedObjectPool. 1765 */ 1766 public static <K, V> KeyedObjectPool<K, V> synchronizedPool(final KeyedObjectPool<K, V> keyedPool) { 1767 /* 1768 * assert !(keyedPool instanceof GenericKeyedObjectPool) : 1769 * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool 1770 * instanceof StackKeyedObjectPool) : 1771 * "StackKeyedObjectPool is already thread-safe"; assert 1772 * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool" 1773 * .equals(keyedPool.getClass().getName()) : 1774 * "CompositeKeyedObjectPools are already thread-safe"; 1775 */ 1776 return new SynchronizedKeyedObjectPool<>(keyedPool); 1777 } 1778 1779 /** 1780 * Returns a synchronized (thread-safe) ObjectPool backed by the specified 1781 * ObjectPool. 1782 * <p> 1783 * <strong>Note:</strong> This should not be used on pool implementations that already 1784 * provide proper synchronization such as the pools provided in the Commons 1785 * Pool library. Wrapping a pool that {@link #wait() waits} for poolable 1786 * objects to be returned before allowing another one to be borrowed with 1787 * another layer of synchronization will cause liveliness issues or a 1788 * deadlock. 1789 * </p> 1790 * 1791 * @param <T> the type of objects in the pool 1792 * @param pool 1793 * the ObjectPool to be "wrapped" in a synchronized ObjectPool. 1794 * @throws IllegalArgumentException 1795 * when {@code pool} is {@code null}. 1796 * @return a synchronized view of the specified ObjectPool. 1797 */ 1798 public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) { 1799 if (pool == null) { 1800 throw new IllegalArgumentException(MSG_NULL_POOL); 1801 } 1802 1803 /* 1804 * assert !(pool instanceof GenericObjectPool) : 1805 * "GenericObjectPool is already thread-safe"; assert !(pool instanceof 1806 * SoftReferenceObjectPool) : 1807 * "SoftReferenceObjectPool is already thread-safe"; assert !(pool 1808 * instanceof StackObjectPool) : 1809 * "StackObjectPool is already thread-safe"; assert 1810 * !"org.apache.commons.pool.composite.CompositeObjectPool" 1811 * .equals(pool.getClass().getName()) : 1812 * "CompositeObjectPools are already thread-safe"; 1813 */ 1814 return new SynchronizedObjectPool<>(pool); 1815 } 1816 1817 /** 1818 * Returns a synchronized (thread-safe) PooledObjectFactory backed by the 1819 * specified PooledObjectFactory. 1820 * 1821 * @param factory 1822 * the PooledObjectFactory to be "wrapped" in a synchronized 1823 * PooledObjectFactory. 1824 * @param <T> the type of objects in the pool 1825 * @return a synchronized view of the specified PooledObjectFactory. 1826 */ 1827 public static <T> PooledObjectFactory<T> synchronizedPooledFactory(final PooledObjectFactory<T> factory) { 1828 return new SynchronizedPooledObjectFactory<>(factory); 1829 } 1830 1831 /** 1832 * PoolUtils instances should NOT be constructed in standard programming. 1833 * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);. 1834 * This constructor is public to permit tools that require a JavaBean 1835 * instance to operate. 1836 */ 1837 public PoolUtils() { 1838 } 1839}