1 22 23 24 package com.mchange.v2.resourcepool; 25 26 import java.util.*; 27 import com.mchange.v2.async.*; 28 import com.mchange.v2.log.*; 29 import com.mchange.v2.lang.ThreadUtils; 30 import com.mchange.v2.util.ResourceClosedException; 31 32 class BasicResourcePool implements ResourcePool 33 { 34 private final static MLogger logger = MLog.getLogger( BasicResourcePool.class ); 35 36 final static int AUTO_CULL_FREQUENCY_DIVISOR = 4; 37 final static int AUTO_MAX_CULL_FREQUENCY = (15 * 60 * 1000); final static int AUTO_MIN_CULL_FREQUENCY = (1 * 1000); 40 41 final static String USE_SCATTERED_ACQUIRE_TASK_KEY = "com.mchange.v2.resourcepool.experimental.useScatteredAcquireTask"; 45 final static boolean USE_SCATTERED_ACQUIRE_TASK; 46 static 47 { 48 String checkScattered = com.mchange.v2.cfg.MultiPropertiesConfig.readVmConfig().getProperty(USE_SCATTERED_ACQUIRE_TASK_KEY); 49 if (checkScattered != null && checkScattered.trim().toLowerCase().equals("true")) 50 { 51 USE_SCATTERED_ACQUIRE_TASK = true; 52 if ( logger.isLoggable( MLevel.INFO ) ) 53 logger.info(BasicResourcePool.class.getName() + " using experimental ScatteredAcquireTask."); 54 } 55 else 56 USE_SCATTERED_ACQUIRE_TASK = false; 57 } 58 60 final Manager mgr; 62 63 final int start; 64 final int min; 65 final int max; 66 final int inc; 67 68 final int num_acq_attempts; 69 final int acq_attempt_delay; 70 71 final long check_idle_resources_delay; final long max_resource_age; final long max_idle_time; final long excess_max_idle_time; final long destroy_unreturned_resc_time; final long expiration_enforcement_delay; 78 final boolean break_on_acquisition_failure; 79 final boolean debug_store_checkout_exceptions; 80 81 final long pool_start_time = System.currentTimeMillis(); 82 83 final BasicResourcePoolFactory factory; 85 final AsynchronousRunner taskRunner; 86 final RunnableQueue asyncEventQueue; 87 final ResourcePoolEventSupport rpes; 88 89 Timer cullAndIdleRefurbishTimer; 91 TimerTask cullTask; 92 TimerTask idleRefurbishTask; 93 HashSet acquireWaiters = new HashSet(); 94 HashSet otherWaiters = new HashSet(); 95 96 int pending_acquires; 97 int pending_removes; 98 99 int target_pool_size; 100 101 102 HashMap managed = new HashMap(); 103 104 105 LinkedList unused = new LinkedList(); 106 107 108 109 HashSet excluded = new HashSet(); 110 111 Map formerResources = new WeakHashMap(); 112 113 Set idleCheckResources = new HashSet(); 114 115 boolean force_kill_acquires = false; 116 117 boolean broken = false; 118 119 121 long failed_checkins = 0; 122 long failed_checkouts = 0; 123 long failed_idle_tests = 0; 124 125 Throwable lastCheckinFailure = null; 126 Throwable lastCheckoutFailure = null; 127 Throwable lastIdleTestFailure = null; 128 Throwable lastResourceTestFailure = null; 129 130 Throwable lastAcquisitionFailiure = null; 131 132 Object exampleResource; 134 135 public long getStartTime() 136 { return pool_start_time; } 137 138 public long getUpTime() 139 { return System.currentTimeMillis() - pool_start_time; } 140 141 public synchronized long getNumFailedCheckins() 142 { return failed_checkins; } 143 144 public synchronized long getNumFailedCheckouts() 145 { return failed_checkouts; } 146 147 public synchronized long getNumFailedIdleTests() 148 { return failed_idle_tests; } 149 150 public synchronized Throwable getLastCheckinFailure() 151 { return lastCheckinFailure; } 152 153 private void setLastCheckinFailure(Throwable t) 155 { 156 assert ( Thread.holdsLock(this)); 157 158 this.lastCheckinFailure = t; 159 this.lastResourceTestFailure = t; 160 } 161 162 public synchronized Throwable getLastCheckoutFailure() 163 { return lastCheckoutFailure; } 164 165 private void setLastCheckoutFailure(Throwable t) 167 { 168 assert ( Thread.holdsLock(this)); 169 170 this.lastCheckoutFailure = t; 171 this.lastResourceTestFailure = t; 172 } 173 174 public synchronized Throwable getLastIdleCheckFailure() 175 { return lastIdleTestFailure; } 176 177 private void setLastIdleCheckFailure(Throwable t) 179 { 180 assert ( Thread.holdsLock(this)); 181 182 this.lastIdleTestFailure = t; 183 this.lastResourceTestFailure = t; 184 } 185 186 public synchronized Throwable getLastResourceTestFailure() 187 { return lastResourceTestFailure; } 188 189 public synchronized Throwable getLastAcquisitionFailure() 190 { return lastAcquisitionFailiure; } 191 192 private synchronized void setLastAcquisitionFailure( Throwable t ) 194 { this.lastAcquisitionFailiure = t; } 195 196 public synchronized int getNumCheckoutWaiters() 197 { return acquireWaiters.size(); } 198 199 private void addToFormerResources( Object resc ) 200 { formerResources.put( resc, null ); } 201 202 private boolean isFormerResource( Object resc ) 203 { return formerResources.keySet().contains( resc ); } 204 205 208 public BasicResourcePool(Manager mgr, 209 int start, 210 int min, 211 int max, 212 int inc, 213 int num_acq_attempts, 214 int acq_attempt_delay, 215 long check_idle_resources_delay, 216 long max_resource_age, 217 long max_idle_time, 218 long excess_max_idle_time, 219 long destroy_unreturned_resc_time, 220 long expiration_enforcement_delay, 221 boolean break_on_acquisition_failure, 222 boolean debug_store_checkout_exceptions, 223 AsynchronousRunner taskRunner, 224 RunnableQueue asyncEventQueue, 225 Timer cullAndIdleRefurbishTimer, 226 BasicResourcePoolFactory factory) 227 throws ResourcePoolException 228 { 229 try 230 { 231 this.mgr = mgr; 232 this.start = start; 233 this.min = min; 234 this.max = max; 235 this.inc = inc; 236 this.num_acq_attempts = num_acq_attempts; 237 this.acq_attempt_delay = acq_attempt_delay; 238 this.check_idle_resources_delay = check_idle_resources_delay; 239 this.max_resource_age = max_resource_age; 240 this.max_idle_time = max_idle_time; 241 this.excess_max_idle_time = excess_max_idle_time; 242 this.destroy_unreturned_resc_time = destroy_unreturned_resc_time; 243 this.break_on_acquisition_failure = break_on_acquisition_failure; 245 this.debug_store_checkout_exceptions = (debug_store_checkout_exceptions && destroy_unreturned_resc_time > 0); 246 this.taskRunner = taskRunner; 247 this.asyncEventQueue = asyncEventQueue; 248 this.cullAndIdleRefurbishTimer = cullAndIdleRefurbishTimer; 249 this.factory = factory; 250 251 this.pending_acquires = 0; 252 this.pending_removes = 0; 253 254 this.target_pool_size = Math.max(start, min); 255 256 if (asyncEventQueue != null) 257 this.rpes = new ResourcePoolEventSupport(this); 258 else 259 this.rpes = null; 260 261 ensureStartResources(); 263 264 if (mustEnforceExpiration()) 265 { 266 if (expiration_enforcement_delay <= 0) 267 this.expiration_enforcement_delay = automaticExpirationEnforcementDelay(); 268 else 269 this.expiration_enforcement_delay = expiration_enforcement_delay; 270 271 this.cullTask = new CullTask(); 272 cullAndIdleRefurbishTimer.schedule( cullTask, minExpirationTime(), this.expiration_enforcement_delay ); 275 } 276 else 277 this.expiration_enforcement_delay = expiration_enforcement_delay; 278 279 if (check_idle_resources_delay > 0) 281 { 282 this.idleRefurbishTask = new CheckIdleResourcesTask(); 283 cullAndIdleRefurbishTimer.schedule( idleRefurbishTask, 284 check_idle_resources_delay, 285 check_idle_resources_delay ); 286 } 287 288 if ( logger.isLoggable( MLevel.FINER ) ) 289 logger.finer( this + " config: [start -> " + this.start + "; min -> " + this.min + "; max -> " + this.max + "; inc -> " + this.inc + 290 "; num_acq_attempts -> " + this.num_acq_attempts + "; acq_attempt_delay -> " + this.acq_attempt_delay + 291 "; check_idle_resources_delay -> " + this.check_idle_resources_delay + "; mox_resource_age -> " + this.max_resource_age + 292 "; max_idle_time -> " + this.max_idle_time + "; excess_max_idle_time -> " + this.excess_max_idle_time + 293 "; destroy_unreturned_resc_time -> " + this.destroy_unreturned_resc_time + 294 "; expiration_enforcement_delay -> " + this.expiration_enforcement_delay + 295 "; break_on_acquisition_failure -> " + this.break_on_acquisition_failure + 296 "; debug_store_checkout_exceptions -> " + this.debug_store_checkout_exceptions + 297 "]"); 298 299 } 300 catch (Exception e) 301 { 302 305 throw ResourcePoolUtils.convertThrowable( e ); 306 } 307 } 308 309 312 private boolean mustTestIdleResources() 314 { return check_idle_resources_delay > 0; } 315 316 private boolean mustEnforceExpiration() 318 { 319 return 320 max_resource_age > 0 || 321 max_idle_time > 0 || 322 excess_max_idle_time > 0 || 323 destroy_unreturned_resc_time > 0; 324 } 325 326 private long minExpirationTime() 328 { 329 long out = Long.MAX_VALUE; 330 if (max_resource_age > 0) 331 out = Math.min( out, max_resource_age ); 332 if (max_idle_time > 0) 333 out = Math.min( out, max_idle_time ); 334 if (excess_max_idle_time > 0) 335 out = Math.min( out, excess_max_idle_time ); 336 if (destroy_unreturned_resc_time > 0) 337 out = Math.min( out, expiration_enforcement_delay ); 338 return out; 339 } 340 341 private long automaticExpirationEnforcementDelay() 342 { 343 long out = minExpirationTime(); 344 out /= AUTO_CULL_FREQUENCY_DIVISOR; 345 out = Math.min( out, AUTO_MAX_CULL_FREQUENCY ); 346 out = Math.max( out, AUTO_MIN_CULL_FREQUENCY ); 347 return out; 348 } 349 350 public long getEffectiveExpirationEnforcementDelay() 351 { return expiration_enforcement_delay; } 352 353 private synchronized boolean isBroken() 354 { return broken; } 355 356 private boolean supportsEvents() 358 { return asyncEventQueue != null; } 359 360 public Object checkoutResource() 361 throws ResourcePoolException, InterruptedException 362 { 363 try { return checkoutResource( 0 ); } 364 catch (TimeoutException e) 365 { 366 if ( logger.isLoggable( MLevel.WARNING ) ) 369 logger.log( MLevel.WARNING, "Huh??? TimeoutException with no timeout set!!!", e); 370 371 throw new ResourcePoolException("Huh??? TimeoutException with no timeout set!!!", e); 372 } 373 } 374 375 private void _recheckResizePool() 377 { 378 assert Thread.holdsLock(this); 379 380 if (! broken) 381 { 382 int msz = managed.size(); 383 385 389 int shrink_count; 390 int expand_count; 391 392 if ((shrink_count = msz - pending_removes - target_pool_size) > 0) 393 shrinkPool( shrink_count ); 394 else if ((expand_count = target_pool_size - (msz + pending_acquires)) > 0) 395 expandPool( expand_count ); 396 } 397 } 398 399 private synchronized void incrementPendingAcquires() 400 { 401 ++pending_acquires; 402 403 if (logger.isLoggable(MLevel.FINEST)) 404 logger.finest("incremented pending_acquires: " + pending_acquires); 405 } 407 408 private synchronized void incrementPendingRemoves() 409 { 410 ++pending_removes; 411 412 if (logger.isLoggable(MLevel.FINEST)) 413 logger.finest("incremented pending_removes: " + pending_removes); 414 } 416 417 private synchronized void decrementPendingAcquires() 418 { 419 --pending_acquires; 420 421 if (logger.isLoggable(MLevel.FINEST)) 422 logger.finest("decremented pending_acquires: " + pending_acquires); 423 } 425 426 private synchronized void decrementPendingRemoves() 427 { 428 --pending_removes; 429 430 if (logger.isLoggable(MLevel.FINEST)) 431 logger.finest("decremented pending_removes: " + pending_removes); 432 } 434 435 private synchronized void recheckResizePool() 437 { _recheckResizePool(); } 438 439 private void expandPool(int count) 441 { 442 assert Thread.holdsLock(this); 443 444 if ( USE_SCATTERED_ACQUIRE_TASK ) 447 { 448 for (int i = 0; i < count; ++i) 449 taskRunner.postRunnable( new ScatteredAcquireTask() ); 450 } 451 else 452 { 453 for (int i = 0; i < count; ++i) 454 taskRunner.postRunnable( new AcquireTask() ); 455 } 456 } 457 458 private void shrinkPool(int count) 460 { 461 assert Thread.holdsLock(this); 462 463 for (int i = 0; i < count; ++i) 464 taskRunner.postRunnable( new RemoveTask() ); 465 } 466 467 474 public Object checkoutResource( long timeout ) 475 throws TimeoutException, ResourcePoolException, InterruptedException 476 { 477 Object resc = prelimCheckoutResource( timeout ); 478 479 boolean refurb = attemptRefurbishResourceOnCheckout( resc ); 480 481 synchronized( this ) 482 { 483 if (!refurb) 484 { 485 removeResource( resc ); 486 ensureMinResources(); 487 resc = null; 488 } 489 else 490 { 491 asyncFireResourceCheckedOut( resc, managed.size(), unused.size(), excluded.size() ); 492 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 493 494 PunchCard card = (PunchCard) managed.get( resc ); 495 if (card == null) { 497 if (logger.isLoggable( MLevel.FINE )) 498 logger.fine("Resource " + resc + " was removed from the pool while it was being checked out " + 499 " or refurbished for checkout."); 500 resc = null; 501 } 502 else 503 { 504 card.checkout_time = System.currentTimeMillis(); 505 if (debug_store_checkout_exceptions) 506 card.checkoutStackTraceException = new Exception ("DEBUG ONLY: Overdue resource check-out stack trace."); 507 } 508 } 509 } 510 511 if (resc == null) 514 return checkoutResource( timeout ); 515 else 516 return resc; 517 } 518 519 private synchronized Object prelimCheckoutResource( long timeout ) 520 throws TimeoutException, ResourcePoolException, InterruptedException 521 { 522 try 523 { 524 ensureNotBroken(); 525 526 int available = unused.size(); 527 if (available == 0) 528 { 529 int msz = managed.size(); 530 531 if (msz < max) 532 { 533 int desired_target = msz + acquireWaiters.size() + 1; 536 537 if (logger.isLoggable(MLevel.FINER)) 538 logger.log(MLevel.FINER, "acquire test -- pool size: " + msz + "; target_pool_size: " + target_pool_size + "; desired target? " + desired_target); 539 540 if (desired_target >= target_pool_size) 541 { 542 desired_target = Math.max(desired_target, target_pool_size + inc); 544 545 target_pool_size = Math.max( Math.min( max, desired_target ), min ); 547 548 _recheckResizePool(); 549 } 550 } 551 else 552 { 553 if (logger.isLoggable(MLevel.FINER)) 554 logger.log(MLevel.FINER, "acquire test -- pool is already maxed out. [managed: " + msz + "; max: " + max + "]"); 555 } 556 557 awaitAvailable(timeout); } 559 560 Object resc = unused.get(0); 561 562 if ( idleCheckResources.contains( resc ) ) 565 { 566 if (Debug.DEBUG && logger.isLoggable( MLevel.FINER)) 567 logger.log( MLevel.FINER, 568 "Resource we want to check out is in idleCheck! (waiting until idle-check completes.) [" + this + "]"); 569 570 573 Thread t = Thread.currentThread(); 576 try 577 { 578 otherWaiters.add ( t ); 579 this.wait( timeout ); 580 ensureNotBroken(); 581 } 582 finally 583 { otherWaiters.remove( t ); } 584 return prelimCheckoutResource( timeout ); 585 } 586 else if ( shouldExpire( resc ) ) 587 { 588 removeResource( resc ); 589 ensureMinResources(); 590 return prelimCheckoutResource( timeout ); 591 } 592 else 593 { 594 unused.remove(0); 595 return resc; 596 } 597 } 598 catch ( ResourceClosedException e ) { 600 if (logger.isLoggable( MLevel.SEVERE )) 603 logger.log( MLevel.SEVERE, this + " -- the pool was found to be closed or broken during an attempt to check out a resource.", e ); 604 605 this.unexpectedBreak(); 606 throw e; 607 } 608 catch ( InterruptedException e ) 609 { 610 if (broken) 614 { 615 if (logger.isLoggable( MLevel.FINER )) 616 logger.log(MLevel.FINER, 617 this + " -- an attempt to checkout a resource was interrupted, because the pool is now closed. " + 618 "[Thread: " + Thread.currentThread().getName() + ']', 619 e ); 620 else if (logger.isLoggable( MLevel.INFO )) 621 logger.log(MLevel.INFO, 622 this + " -- an attempt to checkout a resource was interrupted, because the pool is now closed. " + 623 "[Thread: " + Thread.currentThread().getName() + ']'); 624 } 625 else 626 { 627 if (logger.isLoggable( MLevel.WARNING )) 628 { 629 logger.log(MLevel.WARNING, 630 this + " -- an attempt to checkout a resource was interrupted, and the pool is still live: some other thread " + 631 "must have either interrupted the Thread attempting checkout!", 632 e ); 633 } 634 } 635 throw e; 636 } 637 } 638 639 public synchronized void checkinResource( Object resc ) 640 throws ResourcePoolException 641 { 642 try 643 { 644 if (managed.keySet().contains(resc)) 647 doCheckinManaged( resc ); 648 else if (excluded.contains(resc)) 649 doCheckinExcluded( resc ); 650 else if ( isFormerResource(resc) ) 651 { 652 if ( logger.isLoggable( MLevel.FINER ) ) 653 logger.finer("Resource " + resc + " checked-in after having been checked-in already, or checked-in after " + 654 " having being destroyed for being checked-out too long."); 655 } 656 else 657 throw new ResourcePoolException("ResourcePool" + (broken ? " [BROKEN!]" : "") + ": Tried to check-in a foreign resource!"); 658 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 659 } 660 catch ( ResourceClosedException e ) { 662 666 if ( logger.isLoggable( MLevel.SEVERE ) ) 667 logger.log( MLevel.SEVERE, 668 this + " - checkinResource( ... ) -- even broken pools should allow checkins without exception. probable resource pool bug.", 669 e); 670 671 this.unexpectedBreak(); 672 throw e; 673 } 674 } 675 676 public synchronized void checkinAll() 677 throws ResourcePoolException 678 { 679 try 680 { 681 Set checkedOutNotExcluded = new HashSet( managed.keySet() ); 682 checkedOutNotExcluded.removeAll( unused ); 683 for (Iterator ii = checkedOutNotExcluded.iterator(); ii.hasNext(); ) 684 doCheckinManaged( ii.next() ); 685 for (Iterator ii = excluded.iterator(); ii.hasNext(); ) 686 doCheckinExcluded( ii.next() ); 687 } 688 catch ( ResourceClosedException e ) { 690 694 if ( logger.isLoggable( MLevel.SEVERE ) ) 695 logger.log( MLevel.SEVERE, 696 this + " - checkinAll() -- even broken pools should allow checkins without exception. probable resource pool bug.", 697 e ); 698 699 this.unexpectedBreak(); 700 throw e; 701 } 702 } 703 704 public synchronized int statusInPool( Object resc ) 705 throws ResourcePoolException 706 { 707 try 708 { 709 if ( unused.contains( resc ) ) 710 return KNOWN_AND_AVAILABLE; 711 else if ( managed.keySet().contains( resc ) || excluded.contains( resc ) ) 712 return KNOWN_AND_CHECKED_OUT; 713 else 714 return UNKNOWN_OR_PURGED; 715 } 716 catch ( ResourceClosedException e ) { 718 if ( logger.isLoggable( MLevel.SEVERE ) ) 720 logger.log( MLevel.SEVERE, "Apparent pool break.", e ); 721 this.unexpectedBreak(); 722 throw e; 723 } 724 } 725 726 public synchronized void markBroken(Object resc) 727 { 728 try 729 { 730 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER )) 731 logger.log( MLevel.FINER, "Resource " + resc + " marked broken by pool (" + this + ")."); 732 733 _markBroken( resc ); 734 ensureMinResources(); 735 } 736 catch ( ResourceClosedException e ) { 738 if ( logger.isLoggable( MLevel.SEVERE ) ) 740 logger.log( MLevel.SEVERE, "Apparent pool break.", e ); 741 this.unexpectedBreak(); 742 } 743 } 744 745 public int getMinPoolSize() 747 { return min; } 748 749 public int getMaxPoolSize() 751 { return max; } 752 753 public synchronized int getPoolSize() 754 throws ResourcePoolException 755 { return managed.size(); } 756 757 771 public synchronized int getAvailableCount() 772 { return unused.size(); } 773 774 public synchronized int getExcludedCount() 775 { return excluded.size(); } 776 777 public synchronized int getAwaitingCheckinCount() 778 { return managed.size() - unused.size() + excluded.size(); } 779 780 public synchronized void resetPool() 781 { 782 try 783 { 784 for (Iterator ii = cloneOfManaged().keySet().iterator(); ii.hasNext();) 785 markBrokenNoEnsureMinResources(ii.next()); 786 ensureMinResources(); 787 } 788 catch ( ResourceClosedException e ) { 790 if ( logger.isLoggable( MLevel.SEVERE ) ) 792 logger.log( MLevel.SEVERE, "Apparent pool break.", e ); 793 this.unexpectedBreak(); 794 } 795 } 796 797 public synchronized void close() 798 throws ResourcePoolException 799 { 800 close( true ); 804 } 805 806 public void finalize() throws Throwable 807 { 808 812 if (! broken ) 813 this.close(); 814 } 815 816 public void addResourcePoolListener(ResourcePoolListener rpl) 818 { 819 if ( ! supportsEvents() ) 820 throw new RuntimeException (this + " does not support ResourcePoolEvents. " + 821 "Probably it was constructed by a BasicResourceFactory configured not to support such events."); 822 else 823 rpes.addResourcePoolListener(rpl); 824 } 825 826 public void removeResourcePoolListener(ResourcePoolListener rpl) 828 { 829 if ( ! supportsEvents() ) 830 throw new RuntimeException (this + " does not support ResourcePoolEvents. " + 831 "Probably it was constructed by a BasicResourceFactory configured not to support such events."); 832 else 833 rpes.removeResourcePoolListener(rpl); 834 } 835 836 private synchronized boolean isForceKillAcquiresPending() 837 { return force_kill_acquires; } 838 839 private synchronized void forceKillAcquires() throws InterruptedException 843 { 844 Thread t = Thread.currentThread(); 845 846 try 847 { 848 force_kill_acquires = true; 849 this.notifyAll(); while (acquireWaiters.size() > 0) { 852 otherWaiters.add( t ); 853 this.wait(); 854 } 855 force_kill_acquires = false; 856 } 857 finally 858 { otherWaiters.remove( t ); } 859 } 860 861 private synchronized void unexpectedBreak() 864 { 865 if ( logger.isLoggable( MLevel.SEVERE ) ) 866 logger.log( MLevel.SEVERE, this + " -- Unexpectedly broken!!!", new ResourcePoolException("Unexpected Break Stack Trace!") ); 867 close( false ); 868 } 869 870 private boolean canFireEvents() 872 { return ( asyncEventQueue != null && !isBroken() ); } 873 874 private void asyncFireResourceAcquired( final Object resc, 876 final int pool_size, 877 final int available_size, 878 final int removed_but_unreturned_size ) 879 { 880 if ( canFireEvents() ) 881 { 882 Runnable r = new Runnable () 883 { 884 public void run() 885 {rpes.fireResourceAcquired(resc, pool_size, available_size, removed_but_unreturned_size);} 886 }; 887 asyncEventQueue.postRunnable(r); 888 } 889 } 890 891 private void asyncFireResourceCheckedIn( final Object resc, 893 final int pool_size, 894 final int available_size, 895 final int removed_but_unreturned_size ) 896 { 897 if ( canFireEvents() ) 898 { 899 Runnable r = new Runnable () 900 { 901 public void run() 902 {rpes.fireResourceCheckedIn(resc, pool_size, available_size, removed_but_unreturned_size);} 903 }; 904 asyncEventQueue.postRunnable(r); 905 } 906 } 907 908 private void asyncFireResourceCheckedOut( final Object resc, 910 final int pool_size, 911 final int available_size, 912 final int removed_but_unreturned_size ) 913 { 914 if ( canFireEvents() ) 915 { 916 Runnable r = new Runnable () 917 { 918 public void run() 919 {rpes.fireResourceCheckedOut(resc,pool_size,available_size,removed_but_unreturned_size);} 920 }; 921 asyncEventQueue.postRunnable(r); 922 } 923 } 924 925 private void asyncFireResourceRemoved( final Object resc, 927 final boolean checked_out_resource, 928 final int pool_size, 929 final int available_size, 930 final int removed_but_unreturned_size ) 931 { 932 if ( canFireEvents() ) 933 { 934 Runnable r = new Runnable () 937 { 938 public void run() 939 { 940 rpes.fireResourceRemoved(resc, checked_out_resource, 941 pool_size,available_size,removed_but_unreturned_size); 942 } 943 }; 944 asyncEventQueue.postRunnable(r); 945 } 946 } 947 948 private void destroyResource(final Object resc) 950 { destroyResource( resc, false ); } 951 952 private void destroyResource(final Object resc, boolean synchronous) 954 { 955 class DestroyResourceTask implements Runnable 956 { 957 public void run() 958 { 959 try 960 { 961 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER )) 962 logger.log(MLevel.FINER, "Preparing to destroy resource: " + resc); 963 964 mgr.destroyResource(resc); 965 966 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX && logger.isLoggable( MLevel.FINER )) 967 logger.log(MLevel.FINER, "Successfully destroyed resource: " + resc); 968 } 969 catch ( Exception e ) 970 { 971 if ( logger.isLoggable( MLevel.WARNING ) ) 972 logger.log( MLevel.WARNING, "Failed to destroy resource: " + resc, e ); 973 974 } 977 } 978 } 979 980 Runnable r = new DestroyResourceTask(); 981 if ( synchronous || broken ) { 983 if ( logger.isLoggable(MLevel.FINEST) && !broken && Boolean.TRUE.equals( ThreadUtils.reflectiveHoldsLock( this ) ) ) 984 logger.log( MLevel.FINEST, 985 this + ": Destroyiong a resource on an active pool, synchronousy while holding pool's lock! " + 986 "(not a bug, but a potential bottleneck... is there a good reason for this?)", 987 new Exception ("DEBUG STACK TRACE") ); 988 989 r.run(); 990 } 991 else 992 { 993 try { taskRunner.postRunnable( r ); } 994 catch (Exception e) 995 { 996 if (logger.isLoggable(MLevel.FINER)) 997 logger.log( MLevel.FINER, 998 "AsynchronousRunner refused to accept task to destroy resource. " + 999 "It is probably shared, and has probably been closed underneath us. " + 1000 "Reverting to synchronous destruction. This is not usually a problem.", 1001 e ); 1002 destroyResource( resc, true ); 1003 } 1004 } 1005 } 1006 1007 1008 private void doAcquire() throws Exception 1011 { 1012 assert !Thread.holdsLock( this ); 1013 1014 Object resc = mgr.acquireResource(); 1016 boolean destroy = false; 1017 int msz; 1018 1019 synchronized(this) { 1021 1023 1026 msz = managed.size(); 1027 if (msz < target_pool_size) 1028 assimilateResource(resc); 1029 else 1030 destroy = true; 1031 } 1032 1033 if (destroy) 1034 { 1035 mgr.destroyResource( resc ); if (logger.isLoggable( MLevel.FINER)) 1037 logger.log(MLevel.FINER, "destroying overacquired resource: " + resc); 1038 } 1039 1040 } 1041 1042 public synchronized void setPoolSize( int sz ) throws ResourcePoolException 1043 { 1044 try 1045 { 1046 setTargetPoolSize( sz ); 1047 while ( managed.size() != sz ) 1048 this.wait(); 1049 } 1050 catch (Exception e) 1051 { 1052 String msg = "An exception occurred while trying to set the pool size!"; 1053 if ( logger.isLoggable( MLevel.FINER ) ) 1054 logger.log( MLevel.FINER, msg, e ); 1055 throw ResourcePoolUtils.convertThrowable( msg, e ); 1056 } 1057 } 1058 1059 public synchronized void setTargetPoolSize(int sz) 1060 { 1061 if (sz > max) 1062 { 1063 throw new IllegalArgumentException ("Requested size [" + sz + 1064 "] is greater than max [" + max + 1065 "]."); 1066 } 1067 else if (sz < min) 1068 { 1069 throw new IllegalArgumentException ("Requested size [" + sz + 1070 "] is less than min [" + min + 1071 "]."); 1072 } 1073 1074 this.target_pool_size = sz; 1075 1076 _recheckResizePool(); 1077 } 1078 1079 1080 1087 1090 1104 1107 private void markBrokenNoEnsureMinResources(Object resc) 1109 { 1110 assert Thread.holdsLock( this ); 1111 1112 try 1113 { 1114 _markBroken( resc ); 1115 } 1116 catch ( ResourceClosedException e ) { 1118 if ( logger.isLoggable( MLevel.SEVERE ) ) 1120 logger.log( MLevel.SEVERE, "Apparent pool break.", e ); 1121 this.unexpectedBreak(); 1122 } 1123 } 1124 1125 private void _markBroken( Object resc ) 1127 { 1128 assert Thread.holdsLock( this ); 1129 1130 if ( unused.contains( resc ) ) 1131 removeResource( resc ); 1132 else 1133 excludeResource( resc ); 1134 } 1135 1136 1139 public synchronized void close( boolean close_checked_out_resources ) 1140 { 1141 if (! broken ) { 1143 1147 this.broken = true; 1148 final Collection cleanupResources = ( close_checked_out_resources ? (Collection) cloneOfManaged().keySet() : (Collection) cloneOfUnused() ); 1149 if ( cullTask != null ) 1150 cullTask.cancel(); 1151 if (idleRefurbishTask != null) 1152 idleRefurbishTask.cancel(); 1153 1154 1161 managed.keySet().removeAll( cleanupResources ); 1162 unused.removeAll( cleanupResources ); 1163 Thread resourceDestroyer = new Thread ("Resource Destroyer in BasicResourcePool.close()") 1164 { 1165 public void run() 1166 { 1167 for (Iterator ii = cleanupResources.iterator(); ii.hasNext();) 1168 { 1169 try 1170 { 1171 Object resc = ii.next(); 1172 1174 destroyResource( resc, true ); 1175 } 1176 catch (Exception e) 1177 { 1178 if (Debug.DEBUG) 1179 { 1180 if ( logger.isLoggable( MLevel.FINE ) ) 1182 logger.log( MLevel.FINE, "BasicResourcePool -- A resource couldn't be cleaned up on close()", e ); 1183 } 1184 } 1185 } 1186 } 1187 }; 1188 resourceDestroyer.start(); 1189 1190 for (Iterator ii = acquireWaiters.iterator(); ii.hasNext(); ) 1191 ((Thread ) ii.next()).interrupt(); 1192 for (Iterator ii = otherWaiters.iterator(); ii.hasNext(); ) 1193 ((Thread ) ii.next()).interrupt(); 1194 if (factory != null) 1195 factory.markBroken( this ); 1196 1197 } 1199 else 1200 { 1201 if ( logger.isLoggable( MLevel.WARNING ) ) 1202 logger.warning(this + " -- close() called multiple times."); 1203 1205 } 1209 } 1210 1211 private void doCheckinManaged( final Object resc ) throws ResourcePoolException 1212 { 1213 assert Thread.holdsLock( this ); 1214 1215 if (unused.contains(resc)) 1216 { 1217 if ( Debug.DEBUG ) 1218 throw new ResourcePoolException("Tried to check-in an already checked-in resource: " + resc); 1219 } 1220 else if (broken) 1221 removeResource( resc, true ); else 1223 { 1224 class RefurbishCheckinResourceTask implements Runnable 1225 { 1226 public void run() 1227 { 1228 boolean resc_okay = attemptRefurbishResourceOnCheckin( resc ); 1229 synchronized( BasicResourcePool.this ) 1230 { 1231 PunchCard card = (PunchCard) managed.get( resc ); 1232 1233 if ( resc_okay && card != null) { 1235 unused.add(0, resc ); 1236 1237 card.last_checkin_time = System.currentTimeMillis(); 1238 card.checkout_time = -1; 1239 } 1240 else 1241 { 1242 if (card != null) 1243 card.checkout_time = -1; 1245 removeResource( resc ); 1246 ensureMinResources(); 1247 1248 if (card == null && logger.isLoggable( MLevel.FINE )) 1249 logger.fine("Resource " + resc + " was removed from the pool during its refurbishment for checkin."); 1250 } 1251 1252 asyncFireResourceCheckedIn( resc, managed.size(), unused.size(), excluded.size() ); 1253 BasicResourcePool.this.notifyAll(); 1254 } 1255 } 1256 } 1257 1258 Runnable doMe = new RefurbishCheckinResourceTask(); 1259 taskRunner.postRunnable( doMe ); 1260 } 1261 } 1262 1263 private void doCheckinExcluded( Object resc ) 1264 { 1265 assert Thread.holdsLock( this ); 1266 1267 excluded.remove(resc); 1268 destroyResource(resc); 1269 } 1270 1271 1274 private void awaitAvailable(long timeout) throws InterruptedException , TimeoutException, ResourcePoolException 1275 { 1276 assert Thread.holdsLock( this ); 1277 1278 if (force_kill_acquires) 1279 throw new ResourcePoolException("A ResourcePool cannot acquire a new resource -- the factory or source appears to be down."); 1280 1281 Thread t = Thread.currentThread(); 1282 try 1283 { 1284 acquireWaiters.add( t ); 1285 1286 int avail; 1287 long start = ( timeout > 0 ? System.currentTimeMillis() : -1); 1288 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) 1289 { 1290 if ( logger.isLoggable( MLevel.FINE ) ) 1291 logger.fine("awaitAvailable(): " + 1292 (exampleResource != null ? 1293 exampleResource : 1294 "[unknown]") ); 1295 trace(); 1296 } 1297 while ((avail = unused.size()) == 0) 1298 { 1299 if (pending_acquires == 0 && managed.size() < max) 1313 _recheckResizePool(); 1314 1315 this.wait(timeout); 1316 if (timeout > 0 && System.currentTimeMillis() - start > timeout) 1317 throw new TimeoutException("A client timed out while waiting to acquire a resource from " + this + " -- timeout at awaitAvailable()"); 1318 if (force_kill_acquires) 1319 throw new CannotAcquireResourceException("A ResourcePool could not acquire a resource from its primary factory or source."); 1320 ensureNotBroken(); 1321 } 1322 } 1323 finally 1324 { 1325 acquireWaiters.remove( t ); 1326 if (acquireWaiters.size() == 0) 1327 this.notifyAll(); 1328 } 1329 } 1330 1331 private void assimilateResource( Object resc ) throws Exception 1332 { 1333 assert Thread.holdsLock( this ); 1334 1335 managed.put(resc, new PunchCard()); 1336 unused.add(0, resc); 1337 asyncFireResourceAcquired( resc, managed.size(), unused.size(), excluded.size() ); 1339 this.notifyAll(); 1340 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 1341 if (Debug.DEBUG && exampleResource == null) 1342 exampleResource = resc; 1343 } 1344 1345 private void synchronousRemoveArbitraryResource() 1347 { 1348 assert !Thread.holdsLock( this ); 1349 1350 Object removeMe = null; 1351 1352 synchronized ( this ) 1353 { 1354 if (unused.size() > 0) 1355 { 1356 removeMe = unused.get(0); 1357 managed.remove(removeMe); 1358 unused.remove(removeMe); 1359 } 1360 else 1361 { 1362 Set checkedOut = cloneOfManaged().keySet(); 1363 if ( checkedOut.isEmpty() ) 1364 { 1365 unexpectedBreak(); 1366 logger.severe("A pool from which a resource is requested to be removed appears to have no managed resources?!"); 1367 } 1368 else 1369 excludeResource( checkedOut.iterator().next() ); 1370 } 1371 } 1372 1373 if (removeMe != null) 1374 destroyResource( removeMe, true ); 1375 } 1376 1377 private void removeResource(Object resc) 1378 { removeResource( resc, false ); } 1379 1380 private void removeResource(Object resc, boolean synchronous) 1381 { 1382 assert Thread.holdsLock( this ); 1383 1384 PunchCard pc = (PunchCard) managed.remove(resc); 1385 1386 if (pc != null) 1387 { 1388 if ( pc.checkout_time > 0 && !broken) { 1390 if (logger.isLoggable( MLevel.INFO ) ) 1391 { 1392 logger.info("A checked-out resource is overdue, and will be destroyed: " + resc); 1393 if (pc.checkoutStackTraceException != null) 1394 { 1395 logger.log( MLevel.INFO, 1396 "Logging the stack trace by which the overdue resource was checked-out.", 1397 pc.checkoutStackTraceException ); 1398 } 1399 } 1400 } 1401 } 1402 else if ( logger.isLoggable( MLevel.FINE ) ) 1403 logger.fine("Resource " + resc + " was removed twice. (Lotsa reasons a resource can be removed, sometimes simultaneously. It's okay)"); 1404 1405 unused.remove(resc); 1406 destroyResource(resc, synchronous); 1407 addToFormerResources( resc ); 1408 asyncFireResourceRemoved( resc, false, managed.size(), unused.size(), excluded.size() ); 1409 1410 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 1411 } 1413 1414 private void excludeResource(Object resc) 1417 { 1418 assert Thread.holdsLock( this ); 1419 1420 managed.remove(resc); 1421 excluded.add(resc); 1422 if (Debug.DEBUG && unused.contains(resc) ) 1423 throw new InternalError ( "We should only \"exclude\" checked-out resources!" ); 1424 asyncFireResourceRemoved( resc, true, managed.size(), unused.size(), excluded.size() ); 1425 } 1426 1427 private void removeTowards( int new_sz ) 1428 { 1429 assert Thread.holdsLock( this ); 1430 1431 int num_to_remove = managed.size() - new_sz; 1432 int count = 0; 1433 for (Iterator ii = cloneOfUnused().iterator(); 1434 ii.hasNext() && count < num_to_remove; 1435 ++count) 1436 { 1437 Object resc = ii.next(); 1438 removeResource( resc ); 1439 } 1440 } 1441 1442 private void cullExpired() 1443 { 1444 assert Thread.holdsLock( this ); 1445 1446 if ( logger.isLoggable( MLevel.FINER ) ) 1447 logger.log( MLevel.FINER, "BEGIN check for expired resources. [" + this + "]"); 1448 1449 Collection checkMe = ( destroy_unreturned_resc_time > 0 ? (Collection) cloneOfManaged().keySet() : cloneOfUnused() ); 1451 1452 for ( Iterator ii = checkMe.iterator(); ii.hasNext(); ) 1453 { 1454 Object resc = ii.next(); 1455 if ( shouldExpire( resc ) ) 1456 { 1457 if ( logger.isLoggable( MLevel.FINER ) ) 1458 logger.log( MLevel.FINER, "Removing expired resource: " + resc + " [" + this + "]"); 1459 1460 target_pool_size = Math.max( min, target_pool_size - 1 ); 1462 removeResource( resc ); 1463 1464 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 1465 } 1466 } 1467 if ( logger.isLoggable( MLevel.FINER ) ) 1468 logger.log( MLevel.FINER, "FINISHED check for expired resources. [" + this + "]"); 1469 ensureMinResources(); 1470 } 1471 1472 private void checkIdleResources() 1473 { 1474 assert Thread.holdsLock( this ); 1475 1476 List u = cloneOfUnused(); 1477 for ( Iterator ii = u.iterator(); ii.hasNext(); ) 1478 { 1479 Object resc = ii.next(); 1480 if ( idleCheckResources.add( resc ) ) 1481 taskRunner.postRunnable( new AsyncTestIdleResourceTask( resc ) ); 1482 } 1483 1484 if (Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX) trace(); 1485 } 1486 1487 private boolean shouldExpire( Object resc ) 1488 { 1489 assert Thread.holdsLock( this ); 1490 1491 boolean expired = false; 1492 1493 PunchCard pc = (PunchCard) managed.get( resc ); 1494 1495 if (pc == null) 1501 { 1502 if ( logger.isLoggable( MLevel.FINE ) ) 1503 logger.fine( "Resource " + resc + " was being tested for expiration, but has already been removed from the pool."); 1504 return true; 1505 } 1506 1507 long now = System.currentTimeMillis(); 1508 1509 if (pc.checkout_time < 0) { 1511 long idle_age = now - pc.last_checkin_time; 1512 if (excess_max_idle_time > 0) 1513 { 1514 int msz = managed.size(); 1515 expired = (msz > min && idle_age > excess_max_idle_time); 1516 if ( expired && logger.isLoggable( MLevel.FINER ) ) 1517 logger.log(MLevel.FINER, 1518 "EXPIRED excess idle resource: " + resc + 1519 " ---> idle_time: " + idle_age + 1520 "; excess_max_idle_time: " + excess_max_idle_time + 1521 "; pool_size: " + msz + 1522 "; min_pool_size: " + min + 1523 " [" + this + "]"); 1524 } 1525 if (!expired && max_idle_time > 0) 1526 { 1527 expired = idle_age > max_idle_time; 1528 if ( expired && logger.isLoggable( MLevel.FINER ) ) 1529 logger.log(MLevel.FINER, 1530 "EXPIRED idle resource: " + resc + 1531 " ---> idle_time: " + idle_age + 1532 "; max_idle_time: " + max_idle_time + 1533 " [" + this + "]"); 1534 } 1535 if (!expired && max_resource_age > 0) 1536 { 1537 long abs_age = now - pc.acquisition_time; 1538 expired = ( abs_age > max_resource_age ); 1539 1540 if ( expired && logger.isLoggable( MLevel.FINER ) ) 1541 logger.log(MLevel.FINER, 1542 "EXPIRED old resource: " + resc + 1543 " ---> absolute_age: " + abs_age + 1544 "; max_absolute_age: " + max_resource_age + 1545 " [" + this + "]"); 1546 } 1547 } 1548 else { 1550 long checkout_age = now - pc.checkout_time; 1551 expired = checkout_age > destroy_unreturned_resc_time; 1552 } 1553 1554 return expired; 1555 } 1556 1557 1558 1561 1564 1565 private void ensureStartResources() 1567 { recheckResizePool(); } 1568 1569 private void ensureMinResources() 1571 { recheckResizePool(); } 1572 1573 private boolean attemptRefurbishResourceOnCheckout( Object resc ) 1574 { 1575 assert !Thread.holdsLock( this ); 1576 1577 try 1578 { 1579 mgr.refurbishResourceOnCheckout(resc); 1580 return true; 1581 } 1582 catch (Exception e) 1583 { 1584 if (Debug.DEBUG) 1586 { 1587 if (logger.isLoggable( MLevel.FINE )) 1589 logger.log( MLevel.FINE, "A resource could not be refurbished for checkout. [" + resc + ']', e ); 1590 } 1591 synchronized (this) 1592 { 1593 ++failed_checkouts; 1594 setLastCheckoutFailure(e); 1595 } 1596 return false; 1597 } 1598 } 1599 1600 private boolean attemptRefurbishResourceOnCheckin( Object resc ) 1601 { 1602 assert !Thread.holdsLock( this ); 1603 1604 try 1605 { 1606 mgr.refurbishResourceOnCheckin(resc); 1607 return true; 1608 } 1609 catch (Exception e) 1610 { 1611 if (Debug.DEBUG) 1613 { 1614 if (logger.isLoggable( MLevel.FINE )) 1616 logger.log( MLevel.FINE, "A resource could not be refurbished on checkin. [" + resc + ']', e ); 1617 } 1618 synchronized (this) 1619 { 1620 ++failed_checkins; 1621 setLastCheckinFailure(e); 1622 } 1623 return false; 1624 } 1625 } 1626 1627 private void ensureNotBroken() throws ResourcePoolException 1628 { 1629 assert Thread.holdsLock( this ); 1630 1631 if (broken) 1632 throw new ResourcePoolException("Attempted to use a closed or broken resource pool"); 1633 } 1634 1635 private void trace() 1636 { 1637 assert Thread.holdsLock( this ); 1638 1639 if ( logger.isLoggable( MLevel.FINEST ) ) 1640 { 1641 String exampleResStr = ( exampleResource == null ? 1642 "" : 1643 " (e.g. " + exampleResource +")"); 1644 logger.finest("trace " + this + " [managed: " + managed.size() + ", " + 1645 "unused: " + unused.size() + ", excluded: " + 1646 excluded.size() + ']' + exampleResStr ); 1647 } 1648 } 1649 1650 private final HashMap cloneOfManaged() 1651 { 1652 assert Thread.holdsLock( this ); 1653 1654 return (HashMap) managed.clone(); 1655 } 1656 1657 private final LinkedList cloneOfUnused() 1658 { 1659 assert Thread.holdsLock( this ); 1660 1661 return (LinkedList) unused.clone(); 1662 } 1663 1664 private final HashSet cloneOfExcluded() 1665 { 1666 assert Thread.holdsLock( this ); 1667 1668 return (HashSet) excluded.clone(); 1669 } 1670 1671 class ScatteredAcquireTask implements Runnable 1672 { 1673 int attempts_remaining; 1674 1675 ScatteredAcquireTask() 1676 { this ( (num_acq_attempts >= 0 ? num_acq_attempts : -1) , true ); } 1677 1678 private ScatteredAcquireTask(int attempts_remaining, boolean first_attempt) 1679 { 1680 this.attempts_remaining = attempts_remaining; 1681 if (first_attempt) 1682 { 1683 incrementPendingAcquires(); 1684 if (logger.isLoggable(MLevel.FINEST)) 1685 logger.finest("Starting acquisition series. Incremented pending_acquires [" + pending_acquires + "], " + 1686 " attempts_remaining: " + attempts_remaining); 1687 } 1688 else 1689 { 1690 if (logger.isLoggable(MLevel.FINEST)) 1691 logger.finest("Continuing acquisition series. pending_acquires [" + pending_acquires + "], " + 1692 " attempts_remaining: " + attempts_remaining); 1693 } 1694 } 1695 1696 public void run() 1697 { 1698 try 1699 { 1700 boolean fkap = isForceKillAcquiresPending(); 1701 if (! fkap) 1702 { 1703 BasicResourcePool.this.doAcquire(); 1707 } 1708 decrementPendingAcquires(); 1709 if (logger.isLoggable(MLevel.FINEST)) 1710 logger.finest("Acquisition series terminated " + 1711 (fkap ? "because force-kill-acquires is pending" : "successfully") + 1712 ". Decremented pending_acquires [" + pending_acquires + "], " + 1713 " attempts_remaining: " + attempts_remaining); 1714 } 1715 catch (Exception e) 1716 { 1717 BasicResourcePool.this.setLastAcquisitionFailure(e); 1718 1719 if (attempts_remaining == 0) { 1721 decrementPendingAcquires(); 1722 if ( logger.isLoggable( MLevel.WARNING ) ) 1723 { 1724 logger.log( MLevel.WARNING, 1725 this + " -- Acquisition Attempt Failed!!! Clearing pending acquires. " + 1726 "While trying to acquire a needed new resource, we failed " + 1727 "to succeed more than the maximum number of allowed " + 1728 "acquisition attempts (" + num_acq_attempts + "). " + 1729 "Last acquisition attempt exception: ", 1730 e); 1731 } 1732 if (break_on_acquisition_failure) 1733 { 1734 if ( logger.isLoggable( MLevel.SEVERE ) ) 1736 logger.severe("A RESOURCE POOL IS PERMANENTLY BROKEN! [" + this + "] " + 1737 "(because a series of " + num_acq_attempts + " acquisition attempts " + 1738 "failed.)"); 1739 unexpectedBreak(); 1740 } 1741 else 1742 { 1743 try { forceKillAcquires(); } 1744 catch (InterruptedException ie) 1745 { 1746 if ( logger.isLoggable(MLevel.WARNING) ) 1747 logger.log(MLevel.WARNING, 1748 "Failed to force-kill pending acquisition attempts after acquisition failue, " + 1749 " due to an InterruptedException!", 1750 ie ); 1751 1752 recheckResizePool(); 1755 } 1756 } 1757 if (logger.isLoggable(MLevel.FINEST)) 1758 logger.finest("Acquisition series terminated unsuccessfully. Decremented pending_acquires [" + pending_acquires + "], " + 1759 " attempts_remaining: " + attempts_remaining); 1760 } 1761 else 1762 { 1763 MLevel logLevel = (attempts_remaining > 0 ? MLevel.FINE : MLevel.INFO); 1769 if (logger.isLoggable( logLevel )) 1770 logger.log( logLevel, "An exception occurred while acquiring a poolable resource. Will retry.", e ); 1771 1772 TimerTask doNextAcquire = new TimerTask() 1773 { 1774 public void run() 1775 { taskRunner.postRunnable( new ScatteredAcquireTask( attempts_remaining - 1, false ) ); } 1776 }; 1777 cullAndIdleRefurbishTimer.schedule( doNextAcquire, acq_attempt_delay ); 1778 } 1779 } 1780 } 1781 1782 } 1783 1784 1788 class AcquireTask implements Runnable 1789 { 1790 boolean success = false; 1791 1792 public AcquireTask() 1793 { incrementPendingAcquires(); } 1794 1795 public void run() 1796 { 1797 try 1798 { 1799 Exception lastException = null; 1800 for (int i = 0; shouldTry( i ); ++i) 1801 { 1802 try 1803 { 1804 if (i > 0) 1805 Thread.sleep(acq_attempt_delay); 1806 1807 BasicResourcePool.this.doAcquire(); 1811 1812 success = true; 1813 } 1814 catch (InterruptedException e) 1815 { 1816 throw e; 1819 } 1820 catch (Exception e) 1821 { 1822 1824 MLevel logLevel = (num_acq_attempts > 0 ? MLevel.FINE : MLevel.INFO); 1830 if (logger.isLoggable( logLevel )) 1831 logger.log( logLevel, "An exception occurred while acquiring a poolable resource. Will retry.", e ); 1832 1833 lastException = e; 1834 setLastAcquisitionFailure(e); 1835 } 1836 } 1837 if (!success) 1838 { 1839 if ( logger.isLoggable( MLevel.WARNING ) ) 1840 { 1841 logger.log( MLevel.WARNING, 1842 this + " -- Acquisition Attempt Failed!!! Clearing pending acquires. " + 1843 "While trying to acquire a needed new resource, we failed " + 1844 "to succeed more than the maximum number of allowed " + 1845 "acquisition attempts (" + num_acq_attempts + "). " + 1846 (lastException == null ? "" : "Last acquisition attempt exception: "), 1847 lastException); 1848 } 1849 if (break_on_acquisition_failure) 1850 { 1851 if ( logger.isLoggable( MLevel.SEVERE ) ) 1853 logger.severe("A RESOURCE POOL IS PERMANENTLY BROKEN! [" + this + "]"); 1854 unexpectedBreak(); 1855 } 1856 else 1857 forceKillAcquires(); 1858 } 1859 else 1860 recheckResizePool(); 1861 } 1862 catch ( ResourceClosedException e ) { 1864 if ( Debug.DEBUG ) 1866 { 1867 if ( logger.isLoggable( MLevel.FINE ) ) 1868 logger.log( MLevel.FINE, "a resource pool async thread died.", e ); 1869 } 1870 unexpectedBreak(); 1871 } 1872 catch (InterruptedException e) { 1874 if ( logger.isLoggable( MLevel.WARNING ) ) 1875 { 1876 logger.log( MLevel.WARNING, 1877 BasicResourcePool.this + " -- Thread unexpectedly interrupted while performing an acquisition attempt.", 1878 e ); 1879 } 1880 1881 1884 recheckResizePool(); 1885 } 1886 finally 1887 { decrementPendingAcquires(); } 1888 } 1889 1890 private boolean shouldTry(int attempt_num) 1891 { 1892 return 1897 !success && 1898 !isForceKillAcquiresPending() && 1899 (num_acq_attempts <= 0 || attempt_num < num_acq_attempts); 1900 } 1901 } 1902 1903 1911 class RemoveTask implements Runnable 1912 { 1913 public RemoveTask() 1914 { incrementPendingRemoves(); } 1915 1916 public void run() 1917 { 1918 try 1919 { 1920 synchronousRemoveArbitraryResource(); 1921 recheckResizePool(); 1922 } 1923 finally 1924 { decrementPendingRemoves(); } 1925 } 1926 } 1927 1928 class CullTask extends TimerTask 1929 { 1930 public void run() 1931 { 1932 try 1933 { 1934 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable( MLevel.FINER )) 1935 logger.log( MLevel.FINER, "Checking for expired resources - " + new Date() + " [" + BasicResourcePool.this + "]"); 1936 synchronized ( BasicResourcePool.this ) 1937 { cullExpired(); } 1938 } 1939 catch ( ResourceClosedException e ) { 1941 if ( Debug.DEBUG ) 1942 { 1943 if ( logger.isLoggable( MLevel.FINE ) ) 1944 logger.log( MLevel.FINE, "a resource pool async thread died.", e ); 1945 } 1946 unexpectedBreak(); 1947 } 1948 } 1949 } 1950 1951 class CheckIdleResourcesTask extends TimerTask 1955 { 1956 public void run() 1957 { 1958 try 1959 { 1960 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable(MLevel.FINER)) 1962 logger.log(MLevel.FINER, "Refurbishing idle resources - " + new Date() + " [" + BasicResourcePool.this + "]"); 1963 synchronized ( BasicResourcePool.this ) 1964 { checkIdleResources(); } 1965 } 1966 catch ( ResourceClosedException e ) { 1968 if ( Debug.DEBUG ) 1970 { 1971 if ( logger.isLoggable( MLevel.FINE ) ) 1972 logger.log( MLevel.FINE, "a resource pool async thread died.", e ); 1973 } 1974 unexpectedBreak(); 1975 } 1976 } 1977 } 1978 1979 class AsyncTestIdleResourceTask implements Runnable 1980 { 1981 Object resc; 1983 1984 boolean pending = true; 1986 boolean failed; 1987 1988 AsyncTestIdleResourceTask( Object resc ) 1989 { this.resc = resc; } 1990 1991 public void run() 1992 { 1993 assert !Thread.holdsLock( BasicResourcePool.this ); 1994 1995 try 1996 { 1997 try 1998 { 1999 mgr.refurbishIdleResource( resc ); 2000 } 2001 catch ( Exception e ) 2002 { 2003 if ( logger.isLoggable( MLevel.FINE ) ) 2004 logger.log( MLevel.FINE, "BasicResourcePool: An idle resource is broken and will be purged. [" + resc + ']', e); 2005 2006 synchronized (BasicResourcePool.this) 2007 { 2008 if ( managed.keySet().contains( resc ) ) { 2010 removeResource( resc ); 2011 ensureMinResources(); 2012 } 2013 2014 ++failed_idle_tests; 2015 setLastIdleCheckFailure(e); 2016 } 2017 } 2018 } 2019 finally 2020 { 2021 synchronized (BasicResourcePool.this) 2022 { 2023 idleCheckResources.remove( resc ); 2024 BasicResourcePool.this.notifyAll(); 2025 } 2026 } 2027 } 2028 } 2029 2030 final static class PunchCard 2031 { 2032 long acquisition_time; 2033 long last_checkin_time; 2034 long checkout_time; 2035 Exception checkoutStackTraceException; 2036 2037 PunchCard() 2038 { 2039 this.acquisition_time = System.currentTimeMillis(); 2040 this.last_checkin_time = acquisition_time; 2041 this.checkout_time = -1; 2042 this.checkoutStackTraceException = null; 2043 } 2044 } 2045 2046 2050 2056 2059} 2085 2086 | Popular Tags |