diff --git a/src/main/java/com/alibaba/druid/mock/MockConnection.java b/src/main/java/com/alibaba/druid/mock/MockConnection.java index a9411163a7..6e69d46bca 100644 --- a/src/main/java/com/alibaba/druid/mock/MockConnection.java +++ b/src/main/java/com/alibaba/druid/mock/MockConnection.java @@ -52,6 +52,8 @@ public class MockConnection implements Connection { private Properties connectProperties; + private long id; + public MockConnection(){ this(null); } @@ -63,6 +65,12 @@ public class MockConnection implements Connection { public MockConnection(MockDriver driver, Properties connectProperties){ this.driver = driver; this.connectProperties = connectProperties; + + this.id = driver.generateConnectionId(); + } + + public long getId() { + return id; } public MockDriver getDriver() { @@ -145,7 +153,7 @@ public class MockConnection implements Connection { @Override public boolean isClosed() throws SQLException { if (LOG.isDebugEnabled()) { - LOG.debug("check close " + closed); + LOG.debug("conn-" + id + " isClose : " + closed); } return closed; diff --git a/src/main/java/com/alibaba/druid/mock/MockDriver.java b/src/main/java/com/alibaba/druid/mock/MockDriver.java index ac89a537cd..05d44f400d 100644 --- a/src/main/java/com/alibaba/druid/mock/MockDriver.java +++ b/src/main/java/com/alibaba/druid/mock/MockDriver.java @@ -51,12 +51,18 @@ public class MockDriver implements Driver { private final AtomicLong connectCount = new AtomicLong(); private final AtomicLong connectionCloseCount = new AtomicLong(); + private final AtomicLong connectionIdSeed = new AtomicLong(1000L); + private final List connections = new CopyOnWriteArrayList(); static { registerDriver(instance); } + public long generateConnectionId() { + return connectionIdSeed.incrementAndGet(); + } + public List getConnections() { return connections; } @@ -75,7 +81,7 @@ public class MockDriver implements Driver { connections.remove(conn); if (LOG.isDebugEnabled()) { - LOG.debug("close"); + LOG.debug("conn-" + conn.getId() + " close"); } } @@ -183,7 +189,7 @@ public class MockDriver implements Driver { if (LOG.isDebugEnabled()) { LOG.debug("executeQuery " + sql); } - + MockConnection conn = stmt.getMockConnection(); if (conn != null) { diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 46ef345f58..507cc44840 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -72,7 +72,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private final Condition notEmpty = lock.newCondition(); private final Condition notMaxActive = lock.newCondition(); private final Condition lowWater = lock.newCondition(); - private final Condition idleTimeout = lock.newCondition(); // stats private long connectCount = 0; @@ -692,6 +691,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat initedLatch.countDown(); final List evictList = new ArrayList(); + final List idleList = new ArrayList(); + List checkList = new ArrayList(); FOR_0: for (;;) { // 从前面开始删除 try { @@ -719,7 +720,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat numTestsPerEvictionRun = 1; } - FOR_1: for (int i = 0; i < numTestsPerEvictionRun; ++i) { + for (int i = 0; i < numTestsPerEvictionRun; ++i) { ConnectionHolder connection = connections[i]; if (evictCount == 0 && idleCount == 0 && connection == null) { @@ -727,63 +728,49 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } long idleMillis = System.currentTimeMillis() - connection.getLastActiveMillis(); - if (idleMillis < minEvictableIdleTimeMillis) { - if (evictCount == 0 && idleCount == 0) { - long waitMillis = minEvictableIdleTimeMillis - idleMillis; - idleTimeout.await(waitMillis, TimeUnit.MILLISECONDS); - continue FOR_0; - } - break FOR_1; - } - - if (count > minIdle + evictCount) { - evictCount++; + if (idleMillis >= minEvictableIdleTimeMillis) { + evictList.add(connection); } else { - idleCount++; + idleList.add(connection); } } - - if (evictCount > 0) { - for (int i = 0; i < evictCount; ++i) { - evictList.add(connections[i]); - } - System.arraycopy(connections, evictCount, connections, 0, count - evictCount); - for (int i = 0; i < evictCount; ++i) { - connections[--count] = null; - } - } - - if (idleCount > 0 && isTestWhileIdle()) { - ConnectionHolder[] idleConnections = new ConnectionHolder[idleCount]; - System.arraycopy(connections, 0, idleConnections, 0, idleCount); - System.arraycopy(connections, idleCount, connections, 0, count - idleCount); - for (int i = 0; i < idleCount; ++i) { - connections[--count] = null; - } - - for (ConnectionHolder idleConnection : idleConnections) { - if (testConnectionInternal(idleConnection.getConnection())) { - connections[count++] = idleConnection; - idleConnection.setLastActiveMillis(System.currentTimeMillis()); - idleCheckCount++; - } else { - evictList.add(idleConnection); - } - } + System.arraycopy(connections, numTestsPerEvictionRun, connections, 0, count - numTestsPerEvictionRun); + for (int i = 0; i < numTestsPerEvictionRun; ++i) { + connections[--count] = null; } } finally { lock.unlock(); } - for (ConnectionHolder item : evictList) { - Connection connection = item.getConnection(); - try { - connection.close(); - destroyCount++; - } catch (SQLException e) { - LOG.error("create connection error", e); + for (ConnectionHolder idleConnection : idleList) { + if (!testConnectionInternal(idleConnection.getConnection())) { + evictList.add(idleConnection); + } else { + checkList.add(idleConnection); } } + + int size = checkList.size(); + if (size > 0) { + lock.lock(); + try { + for (int i = 0; i < size; ++i) { + ConnectionHolder connection = checkList.get(i); + connections[count++] = connection; + } + } finally { + lock.unlock(); + } + } + + for (ConnectionHolder item : evictList) { + Connection connection = item.getConnection(); + JdbcUtils.close(connection); + destroyCount++; + } + + idleList.clear(); + checkList.clear(); evictList.clear(); } catch (InterruptedException e) { break; diff --git a/src/test/java/com/alibaba/druid/pool/dbcp/TestIdle.java b/src/test/java/com/alibaba/druid/pool/dbcp/TestIdle.java index a387c784d2..28fadb2cb2 100644 --- a/src/test/java/com/alibaba/druid/pool/dbcp/TestIdle.java +++ b/src/test/java/com/alibaba/druid/pool/dbcp/TestIdle.java @@ -1,30 +1,33 @@ package com.alibaba.druid.pool.dbcp; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; -import junit.framework.Assert; import junit.framework.TestCase; import org.apache.commons.dbcp.BasicDataSource; import com.alibaba.druid.mock.MockConnection; import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DruidDataSource; public class TestIdle extends TestCase { public void test_idle() throws Exception { MockDriver driver = MockDriver.instance; - BasicDataSource dataSource = new BasicDataSource(); +// BasicDataSource dataSource = new BasicDataSource(); + DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl("jdbc:mock:xxx"); dataSource.setDriverClassName("com.alibaba.druid.mock.MockDriver"); - dataSource.setInitialSize(0); + dataSource.setInitialSize(1); dataSource.setMaxActive(4); dataSource.setMaxIdle(4); - dataSource.setMinIdle(1); - dataSource.setMinEvictableIdleTimeMillis(50 * 1); - dataSource.setTimeBetweenEvictionRunsMillis(10); - dataSource.setTestWhileIdle(false); + dataSource.setMinIdle(0); + dataSource.setMinEvictableIdleTimeMillis(5000 * 1); + dataSource.setTimeBetweenEvictionRunsMillis(1000); + dataSource.setTestWhileIdle(true); dataSource.setTestOnBorrow(false); dataSource.setValidationQuery("SELECT 1"); @@ -34,10 +37,15 @@ public class TestIdle extends TestCase { // Assert.assertEquals(dataSource.getInitialSize(), driver.getConnections().size()); System.out.println("raw size : " + driver.getConnections().size()); + PreparedStatement stmt = conn.prepareStatement("SELECT 1"); + ResultSet rs = stmt.executeQuery(); + rs.close(); + stmt.close(); + conn.close(); System.out.println("raw size : " + driver.getConnections().size()); } - + { Connection conn = dataSource.getConnection(); @@ -60,7 +68,7 @@ public class TestIdle extends TestCase { } System.out.println("raw size : " + driver.getConnections().size()); - System.out.println("----------sleep for evict"); + System.out.println("----------sleep for evict"); Thread.sleep(dataSource.getMinEvictableIdleTimeMillis() * 2); System.out.println("raw size : " + driver.getConnections().size()); }