1 2 12 package com.versant.core.jdbc.conn; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.jdo.PoolStatus; 16 import com.versant.core.metric.BaseMetric; 17 import com.versant.core.metric.Metric; 18 import com.versant.core.metric.PercentageMetric; 19 import com.versant.core.logging.LogEventStore; 20 import com.versant.core.jdbc.JdbcConfig; 21 import com.versant.core.jdbc.logging.JdbcConnectionEvent; 22 import com.versant.core.jdbc.logging.JdbcLogEvent; 23 import com.versant.core.jdbc.logging.JdbcPoolEvent; 24 import com.versant.core.jdbc.JdbcConnectionSource; 25 import com.versant.core.jdbc.sql.SqlDriver; 26 import com.versant.core.util.BeanUtils; 27 28 import java.sql.*; 29 import java.util.*; 30 31 import com.versant.core.common.BindingSupportImpl; 32 import com.versant.core.metric.HasMetrics; 33 34 39 public final class JDBCConnectionPool 40 implements Runnable , JdbcConnectionSource, HasMetrics { 41 42 private final Driver jdbcDriver; 43 private final SqlDriver sqlDriver; 44 private final Properties props; 45 private final String url; 46 private final LogEventStore pes; 47 private boolean clearBatch; 48 private final boolean waitForConOnStartup; 49 private boolean jdbcDisablePsCache; 50 private int psCacheMax; 51 private int maxActive; 52 private int maxIdle; 53 private int minIdle; 54 private int reserved; 55 private final boolean testOnAlloc; 56 private final boolean testOnReturn; 57 private final boolean testOnException; 58 private boolean testWhenIdle; 59 private String initSQL; 60 private boolean commitAfterInitSQL; 61 private String validateSQL; 62 private final int retryIntervalMs; 63 private final int retryCount; 64 private boolean closed; 65 private int conTimeout; 66 private int testInterval; 67 private boolean blockWhenFull; 68 private int maxConAge; 69 private int isolationLevel; 70 71 private PooledConnection idleHead; private PooledConnection idleTail; private PooledConnection idleHeadAC; private PooledConnection idleTailAC; private int idleCount; 76 77 private PooledConnection activeHead; private PooledConnection activeTail; private int activeCount; 80 81 private Thread cleanupThread; 82 private long timeLastTest = System.currentTimeMillis(); 83 84 private Properties userProps; 85 86 private BaseMetric metricActive; 87 private BaseMetric metricIdle; 88 private BaseMetric metricMaxActive; 89 private BaseMetric metricCreated; 90 private BaseMetric metricClosed; 91 private BaseMetric metricAllocated; 92 private BaseMetric metricValidated; 93 private BaseMetric metricBad; 94 private BaseMetric metricTimedOut; 95 private BaseMetric metricExpired; 96 private BaseMetric metricWait; 97 private BaseMetric metricFull; 98 99 private int createdCount; 100 private int closedCount; 101 private int allocatedCount; 102 private int validatedCount; 103 private int badCount; 104 private int timedOutCount; 105 private int waitCount; 106 private int fullCount; 107 private int expiredCount; 108 109 private static final String CAT_POOL = "Con Pool"; 110 111 118 public JDBCConnectionPool(JdbcConfig jdbcConfig, LogEventStore pes, 119 Driver jdbcDriver, SqlDriver sqlDriver) { 120 this.pes = pes; 121 this.jdbcDriver = jdbcDriver; 122 this.sqlDriver = sqlDriver; 123 124 url = jdbcConfig.url; 125 props = new Properties(); 126 if (jdbcConfig.user != null) { 127 props.put("user", 128 jdbcConfig.user); 129 } 130 if (jdbcConfig.password != null) { 131 props.put("password", 132 jdbcConfig.password); 133 } 134 if (jdbcConfig.properties != null) { 135 BeanUtils.parseProperties(jdbcConfig.properties, props); 136 } 137 138 userProps = new Properties(); 140 if (jdbcConfig.user != null) { 141 userProps.put("user", jdbcConfig.user); 142 } 143 userProps.put("url", url); 144 userProps.put("driver", jdbcDriver.getClass().getName()); 145 if (jdbcConfig.properties != null) { 146 BeanUtils.parseProperties(jdbcConfig.properties, userProps); 147 } 148 149 jdbcDisablePsCache = jdbcConfig.jdbcDisablePsCache; 150 psCacheMax = jdbcConfig.psCacheMax; 151 waitForConOnStartup = jdbcConfig.waitForConOnStartup; 152 maxActive = jdbcConfig.maxActive; 153 maxIdle = jdbcConfig.maxIdle; 154 minIdle = jdbcConfig.minIdle; 155 reserved = jdbcConfig.reserved; 156 testOnAlloc = jdbcConfig.testOnAlloc; 157 testOnReturn = jdbcConfig.testOnRelease; 158 testOnException = jdbcConfig.testOnException; 159 testWhenIdle = jdbcConfig.testWhenIdle; 160 retryIntervalMs = jdbcConfig.retryIntervalMs > 0 161 ? jdbcConfig.retryIntervalMs 162 : 100; 163 retryCount = jdbcConfig.retryCount; 164 conTimeout = jdbcConfig.conTimeout; 165 testInterval = jdbcConfig.testInterval; 166 blockWhenFull = jdbcConfig.blockWhenFull; 167 maxConAge = jdbcConfig.maxConAge; 168 isolationLevel = jdbcConfig.isolationLevel; 169 170 setValidateSQL(trimToNull(jdbcConfig.validateSQL)); 171 setInitSQL(trimToNull(jdbcConfig.initSQL)); 172 173 if (sqlDriver != null) { 174 if (psCacheMax == 0) { 175 psCacheMax = sqlDriver.getDefaultPsCacheMax(); 176 } 177 clearBatch = sqlDriver.isClearBatchRequired(); 178 if (validateSQL == null) { 179 setValidateSQL(sqlDriver.getConnectionValidateSQL()); 180 } 181 if (initSQL == null) { 182 setInitSQL(sqlDriver.getConnectionInitSQL()); 183 } 184 if (!sqlDriver.isSetTransactionIsolationLevelSupported()) { 185 isolationLevel = 0; 186 } 187 } 188 189 if (maxIdle > maxActive) maxIdle = maxActive; 191 if (minIdle > maxIdle) minIdle = maxIdle; 192 } 193 194 private String trimToNull(String s) { 195 if (s == null) { 196 return null; 197 } 198 s = s.trim(); 199 if (s.length() == 0) { 200 return null; 201 } 202 return s; 203 } 204 205 public void init() { 206 if (cleanupThread != null) return; 207 cleanupThread = new Thread (this, "VOA Pool " + url); 208 cleanupThread.setDaemon(true); 209 cleanupThread.setPriority(Thread.MIN_PRIORITY); 210 cleanupThread.start(); 211 } 212 213 217 public void check() throws Exception { 218 PooledConnection con = null; 219 try { 220 if (waitForConOnStartup) { 221 con = createPooledConnection(0, 10000); 222 } else { 223 con = createPooledConnection(-1, 10000); 224 } 225 if (!validateConnection(con)) { 226 throw BindingSupportImpl.getInstance().runtime("First connection failed validation SQL:\n" + 227 validateSQL); 228 } 229 } finally { 230 if (con != null) destroy(con); 231 } 232 } 233 234 239 private Connection createRealConWithRetry(int retryCount, int millis) { 240 for (int n = 0; ;) { 241 try { 242 return createRealCon(); 243 } catch (RuntimeException e) { 244 if( BindingSupportImpl.getInstance().isOwnDatastoreException(e) ) 245 { 246 if (retryCount < 0 || (retryCount > 0 && ++n > retryCount)) throw e; 247 if (pes.isWarning()) { 248 JdbcLogEvent ev = new JdbcLogEvent(0, 249 JdbcLogEvent.POOL_CON_FAILED, 250 n + " " + e.toString()); 251 ev.updateTotalMs(); 252 pes.log(ev); 253 } 254 try { 255 Thread.sleep(millis); 256 } catch (InterruptedException e1) { 257 } 259 } 260 else 261 { 262 throw e; 263 } 264 } 265 } 266 } 267 268 public int getIsolationLevel() { 269 return isolationLevel; 270 } 271 272 278 public void setIsolationLevel(int isolationLevel) { 279 this.isolationLevel = isolationLevel; 280 } 281 282 public void setClearBatch(boolean clearBatch) { 283 this.clearBatch = clearBatch; 284 } 285 286 public boolean isClearBatch() { 287 return clearBatch; 288 } 289 290 public boolean isJdbcDisablePsCache() { 291 return jdbcDisablePsCache; 292 } 293 294 public void setJdbcDisablePsCache(boolean jdbcDisablePsCache) { 295 this.jdbcDisablePsCache = jdbcDisablePsCache; 296 } 297 298 public int getPsCacheMax() { 299 return psCacheMax; 300 } 301 302 public void setPsCacheMax(int psCacheMax) { 303 this.psCacheMax = psCacheMax; 304 } 305 306 public String getInitSQL() { 307 return initSQL; 308 } 309 310 public void setInitSQL(String initSQL) { 311 String s = endsWithCommit(initSQL); 312 if (s != null) { 313 commitAfterInitSQL = true; 314 this.initSQL = s; 315 } else { 316 commitAfterInitSQL = false; 317 this.initSQL = initSQL; 318 } 319 } 320 321 325 private String endsWithCommit(String s) { 326 if (s == null) return null; 327 s = s.trim(); 328 if (!s.endsWith("commit") && !s.endsWith("COMMIT")) return null; 329 for (int i = s.length() - 7; i >= 0; i--) { 330 char c = s.charAt(i); 331 if (!Character.isWhitespace(c)) { 332 if (c == ';') { 333 return s.substring(0, i); 334 } else { 335 break; 336 } 337 } 338 } 339 return null; 340 } 341 342 public String getValidateSQL() { 343 return validateSQL; 344 } 345 346 public void setValidateSQL(String validateSQL) { 347 this.validateSQL = validateSQL; 348 } 349 350 public int getConTimeout() { 351 return conTimeout; 352 } 353 354 public void setConTimeout(int conTimeout) { 355 this.conTimeout = conTimeout; 356 } 357 358 public int getTestInterval() { 359 return testInterval; 360 } 361 362 public void setTestInterval(int testInterval) { 363 this.testInterval = testInterval; 364 } 365 366 public boolean isTestWhenIdle() { 367 return testWhenIdle; 368 } 369 370 public void setTestWhenIdle(boolean on) { 371 testWhenIdle = on; 372 } 373 374 public boolean isBlockWhenFull() { 375 return blockWhenFull; 376 } 377 378 public void setBlockWhenFull(boolean blockWhenFull) { 379 this.blockWhenFull = blockWhenFull; 380 } 381 382 public int getMaxIdle() { 383 return maxIdle; 384 } 385 386 public void setMaxIdle(int maxIdle) { 387 this.maxIdle = maxIdle; 388 if (cleanupThread != null) cleanupThread.interrupt(); 389 } 390 391 public int getMinIdle() { 392 return minIdle; 393 } 394 395 public void setMinIdle(int minIdle) { 396 this.minIdle = minIdle; 397 if (cleanupThread != null) cleanupThread.interrupt(); 398 } 399 400 public int getMaxActive() { 401 return maxActive; 402 } 403 404 public void setMaxActive(int maxActive) { 405 this.maxActive = maxActive; 406 if (cleanupThread != null) cleanupThread.interrupt(); 407 } 408 409 public int getReserved() { 410 return reserved; 411 } 412 413 public void setReserved(int reserved) { 414 this.reserved = reserved; 415 } 416 417 public int getIdleCount() { 418 return idleCount; 419 } 420 421 public int getActiveCount() { 422 return activeCount; 423 } 424 425 public int getMaxConAge() { 426 return maxConAge; 427 } 428 429 public void setMaxConAge(int maxConAge) { 430 this.maxConAge = maxConAge; 431 } 432 433 436 public void fillStatus(PoolStatus s) { 437 s.fill(maxActive, activeCount, maxIdle, idleCount); 438 } 439 440 443 public String getURL() { 444 return url; 445 } 446 447 450 public Properties getConnectionProperties() { 451 return userProps; 452 } 453 454 457 public Driver getJdbcDriver() { 458 return jdbcDriver; 459 } 460 461 464 public String getDriverName() { 465 return jdbcDriver == null ? "(unknown)" : jdbcDriver.getClass().getName(); 466 } 467 468 474 public Connection getConnection(boolean highPriority, 475 boolean autoCommit) throws SQLException { 476 int maxActive = this.maxActive - (highPriority ? 0 : reserved); 478 PooledConnection con = null; 479 for (; ;) { 480 synchronized (this) { 481 for (; ;) { 482 if (closed) { 483 throw BindingSupportImpl.getInstance().fatal( 484 "Connection pool has been closed"); 485 } 486 if (activeCount >= maxActive) { 487 if (pes.isWarning()) { 488 JdbcPoolEvent event = new JdbcPoolEvent(0, 489 JdbcLogEvent.POOL_FULL, highPriority); 490 update(event); 491 pes.log(event); 492 fullCount++; 493 } 494 if (blockWhenFull) { 495 try { 496 wait(); 497 } catch (InterruptedException e) { 498 } 500 } else { 501 throw BindingSupportImpl.getInstance().poolFull( 502 "JDBC connection pool is full: " + this); 503 } 504 } else { 505 con = removeFromIdleHead(autoCommit); 506 ++activeCount; 507 break; 508 } 509 } 510 } 511 if (con == null) { 512 try { 513 waitCount++; 514 con = createPooledConnection(retryCount, retryIntervalMs); 515 } finally { 516 if (con == null) { 517 synchronized (this) { 518 --activeCount; 519 } 520 } 521 } 522 break; 523 } else { 524 if (testOnAlloc && !validateConnection(con)) { 525 destroy(con); 526 synchronized (this) { 527 --activeCount; 528 } 529 } else { 530 break; 531 } 532 } 533 } 534 if (con.getCachedAutoCommit() != autoCommit) { 536 if (autoCommit) { con.rollback(); 538 } 539 con.setAutoCommit(autoCommit); 540 } 541 con.updateLastActivityTime(); 542 addToActiveHead(con); 543 log(0, JdbcLogEvent.POOL_ALLOC, con, highPriority); 544 allocatedCount++; 545 return con; 546 } 547 548 551 public void testIdleConnections() { 552 for (; ;) { 553 PooledConnection con; 554 synchronized (this) { 555 if (activeCount >= (maxActive - reserved - 1)) break; 558 con = removeFromIdleHead(false); 559 if (con == null) break; 560 ++activeCount; 561 } 562 if (validateConnection(con)) { 563 synchronized (this) { 564 addToIdleTail(con); 565 --activeCount; 566 } 567 break; 568 } else { 569 destroy(con); 570 synchronized (this) { 571 --activeCount; 572 } 573 } 574 } 575 } 576 577 580 private void checkList(PooledConnection tail, PooledConnection head, 581 int size) { 582 if (tail == null) { 583 testTrue(head == null); 584 return; 585 } 586 if (head == null) { 587 testTrue(tail == null); 588 return; 589 } 590 checkList(tail, size); 591 checkList(head, size); 592 testTrue(tail.prev == null); 593 testTrue(head.next == null); 594 } 595 596 599 private void checkList(PooledConnection pc, int size) { 600 if (pc == null) return; 601 int c = -1; 602 for (PooledConnection i = pc; i != null; i = i.prev) { 604 if (i.prev != null) testTrue(i.prev.next == i); 605 ++c; 606 } 607 for (PooledConnection i = pc; i != null; i = i.next) { 609 if (i.next != null) testTrue(i.next.prev == i); 610 ++c; 611 } 612 if (size >= 0) { 613 testEquals(size, c); 614 } 615 } 616 617 private static void testEquals(int a, int b) { 618 if (a != b) { 619 throw BindingSupportImpl.getInstance().internal( 620 "assertion failed: expected " + a + " got " + b); 621 } 622 } 623 624 private static void testTrue(boolean t) { 625 if (!t) { 626 throw BindingSupportImpl.getInstance().internal( 627 "assertion failed: expected true"); 628 } 629 } 630 631 public void returnConnection(Connection con) throws SQLException { 632 con.close(); 633 } 634 635 642 public void returnConnection(PooledConnection con) { 643 if (con.isDestroyed()) return; 644 if ((testOnReturn || testOnException && con.isNeedsValidation()) 645 && !validateConnection(con)) { 646 removeFromActiveList(con); 647 destroy(con); 648 } else if (maxConAge > 0 && ++con.age >= maxConAge) { 649 ++expiredCount; 650 if (pes.isFine()) { 651 JdbcLogEvent ev = new JdbcLogEvent(0, 652 JdbcLogEvent.POOL_CON_EXPIRED, 653 Integer.toString(con.age)); 654 ev.updateTotalMs(); 655 pes.log(ev); 656 } 657 removeFromActiveList(con); 658 destroy(con); 659 } else { 660 synchronized (this) { 661 removeFromActiveList(con); 662 addToIdleTail(con); 663 } 664 } 665 log(0, JdbcLogEvent.POOL_RELEASE, con, false); 666 } 667 668 673 public void closeIdleConnections() { 674 for (int i = idleCount; i > 0; i--) { 675 PooledConnection con = removeFromIdleHead(false); 676 if (con == null) break; 677 destroy(con); 678 } 679 if (cleanupThread != null) cleanupThread.interrupt(); 680 } 681 682 685 private void destroy(PooledConnection con) { 686 closedCount++; 687 con.destroy(); 688 } 689 690 693 public void destroy() { 694 closed = true; 695 if (cleanupThread != null) cleanupThread.interrupt(); 696 for (; ;) { 697 PooledConnection con = removeFromIdleHead(false); 698 if (con == null) break; 699 destroy(con); 700 } 701 synchronized (this) { 704 notifyAll(); 705 } 706 } 707 708 712 public void checkIdleConnections() throws Exception { 713 for (; idleCount > maxIdle;) { 715 PooledConnection con = removeFromIdleHead(false); 716 if (con == null) break; 717 destroy(con); 718 } 719 for (; ;) { 723 if (!needMoreIdleConnections(1)) break; 724 PooledConnection con = createPooledConnection(retryCount, 725 retryIntervalMs); 726 synchronized (this) { 727 if (needMoreIdleConnections(0)) { 728 addToIdleTail(con); 729 continue; 730 } 731 } 732 destroy(con); 733 break; 734 } 735 } 736 737 private synchronized boolean needMoreIdleConnections(int space) { 738 return idleCount < minIdle && idleCount + activeCount < (maxActive - space); 739 } 740 741 745 public void closeTimedOutConnections() { 746 if (conTimeout <= 0) return; 747 for (; ;) { 748 PooledConnection con; 749 synchronized (this) { 750 if (activeTail == null) return; 751 long t = activeTail.getLastActivityTime(); 752 if (t == 0) return; 753 int s = (int)((System.currentTimeMillis() - t) / 1000); 754 if (s < conTimeout) return; 755 con = activeTail; 756 removeFromActiveList(con); 757 } 758 timedOutCount++; 759 if (pes.isWarning()) { 760 JdbcPoolEvent event = new JdbcPoolEvent(0, 761 JdbcLogEvent.POOL_CON_TIMEOUT, false); 762 event.setConnectionID(System.identityHashCode(con)); 763 update(event); 764 pes.log(event); 765 } 766 destroy(con); 767 } 768 } 769 770 779 private synchronized PooledConnection removeFromIdleHead(boolean autoCommit) { 780 PooledConnection ans = removeFromIdleHeadImp(autoCommit); 781 return ans == null ? removeFromIdleHeadImp(!autoCommit) : ans; 782 } 783 784 private PooledConnection removeFromIdleHeadImp(boolean autoCommit) { 785 PooledConnection con; 786 if (autoCommit) { 787 con = idleHeadAC; 788 if (con == null) return null; 789 idleHeadAC = con.prev; 790 con.prev = null; 791 if (idleHeadAC == null) { 792 idleTailAC = null; 793 } else { 794 idleHeadAC.next = null; 795 } 796 } else { 797 con = idleHead; 798 if (con == null) return null; 799 idleHead = con.prev; 800 con.prev = null; 801 if (idleHead == null) { 802 idleTail = null; 803 } else { 804 idleHead.next = null; 805 } 806 } 807 --idleCount; 808 con.idle = false; 809 if (Debug.DEBUG) { 810 checkList(idleTail, idleHead, -1); 811 checkList(idleTailAC, idleHeadAC, -1); 812 } 813 return con; 814 } 815 816 821 private synchronized void addToIdleTail(PooledConnection con) { 822 if (Debug.DEBUG) { 823 if (con.prev != null || con.next != null) { 824 throw BindingSupportImpl.getInstance().internal("con belongs to a list"); 825 } 826 } 827 con.idle = true; 828 if (con.getCachedAutoCommit()) { 829 if (idleTailAC == null) { 830 idleHeadAC = idleTailAC = con; 831 } else { 832 con.next = idleTailAC; 833 idleTailAC.prev = con; 834 idleTailAC = con; 835 } 836 } else { 837 if (idleTail == null) { 838 idleHead = idleTail = con; 839 } else { 840 con.next = idleTail; 841 idleTail.prev = con; 842 idleTail = con; 843 } 844 } 845 ++idleCount; 846 if (Debug.DEBUG) { 847 checkList(idleTail, idleHead, -1); 848 checkList(idleTailAC, idleHeadAC, -1); 849 } 850 notify(); 851 } 852 853 857 private synchronized void addToActiveHead(PooledConnection con) { 858 if (Debug.DEBUG) { 859 if (con.prev != null || con.next != null) { 860 throw BindingSupportImpl.getInstance().internal("con belongs to a list"); 861 } 862 } 863 if (activeHead == null) { 864 activeHead = activeTail = con; 865 } else { 866 con.prev = activeHead; 867 activeHead.next = con; 868 activeHead = con; 869 } 870 if (Debug.DEBUG) checkList(activeTail, activeHead, -1); 871 } 872 873 876 private synchronized void removeFromActiveList(PooledConnection con) { 877 if (con.prev != null) { 878 con.prev.next = con.next; 879 } else { 880 activeTail = con.next; 881 } 882 if (con.next != null) { 883 con.next.prev = con.prev; 884 } else { 885 activeHead = con.prev; 886 } 887 con.prev = con.next = null; 888 --activeCount; 889 if (Debug.DEBUG) checkList(activeTail, activeHead, -1); 890 } 891 892 private JdbcPoolEvent log(long txId, int type, PooledConnection con, 893 boolean highPriority) { 894 if (pes.isFine()) { 895 JdbcPoolEvent event = new JdbcPoolEvent(txId, type, highPriority); 896 event.setAutoCommit(con.getCachedAutoCommit()); 897 event.setConnectionID(System.identityHashCode(con)); 898 update(event); 899 pes.log(event); 900 return event; 901 } 902 return null; 903 } 904 905 private void update(JdbcPoolEvent ev) { 906 ev.update(maxActive, activeCount, maxIdle, idleCount); 907 } 908 909 private Connection createRealCon() { 910 JdbcConnectionEvent ev = null; 911 if (pes.isFine()) { 912 ev = new JdbcConnectionEvent(0, null, url, 913 JdbcConnectionEvent.CON_OPEN); 914 pes.log(ev); 915 } 916 Connection realCon = null; 917 try { 918 realCon = jdbcDriver.connect(url, props); 919 if (realCon == null) { 920 throw BindingSupportImpl.getInstance().fatalDatastore( 921 formatConnectionErr("Unable to connect to " + url)); 922 } 923 } catch (SQLException x) { 924 RuntimeException e = sqlDriver.mapException(x, 925 formatConnectionErr("Unable to connect to " + url + ":\n" + x), 926 false); 927 if (ev != null) { 928 ev.setErrorMsg(e); 929 } 930 throw e; 931 } catch (RuntimeException x) { 932 if (ev != null) { 933 ev.setErrorMsg(x); 934 } 935 throw x; 936 } finally { 937 if (ev != null) { 938 ev.updateTotalMs(); 939 } 940 } 941 createdCount++; 942 return realCon; 943 } 944 945 private String formatConnectionErr(String msg) { 946 StringBuffer s = new StringBuffer (); 947 s.append(msg); 948 s.append("\nJDBC Driver: " + jdbcDriver.getClass().getName()); 949 ArrayList a = new ArrayList(props.keySet()); 950 Collections.sort(a); 951 for (Iterator i = a.iterator(); i.hasNext(); ) { 952 String p = (String )i.next(); 953 Object v = "password".equals(p) ? "(hidden)" : props.get(p); 954 s.append('\n'); 955 s.append(p); 956 s.append('='); 957 s.append(v); 958 } 959 return s.toString(); 960 } 961 962 967 private PooledConnection createPooledConnection(int retryCount, 968 int retryIntervalMs) throws SQLException { 969 Connection realCon = createRealConWithRetry(retryCount, 970 retryIntervalMs); 971 PooledConnection pooledCon = new PooledConnection( 972 JDBCConnectionPool.this, realCon, pes, 973 !jdbcDisablePsCache, psCacheMax); 974 boolean ok = false; 975 try { 976 initConnection(pooledCon); 977 pooledCon.setAutoCommit(false); 978 if (isolationLevel != 0) { 979 pooledCon.setTransactionIsolation(isolationLevel); 980 } 981 ok = true; 982 } finally { 983 if (!ok && realCon != null) { 984 try { 985 pooledCon.closeRealConnection(); 986 } catch (SQLException x) { 987 } 989 } 990 } 991 return pooledCon; 992 } 993 994 997 private void initConnection(Connection con) { 998 if (initSQL == null) return; 999 Statement stat = null; 1000 try { 1001 stat = con.createStatement(); 1002 stat.execute(initSQL); 1003 } catch (SQLException e) { 1004 throw sqlDriver.mapException(e, 1005 "Error executing initSQL on new Connection: " + e + 1006 "\n" + initSQL, true); 1007 } finally { 1008 if (stat != null) { 1009 try { 1010 stat.close(); 1011 } catch (SQLException e) { 1012 } 1014 } 1015 } 1016 if (commitAfterInitSQL) { 1017 try { 1018 con.commit(); 1019 } catch (SQLException e) { 1020 throw sqlDriver.mapException(e, 1021 "Error doing commit after executing initSQL on new Connection: " + e + "\n" + 1022 initSQL, true); 1023 } 1024 } 1025 } 1026 1027 1031 private boolean validateConnection(PooledConnection con) { 1032 validatedCount++; 1033 boolean ans = validateConnectionImp(con); 1034 if (!ans) badCount++; 1035 return ans; 1036 } 1037 1038 private boolean validateConnectionImp(PooledConnection con) { 1039 try { 1040 if (con.isClosed()) return false; 1041 if (validateSQL != null) { 1042 PreparedStatement ps = null; 1043 ResultSet rs = null; 1044 try { 1045 ps = con.prepareStatement(validateSQL); 1046 rs = ps.executeQuery(); 1047 if (!rs.next()) { 1048 if (pes.isWarning()) { 1049 JdbcLogEvent ev = new JdbcLogEvent(0, 1050 JdbcLogEvent.POOL_BAD_CON, 1051 "No row returned"); 1052 ev.updateTotalMs(); 1053 pes.log(ev); 1054 } 1055 return false; 1056 } 1057 } finally { 1058 if (rs != null) rs.close(); 1059 if (ps != null) ps.close(); 1060 } 1061 if (!con.getCachedAutoCommit()) { 1062 con.rollback(); 1063 } 1064 } 1065 return true; 1066 } catch (SQLException e) { 1067 if (pes.isWarning()) { 1068 JdbcLogEvent ev = new JdbcLogEvent(0, 1069 JdbcLogEvent.POOL_BAD_CON, e.toString()); 1070 ev.updateTotalMs(); 1071 pes.log(ev); 1072 } 1073 return false; 1074 } 1075 } 1076 1077 1078 1079 1082 public void run() { 1083 1084 for (; ;) { 1085 1086 try { 1087 Thread.sleep(5000); 1088 } catch (InterruptedException e) { 1089 } 1091 1092 if (closed) break; 1093 1094 if (duration(timeLastTest) >= testInterval) { 1095 timeLastTest = System.currentTimeMillis(); 1096 if (testWhenIdle) testIdleConnections(); 1097 if (conTimeout > 0) closeTimedOutConnections(); 1098 } 1099 1100 try { 1101 checkIdleConnections(); 1102 } catch (Exception e) { 1103 } 1105 } 1106 } 1107 1108 private long duration(long start) { 1109 return (System.currentTimeMillis() - start) / 1000; 1110 } 1111 1112 1115 public String toString() { 1116 PoolStatus ps = new PoolStatus(url); 1117 fillStatus(ps); 1118 return ps.toString(); 1119 } 1120 1121 1124 public void addMetrics(List list) { 1125 list.add(metricActive = new BaseMetric("JDBCPoolActive", 1126 "Pool Active", CAT_POOL, "Number of active JDBC connections in pool", 1127 0, Metric.CALC_AVERAGE)); 1128 list.add(metricMaxActive = new BaseMetric("JDBCPoolMaxActive", 1129 "Pool Max Active", CAT_POOL, "Max number of JDBC connections allowed in pool", 1130 0, Metric.CALC_AVERAGE)); 1131 list.add(metricIdle = new BaseMetric("JDBCPoolIdle", 1132 "Pool Idle", CAT_POOL, "Number of idle JDBC connections in pool", 1133 0, Metric.CALC_AVERAGE)); 1134 list.add(metricWait = new BaseMetric("JDBCPoolWait", 1135 "Pool Wait", CAT_POOL, "Number of times that a caller had to wait for a connection", 1136 0, Metric.CALC_DELTA)); 1137 list.add(metricFull = new BaseMetric("JDBCPoolFull", 1138 "Pool Full", CAT_POOL, "Number of times that the pool was full and a connection was needed", 1139 0, Metric.CALC_DELTA)); 1140 list.add(metricTimedOut = new BaseMetric("JDBCConTimedOut", 1141 "Con Timed Out", CAT_POOL, "Number of active JDBC connections timed out and closed", 1142 0, Metric.CALC_DELTA)); 1143 list.add(metricExpired = new BaseMetric("JDBCConExpired", 1144 "Con Expired", CAT_POOL, "Number of JDBC connections closed due to their age reaching the maximum lifespan", 1145 0, Metric.CALC_DELTA)); 1146 list.add(metricBad = new BaseMetric("JDBCConBad", 1147 "Con Bad", CAT_POOL, "Number of JDBC connections that failed validation test", 1148 0, Metric.CALC_DELTA)); 1149 list.add(metricCreated = new BaseMetric("JDBCConCreated", 1150 "Con Created", CAT_POOL, "Number of JDBC connections created", 1151 0, Metric.CALC_DELTA)); 1152 list.add(metricClosed = new BaseMetric("JDBCConClosed", 1153 "Con Closed", CAT_POOL, "Number of JDBC connections closed", 1154 0, Metric.CALC_DELTA)); 1155 list.add(metricAllocated = new BaseMetric("JDBCConAllocated", 1156 "Con Allocated", CAT_POOL, "Number of JDBC connections given out by the pool", 1157 3, Metric.CALC_DELTA_PER_SECOND)); 1158 list.add(metricValidated = new BaseMetric("JDBCConValidated", 1159 "Con Validated", CAT_POOL, "Number of JDBC connections tested by the pool", 1160 0, Metric.CALC_DELTA)); 1161 list.add(new PercentageMetric("JdbcPoolPercentFull", 1162 "Pool % Full ", CAT_POOL, 1163 "Active connections as a percentage of the maximum", 1164 metricActive, metricMaxActive)); 1165 } 1166 1167 1170 public void sampleMetrics(int[][] buf, int pos) { 1171 buf[metricActive.getIndex()][pos] = activeCount; 1172 buf[metricMaxActive.getIndex()][pos] = maxActive; 1173 buf[metricIdle.getIndex()][pos] = idleCount; 1174 buf[metricWait.getIndex()][pos] = waitCount; 1175 buf[metricFull.getIndex()][pos] = fullCount; 1176 buf[metricTimedOut.getIndex()][pos] = timedOutCount; 1177 buf[metricExpired.getIndex()][pos] = expiredCount; 1178 buf[metricBad.getIndex()][pos] = badCount; 1179 buf[metricAllocated.getIndex()][pos] = allocatedCount; 1180 buf[metricValidated.getIndex()][pos] = validatedCount; 1181 buf[metricCreated.getIndex()][pos] = createdCount; 1182 buf[metricClosed.getIndex()][pos] = closedCount; 1183 } 1184 1185} 1186 | Popular Tags |