1 27 package com.lutris.appserver.server.sql.datasource; 28 29 import java.lang.reflect.Constructor ; 30 import java.sql.SQLException ; 31 import java.util.Date ; 32 import java.util.LinkedList ; 33 import java.util.NoSuchElementException ; 34 35 import javax.sql.DataSource ; 36 import javax.naming.Context ; 37 import javax.naming.InitialContext ; 38 import javax.naming.NamingException ; 39 40 41 import org.enhydra.dods.CommonConstants; 42 import org.enhydra.dods.DODS; 43 44 import com.lutris.appserver.server.sql.ConnectionAllocator; 45 import com.lutris.appserver.server.sql.DBConnection; 46 import com.lutris.appserver.server.sql.DataSourceDBConnectionFactory; 47 import com.lutris.appserver.server.sql.ExtendedConnectionAllocator; 48 import com.lutris.appserver.server.sql.ExtendedDBConnection; 49 import com.lutris.appserver.server.sql.LogicalDatabase; 50 51 import com.lutris.logging.Logger; 52 import com.lutris.util.Config; 53 import com.lutris.util.ConfigException; 54 import com.lutris.util.KeywordValueException; 55 56 105 public class DataSourceConnectionAllocator implements 106 ExtendedConnectionAllocator { 107 108 111 protected LogicalDatabase logicalDatabase = null; 112 113 116 protected DataSource dataSource; 117 118 121 protected String shutDownStr; 122 123 126 protected String url; 127 128 131 protected String user; 132 133 136 protected String password; 137 138 142 private int maxPoolSize; 143 144 147 private int currentPoolSize; 148 149 152 private int biggestPoolSize; 153 154 157 private Date biggestPoolDate; 158 159 162 protected long numRequests; 163 164 167 private ConnectionPool allocatePool; 168 169 173 private long connectionIdileTimeout = -1; 174 175 178 private ConnectionPool releasePool; 179 180 private int requestCounter = 0; 181 182 private int waitCounter = 0; 183 184 private CountMonitor waitConnectionMonitor; 185 186 private Object allocateMonitor; 187 188 private Object releaseMonitor; 189 190 193 protected int maxWaitingConnections; 194 195 protected int initWaitingConnections; 196 197 202 private int maxConnectionUsages = -1; 203 204 208 protected boolean sqlLogging; 209 210 213 protected boolean disableConnectionPool = false; 214 215 218 private int timeOut; 219 220 224 protected int queryTimeOut; 225 226 230 protected int transactionTimeOut; 231 232 236 protected int maxPreparedStatements; 237 238 242 protected int generation = 1; 243 244 245 249 class ConnectionPool { 250 251 int dropCount = 0; 252 253 LinkedList pool; 254 255 258 public ConnectionPool() { 259 pool = new LinkedList (); 260 261 } 262 263 } 264 265 266 270 class CountMonitor { 271 272 int waitCounter = 0; 273 274 int notifyCounter = 0; 275 276 int maxPoolSize = 0; 277 278 public CountMonitor(int pSize) { 279 maxPoolSize = pSize; 280 } 281 282 public synchronized void countNotify(int maxNotify) { 283 if ((maxPoolSize == 0) && (waitCounter <= 0)) { 284 if (notifyCounter < maxNotify) { 285 notifyCounter++; 286 } else { 287 notifyCounter = maxNotify; 288 } 289 } else if ((notifyCounter < maxPoolSize) && (waitCounter <= 0)) { 290 if (notifyCounter < maxNotify) { 291 notifyCounter++; 292 } else { 293 notifyCounter = maxNotify; 294 } 295 } 296 this.notify(); 297 } 298 299 public synchronized void countWait() throws InterruptedException { 300 if (notifyCounter > 0) { 301 notifyCounter--; 302 if ((waitCounter > 0) && (notifyCounter > 0)) { 303 int countX = waitCounter; 304 if (waitCounter > notifyCounter) { 305 countX = notifyCounter; 306 } 307 for (int i = 0; i < countX; i++) { 308 this.notify(); 309 } 310 } 311 } else { 312 waitCounter++; 313 try { 314 this.wait(); 315 } finally { 316 waitCounter--; 317 if ((waitCounter > 0) && (notifyCounter > 0)) { 318 int countX = waitCounter; 319 if (waitCounter > notifyCounter) { 320 countX = notifyCounter; 321 } 322 for (int i = 0; i < countX; i++) { 323 this.notify(); 324 notifyCounter--; 325 } 326 } 327 328 } 329 } 330 } 331 332 public synchronized long countWait(long timeout) 333 throws InterruptedException { 334 long ret = timeout; 335 if (notifyCounter > 0) { 336 notifyCounter--; 337 if ((waitCounter > 0) && (notifyCounter > 0)) { 338 int countX = waitCounter; 339 if (waitCounter > notifyCounter) { 340 countX = notifyCounter; 341 } 342 for (int i = 0; i < countX; i++) { 343 this.notify(); 344 notifyCounter--; 345 } 346 } 347 return ret; 348 } else { 349 ret = System.currentTimeMillis(); 350 waitCounter++; 351 try { 352 this.wait(timeout); 353 } catch (Exception e) { 354 e.printStackTrace(); 355 } finally { 356 waitCounter--; 357 ret = timeout - (System.currentTimeMillis() - ret); 358 if (ret < 0) { 359 ret = 0; 360 } 361 if ((notifyCounter > 0) && (ret > 0)) { 362 notifyCounter--; 363 } 364 if ((waitCounter > 0) && (notifyCounter > 0)) { 365 int countX = waitCounter; 366 if (waitCounter > notifyCounter) { 367 countX = notifyCounter; 368 } 369 for (int i = 0; i < countX; i++) { 370 this.notify(); 371 notifyCounter--; 372 } 373 } 374 } 376 return ret; } 378 } 379 } 380 381 384 private DataSourceDBConnectionFactory dbConnectionFactory = null; 385 386 387 390 private String dbConnectionFactoryName = null; 391 392 400 private DataSourceDBConnectionFactory createDBConnectionFactory( 401 String factoryName) { 402 Class connectionFactoryClass = null; 403 Constructor connectionFactoryConstructor = null; 404 Class [] methodTypes = {}; 405 Object [] methodArgs = {}; 406 DataSourceDBConnectionFactory factory = null; 407 if (factoryName != null) { 408 try { 409 connectionFactoryClass = Class.forName(factoryName); 410 factory = (DataSourceDBConnectionFactory) connectionFactoryClass 411 .newInstance(); 412 } catch (Exception e) { 413 DODS 414 .getLogChannel() 415 .write( 416 Logger.INFO, 417 "Faild to make Connection Factory :" 418 + factoryName 419 + " creating DataSourceDBConnectionFactory insted"); 420 factory = null; 421 } 422 } 423 if (factoryName == null || factory == null) { 424 factory = new DataSourceDBConnectionFactory(); 425 } 426 return factory; 427 } 428 429 435 protected DBConnection createConnection() throws java.sql.SQLException { 436 DBConnection dbConnection; 437 if (dataSource != null) 438 dbConnection = dbConnectionFactory.createConnection( 439 (ConnectionAllocator) this, dataSource, 440 maxPreparedStatements, sqlLogging, generation); 441 else 442 dbConnection = dbConnectionFactory.createConnection( 443 (ConnectionAllocator) this, url, user, password, 444 maxPreparedStatements, sqlLogging, generation); 445 return dbConnection; 446 } 447 448 458 public DataSourceConnectionAllocator(LogicalDatabase logicalDatabase, Config conConfig) throws ConfigException { 459 this.logicalDatabase = logicalDatabase; 460 try { 461 String stringValue = ""; 462 try { 463 if (conConfig.getDataSource("DataSourceName") != null) { 464 465 if (conConfig.getDataSource("DataSourceName") instanceof DataSource ) 466 dataSource = (DataSource ) conConfig.getDataSource("DataSourceName"); 467 else if (conConfig.getDataSource("DataSourceName") instanceof String ) { 468 String jndiName = (String ) conConfig.getDataSource("DataSourceName"); 469 if (jndiName.startsWith("jndi:")) { 470 stringValue = jndiName.substring(5); 471 } else 472 stringValue = jndiName; 473 474 InitialContext context = null; 475 Context envCtx = null; 476 477 try { 478 context = new InitialContext (); 479 envCtx = (Context ) context.lookup("java:comp/env"); 480 481 } catch (NamingException ex) { 482 envCtx = null; 483 } 484 try { 485 dataSource = (DataSource ) envCtx.lookup(stringValue); 486 } catch (Exception ex) { 487 dataSource = null; 488 } 489 if (dataSource == null) { 490 try { 491 dataSource = (DataSource ) context.lookup(stringValue); 492 } catch (Exception ex) { 493 dataSource = null; 494 } 495 } 496 } else 497 dataSource = null; 498 } 499 } catch (Exception ex) { 500 dataSource = null; 501 } 502 if (dataSource == null) { 503 url = conConfig.getString("Url"); 504 user = conConfig.getString("User"); 505 password = conConfig.getString("Password"); 506 } 507 timeOut = conConfig.getInt("AllocationTimeout", 1000); 508 maxPoolSize = conConfig.getInt("MaxPoolSize", 0); 509 sqlLogging = conConfig.getBoolean("Logging", false); 510 disableConnectionPool = conConfig.getBoolean("DisableConnectionPool", false); 511 shutDownStr = conConfig.getString("ShutDownString", null); 512 queryTimeOut = conConfig.getInt("QueryTimeout", 0); 513 transactionTimeOut = conConfig.getInt("TransactionTimeout", 0); 514 maxPreparedStatements = conConfig.getInt("MaxPreparedStatements", -1); 515 maxConnectionUsages = conConfig.getInt("MaxConnectionUsages", -1); 516 maxWaitingConnections = conConfig.getInt("MaxWaitingConnections", Integer.MAX_VALUE); 517 initWaitingConnections = conConfig.getInt("InitConnectionsPoolSize", -1); 518 connectionIdileTimeout = conConfig.getLong("ConnectionIdleTimeout", -1); 519 520 dbConnectionFactoryName = conConfig.getString(CommonConstants.CONNECTION_FACTORY, null); 521 dbConnectionFactory = createDBConnectionFactory(dbConnectionFactoryName); 522 523 } catch (KeywordValueException except) { 524 throw new ConfigException("Bad DatabaseManager.DB." + logicalDatabase.getName() 525 + ".Connection section defined in config file."); 526 } 527 currentPoolSize = 0; 528 529 allocatePool = new ConnectionPool(); 530 releasePool = new ConnectionPool(); 531 532 waitConnectionMonitor = new CountMonitor(maxPoolSize); 533 allocateMonitor = new Object (); 534 releaseMonitor = new Object (); 535 536 biggestPoolSize = 0; 538 biggestPoolDate = new Date (); 539 numRequests = 0; 540 try { 541 initConnectionPool(initWaitingConnections); 542 } catch (SQLException e) { 543 } 544 } 545 546 553 private void initConnectionPool(int initWaitingConnections) 554 throws SQLException { 555 if (initWaitingConnections > maxPoolSize) { 556 initWaitingConnections = maxPoolSize; 557 } 558 if (initWaitingConnections > 0) { 559 DBConnection newConnection; 560 for (int i = 1; i <= initWaitingConnections; i++) { 561 newConnection = createConnection(); 562 if (!newConnection.getConnection().isClosed()) { 563 if (maxConnectionUsages > 0) { 564 ((ExtendedDBConnection) newConnection) 565 .setConnectionUsageCounter(maxConnectionUsages); 566 } else { 567 ((ExtendedDBConnection) newConnection) 568 .setConnectionUsageCounter(Integer.MAX_VALUE); 569 } 570 allocatePool.pool.addLast(newConnection); 571 currentPoolSize++; 572 waitConnectionMonitor.countNotify(initWaitingConnections); 573 if (currentPoolSize > biggestPoolSize) { 574 biggestPoolSize = currentPoolSize; 575 biggestPoolDate = new Date (); 576 } 577 } 578 } 579 } 580 } 581 582 583 587 public DBConnection allocate() throws SQLException { 588 boolean createNewConn = true; 589 boolean connected = false; 590 DBConnection conn = null; 591 long enterWaitTime = 0; 592 long timeToWait = -1; 593 boolean newConn = false; 594 if (timeOut > 0) 595 timeToWait = timeOut; 596 if (disableConnectionPool) { 597 try { 598 conn = createConnection(); 599 } catch (SQLException e) { 600 DODS.getLogChannel().write( 601 Logger.EMERGENCY, 602 "ConnectionAllocator: " 603 + "failed to allocate a new connection" 604 + "\n (connection pool is not used!) \n"); 605 throw e; 606 } 607 } else { 608 while (conn == null) { 609 connected = false; 610 newConn = false; 611 synchronized (allocateMonitor) { 612 if (allocatePool.pool.isEmpty()) { 613 switchPools(); 614 } 615 if (allocatePool.pool.isEmpty()) { 616 if (createNewConn 617 && ((currentPoolSize < maxPoolSize) || (maxPoolSize <= 0))) { 618 try { 619 620 conn = createConnection(); 621 if (maxConnectionUsages > 0) { 622 ((ExtendedDBConnection) conn) 623 .setConnectionUsageCounter(maxConnectionUsages); 624 } else { 625 ((ExtendedDBConnection) conn) 626 .setConnectionUsageCounter(Integer.MAX_VALUE); 627 } 628 currentPoolSize++; 629 newConn = true; 630 if (currentPoolSize > biggestPoolSize) { 631 biggestPoolSize = currentPoolSize; 632 biggestPoolDate = new Date (); 633 } 634 } catch (SQLException e) { 635 conn = null; 636 if (currentPoolSize > 0) { 637 DODS.getLogChannel().write( 638 Logger.INFO, 639 "ConnectionAllocator: " 640 + "failed to allocate a new connection due to" 641 + e.toString() 642 + "Error code: " 643 + e.getErrorCode() 644 + "\n" 645 + "SQLState: " 646 + e.getSQLState() 647 + "\n" 648 + "\nCurrent pool size is: " 649 + currentPoolSize 650 + "\nMaximum configured pool size is now " 651 + maxPoolSize 652 + "\nContinuing...\n"); 653 createNewConn = false; 654 } else { 655 DODS.getLogChannel().write( 656 Logger.EMERGENCY, 657 "ConnectionAllocator: " 658 + "failed to allocate a new connection" 659 + "\nThe connection pool is empty!\n" 660 + e.toString() 661 + "Error code: " 662 + e.getErrorCode() 663 + "\n" 664 + "SQLState: " 665 + e.getSQLState() 666 + "\n" 667 + "\nCurrent pool size is: " 668 + currentPoolSize 669 + "\nMaximum configured pool size is now " 670 + maxPoolSize 671 + "\nContinuing...\n"); 672 throw e; 673 } 674 } 675 } 676 } 677 try { 678 if (conn == null) { 679 conn = (ExtendedDBConnection) allocatePool.pool 680 .removeFirst(); 681 } 682 } catch (NoSuchElementException e) { 683 } 684 685 if (conn != null) { 686 connected = true; 687 if (maxConnectionUsages > 0) { 688 int connUsages = ((ExtendedDBConnection) conn) 689 .getConnectionUsageCounter(); 690 if (connUsages > 0) { 691 ((ExtendedDBConnection) conn) 692 .setConnectionUsageCounter(--connUsages); 693 } else { 694 conn.close(); 697 currentPoolSize--; 698 DODS.getLogChannel().write( 699 Logger.DEBUG, 700 "ConnectionAllocator: connection closed due to usage counter. currentPoolSize=" 701 + currentPoolSize + "\n"); 702 conn = null; 703 } 704 } 705 if (conn != null) { 706 if (((ExtendedDBConnection) conn).isDroped() 707 || conn.getConnection().isClosed() 708 || (conn.getGeneration() < generation) 709 || conn.isMarkedForDrop()) { 710 conn.close(); 711 currentPoolSize--; 712 DODS.getLogChannel().write( 713 Logger.DEBUG, 714 "ConnectionAllocator: Inactiv connection closed due allocate() operation. Geting new one. currentPoolSize=" 715 + currentPoolSize 716 + "\n"); 717 conn = null; 718 } 719 } 720 if ((conn != null) && (connectionIdileTimeout > 0)) { 721 if ((System.currentTimeMillis() - ((ExtendedDBConnection) conn) 722 .getConnectionEnterPoolTime()) > connectionIdileTimeout) { 723 conn.close(); 724 currentPoolSize--; 725 DODS.getLogChannel().write( 726 Logger.DEBUG, 727 "ConnectionAllocator: Connection closed due allocate() operation - long connection idile time. Geting new one. currentPoolSize=" 728 + currentPoolSize 729 + "\n"); 730 conn = null; 731 } 732 } 733 } 734 } 735 if (conn == null) { 736 try { 737 if (timeToWait == 0) { 738 DODS.getLogChannel().write( 739 Logger.EMERGENCY, 740 "ConnectionAllocator:" 741 + "allocation of a new connection timed out." 742 + "Possible dead lock avoided."); 743 String msg = "Connections are currently unavailable.\n" 744 + "Possible dead lock avoided."; 745 throw new SQLException (msg); 746 747 } else if (timeToWait > 0) { 748 timeToWait = waitConnectionMonitor 749 .countWait(timeToWait); 750 } else { 751 waitConnectionMonitor.countWait(); 752 } 753 754 } catch (InterruptedException intEx) { 755 } 756 } 757 } 758 } 759 conn.allocate(); 760 return conn; 761 } 762 763 766 private void switchPools() { 767 synchronized (releaseMonitor) { 768 if (releasePool.pool.size() > allocatePool.pool.size()) { 769 LinkedList tmp = allocatePool.pool; 770 allocatePool.pool = releasePool.pool; 771 releasePool.pool = tmp; 772 } 773 } 774 } 775 776 781 public void release(DBConnection dbConnection) { 782 if (dbConnection != null) { 783 if (disableConnectionPool) { 784 dbConnection.close(); 785 dbConnection = null; 786 } else { 787 int releaseSize = 0; 788 synchronized (releaseMonitor) { 789 if (connectionIdileTimeout > 0) { 790 ((ExtendedDBConnection) dbConnection) 791 .setConnectionEnterPoolTime(System 792 .currentTimeMillis()); 793 } 794 releasePool.pool.addLast(dbConnection); 795 releaseSize = releasePool.pool.size(); 796 } 797 waitConnectionMonitor.countNotify(releaseSize); 798 } 799 } 800 } 801 802 814 public void drop(DBConnection dbConnection) { 815 int releasedCounter = 1; 816 LinkedList newAllocatePool = new LinkedList (); 817 LinkedList newReleasePool = new LinkedList (); 818 LinkedList tmpPool; 819 synchronized (allocateMonitor) { 820 if (generation <= dbConnection.getGeneration()) { 821 generation++; } 823 synchronized (releaseMonitor) { 824 tmpPool = releasePool.pool; 825 releasePool.pool = newReleasePool; 826 } 827 try { 828 while (!tmpPool.isEmpty()) { 829 DBConnection connect = (DBConnection) tmpPool.removeFirst(); 830 if (connect.getGeneration() < generation) { 831 connect.close(); 832 releasedCounter++; 833 currentPoolSize--; 834 } else { 835 newAllocatePool.addLast(connect); 836 } 837 } 838 } catch (NoSuchElementException e) { 839 } 840 try { 841 while (!allocatePool.pool.isEmpty()) { 842 DBConnection connect = (DBConnection) allocatePool.pool 843 .removeFirst(); 844 if (connect.getGeneration() < generation) { 845 connect.close(); 846 releasedCounter++; 847 currentPoolSize--; 848 } else { 849 newAllocatePool.addLast(connect); 850 } 851 } 852 } catch (NoSuchElementException e) { 853 } 854 allocatePool.pool = newAllocatePool; 855 dbConnection.close(); 856 currentPoolSize--; 857 } 858 for (int i = 0; i < releasedCounter; i++) { 859 waitConnectionMonitor.countNotify(releasedCounter); 860 } 861 } 862 863 867 public void dropAllNow() { 868 if (shutDownStr != null) { 869 try { 870 DBConnection tmpConn = allocate(); 871 tmpConn.execute(shutDownStr); 872 tmpConn.release(); 873 } catch (SQLException e1) { 874 } 875 } 876 synchronized (releaseMonitor) { 877 synchronized (allocateMonitor) { 878 try { 879 while (!allocatePool.pool.isEmpty()) { 880 DBConnection connect = (DBConnection) allocatePool.pool 881 .removeFirst(); 882 connect.close(); 883 currentPoolSize--; 884 } 885 } catch (NoSuchElementException e) {} 886 } 887 try { 888 while (!releasePool.pool.isEmpty()) { 889 DBConnection connect = (DBConnection) releasePool.pool 890 .removeFirst(); 891 connect.close(); 892 currentPoolSize--; 893 } 894 } catch (NoSuchElementException e) { 895 } 896 } 897 } 898 899 904 public int getActiveCount() { 905 return currentPoolSize; 906 } 907 908 913 public int getMaxCount() { 914 return biggestPoolSize; 915 } 916 917 923 public Date getMaxCountDate() { 924 return biggestPoolDate; 925 } 926 927 930 public void resetMaxCount() { 931 biggestPoolSize = currentPoolSize; 932 biggestPoolDate = new Date (); 933 } 934 935 940 public long getRequestCount() { 941 return numRequests; 942 } 943 944 949 protected void finalize() { 950 dropAllNow(); 951 } 952 953 957 public String getDatabaseName() { 958 return logicalDatabase.getName(); 959 } 960 961 962 965 public void IncrementRequesteCount() { 966 numRequests++; 967 } 968 } | Popular Tags |