From 5f8b154bb2fc07666f3edacd6c698b1139e2ae2a Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 18 May 2013 22:01:29 +0800 Subject: [PATCH 1/4] bug fixed sql runningCount & add statLog support --- .../druid/pool/DruidAbstractDataSource.java | 19 ++- .../alibaba/druid/pool/DruidDataSource.java | 155 +++++++++++++++++- .../druid/pool/DruidDataSourceStatLogger.java | 21 +++ .../pool/DruidDataSourceStatLoggerImpl.java | 25 +++ .../druid/pool/DruidDataSourceStatValue.java | 77 +++++++++ .../druid/stat/JdbcDataSourceStat.java | 41 ++++- .../com/alibaba/druid/stat/JdbcSqlStat.java | 82 ++++++++- .../alibaba/druid/stat/JdbcSqlStatValue.java | 95 +++++++++++ .../com/alibaba/druid/util/Histogram.java | 8 + .../bvt/pool/TestOnBorrowFileAndNameTest.java | 4 +- .../pool/TimeBetweenLogStatsMillisTest.java | 30 ++++ .../filter/MergeStatFilterTest_tddl_2.java | 78 +++++++++ 12 files changed, 620 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLogger.java create mode 100644 src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java create mode 100644 src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java create mode 100644 src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/proxy/filter/MergeStatFilterTest_tddl_2.java diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 6fc3528c78..690cbdc9c1 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -210,7 +210,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements private ObjectName objectName; - private final AtomicLong executeCount = new AtomicLong(); + protected final AtomicLong executeCount = new AtomicLong(); protected volatile Throwable createError; protected volatile Throwable lastError; @@ -231,7 +231,10 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements private Boolean useUnfairLock = null; - private boolean useLocalSessionState = true; + private boolean useLocalSessionState = true; + + protected long timeBetweenLogStatsMillis; + protected DruidDataSourceStatLogger statLogger = new DruidDataSourceStatLoggerImpl(); public DruidAbstractDataSource(boolean lockFair){ lock = new ReentrantLock(lockFair); @@ -239,15 +242,23 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements notEmpty = lock.newCondition(); empty = lock.newCondition(); } - + public boolean isUseLocalSessionState() { return useLocalSessionState; } - + public void setUseLocalSessionState(boolean useLocalSessionState) { this.useLocalSessionState = useLocalSessionState; } + public long getTimeBetweenLogStatsMillis() { + return timeBetweenLogStatsMillis; + } + + public void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis) { + this.timeBetweenLogStatsMillis = timeBetweenLogStatsMillis; + } + public boolean isOracle() { return isOracle; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 6ddbc2c4f1..036e100749 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -119,6 +119,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat // threads private CreateConnectionThread createConnectionThread; private DestroyConnectionThread destoryConnectionThread; + private LogStatsThread logStatsThread; private final CountDownLatch initedLatch = new CountDownLatch(2); @@ -131,7 +132,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private volatile boolean closed = false; private long closeTimeMillis = -1L; - private JdbcDataSourceStat dataSourceStat; + protected JdbcDataSourceStat dataSourceStat; private boolean useGloalDataSourceStat = false; @@ -436,6 +437,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat + maxActive); } + if (timeBetweenLogStatsMillis > 0 && useGloalDataSourceStat) { + throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGloalDataSourceStat=true"); + } + if (this.driverClass != null) { this.driverClass = driverClass.trim(); } @@ -492,7 +497,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat SQLException connectError = null; try { - // 初始化连接 + // init connections for (int i = 0, size = getInitialSize(); i < size; ++i) { Connection conn = createPhysicalConnection(); DruidConnectionHolder holder = new DruidConnectionHolder(this, conn); @@ -508,6 +513,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat connectError = ex; } + createAndLogThread(); createAndStartCreatorThread(); createAndStartDestroyThread(); @@ -535,6 +541,16 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + private void createAndLogThread() { + if (this.timeBetweenLogStatsMillis <= 0) { + return; + } + + String threadName = "Druid-ConnectionPool-Log-" + System.identityHashCode(this); + logStatsThread = new LogStatsThread(threadName); + logStatsThread.start(); + } + private void createAndStartDestroyThread() { String threadName = "Druid-ConnectionPool-Destory-" + System.identityHashCode(this); destoryConnectionThread = new DestroyConnectionThread(threadName); @@ -1047,7 +1063,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat recycleErrorCount.incrementAndGet(); } } - + public long getRecycleErrorCount() { return recycleErrorCount.get(); } @@ -1078,6 +1094,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return; } + if (logStatsThread != null) { + logStatsThread.interrupt(); + } + if (createConnectionThread != null) { createConnectionThread.interrupt(); } @@ -1236,13 +1256,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat @Override public Connection getConnection(String username, String password) throws SQLException { if (!StringUtils.equals(username, this.username)) { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); + throw new UnsupportedOperationException("Not supported by DruidDataSource"); } - + if (!StringUtils.equals(password, this.password)) { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); + throw new UnsupportedOperationException("Not supported by DruidDataSource"); } - + return getConnection(); } @@ -1311,6 +1331,103 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } } + public void logStats() { + final DruidDataSourceStatLogger statLogger = this.statLogger; + if (statLogger == null) { + return; + } + + DruidDataSourceStatValue statValue = getStatValueAndReset(); + + statLogger.log(statValue); + } + + public DruidDataSourceStatValue getStatValueAndReset() { + DruidDataSourceStatValue value = new DruidDataSourceStatValue(); + + lock.lock(); + try { + value.poolingCount = this.poolingCount; + value.poolingPeak = this.poolingPeak; + value.poolingPeakTime = this.poolingPeakTime; + + value.activeCount = this.activeCount; + value.activePeak = this.activePeak; + value.activePeakTime = this.activePeakTime; + + value.connectCount = this.connectCount; + value.closeCount = this.closeCount; + value.waitThreadCount = lock.getWaitQueueLength(notEmpty); + value.notEmptyWaitCount = this.notEmptyWaitCount; + value.notEmptyWaitNanos = this.notEmptyWaitNanos; + + // reset + this.poolingPeak = 0; + this.poolingPeakTime = 0; + this.activePeak = 0; + this.activePeakTime = 0; + this.connectCount = 0; + this.closeCount = 0; + + this.notEmptyWaitCount = 0; + this.notEmptyWaitNanos = 0; + } finally { + lock.unlock(); + } + + value.name = this.getName(); + value.dbType = this.getDbType(); + value.driverClassName = this.getDriverClassName(); + + value.url = this.getUrl(); + value.userName = this.getUsername(); + value.filterClassNames = this.getFilterClassNames(); + + value.initialSize = this.getInitialSize(); + value.minIdle = this.getMinIdle(); + value.maxActive = this.getMaxActive(); + + value.queryTimeout = this.getQueryTimeout(); + value.transactionQueryTimeout = this.getTransactionQueryTimeout(); + value.loginTimeout = this.getLoginTimeout(); + value.validConnectionCheckerClassName = this.getValidConnectionCheckerClassName(); + value.exceptionSorterClassName = this.getExceptionSorterClassName(); + + value.testOnBorrow = this.isTestOnBorrow(); + value.testOnReturn = this.isTestOnReturn(); + value.testWhileIdle = this.isTestWhileIdle(); + + value.defaultAutoCommit = this.isDefaultAutoCommit(); + value.defaultReadOnly = this.isDefaultAutoCommit(); + value.defaultTransactionIsolation = this.getDefaultTransactionIsolation(); + + value.logicConnectErrorCount = connectErrorCount.getAndSet(0); + + value.physicalConnectCount = createCount.getAndSet(0); + value.physicalCloseCount = destroyCount.getAndSet(0); + value.physicalConnectErrorCount = createErrorCount.getAndSet(0); + + value.executeCount = this.executeCount.getAndSet(0); + value.errorCount = errorCount.getAndSet(0); + value.commitCount = commitCount.getAndSet(0); + value.rollbackCount = rollbackCount.getAndSet(0); + + value.PSCacheHitCount = cachedPreparedStatementHitCount.getAndSet(0); + value.PSCacheMissCount = cachedPreparedStatementMissCount.getAndSet(0); + + value.startTransactionCount = startTransactionCount.getAndSet(0); + value.transactionHistogram = this.getTransactionHistogram().toArrayAndReset(); + + value.connectionHoldTimeHistogram = this.getDataSourceStat().getConnectionHoldHistogram().toArrayAndReset(); + value.removeAbandoned = this.isRemoveAbandoned(); + value.clobOpenCount = this.getDataSourceStat().getClobOpenCountAndReset(); + value.blobOpenCount = this.getDataSourceStat().getBlobOpenCountAndReset(); + + value.sqlList = this.getDataSourceStat().getSqlStatMapAndReset(); + + return value; + } + public long getRemoveAbandonedCount() { return removeAbandonedCount; } @@ -1454,6 +1571,30 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } + public class LogStatsThread extends Thread { + + public LogStatsThread(String name){ + super(name); + this.setDaemon(true); + } + + public void run() { + try { + for (;;) { + try { + logStats(); + } catch (Exception e) { + LOG.error("logStats error", e); + } + + Thread.sleep(timeBetweenLogStatsMillis); + } + } catch (InterruptedException e) { + // skip + } + } + } + public int removeAbandoned() { int removeCount = 0; diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLogger.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLogger.java new file mode 100644 index 0000000000..80b46da108 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLogger.java @@ -0,0 +1,21 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.pool; + +public interface DruidDataSourceStatLogger { + + void log(DruidDataSourceStatValue statValue); +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java new file mode 100644 index 0000000000..783501f539 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java @@ -0,0 +1,25 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.pool; + +public class DruidDataSourceStatLoggerImpl implements DruidDataSourceStatLogger { + + @Override + public void log(DruidDataSourceStatValue statValue) { + + } + +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java new file mode 100644 index 0000000000..05018f9977 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java @@ -0,0 +1,77 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.pool; + +import java.util.List; + +import com.alibaba.druid.stat.JdbcSqlStatValue; + +public class DruidDataSourceStatValue { + + public int activeCount; + public int activePeak; + public long activePeakTime; + + public int poolingCount; + public int poolingPeak; + public long poolingPeakTime; + + public long connectCount; + public long closeCount; + public long waitThreadCount; + public long notEmptyWaitCount; + public long notEmptyWaitNanos; + + public String name; + public String dbType; + public String driverClassName; + public String url; + public String userName; + public List filterClassNames; + + public int initialSize; + public int minIdle; + public int maxActive; + public int queryTimeout; + public int transactionQueryTimeout; + public int loginTimeout; + public String validConnectionCheckerClassName; + public String exceptionSorterClassName; + public boolean testOnBorrow; + public boolean testOnReturn; + public boolean testWhileIdle; + public boolean defaultAutoCommit; + public boolean defaultReadOnly; + public int defaultTransactionIsolation; + public long logicConnectErrorCount; + public long physicalConnectCount; + public long physicalCloseCount; + public long physicalConnectErrorCount; + public long executeCount; + public long errorCount; + public long commitCount; + public long rollbackCount; + public long PSCacheHitCount; + public long PSCacheMissCount; + public long startTransactionCount; + public long[] transactionHistogram; + public long[] connectionHoldTimeHistogram; + public boolean removeAbandoned; + public long clobOpenCount; + public long blobOpenCount; + + public List sqlList; +} diff --git a/src/main/java/com/alibaba/druid/stat/JdbcDataSourceStat.java b/src/main/java/com/alibaba/druid/stat/JdbcDataSourceStat.java index 661b06dea1..b34d71c410 100644 --- a/src/main/java/com/alibaba/druid/stat/JdbcDataSourceStat.java +++ b/src/main/java/com/alibaba/druid/stat/JdbcDataSourceStat.java @@ -15,9 +15,10 @@ */ package com.alibaba.druid.stat; -import java.util.HashMap; +import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; @@ -257,7 +258,7 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean { } public Map getSqlStatMap() { - Map map = new HashMap(); + Map map = new LinkedHashMap(sqlStatMap.size()); lock.readLock().lock(); try { map.putAll(sqlStatMap); @@ -266,6 +267,34 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean { } return map; } + + public List getSqlStatMapAndReset() { + List stats = new ArrayList(sqlStatMap.size()); + lock.writeLock().lock(); + try { + Iterator> iter = sqlStatMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + JdbcSqlStat stat = entry.getValue(); + if (stat.getExecuteCount() == 0 && stat.getRunningCount() == 0) { + stat.setRemoved(true); + iter.remove(); + } else { + stats.add(entry.getValue()); + } + } + } finally { + lock.writeLock().unlock(); + } + + List values = new ArrayList(stats.size()); + for (int i = 0; i < stats.size(); ++i) { + JdbcSqlStat stat = stats.get(i); + JdbcSqlStatValue value = stat.getValueAndReset(); + values.add(value); + } + return values; + } public JdbcSqlStat getSqlStat(String sql) { lock.readLock().lock(); @@ -346,6 +375,10 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean { public long getClobOpenCount() { return clobOpenCount.get(); } + + public long getClobOpenCountAndReset() { + return clobOpenCount.getAndSet(0); + } public void incrementClobOpenCount() { clobOpenCount.incrementAndGet(); @@ -354,6 +387,10 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean { public long getBlobOpenCount() { return blobOpenCount.get(); } + + public long getBlobOpenCountAndReset() { + return blobOpenCount.getAndSet(0); + } public void incrementBlobOpenCount() { blobOpenCount.incrementAndGet(); diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java index 33de13886a..7d5943f256 100644 --- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java +++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java @@ -323,7 +323,6 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { executeSpanNanoTotalUpdater.set(this, 0); executeSpanNanoMaxUpdater.set(this, 0); executeNanoSpanMaxOccurTime = 0; - runningCountUpdater.set(this, 0); concurrentMaxUpdater.set(this, 0); executeErrorCountUpdater.set(this, 0); @@ -380,6 +379,87 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { readerOpenCountUpdater.set(this, 0); } + public JdbcSqlStatValue getValueAndReset() { + JdbcSqlStatValue val = new JdbcSqlStatValue(); + + val.executeLastStartTime = executeLastStartTime; + executeLastStartTime = 0; + + val.executeBatchSizeTotal = executeBatchSizeTotalUpdater.getAndSet(this, 0); + val.executeBatchSizeMax = executeBatchSizeMaxUpdater.getAndSet(this, 0); + + val.executeSuccessCount = executeSuccessCountUpdater.getAndSet(this, 0); + val.executeSpanNanoTotal = executeSpanNanoTotalUpdater.getAndSet(this, 0); + val.executeSpanNanoMax = executeSpanNanoMaxUpdater.getAndSet(this, 0); + val.executeNanoSpanMaxOccurTime = executeNanoSpanMaxOccurTime; + executeNanoSpanMaxOccurTime = 0; + + val.runningCount = this.runningCount; + + val.concurrentMax = concurrentMaxUpdater.getAndSet(this, 0); + + val.executeErrorCount = executeErrorCountUpdater.getAndSet(this, 0); + + val.executeErrorLast = executeErrorLast; + executeErrorLast = null; + + val.executeErrorLastTime = executeErrorLastTime; + executeErrorLastTime = 0; + + val.updateCount = updateCountUpdater.getAndSet(this, 0); + val.updateCountMax = updateCountMaxUpdater.getAndSet(this, 0); + val.fetchRowCount = fetchRowCountUpdater.getAndSet(this, 0); + val.fetchRowCountMax = fetchRowCountMaxUpdater.getAndSet(this, 0); + + val.histogram_0_1 = histogram_0_1_Updater.getAndSet(this, 0); + val.histogram_1_10 = histogram_1_10_Updater.getAndSet(this, 0); + val.histogram_10_100 = histogram_10_100_Updater.getAndSet(this, 0); + val.histogram_100_1000 = histogram_100_1000_Updater.getAndSet(this, 0); + val.histogram_1000_10000 = histogram_1000_10000_Updater.getAndSet(this, 0); + val.histogram_10000_100000 = histogram_10000_100000_Updater.getAndSet(this, 0); + val.histogram_100000_1000000 = histogram_100000_1000000_Updater.getAndSet(this, 0); + val.histogram_1000000_more = histogram_1000000_more_Updater.getAndSet(this, 0); + + val.lastSlowParameters = lastSlowParameters; + lastSlowParameters = null; + + val.inTransactionCount = inTransactionCountUpdater.getAndSet(this, 0); + val.resultSetHoldTimeNano = resultSetHoldTimeNanoUpdater.getAndSet(this, 0); + val.executeAndResultSetHoldTime = executeAndResultSetHoldTimeUpdater.getAndSet(this, 0); + + val.fetchRowCount_0_1 = fetchRowCount_0_1_Updater.getAndSet(this, 0); + val.fetchRowCount_1_10 = fetchRowCount_1_10_Updater.getAndSet(this, 0); + val.fetchRowCount_10_100 = fetchRowCount_10_100_Updater.getAndSet(this, 0); + val.fetchRowCount_100_1000 = fetchRowCount_100_1000_Updater.getAndSet(this, 0); + val.fetchRowCount_1000_10000 = fetchRowCount_1000_10000_Updater.getAndSet(this, 0); + val.fetchRowCount_10000_more = fetchRowCount_10000_more_Updater.getAndSet(this, 0); + + val.updateCount_0_1 = updateCount_0_1_Updater.getAndSet(this, 0); + val.updateCount_1_10 = updateCount_1_10_Updater.getAndSet(this, 0); + val.updateCount_10_100 = updateCount_10_100_Updater.getAndSet(this, 0); + val.updateCount_100_1000 = updateCount_100_1000_Updater.getAndSet(this, 0); + val.updateCount_1000_10000 = updateCount_1000_10000_Updater.getAndSet(this, 0); + val.updateCount_10000_more = updateCount_10000_more_Updater.getAndSet(this, 0); + + val.executeAndResultHoldTime_0_1 = executeAndResultHoldTime_0_1_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_1_10 = executeAndResultHoldTime_1_10_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_10_100 = executeAndResultHoldTime_10_100_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_100_1000 = executeAndResultHoldTime_100_1000_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_1000_10000 = executeAndResultHoldTime_1000_10000_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_10000_100000 = executeAndResultHoldTime_10000_100000_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_100000_1000000 = executeAndResultHoldTime_100000_1000000_Updater.getAndSet(this, 0); + val.executeAndResultHoldTime_1000000_more = executeAndResultHoldTime_1000000_more_Updater.getAndSet(this, 0); + + val.blobOpenCount = blobOpenCountUpdater.getAndSet(this, 0); + val.clobOpenCount = clobOpenCountUpdater.getAndSet(this, 0); + val.readStringLength = readStringLengthUpdater.getAndSet(this, 0); + val.readBytesLength = readBytesLengthUpdater.getAndSet(this, 0); + val.inputStreamOpenCount = inputStreamOpenCountUpdater.getAndSet(this, 0); + val.readerOpenCount = readerOpenCountUpdater.getAndSet(this, 0); + + return val; + } + public long getConcurrentMax() { return concurrentMax; } diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java new file mode 100644 index 0000000000..67b8a7b5fb --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.stat; + +public class JdbcSqlStatValue { + + public String sql; + public long id; + public String dataSource; + public long executeLastStartTime; + + public long executeBatchSizeTotal; + public int executeBatchSizeMax; + + public long executeSuccessCount; + public long executeSpanNanoTotal; + public long executeSpanNanoMax; + public int runningCount; + public int concurrentMax; + public long resultSetHoldTimeNano; + public long executeAndResultSetHoldTime; + + public String name; + public String file; + public String dbType; + + public long executeNanoSpanMaxOccurTime; + + public long executeErrorCount; + public Throwable executeErrorLast; + public long executeErrorLastTime; + + public long updateCount; + public long updateCountMax; + public long fetchRowCount; + public long fetchRowCountMax; + + public long inTransactionCount; + + public String lastSlowParameters; + + public long clobOpenCount; + public long blobOpenCount; + public long readStringLength; + public long readBytesLength; + + public long inputStreamOpenCount; + public long readerOpenCount; + + public long histogram_0_1; + public long histogram_1_10; + public int histogram_10_100; + public int histogram_100_1000; + public int histogram_1000_10000; + public int histogram_10000_100000; + public int histogram_100000_1000000; + public int histogram_1000000_more; + + public long executeAndResultHoldTime_0_1; + public long executeAndResultHoldTime_1_10; + public int executeAndResultHoldTime_10_100; + public int executeAndResultHoldTime_100_1000; + public int executeAndResultHoldTime_1000_10000; + public int executeAndResultHoldTime_10000_100000; + public int executeAndResultHoldTime_100000_1000000; + public int executeAndResultHoldTime_1000000_more; + + public long fetchRowCount_0_1; + public long fetchRowCount_1_10; + public long fetchRowCount_10_100; + public int fetchRowCount_100_1000; + public int fetchRowCount_1000_10000; + public int fetchRowCount_10000_more; + + public long updateCount_0_1; + public long updateCount_1_10; + public long updateCount_10_100; + public int updateCount_100_1000; + public int updateCount_1000_10000; + public int updateCount_10000_more; + +} diff --git a/src/main/java/com/alibaba/druid/util/Histogram.java b/src/main/java/com/alibaba/druid/util/Histogram.java index 147c746e36..468985297b 100644 --- a/src/main/java/com/alibaba/druid/util/Histogram.java +++ b/src/main/java/com/alibaba/druid/util/Histogram.java @@ -76,6 +76,14 @@ public class Histogram { } return array; } + + public long[] toArrayAndReset() { + long[] array = new long[rangeCounters.length()]; + for (int i = 0; i < rangeCounters.length(); i++) { + array[i] = rangeCounters.getAndSet(i, 0); + } + return array; + } public long[] getRanges() { return ranges; diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestOnBorrowFileAndNameTest.java b/src/test/java/com/alibaba/druid/bvt/pool/TestOnBorrowFileAndNameTest.java index d520a83716..60caa98cc1 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/TestOnBorrowFileAndNameTest.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestOnBorrowFileAndNameTest.java @@ -5,9 +5,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Iterator; -import junit.framework.Assert; import junit.framework.TestCase; +import org.junit.Assert; + import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.stat.DruidDataSourceStatManager; import com.alibaba.druid.stat.JdbcSqlStat; @@ -24,6 +25,7 @@ public class TestOnBorrowFileAndNameTest extends TestCase { dataSource.setName("com.alibaba.dragoon.monitor"); dataSource.setMinIdle(0); dataSource.setPoolPreparedStatements(false); + dataSource.setTestOnBorrow(true); dataSource.setValidationQuery("SELECT 1"); dataSource.setFilters("stat"); diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest.java b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest.java new file mode 100644 index 0000000000..7179724e94 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest.java @@ -0,0 +1,30 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.JdbcUtils; + +public class TimeBetweenLogStatsMillisTest extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTimeBetweenLogStatsMillis(1000); + // dataSource.setFilters("log4j"); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_0() throws Exception { + dataSource.init(); + Assert.assertEquals(1000, dataSource.getTimeBetweenLogStatsMillis()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/proxy/filter/MergeStatFilterTest_tddl_2.java b/src/test/java/com/alibaba/druid/bvt/proxy/filter/MergeStatFilterTest_tddl_2.java new file mode 100644 index 0000000000..7918fe4e3b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/proxy/filter/MergeStatFilterTest_tddl_2.java @@ -0,0 +1,78 @@ +/* + * Copyright 1999-2011 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.druid.bvt.proxy.filter; + +import java.sql.Connection; +import java.sql.Statement; +import java.util.Set; + +import javax.management.openmbean.TabularData; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.stat.DruidDataSourceStatManager; +import com.alibaba.druid.stat.JdbcStatManager; +import com.alibaba.druid.support.json.JSONUtils; +import com.alibaba.druid.util.JdbcUtils; + +public class MergeStatFilterTest_tddl_2 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + TabularData sqlList = JdbcStatManager.getInstance().getSqlList(); + if (sqlList.size() > 0) { + for (Object item : JdbcStatManager.getInstance().getSqlList().values()) { + String text = JSONUtils.toJSONString(item); + System.out.println(text); + } + } + + Assert.assertEquals(0, JdbcStatManager.getInstance().getSqlList().size()); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xx"); + dataSource.setFilters("mergeStat"); + dataSource.setDbType("mysql"); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + + Assert.assertEquals(0, JdbcStatManager.getInstance().getSqlList().size()); + } + + public void test_merge() throws Exception { + for (int i = 1000; i < 2000; ++i) { + String tableName = "t" + i; + String sql = "insert into " + tableName + " (fid, fname) values (?, ?)"; + Connection conn = dataSource.getConnection(); + + Statement stmt = conn.createStatement(); + stmt.execute(sql); + stmt.close(); + + conn.close(); + } + + Assert.assertEquals(1, dataSource.getDataSourceStat().getSqlStatMap().size()); + + } + +} From e21b08262b2bcf644f839b21d0028d44e3ebc74e Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 19 May 2013 02:31:24 +0800 Subject: [PATCH 2/4] bug fixed sql runningCount & add statLog support --- .../druid/pool/DruidAbstractDataSource.java | 19 +++ .../alibaba/druid/pool/DruidDataSource.java | 4 +- .../druid/pool/DruidDataSourceMBean.java | 6 + .../pool/DruidDataSourceStatLoggerImpl.java | 106 ++++++++++++++++ .../druid/pool/DruidDataSourceStatValue.java | 119 +++++++++++------- .../alibaba/druid/stat/JdbcSqlStatValue.java | 95 +++++++++++--- 6 files changed, 279 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 690cbdc9c1..6adb7d53bb 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -251,6 +251,25 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements this.useLocalSessionState = useLocalSessionState; } + public DruidDataSourceStatLogger getStatLogger() { + return statLogger; + } + + public void setStatLoggerClassName(String className) { + Class clazz; + try { + clazz = Class.forName(className); + DruidDataSourceStatLogger statLogger = (DruidDataSourceStatLogger) clazz.newInstance(); + this.setStatLogger(statLogger); + } catch (Exception e) { + throw new IllegalArgumentException(className, e); + } + } + + public void setStatLogger(DruidDataSourceStatLogger statLogger) { + this.statLogger = statLogger; + } + public long getTimeBetweenLogStatsMillis() { return timeBetweenLogStatsMillis; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 036e100749..c10d4c0ea5 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -1412,8 +1412,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat value.commitCount = commitCount.getAndSet(0); value.rollbackCount = rollbackCount.getAndSet(0); - value.PSCacheHitCount = cachedPreparedStatementHitCount.getAndSet(0); - value.PSCacheMissCount = cachedPreparedStatementMissCount.getAndSet(0); + value.pstmtCacheHitCount = cachedPreparedStatementHitCount.getAndSet(0); + value.pstmtCacheMissCount = cachedPreparedStatementMissCount.getAndSet(0); value.startTransactionCount = startTransactionCount.getAndSet(0); value.transactionHistogram = this.getTransactionHistogram().toArrayAndReset(); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java index 5e2d5e364c..270de4d309 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java @@ -72,4 +72,10 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { void clearStatementCache() throws SQLException; long getDiscardCount(); + + void setStatLoggerClassName(String className); + + long getTimeBetweenLogStatsMillis(); + + void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis); } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java index 783501f539..0de10684f0 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java @@ -15,11 +15,117 @@ */ package com.alibaba.druid.pool; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.alibaba.druid.stat.JdbcSqlStatValue; +import com.alibaba.druid.support.json.JSONUtils; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + public class DruidDataSourceStatLoggerImpl implements DruidDataSourceStatLogger { + private static Log LOG = LogFactory.getLog(DruidDataSourceStatLoggerImpl.class); + @Override public void log(DruidDataSourceStatValue statValue) { + if (LOG.isInfoEnabled()) { + Map map = new LinkedHashMap(); + map.put("url", statValue.url); + map.put("dbType", statValue.dbType); + map.put("name", statValue.name); + map.put("activeCount", statValue.activeCount); + map.put("activePeak", statValue.activePeak); + + map.put("activePeakTime", statValue.getActivePeakTime()); + map.put("poolingCount", statValue.poolingCount); + map.put("poolingPeak", statValue.poolingPeak); + map.put("poolingPeakTime", statValue.getPoolingPeakTime()); + map.put("connectCount", statValue.connectCount); + + map.put("closeCount", statValue.closeCount); + map.put("waitThreadCount", statValue.waitThreadCount); + map.put("notEmptyWaitCount", statValue.notEmptyWaitCount); + map.put("notEmptyWaitMillis", statValue.getNotEmptyWaitMillis()); + map.put("logicConnectErrorCount", statValue.logicConnectErrorCount); + + map.put("physicalConnectCount", statValue.physicalConnectCount); + map.put("physicalCloseCount", statValue.physicalCloseCount); + map.put("physicalConnectErrorCount", statValue.physicalConnectErrorCount); + map.put("executeCount", statValue.executeCount); + if (statValue.errorCount > 0) { + map.put("errorCount", statValue.errorCount); + } + if (statValue.commitCount > 0) { + map.put("commitCount", statValue.commitCount); + } + if (statValue.rollbackCount > 0) { + map.put("rollbackCount", statValue.rollbackCount); + } + map.put("pstmtCacheHitCount", statValue.pstmtCacheHitCount); + map.put("pstmtCacheMissCount", statValue.pstmtCacheMissCount); + if (statValue.startTransactionCount > 0) { + map.put("startTransactionCount", statValue.startTransactionCount); + map.put("transactionHistogram", statValue.transactionHistogram); + } + map.put("connectionHoldTimeHistogram", statValue.connectionHoldTimeHistogram); + if (statValue.clobOpenCount > 0) { + map.put("clobOpenCount", statValue.clobOpenCount); + } + if (statValue.blobOpenCount > 0) { + map.put("blobOpenCount", statValue.blobOpenCount); + } + + ArrayList> sqlList = new ArrayList>(); + for (JdbcSqlStatValue sqlStat : statValue.sqlList) { + Map sqlStatMap = new LinkedHashMap(); + sqlStatMap.put("sql", sqlStat.sql); + sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); + if (sqlStat.executeErrorCount > 0) { + sqlStatMap.put("executeErrorCount", sqlStat.executeErrorCount); + } + if (sqlStat.runningCount > 0) { + sqlStatMap.put("runningCount", sqlStat.runningCount); + } + sqlStatMap.put("concurrentMax", sqlStat.concurrentMax); + + sqlStatMap.put("executeMillisMax", sqlStat.getExecuteMillisMax()); + sqlStatMap.put("executeMillisTotal", sqlStat.getExecuteMillisTotal()); + + sqlStatMap.put("executeHistogram", sqlStat.getExecuteHistogram()); + sqlStatMap.put("executeAndResultHoldHistogram", sqlStat.getExecuteAndResultHoldHistogram()); + if (sqlStat.fetchRowCount > 0) { + sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCount); + sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCountMax); + sqlStatMap.put("fetchRowHistogram", sqlStat.getFetchRowHistogram()); + } + + if (sqlStat.updateCount > 0) { + sqlStatMap.put("updateCount", sqlStat.updateCount); + sqlStatMap.put("updateCountMax", sqlStat.updateCountMax); + sqlStatMap.put("updateHistogram", sqlStat.getUpdateHistogram()); + } + + if (sqlStat.inTransactionCount > 0) { + sqlStatMap.put("inTransactionCount", sqlStat.inTransactionCount); + } + + if (sqlStat.clobOpenCount > 0) { + sqlStatMap.put("clobOpenCount", sqlStat.clobOpenCount); + } + + if (sqlStat.blobOpenCount > 0) { + sqlStatMap.put("blobOpenCount", sqlStat.blobOpenCount); + } + + } + + String text = JSONUtils.toJSONString(map); + + LOG.info(text); + } } } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java index 05018f9977..524bd2726c 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java @@ -15,63 +15,86 @@ */ package com.alibaba.druid.pool; +import java.util.Date; import java.util.List; import com.alibaba.druid.stat.JdbcSqlStatValue; public class DruidDataSourceStatValue { - public int activeCount; - public int activePeak; - public long activePeakTime; + public String name; + public String dbType; + public String driverClassName; + public String url; + public String userName; + public List filterClassNames; + public boolean removeAbandoned; - public int poolingCount; - public int poolingPeak; - public long poolingPeakTime; + public int initialSize; + public int minIdle; + public int maxActive; + public int queryTimeout; + public int transactionQueryTimeout; + public int loginTimeout; + public String validConnectionCheckerClassName; + public String exceptionSorterClassName; + public boolean testOnBorrow; + public boolean testOnReturn; + public boolean testWhileIdle; + public boolean defaultAutoCommit; + public boolean defaultReadOnly; + public int defaultTransactionIsolation; - public long connectCount; - public long closeCount; - public long waitThreadCount; - public long notEmptyWaitCount; - public long notEmptyWaitNanos; + public int activeCount; + public int activePeak; + public long activePeakTime; - public String name; - public String dbType; - public String driverClassName; - public String url; - public String userName; - public List filterClassNames; + public int poolingCount; + public int poolingPeak; + public long poolingPeakTime; + + public long connectCount; + public long closeCount; + public long waitThreadCount; + public long notEmptyWaitCount; + public long notEmptyWaitNanos; + + public long logicConnectErrorCount; + public long physicalConnectCount; + public long physicalCloseCount; + public long physicalConnectErrorCount; + public long executeCount; + public long errorCount; + public long commitCount; + public long rollbackCount; + public long pstmtCacheHitCount; + public long pstmtCacheMissCount; + public long startTransactionCount; + public long[] transactionHistogram; + public long[] connectionHoldTimeHistogram; + + public long clobOpenCount; + public long blobOpenCount; - public int initialSize; - public int minIdle; - public int maxActive; - public int queryTimeout; - public int transactionQueryTimeout; - public int loginTimeout; - public String validConnectionCheckerClassName; - public String exceptionSorterClassName; - public boolean testOnBorrow; - public boolean testOnReturn; - public boolean testWhileIdle; - public boolean defaultAutoCommit; - public boolean defaultReadOnly; - public int defaultTransactionIsolation; - public long logicConnectErrorCount; - public long physicalConnectCount; - public long physicalCloseCount; - public long physicalConnectErrorCount; - public long executeCount; - public long errorCount; - public long commitCount; - public long rollbackCount; - public long PSCacheHitCount; - public long PSCacheMissCount; - public long startTransactionCount; - public long[] transactionHistogram; - public long[] connectionHoldTimeHistogram; - public boolean removeAbandoned; - public long clobOpenCount; - public long blobOpenCount; - public List sqlList; + + public Date getPoolingPeakTime() { + if (poolingPeakTime <= 0) { + return null; + } + + return new Date(poolingPeakTime); + } + + public Date getActivePeakTime() { + if (activePeakTime <= 0) { + return null; + } + + return new Date(activePeakTime); + } + + public long getNotEmptyWaitMillis() { + return notEmptyWaitNanos / (1000 * 1000); + } } diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java index 67b8a7b5fb..751aafb0cf 100644 --- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java +++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStatValue.java @@ -69,27 +69,82 @@ public class JdbcSqlStatValue { public int histogram_100000_1000000; public int histogram_1000000_more; - public long executeAndResultHoldTime_0_1; - public long executeAndResultHoldTime_1_10; - public int executeAndResultHoldTime_10_100; - public int executeAndResultHoldTime_100_1000; - public int executeAndResultHoldTime_1000_10000; - public int executeAndResultHoldTime_10000_100000; - public int executeAndResultHoldTime_100000_1000000; - public int executeAndResultHoldTime_1000000_more; + public long[] getExecuteHistogram() { + return new long[] { histogram_0_1, // + histogram_1_10, // + histogram_10_100, // + histogram_100_1000, // + histogram_1000_10000, // + histogram_10000_100000, // + histogram_100000_1000000, // + histogram_1000000_more, // + }; + } - public long fetchRowCount_0_1; - public long fetchRowCount_1_10; - public long fetchRowCount_10_100; - public int fetchRowCount_100_1000; - public int fetchRowCount_1000_10000; - public int fetchRowCount_10000_more; + public long executeAndResultHoldTime_0_1; + public long executeAndResultHoldTime_1_10; + public int executeAndResultHoldTime_10_100; + public int executeAndResultHoldTime_100_1000; + public int executeAndResultHoldTime_1000_10000; + public int executeAndResultHoldTime_10000_100000; + public int executeAndResultHoldTime_100000_1000000; + public int executeAndResultHoldTime_1000000_more; - public long updateCount_0_1; - public long updateCount_1_10; - public long updateCount_10_100; - public int updateCount_100_1000; - public int updateCount_1000_10000; - public int updateCount_10000_more; + public long[] getExecuteAndResultHoldHistogram() { + return new long[] { executeAndResultHoldTime_0_1, // + executeAndResultHoldTime_1_10, // + executeAndResultHoldTime_10_100, // + executeAndResultHoldTime_100_1000, // + executeAndResultHoldTime_1000_10000, // + executeAndResultHoldTime_10000_100000, // + executeAndResultHoldTime_100000_1000000, // + executeAndResultHoldTime_1000000_more, // + }; + } + public long fetchRowCount_0_1; + public long fetchRowCount_1_10; + public long fetchRowCount_10_100; + public int fetchRowCount_100_1000; + public int fetchRowCount_1000_10000; + public int fetchRowCount_10000_more; + + public long[] getFetchRowHistogram() { + return new long[] { fetchRowCount_0_1, // + fetchRowCount_1_10, // + fetchRowCount_10_100, // + fetchRowCount_100_1000, // + fetchRowCount_1000_10000, // + fetchRowCount_10000_more, // + }; + } + + public long updateCount_0_1; + public long updateCount_1_10; + public long updateCount_10_100; + public int updateCount_100_1000; + public int updateCount_1000_10000; + public int updateCount_10000_more; + + public long[] getUpdateHistogram() { + return new long[] { updateCount_0_1, // + updateCount_1_10, // + updateCount_10_100, // + updateCount_100_1000, // + updateCount_1000_10000, // + updateCount_10000_more, // + }; + } + + public long getExecuteCount() { + return executeErrorCount + executeSuccessCount; + } + + public long getExecuteMillisMax() { + return executeSpanNanoMax / (1000 * 1000); + } + + public long getExecuteMillisTotal() { + return executeSpanNanoTotal / (1000 * 1000); + } } From 9a892241ea886a68414a7538b929d8211cc60f53 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 19 May 2013 17:13:45 +0800 Subject: [PATCH 3/4] support logStats --- .../alibaba/druid/pool/DruidDataSource.java | 28 ++-- .../pool/DruidDataSourceStatLoggerImpl.java | 137 +++++++++++------- .../druid/pool/DruidDataSourceStatValue.java | 2 +- .../com/alibaba/druid/stat/JdbcSqlStat.java | 1 + .../druid/support/logging/SLF4JImpl.java | 1 + .../com/alibaba/druid/util/Histogram.java | 3 +- .../alibaba/druid/util/JdbcSqlStatUtils.java | 16 ++ .../pool/TimeBetweenLogStatsMillisTest2.java | 30 ++++ .../pool/TimeBetweenLogStatsMillisTest3.java | 46 ++++++ 9 files changed, 203 insertions(+), 61 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest2.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest3.java diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index c10d4c0ea5..1db4b9488d 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -82,6 +82,7 @@ import com.alibaba.druid.util.JdbcUtils; import com.alibaba.druid.util.StringUtils; import com.alibaba.druid.wall.WallFilter; +; /** * @author ljw * @author wenshao @@ -176,14 +177,23 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat { String property = System.getProperty("druid.filters"); - if (property == null || property.length() == 0) { - return; + if (property != null && property.length() > 0) { + try { + this.setFilters(property); + } catch (SQLException e) { + LOG.error("setFilters error", e); + } } - - try { - this.setFilters(property); - } catch (SQLException e) { - LOG.error("setFilters error", e); + } + { + String property = System.getProperty("druid.timeBetweenLogStatsMillis"); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setTimeBetweenLogStatsMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property 'timeBetweenLogStatsMillis'", e); + } } } } @@ -1336,9 +1346,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (statLogger == null) { return; } - + DruidDataSourceStatValue statValue = getStatValueAndReset(); - + statLogger.log(statValue); } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java index 0de10684f0..f60a6417bc 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java @@ -15,6 +15,8 @@ */ package com.alibaba.druid.pool; +import static com.alibaba.druid.util.JdbcSqlStatUtils.rtrim; + import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; @@ -37,24 +39,43 @@ public class DruidDataSourceStatLoggerImpl implements DruidDataSourceStatLogger map.put("dbType", statValue.dbType); map.put("name", statValue.name); map.put("activeCount", statValue.activeCount); - map.put("activePeak", statValue.activePeak); - map.put("activePeakTime", statValue.getActivePeakTime()); + if (statValue.activePeak > 0) { + map.put("activePeak", statValue.activePeak); + map.put("activePeakTime", statValue.getActivePeakTime()); + } map.put("poolingCount", statValue.poolingCount); - map.put("poolingPeak", statValue.poolingPeak); - map.put("poolingPeakTime", statValue.getPoolingPeakTime()); + if (statValue.poolingPeak > 0) { + map.put("poolingPeak", statValue.poolingPeak); + map.put("poolingPeakTime", statValue.getPoolingPeakTime()); + } map.put("connectCount", statValue.connectCount); - map.put("closeCount", statValue.closeCount); - map.put("waitThreadCount", statValue.waitThreadCount); - map.put("notEmptyWaitCount", statValue.notEmptyWaitCount); - map.put("notEmptyWaitMillis", statValue.getNotEmptyWaitMillis()); - map.put("logicConnectErrorCount", statValue.logicConnectErrorCount); - map.put("physicalConnectCount", statValue.physicalConnectCount); - map.put("physicalCloseCount", statValue.physicalCloseCount); - map.put("physicalConnectErrorCount", statValue.physicalConnectErrorCount); - map.put("executeCount", statValue.executeCount); + if (statValue.waitThreadCount > 0) { + map.put("waitThreadCount", statValue.waitThreadCount); + } + if (statValue.notEmptyWaitCount > 0) { + map.put("notEmptyWaitCount", statValue.notEmptyWaitCount); + } + if (statValue.getNotEmptyWaitMillis() > 0) { + map.put("notEmptyWaitMillis", statValue.getNotEmptyWaitMillis()); + } + if (statValue.logicConnectErrorCount > 0) { + map.put("logicConnectErrorCount", statValue.logicConnectErrorCount); + } + if (statValue.physicalConnectCount > 0) { + map.put("physicalConnectCount", statValue.physicalConnectCount); + } + if (statValue.physicalCloseCount > 0) { + map.put("physicalCloseCount", statValue.physicalCloseCount); + } + if (statValue.physicalConnectErrorCount > 0) { + map.put("physicalConnectErrorCount", statValue.physicalConnectErrorCount); + } + if (statValue.executeCount > 0) { + map.put("executeCount", statValue.executeCount); + } if (statValue.errorCount > 0) { map.put("errorCount", statValue.errorCount); } @@ -64,13 +85,19 @@ public class DruidDataSourceStatLoggerImpl implements DruidDataSourceStatLogger if (statValue.rollbackCount > 0) { map.put("rollbackCount", statValue.rollbackCount); } - map.put("pstmtCacheHitCount", statValue.pstmtCacheHitCount); - map.put("pstmtCacheMissCount", statValue.pstmtCacheMissCount); + if (statValue.pstmtCacheHitCount > 0) { + map.put("pstmtCacheHitCount", statValue.pstmtCacheHitCount); + } + if (statValue.pstmtCacheMissCount > 0) { + map.put("pstmtCacheMissCount", statValue.pstmtCacheMissCount); + } if (statValue.startTransactionCount > 0) { map.put("startTransactionCount", statValue.startTransactionCount); - map.put("transactionHistogram", statValue.transactionHistogram); + map.put("transactionHistogram", rtrim(statValue.transactionHistogram)); + } + if (statValue.connectCount > 0) { + map.put("connectionHoldTimeHistogram", rtrim(statValue.connectionHoldTimeHistogram)); } - map.put("connectionHoldTimeHistogram", statValue.connectionHoldTimeHistogram); if (statValue.clobOpenCount > 0) { map.put("clobOpenCount", statValue.clobOpenCount); } @@ -79,47 +106,57 @@ public class DruidDataSourceStatLoggerImpl implements DruidDataSourceStatLogger } ArrayList> sqlList = new ArrayList>(); - for (JdbcSqlStatValue sqlStat : statValue.sqlList) { - Map sqlStatMap = new LinkedHashMap(); - sqlStatMap.put("sql", sqlStat.sql); - sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); - if (sqlStat.executeErrorCount > 0) { - sqlStatMap.put("executeErrorCount", sqlStat.executeErrorCount); - } - if (sqlStat.runningCount > 0) { - sqlStatMap.put("runningCount", sqlStat.runningCount); - } - sqlStatMap.put("concurrentMax", sqlStat.concurrentMax); + if (statValue.sqlList.size() > 0) { + for (JdbcSqlStatValue sqlStat : statValue.sqlList) { + Map sqlStatMap = new LinkedHashMap(); + sqlStatMap.put("sql", sqlStat.sql); - sqlStatMap.put("executeMillisMax", sqlStat.getExecuteMillisMax()); - sqlStatMap.put("executeMillisTotal", sqlStat.getExecuteMillisTotal()); + if (sqlStat.getExecuteCount() > 0) { + sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); + sqlStatMap.put("executeMillisMax", sqlStat.getExecuteMillisMax()); + sqlStatMap.put("executeMillisTotal", sqlStat.getExecuteMillisTotal()); - sqlStatMap.put("executeHistogram", sqlStat.getExecuteHistogram()); - sqlStatMap.put("executeAndResultHoldHistogram", sqlStat.getExecuteAndResultHoldHistogram()); - if (sqlStat.fetchRowCount > 0) { - sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCount); - sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCountMax); - sqlStatMap.put("fetchRowHistogram", sqlStat.getFetchRowHistogram()); - } + sqlStatMap.put("executeHistogram", rtrim(sqlStat.getExecuteHistogram())); + sqlStatMap.put("executeAndResultHoldHistogram", + rtrim(sqlStat.getExecuteAndResultHoldHistogram())); + } - if (sqlStat.updateCount > 0) { - sqlStatMap.put("updateCount", sqlStat.updateCount); - sqlStatMap.put("updateCountMax", sqlStat.updateCountMax); - sqlStatMap.put("updateHistogram", sqlStat.getUpdateHistogram()); - } + if (sqlStat.executeErrorCount > 0) { + sqlStatMap.put("executeErrorCount", sqlStat.executeErrorCount); + } + if (sqlStat.runningCount > 0) { + sqlStatMap.put("runningCount", sqlStat.runningCount); + } + sqlStatMap.put("concurrentMax", sqlStat.concurrentMax); - if (sqlStat.inTransactionCount > 0) { - sqlStatMap.put("inTransactionCount", sqlStat.inTransactionCount); - } + if (sqlStat.fetchRowCount > 0) { + sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCount); + sqlStatMap.put("fetchRowCount", sqlStat.fetchRowCountMax); + sqlStatMap.put("fetchRowHistogram", rtrim(sqlStat.getFetchRowHistogram())); + } - if (sqlStat.clobOpenCount > 0) { - sqlStatMap.put("clobOpenCount", sqlStat.clobOpenCount); - } + if (sqlStat.updateCount > 0) { + sqlStatMap.put("updateCount", sqlStat.updateCount); + sqlStatMap.put("updateCountMax", sqlStat.updateCountMax); + sqlStatMap.put("updateHistogram", rtrim(sqlStat.getUpdateHistogram())); + } - if (sqlStat.blobOpenCount > 0) { - sqlStatMap.put("blobOpenCount", sqlStat.blobOpenCount); + if (sqlStat.inTransactionCount > 0) { + sqlStatMap.put("inTransactionCount", sqlStat.inTransactionCount); + } + + if (sqlStat.clobOpenCount > 0) { + sqlStatMap.put("clobOpenCount", sqlStat.clobOpenCount); + } + + if (sqlStat.blobOpenCount > 0) { + sqlStatMap.put("blobOpenCount", sqlStat.blobOpenCount); + } + + sqlList.add(sqlStatMap); } + map.put("sqlList", sqlList); } String text = JSONUtils.toJSONString(map); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java index 524bd2726c..5f7f717962 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatValue.java @@ -43,7 +43,7 @@ public class DruidDataSourceStatValue { public boolean testWhileIdle; public boolean defaultAutoCommit; public boolean defaultReadOnly; - public int defaultTransactionIsolation; + public Integer defaultTransactionIsolation; public int activeCount; public int activePeak; diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java index 7d5943f256..74a9dc0fbf 100644 --- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java +++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java @@ -382,6 +382,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean { public JdbcSqlStatValue getValueAndReset() { JdbcSqlStatValue val = new JdbcSqlStatValue(); + val.sql = sql; val.executeLastStartTime = executeLastStartTime; executeLastStartTime = 0; diff --git a/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java b/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java index 81fc923eaa..cc5ab7e659 100644 --- a/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java @@ -66,6 +66,7 @@ public class SLF4JImpl implements Log { @Override public void info(String msg) { infoCount++; + log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null); } @Override diff --git a/src/main/java/com/alibaba/druid/util/Histogram.java b/src/main/java/com/alibaba/druid/util/Histogram.java index 468985297b..6934202b91 100644 --- a/src/main/java/com/alibaba/druid/util/Histogram.java +++ b/src/main/java/com/alibaba/druid/util/Histogram.java @@ -76,12 +76,13 @@ public class Histogram { } return array; } - + public long[] toArrayAndReset() { long[] array = new long[rangeCounters.length()]; for (int i = 0; i < rangeCounters.length(); i++) { array[i] = rangeCounters.getAndSet(i, 0); } + return array; } diff --git a/src/main/java/com/alibaba/druid/util/JdbcSqlStatUtils.java b/src/main/java/com/alibaba/druid/util/JdbcSqlStatUtils.java index ba3ab0b267..1e9c99cb58 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcSqlStatUtils.java +++ b/src/main/java/com/alibaba/druid/util/JdbcSqlStatUtils.java @@ -16,6 +16,7 @@ package com.alibaba.druid.util; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Map; import com.alibaba.druid.stat.JdbcSqlStat; @@ -41,4 +42,19 @@ public class JdbcSqlStatUtils { return null; } } + + public static long[] rtrim(long[] array) { + int notZeroLen = array.length; + for (int i = array.length - 1; i >= 0; --i, notZeroLen--) { + if (array[i] != 0) { + break; + } + } + + if (notZeroLen != array.length) { + array = Arrays.copyOf(array, notZeroLen); + } + + return array; + } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest2.java b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest2.java new file mode 100644 index 0000000000..5eef91891b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest2.java @@ -0,0 +1,30 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.JdbcUtils; + +public class TimeBetweenLogStatsMillisTest2 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + System.setProperty("druid.timeBetweenLogStatsMillis", "1000"); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + System.clearProperty("druid.timeBetweenLogStatsMillis"); + } + + public void test_0() throws Exception { + dataSource.init(); + Assert.assertEquals(1000, dataSource.getTimeBetweenLogStatsMillis()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest3.java b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest3.java new file mode 100644 index 0000000000..4373f3b495 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/TimeBetweenLogStatsMillisTest3.java @@ -0,0 +1,46 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.JdbcUtils; + +public class TimeBetweenLogStatsMillisTest3 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + System.setProperty("druid.timeBetweenLogStatsMillis", "10"); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setFilters("stat"); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + System.clearProperty("druid.timeBetweenLogStatsMillis"); + } + + public void test_0() throws Exception { + dataSource.init(); + for (int i = 0; i < 10; ++i) { + Connection conn = dataSource.getConnection(); + PreparedStatement stmt = conn.prepareStatement("select ?"); + stmt.setString(1, "aaa"); + ResultSet rs = stmt.executeQuery(); + rs.close(); + stmt.close(); + conn.close(); + + Thread.sleep(10); + } + Assert.assertEquals(10, dataSource.getTimeBetweenLogStatsMillis()); + } +} From 39895d814054084d6c22773dc85aef94d540c632 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 19 May 2013 18:47:33 +0800 Subject: [PATCH 4/4] 0.2.19 --- pom.xml | 2 +- src/main/java/com/alibaba/druid/VERSION.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c85f241923..688d2c145b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.alibaba druid - 0.2.19-SNAPSHOT + 0.2.19 jar druid diff --git a/src/main/java/com/alibaba/druid/VERSION.java b/src/main/java/com/alibaba/druid/VERSION.java index f9dfab2ea6..4e81edcb72 100644 --- a/src/main/java/com/alibaba/druid/VERSION.java +++ b/src/main/java/com/alibaba/druid/VERSION.java @@ -19,7 +19,7 @@ public final class VERSION { public final static int MajorVersion = 0; public final static int MinorVersion = 2; - public final static int RevisionVersion = 18; + public final static int RevisionVersion = 19; public static String getVersionNumber() { return VERSION.MajorVersion + "." + VERSION.MinorVersion + "." + VERSION.RevisionVersion;