1 27 package com.lutris.appserver.server.sql.standard; 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 org.enhydra.dods.CommonConstants; 36 import org.enhydra.dods.DODS; 37 38 import com.lutris.appserver.server.sql.AbstractDBConnectionFactory; 39 import com.lutris.appserver.server.sql.ConnectionAllocator; 40 import com.lutris.appserver.server.sql.DBConnection; 41 import com.lutris.appserver.server.sql.ExtendedConnectionAllocator; 42 import com.lutris.appserver.server.sql.ExtendedDBConnection; 43 import com.lutris.appserver.server.sql.LogicalDatabase; 44 import com.lutris.appserver.server.sql.StandardDBConnectionFactory; 45 import com.lutris.logging.Logger; 46 import com.lutris.util.Config; 47 import com.lutris.util.ConfigException; 48 import com.lutris.util.KeywordValueException; 49 50 101 102 103 public class StandardConnectionAllocator implements ExtendedConnectionAllocator { 104 105 108 protected LogicalDatabase logicalDatabase = null; 109 110 113 protected String url; 114 115 118 protected String user; 119 120 123 protected String password; 124 125 128 protected String shutDownStr; 129 130 134 private int maxPoolSize; 135 136 139 private int currentPoolSize; 140 141 144 private int biggestPoolSize; 145 146 149 private Date biggestPoolDate; 150 151 154 protected long numRequests; 155 156 159 private ConnectionPool allocatePool; 160 161 165 private long connectionIdileTimeout = -1; 166 167 170 private ConnectionPool releasePool; 171 172 private int requestCounter = 0; 173 174 private int waitCounter = 0; 175 176 private CountMonitor waitConnectionMonitor; 177 178 private Object allocateMonitor; 179 180 private Object releaseMonitor; 181 182 185 protected int maxWaitingConnections; 186 187 protected int initWaitingConnections; 188 189 194 private int maxConnectionUsages = -1; 195 196 197 200 protected boolean sqlLogging; 201 202 205 private int timeOut; 206 207 211 protected int queryTimeOut; 212 213 217 protected int transactionTimeOut; 218 219 223 protected int maxPreparedStatements; 224 225 229 protected int generation = 1; 230 231 232 236 class ConnectionPool { 237 238 int dropCount = 0; 239 240 LinkedList pool; 241 242 245 public ConnectionPool() { 246 pool = new LinkedList (); 247 248 } 249 250 } 251 252 253 257 class CountMonitor { 258 259 int waitCounter = 0; 260 261 int notifyCounter = 0; 262 263 int maxPoolSize = 0; 264 265 public CountMonitor(int pSize) { 266 maxPoolSize = pSize; 267 } 268 269 public synchronized void countNotify(int maxNotify) { 270 if ((maxPoolSize == 0) && (waitCounter <= 0)) { 271 if (notifyCounter < maxNotify) { 272 notifyCounter++; 273 } else { 274 notifyCounter = maxNotify; 275 } 276 } else if ((notifyCounter < maxPoolSize) && (waitCounter <= 0)) { 277 if (notifyCounter < maxNotify) { 278 notifyCounter++; 279 } else { 280 notifyCounter = maxNotify; 281 } 282 } 283 this.notify(); 284 } 285 286 public synchronized void countWait() throws InterruptedException { 287 if (notifyCounter > 0) { 288 notifyCounter--; 289 if ((waitCounter > 0) && (notifyCounter > 0)) { 290 int countX = waitCounter; 291 if (waitCounter > notifyCounter) { 292 countX = notifyCounter; 293 } 294 for (int i = 0; i < countX; i++) { 295 this.notify(); 296 } 297 } 298 } else { 299 waitCounter++; 300 try { 301 this.wait(); 302 } finally { 303 waitCounter--; 304 if ((waitCounter > 0) && (notifyCounter > 0)) { 305 int countX = waitCounter; 306 if (waitCounter > notifyCounter) { 307 countX = notifyCounter; 308 } 309 for (int i = 0; i < countX; i++) { 310 this.notify(); 311 notifyCounter--; 312 } 313 } 314 315 } 316 } 317 } 318 319 public synchronized long countWait(long timeout) throws InterruptedException { 320 long ret = timeout; 321 if (notifyCounter > 0) { 322 notifyCounter--; 323 if ((waitCounter > 0) && (notifyCounter > 0)) { 324 int countX = waitCounter; 325 if (waitCounter > notifyCounter) { 326 countX = notifyCounter; 327 } 328 for (int i = 0; i < countX; i++) { 329 this.notify(); 330 notifyCounter--; 331 } 332 } 333 return ret; 334 } else { 335 ret = System.currentTimeMillis(); 336 waitCounter++; 337 try { 338 this.wait(timeout); 339 }catch (Exception e) { 340 e.printStackTrace(); 341 } finally { 342 waitCounter--; 343 ret = timeout - (System.currentTimeMillis() - ret); 344 if (ret < 0) { 345 ret = 0; 346 } 347 if ((notifyCounter > 0) && (ret > 0)) { 348 notifyCounter--; 349 } 350 if ((waitCounter > 0) && (notifyCounter > 0)) { 351 int countX = waitCounter; 352 if (waitCounter > notifyCounter) { 353 countX = notifyCounter; 354 } 355 for (int i = 0; i < countX; i++) { 356 this.notify(); 357 notifyCounter--; 358 } 359 } 360 } 362 return ret; } 364 } 365 } 366 367 370 private AbstractDBConnectionFactory dbConnectionFactory = null; 371 372 373 376 private String dbConnectionFactoryName = null; 377 378 379 380 385 private AbstractDBConnectionFactory createDBConnectionFactory(String factoryName) { 386 Class connectionFactoryClass = null; 387 Constructor connectionFactoryConstructor = null; 388 Class [] methodTypes = {}; 389 Object [] methodArgs = {}; 390 AbstractDBConnectionFactory factory = null; 391 if (factoryName != null) { 392 try { 393 connectionFactoryClass = Class.forName(factoryName); 394 factory = (AbstractDBConnectionFactory) connectionFactoryClass.newInstance(); 395 } catch (Exception e) { 396 DODS.getLogChannel().write( 397 Logger.INFO, 398 "Faild to make Connection Factory :" 399 + factoryName 400 + " creating StandardDBConnectionFactory insted"); 401 factory = null; 402 } 403 } 404 if (factoryName == null || factory == null) { 405 factory = new StandardDBConnectionFactory(); 406 } 407 return factory; 408 } 409 410 416 protected DBConnection createConnection() throws java.sql.SQLException { 417 DBConnection dbConnection = dbConnectionFactory.createConnection( 418 (ConnectionAllocator) this, url, user, password, 419 maxPreparedStatements, sqlLogging, generation); 420 return dbConnection; 421 } 422 423 424 425 431 public StandardConnectionAllocator(LogicalDatabase logicalDatabase, 432 Config conConfig) throws ConfigException { 433 this.logicalDatabase = logicalDatabase; 434 try { 435 url = conConfig.getString("Url"); 436 user = conConfig.getString("User"); 437 password = conConfig.getString("Password"); 438 timeOut = conConfig.getInt("AllocationTimeout", 1000); 439 maxPoolSize = conConfig.getInt("MaxPoolSize", 0); 440 sqlLogging = conConfig.getBoolean("Logging", false); 441 queryTimeOut = conConfig.getInt("QueryTimeout", 0); 442 shutDownStr = conConfig.getString("ShutDownString",null); 443 transactionTimeOut = conConfig.getInt ("TransactionTimeout", 0); 444 maxPreparedStatements = conConfig.getInt ("MaxPreparedStatements", -1); 445 maxConnectionUsages = conConfig.getInt ("MaxConnectionUsages", -1); 446 maxWaitingConnections = conConfig.getInt ("MaxWaitingConnections", Integer.MAX_VALUE); 447 initWaitingConnections = conConfig.getInt ("InitConnectionsPoolSize", -1); 448 connectionIdileTimeout = conConfig.getLong("ConnectionIdleTimeout", -1); 449 450 451 dbConnectionFactoryName = conConfig.getString(CommonConstants.CONNECTION_FACTORY,null); 452 dbConnectionFactory = createDBConnectionFactory(dbConnectionFactoryName); 453 454 } catch (KeywordValueException except) { 455 throw new ConfigException("Bad DatabaseManager.DB." 456 + logicalDatabase.getName() 457 + ".Connection section defined in config file."); 458 } 459 currentPoolSize = 0; 460 461 allocatePool = new ConnectionPool(); 462 releasePool = new ConnectionPool(); 463 464 waitConnectionMonitor = new CountMonitor(maxPoolSize); 465 allocateMonitor = new Object (); 466 releaseMonitor = new Object (); 467 468 biggestPoolSize = 0; 469 biggestPoolDate = new Date (); 470 numRequests = 0; 471 472 try { 473 initConnectionPool(initWaitingConnections); 474 } catch (SQLException e) { 475 } 476 } 477 478 482 private void initConnectionPool(int initWaitingConnections) 483 throws SQLException { 484 if (initWaitingConnections > maxPoolSize) { 485 initWaitingConnections = maxPoolSize; 486 } 487 if (initWaitingConnections > 0) { 488 DBConnection newConnection; 489 for (int i = 1; i <= initWaitingConnections; i++) { 490 newConnection = createConnection(); 491 if (!newConnection.getConnection().isClosed()) { 492 if (maxConnectionUsages > 0) { 493 ((ExtendedDBConnection) newConnection) 494 .setConnectionUsageCounter(maxConnectionUsages); 495 } else { 496 ((ExtendedDBConnection) newConnection) 497 .setConnectionUsageCounter(Integer.MAX_VALUE); 498 } 499 allocatePool.pool.addLast(newConnection); 500 currentPoolSize++; 501 waitConnectionMonitor.countNotify(initWaitingConnections); 502 if (currentPoolSize > biggestPoolSize) { 503 biggestPoolSize = currentPoolSize; 504 biggestPoolDate = new Date (); 505 } 506 } 507 } 508 } 509 } 510 511 512 516 public DBConnection allocate() throws SQLException { 517 boolean createNewConn = true; 518 boolean connected = false; 519 DBConnection conn = null; 520 long enterWaitTime = 0; 521 long timeToWait = -1; 522 boolean newConn = false; 523 if (timeOut > 0) { 524 timeToWait = timeOut; 525 } 526 while (conn == null) { 527 connected = false; 528 newConn = false; 529 synchronized (allocateMonitor) { 530 if (allocatePool.pool.isEmpty()) { 531 switchPools(); 532 } 533 if (allocatePool.pool.isEmpty()) { 534 if (createNewConn && ((currentPoolSize < maxPoolSize) || (maxPoolSize <= 0))) { 535 try { 536 conn = createConnection(); 537 if (maxConnectionUsages > 0) { 538 ((ExtendedDBConnection) conn) 539 .setConnectionUsageCounter(maxConnectionUsages); 540 } else { 541 ((ExtendedDBConnection) conn) 542 .setConnectionUsageCounter(Integer.MAX_VALUE); 543 } 544 currentPoolSize++; 545 newConn = true; 546 if (currentPoolSize > biggestPoolSize) { 547 biggestPoolSize = currentPoolSize; 548 biggestPoolDate = new Date (); 549 } 550 } catch (SQLException e) { 551 conn = null; 552 if (currentPoolSize > 0) { 553 DODS.getLogChannel().write( 554 Logger.INFO, 555 "ConnectionAllocator: " 556 + "failed to allocate a new connection due to" 557 + e.toString() 558 + "Error code: " 559 + e.getErrorCode() 560 + "\n" 561 + "SQLState: " 562 + e.getSQLState() 563 + "\n" 564 + "\nCurrent pool size is: " 565 + currentPoolSize 566 + "\nMaximum configured pool size is now " 567 + maxPoolSize 568 + "\nContinuing...\n"); 569 createNewConn = false; 570 } else { 571 DODS.getLogChannel().write( 572 Logger.EMERGENCY, 573 "ConnectionAllocator: " 574 + "failed to allocate a new connection" 575 + "\nThe connection pool is empty!\n" 576 + e.toString() 577 + "Error code: " 578 + e.getErrorCode() 579 + "\n" 580 + "SQLState: " 581 + e.getSQLState() 582 + "\n" 583 + "\nCurrent pool size is: " 584 + currentPoolSize 585 + "\nMaximum configured pool size is now " 586 + maxPoolSize 587 + "\nContinuing...\n"); 588 throw e; 589 } 590 } 591 } 592 } 593 try { 594 if (conn == null) { 595 conn = (ExtendedDBConnection) allocatePool.pool.removeFirst(); 596 } 597 } catch (NoSuchElementException e) { 598 } 599 600 if (conn != null) { 601 connected = true; 602 if (maxConnectionUsages > 0) { 603 int connUsages = ((ExtendedDBConnection)conn).getConnectionUsageCounter(); 604 if (connUsages > 0) { 605 ((ExtendedDBConnection) conn) 606 .setConnectionUsageCounter(--connUsages); 607 } else { 608 conn.close(); 610 currentPoolSize--; 611 DODS.getLogChannel().write( 612 Logger.DEBUG, 613 "ConnectionAllocator: connection closed due to usage counter. currentPoolSize=" 614 + currentPoolSize + "\n"); 615 conn = null; 616 } 617 } 618 if (conn != null) { 619 if (((ExtendedDBConnection) conn).isDroped() 620 || conn.getConnection().isClosed() 621 || (conn.getGeneration() < generation) 622 || conn.isMarkedForDrop()) { 623 conn.close(); 624 currentPoolSize--; 625 DODS.getLogChannel().write( 626 Logger.DEBUG, 627 "ConnectionAllocator: Inactiv connection closed due allocate() operation. Geting new one. currentPoolSize=" 628 + currentPoolSize + "\n"); 629 conn = null; 630 } 631 } 632 if ((conn != null) && (connectionIdileTimeout > 0)) { 633 if ((System.currentTimeMillis() - ((ExtendedDBConnection) conn) 634 .getConnectionEnterPoolTime()) > connectionIdileTimeout) { 635 conn.close(); 636 currentPoolSize--; 637 DODS.getLogChannel().write( 638 Logger.DEBUG, 639 "ConnectionAllocator: Connection closed due allocate() operation - long connection idile time. Geting new one. currentPoolSize=" 640 + currentPoolSize + "\n"); 641 conn = null; 642 } 643 } 644 } 645 } 646 if (conn == null) { 647 try { 648 if (timeToWait == 0) { 649 DODS.getLogChannel().write( 650 Logger.EMERGENCY, 651 "ConnectionAllocator:" 652 + "allocation of a new connection timed out." 653 + "Possible dead lock avoided."); 654 String msg = "Connections are currently unavailable.\n" 655 + "Possible dead lock avoided."; 656 throw new SQLException (msg); 657 658 } else if (timeToWait > 0) { 659 timeToWait = waitConnectionMonitor.countWait(timeToWait); 660 } else { 661 waitConnectionMonitor.countWait(); 662 } 663 664 } catch (InterruptedException intEx) { 665 } 666 } 667 } 668 conn.allocate(); 669 return conn; 670 } 671 672 675 private void switchPools() { 676 synchronized (releaseMonitor) { 677 if (releasePool.pool.size() > allocatePool.pool.size()) { 678 LinkedList tmp = allocatePool.pool; 679 allocatePool.pool = releasePool.pool; 680 releasePool.pool = tmp; 681 } 682 } 683 } 684 685 690 public void release(DBConnection dbConnection) { 691 if (dbConnection != null) { 692 int releaseSize = 0; 693 synchronized (releaseMonitor) { 694 if (connectionIdileTimeout > 0) { 695 ((ExtendedDBConnection) dbConnection).setConnectionEnterPoolTime(System.currentTimeMillis()); 696 } 697 releasePool.pool.addLast(dbConnection); 698 releaseSize = releasePool.pool.size(); 699 } 700 waitConnectionMonitor.countNotify(releaseSize); 701 } 702 703 } 704 705 720 public void drop(DBConnection dbConnection) { 721 int releasedCounter = 1; 722 LinkedList newAllocatePool = new LinkedList (); 723 LinkedList newReleasePool = new LinkedList (); 724 LinkedList tmpPool; 725 synchronized (allocateMonitor) { 726 if (generation <= dbConnection.getGeneration()) { 727 generation++; } 729 synchronized (releaseMonitor) { 730 tmpPool = releasePool.pool; 731 releasePool.pool = newReleasePool; 732 } 733 try { 734 while (!tmpPool.isEmpty()) { 735 DBConnection connect = (DBConnection) tmpPool.removeFirst(); 736 if (connect.getGeneration() < generation) { 737 connect.close(); 738 releasedCounter++; 739 currentPoolSize--; 740 } else { 741 newAllocatePool.addLast(connect); 742 } 743 } 744 } catch (NoSuchElementException e) { 745 } 746 try { 747 while (!allocatePool.pool.isEmpty()) { 748 DBConnection connect = (DBConnection) allocatePool.pool 749 .removeFirst(); 750 if (connect.getGeneration() < generation) { 751 connect.close(); 752 releasedCounter++; 753 currentPoolSize--; 754 } else { 755 newAllocatePool.addLast(connect); 756 } 757 } 758 } catch (NoSuchElementException e) { 759 } 760 allocatePool.pool = newAllocatePool; 761 dbConnection.close(); 762 currentPoolSize--; 763 } 764 for (int i = 0; i < releasedCounter; i++) { 765 waitConnectionMonitor.countNotify(releasedCounter); 766 } 767 } 768 769 773 public void dropAllNow() { 774 if (shutDownStr!=null) { 775 try { 776 DBConnection tmpConn = allocate(); 777 tmpConn.execute(shutDownStr); 778 tmpConn.release(); 779 } catch (SQLException e1) {} 780 } 781 synchronized (releaseMonitor) { 782 synchronized (allocateMonitor) { 783 try { 784 while (!allocatePool.pool.isEmpty()) { 785 DBConnection connect = (DBConnection) allocatePool.pool.removeFirst(); 786 connect.close(); 787 currentPoolSize--; 788 } 789 } catch (NoSuchElementException e) {} 790 } 791 try { 792 while (!releasePool.pool.isEmpty()) { 793 DBConnection connect = (DBConnection) releasePool.pool.removeFirst(); 794 connect.close(); 795 currentPoolSize--; 796 } 797 } catch (NoSuchElementException e) {} 798 } 799 } 800 801 806 public int getActiveCount() { 807 return currentPoolSize; 808 } 809 810 815 public int getMaxCount() { 816 return biggestPoolSize; 817 } 818 819 825 public Date getMaxCountDate() { 826 return biggestPoolDate; 827 } 828 829 832 public void resetMaxCount() { 833 biggestPoolSize = currentPoolSize; 834 biggestPoolDate = new Date (); 835 } 836 837 842 public long getRequestCount() { 843 return numRequests; 844 } 845 846 851 protected void finalize() { 852 dropAllNow(); 853 } 854 855 859 public String getDatabaseName() { 860 return logicalDatabase.getName(); 861 } 862 863 864 867 public void IncrementRequesteCount() { 868 numRequests++; 869 } 870 } | Popular Tags |