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