From b66c366f93da2a7cd7324c7bb4ee9c08a748d7b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E9=93=81?= Date: Fri, 11 Mar 2016 21:26:40 +0800 Subject: [PATCH] support maxEvictableIdleTimeMillis --- .../druid/pool/DruidAbstractDataSource.java | 22 ++++- .../alibaba/druid/pool/DruidDataSource.java | 76 ++++++++++++---- .../basic/MaxEvictableIdleTimeMillisTest.java | 86 +++++++++++++++++++ .../MaxEvictableIdleTimeMillisTest2.java | 49 +++++++++++ .../bvt/pool/dynamic/MaxActiveChangeTest.java | 25 +++--- .../bvt/sql/schemaStat/SchemaStatTest2.java | 33 +++++++ 6 files changed, 263 insertions(+), 28 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest2.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest2.java diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index 6a56cb01d9..82ce628163 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -97,7 +97,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements * @see #setMinEvictableIdleTimeMillis */ public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L; - public static final long DEFAULT_PHY_TIMEOUT_MILLIS = 1000L * 60L * 60L * 7; + public static final long DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 60L * 7; + public static final long DEFAULT_PHY_TIMEOUT_MILLIS = -1; protected volatile boolean defaultAutoCommit = true; protected volatile Boolean defaultReadOnly; @@ -159,6 +160,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements protected volatile int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; protected volatile long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + protected volatile long maxEvictableIdleTimeMillis = DEFAULT_MAX_EVICTABLE_IDLE_TIME_MILLIS; protected volatile long phyTimeoutMillis = DEFAULT_PHY_TIMEOUT_MILLIS; @@ -692,8 +694,26 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements if (minEvictableIdleTimeMillis < 1000 * 30) { LOG.error("minEvictableIdleTimeMillis should be greater than 30000"); } + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } + + public long getMaxEvictableIdleTimeMillis() { + return maxEvictableIdleTimeMillis; + } + + + public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) { + if (maxEvictableIdleTimeMillis < 1000 * 30) { + LOG.error("maxEvictableIdleTimeMillis should be greater than 30000"); + } + + if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) { + throw new IllegalArgumentException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis"); + } + + this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis; + } public long getPhyTimeoutMillis() { return phyTimeoutMillis; diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 2820c557ae..c4b1ba49c1 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -53,6 +53,8 @@ import javax.sql.ConnectionEventListener; import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; +import org.apache.ibatis.jdbc.SQL; + import com.alibaba.druid.Constants; import com.alibaba.druid.TransactionTimeoutException; import com.alibaba.druid.VERSION; @@ -283,6 +285,39 @@ public class DruidDataSource extends DruidAbstractDataSource this.setFailFast(value); } } + { + String property = properties.getProperty("druid.phyTimeoutMillis"); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setPhyTimeoutMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property 'druid.phyTimeoutMillis'", e); + } + } + } + { + String property = properties.getProperty("druid.minEvictableIdleTimeMillis"); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setMinEvictableIdleTimeMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property 'druid.minEvictableIdleTimeMillis'", e); + } + } + } + { + String property = properties.getProperty("druid.maxEvictableIdleTimeMillis"); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setMaxEvictableIdleTimeMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property 'druid.maxEvictableIdleTimeMillis'", e); + } + } + } } public boolean isUseGlobalDataSourceStat() { @@ -541,8 +576,6 @@ public class DruidDataSource extends DruidAbstractDataSource return; } - init = true; - initStackTrace = Utils.toString(Thread.currentThread().getStackTrace()); this.id = DruidDriver.createDataSourceId(); @@ -589,13 +622,16 @@ public class DruidDataSource extends DruidAbstractDataSource } if (getInitialSize() > maxActive) { - throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " - + maxActive); + throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " + maxActive); } if (timeBetweenLogStatsMillis > 0 && useGlobalDataSourceStat) { throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGlobalDataSourceStat=true"); } + + if (maxEvictableIdleTimeMillis < minEvictableIdleTimeMillis) { + throw new SQLException("maxEvictableIdleTimeMillis must be grater than minEvictableIdleTimeMillis"); + } if (this.driverClass != null) { this.driverClass = driverClass.trim(); @@ -666,6 +702,7 @@ public class DruidDataSource extends DruidAbstractDataSource createAndStartDestroyThread(); initedLatch.await(); + init = true; initedTime = new Date(); registerMbean(); @@ -674,7 +711,7 @@ public class DruidDataSource extends DruidAbstractDataSource throw connectError; } } catch (SQLException e) { - LOG.error("dataSource init error", e); + LOG.error("{dataSource-" + this.getID() + "} init error", e); throw e; } catch (InterruptedException e) { throw new SQLException(e.getMessage(), e); @@ -2185,24 +2222,33 @@ public class DruidDataSource extends DruidAbstractDataSource try { final int checkCount = poolingCount - minIdle; final long currentTimeMillis = System.currentTimeMillis(); - for (int i = 0; i < checkCount; ++i) { + for (int i = 0; i < poolingCount; ++i) { DruidConnectionHolder connection = connections[i]; - long phyConnectTimeMillis = connection.getTimeMillis() - currentTimeMillis;//physical connection connected time - if( phyConnectTimeMillis > phyTimeoutMillis ){ - evictList.add(connection);//if physical connection connected greater than phyTimeoutMillis, close the connection, for mysql 8 hours timeout - continue; - } - if (checkTime) { + long phyConnectTimeMillis = connection.getTimeMillis() - currentTimeMillis;//physical connection connected time + if (phyTimeoutMillis > 0 && phyConnectTimeMillis > phyTimeoutMillis) { + evictList.add(connection); + continue; + } + long idleMillis = currentTimeMillis - connection.getLastActiveTimeMillis(); - if (idleMillis >= minEvictableIdleTimeMillis) { + + if (idleMillis < minEvictableIdleTimeMillis) { + break; + } + + if (checkTime && i < checkCount) { + evictList.add(connection); + } else if (idleMillis > maxEvictableIdleTimeMillis) { + evictList.add(connection); + } + } else { + if (i < checkCount) { evictList.add(connection); } else { break; } - } else { - evictList.add(connection); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest.java b/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest.java new file mode 100644 index 0000000000..963e80d2c5 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest.java @@ -0,0 +1,86 @@ +package com.alibaba.druid.bvt.pool.basic; + +import java.sql.Connection; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.GetConnectionTimeoutException; +import com.alibaba.druid.util.JdbcUtils; + +import junit.framework.TestCase; + +public class MaxEvictableIdleTimeMillisTest extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setMaxActive(50); + dataSource.setMinIdle(5); + dataSource.setMinEvictableIdleTimeMillis(10); + dataSource.setMaxEvictableIdleTimeMillis(100); + dataSource.setMaxWait(20); + dataSource.init(); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_error() throws Exception { + Exception error = null; + try { + dataSource.setMaxEvictableIdleTimeMillis(1); + } catch (Exception ex) { + error = ex; + } + Assert.assertNotNull(error); + Assert.assertEquals(100, dataSource.getMaxEvictableIdleTimeMillis()); + } + + public void test_error2() throws Exception { + Exception error = null; + try { + dataSource.setMaxEvictableIdleTimeMillis(1); + } catch (Exception ex) { + error = ex; + } + Assert.assertNotNull(error); + Assert.assertEquals(100, dataSource.getMaxEvictableIdleTimeMillis()); + } + + public void test_max() throws Exception { + connect(10); + + Assert.assertEquals(10, dataSource.getPoolingCount()); + Thread.sleep(20); + dataSource.shrink(true); + Assert.assertEquals(5, dataSource.getPoolingCount()); + + Thread.sleep(100); + dataSource.shrink(true); + Assert.assertEquals(0, dataSource.getPoolingCount()); + } + + public int connect(int count) throws Exception { + int successCount = 0; + Connection[] connections = new Connection[count]; + for (int i = 0; i < count; ++i) { + try { + connections[i] = dataSource.getConnection(); + successCount++; + } catch (GetConnectionTimeoutException e) { + // skip + } + } + + for (int i = 0; i < count; ++i) { + JdbcUtils.close(connections[i]); + } + + return successCount; + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest2.java b/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest2.java new file mode 100644 index 0000000000..5db8e2b2c8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/basic/MaxEvictableIdleTimeMillisTest2.java @@ -0,0 +1,49 @@ +package com.alibaba.druid.bvt.pool.basic; + +import java.sql.Connection; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.GetConnectionTimeoutException; +import com.alibaba.druid.util.JdbcUtils; + +import junit.framework.TestCase; + +public class MaxEvictableIdleTimeMillisTest2 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setMaxActive(50); + dataSource.setMinIdle(5); + + + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_error() throws Exception { + Exception error = null; + try { + dataSource.setMinEvictableIdleTimeMillis(20); + dataSource.setMaxEvictableIdleTimeMillis(30); + dataSource.setMinEvictableIdleTimeMillis(100); + dataSource.setMaxWait(20); + dataSource.init(); + } catch (Exception ex) { + error = ex; + ex.printStackTrace(); + } + Assert.assertNotNull(error); + Assert.assertTrue(dataSource.isInited()); + Assert.assertEquals(30, dataSource.getMaxEvictableIdleTimeMillis()); + } + + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/dynamic/MaxActiveChangeTest.java b/src/test/java/com/alibaba/druid/bvt/pool/dynamic/MaxActiveChangeTest.java index b7ad752e4a..f262bc2f1f 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/dynamic/MaxActiveChangeTest.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/dynamic/MaxActiveChangeTest.java @@ -33,7 +33,7 @@ public class MaxActiveChangeTest extends TestCase { dataSource.setUrl("jdbc:mock:xxx"); dataSource.setTestOnBorrow(false); dataSource.setMaxActive(3); - dataSource.setMinIdle(1); + dataSource.setMinIdle(2); dataSource.setMinEvictableIdleTimeMillis(1000 * 60 * 5); dataSource.setMaxWait(20); dataSource.init(); @@ -61,44 +61,45 @@ public class MaxActiveChangeTest extends TestCase { Assert.assertEquals(3, dataSource.getPoolingCount()); } - dataSource.setMaxActive(4); + dataSource.setMaxActive(5); for (int i = 0; i < 10; ++i) { - Assert.assertEquals(4, connect(4)); - Assert.assertEquals(4, dataSource.getPoolingCount()); + Assert.assertEquals(5, connect(5)); + Assert.assertEquals(5, dataSource.getPoolingCount()); } dataSource.shrink(); - Assert.assertEquals(1, dataSource.getPoolingCount()); + Assert.assertEquals(2, dataSource.getPoolingCount()); for (int i = 0; i < 10; ++i) { - Assert.assertEquals(4, connect(4)); - Assert.assertEquals(4, dataSource.getPoolingCount()); + Assert.assertEquals(5, connect(5)); + Assert.assertEquals(5, dataSource.getPoolingCount()); } - Assert.assertEquals(4, dataSource.getPoolingCount()); + Assert.assertEquals(5, dataSource.getPoolingCount()); dataSource.setMaxActive(3); - Assert.assertEquals(4, dataSource.getPoolingCount()); + Assert.assertEquals(5, dataSource.getPoolingCount()); dataSource.shrink(); - Assert.assertEquals(1, dataSource.getPoolingCount()); + Assert.assertEquals(2, dataSource.getPoolingCount()); // 确保收缩之后不会再长上去 for (int i = 0; i < 10; ++i) { - Assert.assertEquals(3, connect(4)); + Assert.assertEquals(3, connect(5)); Assert.assertEquals(3, dataSource.getPoolingCount()); } dataSource.setMaxActive(2); dataSource.shrink(); - Assert.assertEquals(1, dataSource.getPoolingCount()); + Assert.assertEquals(2, dataSource.getPoolingCount()); for (int i = 0; i < 10; ++i) { Assert.assertEquals(2, connect(3)); Assert.assertEquals(2, dataSource.getPoolingCount()); } + dataSource.setMinIdle(1); dataSource.setMaxActive(1); dataSource.shrink(); Assert.assertEquals(1, dataSource.getPoolingCount()); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest2.java b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest2.java new file mode 100644 index 0000000000..d552cb71d8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/schemaStat/SchemaStatTest2.java @@ -0,0 +1,33 @@ +package com.alibaba.druid.bvt.sql.schemaStat; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.util.JdbcConstants; + +import junit.framework.TestCase; + +public class SchemaStatTest2 extends TestCase { + public void test_schemaStat() throws Exception { + String sql = "select " + + " create_time_dd as 来电日期" + + " from alisec_app.adl_tb_wing_rubbish_laidian_new_reason_realname_fdt " + + " order by 来电日期 desc limit 30;"; + + + String dbType = JdbcConstants.MYSQL; + SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, dbType); + SQLStatement stmt = parser.parseStatementList().get(0); + + SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(dbType); + stmt.accept(statVisitor); + + System.out.println(statVisitor.getColumns()); + + Assert.assertEquals(1, statVisitor.getColumns().size()); + } +}