1 29 30 package com.caucho.jca; 31 32 import com.caucho.config.ConfigException; 33 import com.caucho.config.types.Period; 34 import com.caucho.lifecycle.Lifecycle; 35 import com.caucho.log.Log; 36 import com.caucho.management.server.AbstractManagedObject; 37 import com.caucho.management.server.ConnectionPoolMXBean; 38 import com.caucho.util.Alarm; 39 import com.caucho.util.AlarmListener; 40 import com.caucho.util.L10N; 41 import com.caucho.util.LifoSet; 42 import com.caucho.util.WeakAlarm; 43 44 import javax.resource.NotSupportedException ; 45 import javax.resource.ResourceException ; 46 import javax.resource.spi.ConnectionManager ; 47 import javax.resource.spi.ConnectionRequestInfo ; 48 import javax.resource.spi.ManagedConnection ; 49 import javax.resource.spi.ManagedConnectionFactory ; 50 import javax.resource.spi.ValidatingManagedConnectionFactory ; 51 import javax.security.auth.Subject ; 52 import javax.transaction.xa.XAResource ; 53 import javax.transaction.xa.Xid ; 54 import java.util.ArrayList ; 55 import java.util.Set ; 56 import java.util.logging.Level ; 57 import java.util.logging.Logger ; 58 59 62 public class ConnectionPool extends AbstractManagedObject 63 implements ConnectionManager , AlarmListener, ConnectionPoolMXBean { 64 private static final L10N L = new L10N(ConnectionPool.class); 65 private static final Logger log = Log.open(ConnectionPool.class); 66 67 private static int _idGen; 68 69 private String _name; 70 71 private UserTransactionProxy _tm; 72 73 private int _maxConnections = 128; 75 76 private int _maxOverflowConnections = 0; 78 79 private int _maxCreateConnections = 5; 81 82 private long _maxIdleTime = 30000L; 84 85 private long _maxActiveTime = 6L * 60000L * 1000L; 87 88 private long _maxPoolTime = 24L * 60000L * 1000L; 90 91 private long _connectionWaitTime = 600 * 1000L; 93 94 private long _connectionWaitCount = _connectionWaitTime / 1000L; 96 97 private boolean _enableLocalTransaction = true; 99 100 private boolean _enableXA = true; 102 103 private boolean _isLocalTransactionOptimization = true; 105 106 private boolean _isShareable = true; 108 109 private boolean _saveAllocationStackTrace = false; 111 112 private final ArrayList <PoolItem> _pool = new ArrayList <PoolItem>(); 113 114 private final LifoSet<ManagedConnection > _idlePool 115 = new LifoSet<ManagedConnection >(); 116 117 private final ArrayList <PoolItem> _alarmConnections 119 = new ArrayList <PoolItem>(); 120 121 private Alarm _alarm; 122 123 private long _lastValidCheckTime; 125 126 private int _idCount; 127 128 private int _createCount; 129 130 private final Lifecycle _lifecycle = new Lifecycle(); 131 132 ConnectionPool() 133 { 134 } 135 136 139 public void setName(String name) 140 { 141 _name = name; 142 } 143 144 147 public String getName() 148 { 149 return _name; 150 } 151 152 155 public void setTransactionManager(UserTransactionProxy tm) 156 { 157 _tm = tm; 158 } 159 160 163 public UserTransactionProxy getTransactionManager() 164 { 165 return _tm; 166 } 167 168 171 public boolean isShareable() 172 { 173 return _isShareable; 174 } 175 176 179 public void setShareable(boolean isShareable) 180 { 181 _isShareable = isShareable; 182 } 183 184 187 public boolean isLocalTransactionOptimization() 188 { 189 return _isLocalTransactionOptimization; 190 } 191 192 195 public void setLocalTransactionOptimization(boolean enable) 196 { 197 _isLocalTransactionOptimization = enable; 198 } 199 200 203 public boolean allowLocalTransactionOptimization() 204 { 205 return _isLocalTransactionOptimization && _isShareable; 206 } 207 208 211 public boolean getSaveAllocationStackTrace() 212 { 213 return _saveAllocationStackTrace; 214 } 215 216 219 public void setSaveAllocationStackTrace(boolean save) 220 { 221 _saveAllocationStackTrace = save; 222 } 223 224 227 public void setLocalTransaction(boolean localTransaction) 228 { 229 _enableLocalTransaction = localTransaction; 230 } 231 232 235 public boolean isLocalTransaction() 236 { 237 return _enableLocalTransaction; 238 } 239 240 243 public void setXATransaction(boolean enable) 244 { 245 _enableXA = enable; 246 } 247 248 251 public boolean isXATransaction() 252 { 253 return _enableXA; 254 } 255 256 259 public long getMaxIdleTime() 260 { 261 if (Long.MAX_VALUE / 2 <= _maxIdleTime) 262 return -1; 263 else 264 return _maxIdleTime; 265 } 266 267 270 public void setMaxIdleTime(long maxIdleTime) 271 { 272 if (maxIdleTime < 0) 273 _maxIdleTime = Long.MAX_VALUE / 2; 274 else 275 _maxIdleTime = maxIdleTime; 276 } 277 278 281 public long getMaxActiveTime() 282 { 283 if (Long.MAX_VALUE / 2 <= _maxActiveTime) 284 return -1; 285 else 286 return _maxActiveTime; 287 } 288 289 292 public void setMaxActiveTime(long maxActiveTime) 293 { 294 if (maxActiveTime < 0) 295 _maxActiveTime = Long.MAX_VALUE / 2; 296 else 297 _maxActiveTime = maxActiveTime; 298 } 299 300 303 public long getMaxPoolTime() 304 { 305 if (Long.MAX_VALUE / 2 <= _maxPoolTime) 306 return -1; 307 else 308 return _maxPoolTime; 309 } 310 311 314 public void setMaxPoolTime(long maxPoolTime) 315 { 316 if (maxPoolTime < 0) 317 _maxPoolTime = Long.MAX_VALUE / 2; 318 else 319 _maxPoolTime = maxPoolTime; 320 } 321 322 325 public void setMaxConnections(int maxConnections) 326 throws ConfigException 327 { 328 if (maxConnections == 0) 329 throw new ConfigException(L.l("max-connections '0' must be at least 1.")); 330 331 _maxConnections = maxConnections; 332 333 if (maxConnections < 0) 334 _maxConnections = Integer.MAX_VALUE / 2; 335 } 336 337 340 public int getMaxConnections() 341 { 342 if (_maxConnections < Integer.MAX_VALUE / 2) 343 return _maxConnections; 344 else 345 return -1; 346 } 347 348 351 public void setConnectionWaitTime(Period waitTime) 352 { 353 _connectionWaitTime = waitTime.getPeriod(); 354 355 if (_connectionWaitTime < 0) 356 _connectionWaitTime = Long.MAX_VALUE / 2; 357 358 _connectionWaitCount = _connectionWaitTime / 1000; 359 } 360 361 364 public long getConnectionWaitTime() 365 { 366 if (_connectionWaitTime < Long.MAX_VALUE / 2) 367 return _connectionWaitTime; 368 else 369 return -1; 370 } 371 372 375 public void setMaxOverflowConnections(int maxOverflowConnections) 376 { 377 _maxOverflowConnections = maxOverflowConnections; 378 } 379 380 383 public int getMaxOverflowConnections() 384 { 385 return _maxOverflowConnections; 386 } 387 388 391 public void setMaxCreateConnections(int maxConnections) 392 throws ConfigException 393 { 394 if (maxConnections == 0) 395 throw new ConfigException(L.l("max-create-connections '0' must be at least 1.")); 396 397 _maxCreateConnections = maxConnections; 398 399 if (maxConnections < 0) 400 _maxCreateConnections = Integer.MAX_VALUE / 2; 401 402 } 403 404 407 public int getMaxCreateConnections() 408 { 409 if (_maxCreateConnections < Integer.MAX_VALUE / 2) 410 return _maxCreateConnections; 411 else 412 return -1; 413 } 414 415 418 public Object init(ManagedConnectionFactory mcf) 419 throws ConfigException, ResourceException 420 { 421 if (! _lifecycle.toInit()) 422 return null; 423 424 if (_name == null) 425 _name = "connection-pool-" + _idGen++; 426 427 if (_tm == null) 428 throw new ConfigException(L.l("the connection manager needs a transaction manager.")); 429 430 registerSelf(); 431 432 _alarm = new WeakAlarm(this); 433 434 if (! (mcf instanceof ValidatingManagedConnectionFactory )) { 435 _lastValidCheckTime = Long.MAX_VALUE / 2; 437 } 438 439 if (_enableXA) { 441 Subject subject = null; 442 ManagedConnection mConn = mcf.createManagedConnection(subject, null); 443 444 try { 445 XAResource xa = mConn.getXAResource(); 446 447 _tm.recover(xa); 448 } catch (NotSupportedException e) { 449 _enableXA = false; 450 log.finer(e.toString()); 451 } catch (Throwable e) { 452 log.log(Level.FINER, e.toString(), e); 453 } finally { 454 mConn.destroy(); 455 } 456 } 457 458 return mcf.createConnectionFactory(this); 459 } 460 461 464 public void start() 465 { 466 if (! _lifecycle.toActive()) 467 return; 468 469 if (0 < _maxIdleTime && _maxIdleTime < 1000) 470 _alarm.queue(1000); 471 else if (1000 < _maxIdleTime && _maxIdleTime < 60000) 472 _alarm.queue(_maxIdleTime); 473 else 474 _alarm.queue(60000); 475 } 476 477 480 String generateId() 481 { 482 return String.valueOf(_idCount++); 483 } 484 485 490 public Object allocateConnection(ManagedConnectionFactory mcf, 491 ConnectionRequestInfo info) 492 throws ResourceException 493 { 494 Subject subject = null; 495 496 return allocate(mcf, subject, info); 497 } 498 499 502 void toIdle(PoolItem item) 503 { 504 if (_pool.size() <= _maxConnections && ! item.isConnectionError()) { 505 ManagedConnection mConn = item.getManagedConnection(); 506 if (mConn != null) { 507 try { 508 mConn.cleanup(); 509 510 synchronized (_idlePool) { 511 _idlePool.add(mConn); 512 } 513 514 synchronized (_pool) { 515 _pool.notify(); 516 } 517 518 return; 519 } catch (Throwable e) { 520 log.log(Level.FINE, e.toString(), e); 521 } 522 } 523 } 524 525 toDead(item); 526 } 527 528 531 public PoolItem getDelegatePoolItem(Xid xid) 532 { 533 ArrayList <PoolItem> pool = _pool; 534 535 synchronized (pool) { 536 int size = pool.size(); 537 for (int i = 0; i < size; i++) { 538 PoolItem item = pool.get(i); 539 540 if (xid.equals(item.getXid())) 541 return item; 542 } 543 } 544 545 return null; 546 } 547 548 551 public int getConnectionCount() 552 { 553 return _pool.size(); 554 } 555 556 559 public int getConnectionIdleCount() 560 { 561 return _idlePool.size(); 562 } 563 564 567 public int getConnectionActiveCount() 568 { 569 return _pool.size() - _idlePool.size(); 570 } 571 572 575 public void clear() 576 { 577 ArrayList <PoolItem> pool = _pool; 578 579 if (pool == null) 580 return; 581 582 ArrayList <PoolItem> clearItems = new ArrayList <PoolItem>(); 583 584 synchronized (pool) { 585 clearItems.addAll(pool); 586 587 pool.clear(); 588 _idlePool.clear(); 589 } 590 591 for (int i = 0; i < clearItems.size(); i++) { 592 PoolItem poolItem = clearItems.get(i); 593 594 try { 595 poolItem.destroy(); 596 } catch (Throwable e) { 597 log.log(Level.WARNING, e.toString(), e); 598 } 599 } 600 } 601 602 605 UserTransactionImpl getTransaction() 606 { 607 return _tm.getTransaction(); 608 } 609 610 613 private Object allocate(ManagedConnectionFactory mcf, 614 Subject subject, 615 ConnectionRequestInfo info) 616 throws ResourceException 617 { 618 UserPoolItem userPoolItem = null; 619 620 try { 621 UserTransactionImpl transaction = _tm.getTransaction(); 622 623 if (transaction == null) 624 return allocatePool(mcf, subject, info, null).allocateUserConnection(); 625 626 userPoolItem = transaction.allocate(mcf, subject, info); 627 628 if (userPoolItem == null) 629 userPoolItem = allocatePool(mcf, subject, info, null); 630 631 return userPoolItem.allocateUserConnection(); 632 } catch (RuntimeException e) { 633 if (userPoolItem != null) 634 userPoolItem.close(); 635 636 throw e; 637 } catch (ResourceException e) { 638 if (userPoolItem != null) 639 userPoolItem.close(); 640 641 throw e; 642 } catch (Throwable e) { 643 if (userPoolItem != null) 644 userPoolItem.close(); 645 646 throw new ResourceException (e); 647 } 648 } 649 650 653 UserPoolItem allocatePool(ManagedConnectionFactory mcf, 654 Subject subject, 655 ConnectionRequestInfo info, 656 UserPoolItem oldUserItem) 657 throws ResourceException 658 { 659 ManagedConnection mConn; 660 661 long timeoutCount = _connectionWaitCount; 662 663 while (_lifecycle.isActive()) { 664 UserPoolItem userPoolItem = allocateIdle(mcf, subject, 665 info, oldUserItem); 666 667 if (userPoolItem != null) 668 return userPoolItem; 669 670 userPoolItem = create(mcf, subject, info, false, oldUserItem); 671 672 if (userPoolItem != null) 673 return userPoolItem; 674 675 if (timeoutCount-- < 0) 676 break; 677 } 678 679 if (! _lifecycle.isActive()) 680 throw new IllegalStateException (L.l("connection pool closed")); 681 682 UserPoolItem userPoolItem = create(mcf, subject, info, true, oldUserItem); 683 684 if (userPoolItem == null) 685 throw new NullPointerException (L.l("ConnectionPool create should not return a null PoolItem for overflow connections.")); 686 687 return userPoolItem; 688 } 689 690 693 private UserPoolItem allocateIdle(ManagedConnectionFactory mcf, 694 Subject subject, 695 ConnectionRequestInfo info, 696 UserPoolItem oldUserItem) 697 throws ResourceException 698 { 699 while (_lifecycle.isActive()) { 700 ManagedConnection mConn; 701 702 long now = Alarm.getCurrentTime(); 703 704 if (_lastValidCheckTime + 1000L < now) { 705 _lastValidCheckTime = now; 706 707 if (mcf instanceof ValidatingManagedConnectionFactory ) { 708 ValidatingManagedConnectionFactory vmcf; 709 vmcf = (ValidatingManagedConnectionFactory ) mcf; 710 711 validate(vmcf); 712 } 713 } 714 715 synchronized (_idlePool) { 718 mConn = mcf.matchManagedConnections(_idlePool, subject, info); 719 720 if (mConn == null) 722 return null; 723 724 _idlePool.remove(mConn); 725 } 726 727 PoolItem poolItem = null; 728 729 synchronized (_pool) { 730 for (int i = _pool.size() - 1; i >= 0; i--) { 731 poolItem = _pool.get(i); 732 733 if (poolItem.getManagedConnection() == mConn) 734 break; 735 } 736 } 737 738 if (poolItem == null) 739 throw new IllegalStateException (L.l("No matching PoolItem found for {0}", 740 mConn)); 741 742 UserPoolItem userPoolItem = null; 743 744 userPoolItem = poolItem.toActive(subject, info, oldUserItem); 746 if (userPoolItem != null) 747 return userPoolItem; 748 749 toDead(poolItem); 750 } 751 752 return null; 753 } 754 755 758 private void validate(ValidatingManagedConnectionFactory mcf) 759 { 760 Set invalid = null; 761 762 synchronized (_idlePool) { 763 } 764 } 765 766 769 private UserPoolItem create(ManagedConnectionFactory mcf, 770 Subject subject, 771 ConnectionRequestInfo info, 772 boolean isOverflow, 773 UserPoolItem oldUserItem) 774 throws ResourceException 775 { 776 synchronized (_pool) { 777 int size = _pool.size(); 778 779 if (isOverflow && 780 _maxConnections + _maxOverflowConnections <= _createCount + size) { 781 throw new ResourceException (L.l("Connection pool is full. Can't allocate connection.")); 782 } 783 else if (! isOverflow && 785 (_maxConnections <= _createCount + size || 786 _maxCreateConnections <= _createCount)) { 787 try { 788 _pool.wait(1000); 789 } catch (Throwable e) { 790 log.log(Level.FINE, e.toString(), e); 791 } 792 793 return null; 794 } 795 796 _createCount++; 797 } 798 799 PoolItem poolItem = null; 800 try { 801 ManagedConnection mConn = mcf.createManagedConnection(subject, info); 802 803 if (mConn == null) 804 throw new ResourceException (L.l("'{0}' did not return a connection from createManagedConnection", 805 mcf)); 806 807 poolItem = new PoolItem(this, mcf, mConn); 808 809 UserPoolItem userPoolItem; 810 811 userPoolItem = poolItem.toActive(subject, info, oldUserItem); 813 if (userPoolItem != null) 814 return userPoolItem; 815 816 throw new IllegalStateException (L.l("Connection '{0}' was not valid on creation", 817 poolItem)); 818 } finally { 819 synchronized (_pool) { 820 _createCount--; 821 822 if (poolItem != null) 823 _pool.add(poolItem); 824 825 _pool.notify(); 826 } 827 } 828 } 829 830 833 public void handleAlarm(Alarm alarm) 834 { 835 if (! _lifecycle.isActive()) 836 return; 837 838 try { 839 long now = Alarm.getCurrentTime(); 840 841 _alarmConnections.clear(); 842 843 synchronized (_pool) { 844 _alarmConnections.addAll(_pool); 845 } 846 847 for (int i = _alarmConnections.size() - 1; i >= 0; i--) { 848 PoolItem item = _alarmConnections.get(i); 849 850 if (! item.isValid()) 851 toDead(item); 852 } 853 854 _alarmConnections.clear(); 855 } finally { 856 if (! _lifecycle.isActive()) { 857 } 858 else if (0 < _maxIdleTime && _maxIdleTime < 1000) 859 _alarm.queue(1000); 860 else if (1000 < _maxIdleTime && _maxIdleTime < 60000) 861 _alarm.queue(_maxIdleTime); 862 else 863 _alarm.queue(60000); 864 } 865 } 866 867 870 void toDead(PoolItem item) 871 { 872 synchronized (_idlePool) { 873 _idlePool.remove(item.getManagedConnection()); 874 } 875 876 synchronized (_pool) { 877 _pool.remove(item); 878 } 879 880 try { 881 item.destroy(); 882 } catch (Throwable e) { 883 log.log(Level.WARNING, e.toString(), e); 884 } 885 } 886 887 890 public void stop() 891 { 892 if (! _lifecycle.toStop()) 893 return; 894 895 if (_alarm != null) 896 _alarm.dequeue(); 897 } 898 899 902 public void destroy() 903 { 904 stop(); 905 906 if (! _lifecycle.toDestroy()) 907 return; 908 909 ArrayList <PoolItem> pool = _pool; 910 911 synchronized (pool) { 912 for (int i = 0; i < pool.size(); i++) { 913 PoolItem poolItem = pool.get(i); 914 915 try { 916 poolItem.destroy(); 917 } catch (Throwable e) { 918 log.log(Level.WARNING, e.toString(), e); 919 } 920 } 921 922 pool.clear(); 923 } 924 } 925 926 public String toString() 927 { 928 return "ConnectionPool[" + getName() + "]"; 929 } 930 } 931 | Popular Tags |