diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 8c4ad23747..31c3dea211 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -2402,4 +2402,94 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat public void setLogDiffrentThread(boolean logDiffrentThread) { this.logDiffrentThread = logDiffrentThread; } + + public DruidPooledConnection tryGetConnection() throws SQLException { + if (poolingCount == 0) { + return null; + } + return getConnection(); + } + + @Override + public int fill() throws SQLException { + return this.fill(this.maxActive); + } + + @Override + public int fill(int toCount) throws SQLException { + if (closed) { + throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); + } + + if (toCount < 0) { + throw new IllegalArgumentException("toCount can't not be less than zero"); + } + + init(); + + if (toCount > this.maxActive) { + toCount = this.maxActive; + } + + int fillCount = 0; + for (;;) { + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + connectErrorCount.incrementAndGet(); + throw new SQLException("interrupt", e); + } + + boolean fillable = this.isFillable(toCount); + + lock.unlock(); + + if (!fillable) { + break; + } + + DruidConnectionHolder holder; + try { + Connection conn = createPhysicalConnection(); + holder = new DruidConnectionHolder(this, conn); + } catch (SQLException e) { + LOG.error("fill connection error", e); + connectErrorCount.incrementAndGet(); + throw e; + } + + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + connectErrorCount.incrementAndGet(); + throw new SQLException("interrupt", e); + } + + try { + if (!this.isFillable(toCount)) { + JdbcUtils.close(holder.getConnection()); + break; + } + this.putLast(holder, System.currentTimeMillis()); + fillCount++; + } finally { + lock.unlock(); + } + } + + if (LOG.isInfoEnabled()) { + LOG.info("fill " + fillCount + " connections"); + } + + return fillCount; + } + + private boolean isFillable(int toCount) { + int currentCount = this.poolingCount + this.activeCount; + if (currentCount >= toCount || currentCount >= this.maxActive) { + return false; + } else { + return true; + } + } } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java index 3af9d08463..11ded24669 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java @@ -81,4 +81,8 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { void setTimeBetweenLogStatsMillis(long timeBetweenLogStatsMillis); void setConnectionProperties(String connectionProperties); + + int fill() throws SQLException; + + int fill(int toCount) throws SQLException; } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill.java new file mode 100644 index 0000000000..724ae1a656 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill.java @@ -0,0 +1,56 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; + +public class DruidDataSourceTest_fill extends TestCase { + + private DruidDataSource dataSource; + + private int maxActive = 10; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setMaxActive(maxActive); + dataSource.setTestOnBorrow(false); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_fill_0() throws Exception { + int fillCount = dataSource.fill(3); + Assert.assertEquals(3, fillCount); + } + + public void test_fill_1() throws Exception { + int fillCount = dataSource.fill(1000); + Assert.assertEquals(maxActive, fillCount); + } + + public void test_fill_2() throws Exception { + int fillCount = dataSource.fill(maxActive); + Assert.assertEquals(maxActive, fillCount); + } + + public void test_fill_3() throws Exception { + int fillCount = dataSource.fill(); + Assert.assertEquals(maxActive, fillCount); + } + + public void test_fill_5() throws Exception { + Exception error = null; + try { + dataSource.fill(-1); + } catch (IllegalArgumentException e) { + error = e; + } + Assert.assertNotNull(error); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill2.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill2.java new file mode 100644 index 0000000000..789723c6eb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_fill2.java @@ -0,0 +1,86 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; + +public class DruidDataSourceTest_fill2 extends TestCase { + + private DruidDataSource dataSource; + + private int maxActive = 100; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setMaxActive(maxActive); + dataSource.setTestOnBorrow(false); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_fill() throws Exception { + final AtomicLong errorCount = new AtomicLong(); + + final int THREAD_COUNT = 100; + final CountDownLatch startLatch = new CountDownLatch(THREAD_COUNT); + final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); + Thread[] threads = new Thread[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; ++i) { + threads[i] = new Thread("thread-" + i) { + + public void run() { + startLatch.countDown(); + try { + Connection conn = dataSource.getConnection(); + Thread.sleep(2); + conn.close(); + } catch (Exception e) { + errorCount.incrementAndGet(); + } finally { + endLatch.countDown(); + } + } + }; + threads[i].start(); + } + + startLatch.await(1000, TimeUnit.MILLISECONDS); + + final CountDownLatch fillLatch = new CountDownLatch(THREAD_COUNT); + final AtomicLong fillErrorCount = new AtomicLong(); + final AtomicLong fillCount = new AtomicLong(); + Thread fillThread = new Thread() { + + public void run() { + try { + int count = dataSource.fill(); + fillCount.getAndSet(count); + } catch (Exception e) { + fillErrorCount.incrementAndGet(); + } finally { + fillLatch.countDown(); + } + } + }; + fillThread.start(); + + fillLatch.await(1000, TimeUnit.MILLISECONDS); + + Assert.assertEquals(0, fillErrorCount.get()); + + endLatch.await(1000, TimeUnit.MILLISECONDS); + + Assert.assertEquals(true, fillCount.get() > 0); + + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_tryGet.java b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_tryGet.java new file mode 100644 index 0000000000..d337cec62b --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/DruidDataSourceTest_tryGet.java @@ -0,0 +1,37 @@ +package com.alibaba.druid.bvt.pool; + +import org.junit.Assert; + +import junit.framework.TestCase; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; + +public class DruidDataSourceTest_tryGet extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setMaxActive(1); + dataSource.setInitialSize(1); + dataSource.setTestOnBorrow(false); + dataSource.init(); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_0() throws Exception { + DruidPooledConnection conn1 = this.dataSource.tryGetConnection(); + Assert.assertNotNull(conn1); + + DruidPooledConnection conn2 = this.dataSource.tryGetConnection(); + Assert.assertNull(conn2); + + conn1.close(); + } + +}