diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index d3e6821417..9477ed6eca 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -143,7 +143,7 @@ public abstract class DruidAbstractDataSource implements DruidAbstractDataSource protected boolean removeAbandoned; - protected int removeAbandonedTimeoutMillis; + protected long removeAbandonedTimeoutMillis; protected boolean logAbandoned; @@ -283,18 +283,18 @@ public abstract class DruidAbstractDataSource implements DruidAbstractDataSource } public int getRemoveAbandonedTimeout() { - return removeAbandonedTimeoutMillis / 1000; + return (int) (removeAbandonedTimeoutMillis / 1000); } public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { this.removeAbandonedTimeoutMillis = removeAbandonedTimeout * 1000; } - public void setRemoveAbandonedTimeoutMillis(int removeAbandonedTimeoutMillis) { + public void setRemoveAbandonedTimeoutMillis(long removeAbandonedTimeoutMillis) { this.removeAbandonedTimeoutMillis = removeAbandonedTimeoutMillis; } - public int getRemoveAbandonedTimeoutMillis() { + public long getRemoveAbandonedTimeoutMillis() { return removeAbandonedTimeoutMillis; } diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java index 54ed369f73..35486294a1 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSourceMBean.java @@ -48,7 +48,7 @@ public interface DruidAbstractDataSourceMBean { boolean isRemoveAbandoned(); - int getRemoveAbandonedTimeoutMillis(); + long getRemoveAbandonedTimeoutMillis(); List getActiveConnectionStackTrace(); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index be115fb41a..946d16d7a3 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -818,41 +818,51 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat shrink(true); if (isRemoveAbandoned()) { - Iterator> iter = activeConnections.entrySet().iterator(); - - long currentMillis = System.currentTimeMillis(); - - for (; iter.hasNext();) { - Map.Entry entry = iter.next(); - ActiveConnectionTraceInfo activeInfo = entry.getValue(); - long timeMillis = activeInfo.getConnectTime() - currentMillis; - - if (timeMillis >= removeAbandonedTimeoutMillis) { - PoolableConnection pooledConnection = entry.getKey(); - JdbcUtils.close(pooledConnection); - removeAbandonedCount++; - - if (isLogAbandoned()) { - StringBuilder buf = new StringBuilder(); - buf.append("abandon connection, open stackTrace\n"); - - StackTraceElement[] trace = activeInfo.getStackTrace(); - for (int i = 0; i < trace.length; i++) { - buf.append("\tat "); - buf.append(trace[i].toString()); - buf.append("\n"); - } - - LOG.error(buf.toString()); - } - } - } + removeAbandoned(); } } catch (InterruptedException e) { break; } } } + + } + + public int removeAbandoned() { + int removeCount = 0; + + Iterator> iter = activeConnections.entrySet().iterator(); + + long currentMillis = System.currentTimeMillis(); + + for (; iter.hasNext();) { + Map.Entry entry = iter.next(); + ActiveConnectionTraceInfo activeInfo = entry.getValue(); + long timeMillis = activeInfo.getConnectTime() - currentMillis; + + if (timeMillis >= removeAbandonedTimeoutMillis) { + PoolableConnection pooledConnection = entry.getKey(); + JdbcUtils.close(pooledConnection); + removeAbandonedCount++; + removeCount++; + + if (isLogAbandoned()) { + StringBuilder buf = new StringBuilder(); + buf.append("abandon connection, open stackTrace\n"); + + StackTraceElement[] trace = activeInfo.getStackTrace(); + for (int i = 0; i < trace.length; i++) { + buf.append("\tat "); + buf.append(trace[i].toString()); + buf.append("\n"); + } + + LOG.error(buf.toString()); + } + } + } + + return removeCount; } public DataSourceProxyConfig getConfig() { diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java index 186efab4fc..a91ce40578 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java @@ -24,6 +24,8 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { void shrink(); + int removeAbandoned(); + String toString(); int getWaitThreadCount(); @@ -31,7 +33,7 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { int getLockQueueLength(); long getNotEmptyWaitCount(); - + long getNotEmptySignalCount(); long getNotEmptyWaitMillis(); @@ -39,10 +41,10 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { long getNotEmptyWaitNanos(); void resetStat(); - + boolean isResetStatEnable(); - + void setResetStatEnable(boolean resetStatEnable); - + String getVersion(); } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_Starvation.java b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_Starvation.java index 59b17fc19b..b6adf3ad9d 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_Starvation.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestIdle3_Concurrent_Starvation.java @@ -1,13 +1,12 @@ package com.alibaba.druid.bvt.pool; -import java.lang.management.ManagementFactory; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicInteger; -import javax.management.ObjectName; - import junit.framework.Assert; import junit.framework.TestCase; @@ -35,9 +34,9 @@ public class TestIdle3_Concurrent_Starvation extends TestCase { dataSource.setTestOnBorrow(false); dataSource.setValidationQuery("SELECT 1"); dataSource.setFilters("stat"); - + } - + protected void tearDown() throws Exception { dataSource.close(); } @@ -83,10 +82,11 @@ public class TestIdle3_Concurrent_Starvation extends TestCase { Thread[] threads = new Thread[threadCount]; final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch endLatch = new CountDownLatch(threadCount); - + final AtomicInteger pass = new AtomicInteger(); final CyclicBarrier closedBarrier = new CyclicBarrier(threadCount, new Runnable() { + public void run() { Assert.assertEquals(threadCount, dataSource.getPoolingCount()); dataSource.shrink(false); @@ -98,6 +98,7 @@ public class TestIdle3_Concurrent_Starvation extends TestCase { } }); final CyclicBarrier closeBarrier = new CyclicBarrier(threadCount, new Runnable() { + public void run() { Assert.assertEquals(threadCount, dataSource.getActiveCount()); } @@ -110,10 +111,14 @@ public class TestIdle3_Concurrent_Starvation extends TestCase { try { startLatch.await(); for (int i = 0; i < 1000 * 1; ++i) { - + Connection conn = dataSource.getConnection(); closeBarrier.await(); - + PreparedStatement stmt = conn.prepareStatement("SELECT 1"); + ResultSet rs = stmt.executeQuery(); + rs.next(); + rs.close(); + stmt.close(); conn.close(); closedBarrier.await(); } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/TestStat.java b/src/test/java/com/alibaba/druid/bvt/pool/TestStat.java index 7f22b7d69a..ef3e920b9a 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/TestStat.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/TestStat.java @@ -19,6 +19,8 @@ public class TestStat extends TestCase { dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mock:xxx"); dataSource.setName("com.alibaba.dragoon.monitor"); + dataSource.setMinIdle(0); + dataSource.setPoolPreparedStatements(false); } @@ -44,6 +46,8 @@ public class TestStat extends TestCase { rs.close(); stmt.close(); + dataSource.shrink(); + JdbcStatManager.getInstance().getDataSourceList(); Assert.assertEquals(1, DruidDataSourceStatManager.getInstance().getDataSourceList().size());