From 4dc2a42405f4a921d3fa4af9a9af8d12bb24c727 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 9 Dec 2011 08:32:10 +0800 Subject: [PATCH] ha --- .../druid/pool/DruidAbstractDataSource.java | 11 +- .../alibaba/druid/pool/DruidDataSource.java | 18 +-- .../druid/pool/DruidDataSourceMBean.java | 4 + .../alibaba/druid/pool/ha/HADataSource.java | 67 +------- .../druid/pool/ha/MultiDataSource.java | 12 +- .../pool/ha/config/DruidDataSourceConfig.java | 48 +++++- .../pool/ha/config/MultiDataSourceConfig.java | 10 ++ .../ha/config/URLConnectionConfigLoader.java | 77 ++++++++- .../com/alibaba/druid/pool/CobarTest.java | 44 ++++++ .../druid/pool/URLConfigerLoaderTest.java | 15 ++ .../pool/benckmark/Case_Concurrent_50.java | 149 ++++++++++++++++++ 11 files changed, 366 insertions(+), 89 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/pool/CobarTest.java create mode 100644 src/test/java/com/alibaba/druid/pool/URLConfigerLoaderTest.java create mode 100644 src/test/java/com/alibaba/druid/pool/benckmark/Case_Concurrent_50.java diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index d558d55814..1905150412 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -40,6 +40,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Logger; import javax.management.JMException; +import javax.management.ObjectName; import javax.management.openmbean.CompositeDataSupport; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; @@ -194,6 +195,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements private boolean dupCloseLogEnable = true; + private ObjectName objectName; public boolean isDupCloseLogEnable() { return dupCloseLogEnable; @@ -202,7 +204,14 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements public void setDupCloseLogEnable(boolean dupCloseLogEnable) { this.dupCloseLogEnable = dupCloseLogEnable; } - + + public ObjectName getObjectName() { + return objectName; + } + + public void setObjectName(ObjectName objectName) { + this.objectName = objectName; + } public Histogram getTransactionHistogram() { return transactionHistogram; diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index 22295429ad..70cb19a211 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -108,8 +108,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private String initStackTrace; - private ObjectName objectName; - public DruidDataSource(){ } @@ -117,14 +115,6 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat return initStackTrace; } - public ObjectName getObjectName() { - return objectName; - } - - public void setObjectName(ObjectName objectName) { - this.objectName = objectName; - } - public boolean isResetStatEnable() { return resetStatEnable; } @@ -703,7 +693,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat for (;;) { if (poolingCount == 0) { - empty.signal(); // send signal to CreateThread create connection + if (notEmptyWaitThreadCount == 0) { + empty.signal(); // send signal to CreateThread create connection + } if (estimate <= 0) { throw new GetConnectionTimeoutException(); @@ -712,9 +704,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat notEmptyWaitThreadCount++; try { long startEstimate = estimate; - estimate = notEmpty.awaitNanos(estimate); // signal by - // recycle or - // creator + estimate = notEmpty.awaitNanos(estimate); // signal by recycle or creator notEmptyWaitCount++; notEmptyWaitNanos += (startEstimate - estimate); diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java index bf78433e1a..9d0a27f8f2 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceMBean.java @@ -17,6 +17,8 @@ package com.alibaba.druid.pool; import java.util.Date; +import javax.management.ObjectName; + /** * @author wenshao */ @@ -73,4 +75,6 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean { Date getPoolingPeakTime(); long getErrorCount(); + + ObjectName getObjectName(); } diff --git a/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java index aacad2924c..6eb8234c4d 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java @@ -2,9 +2,7 @@ package com.alibaba.druid.pool.ha; import java.sql.Connection; import java.sql.SQLException; -import java.util.AbstractList; import java.util.List; -import java.util.RandomAccess; import javax.sql.DataSource; @@ -13,18 +11,15 @@ import com.alibaba.druid.logging.LogFactory; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.ha.balance.Balancer; import com.alibaba.druid.pool.ha.balance.RoundRobinBlancer; -import com.alibaba.druid.util.JdbcUtils; public class HADataSource extends MultiDataSource implements DataSource { - private final static Log LOG = LogFactory.getLog(HADataSource.class); + private final static Log LOG = LogFactory.getLog(HADataSource.class); - protected DruidDataSource master; - protected DruidDataSource slave; + protected DruidDataSource master; + protected DruidDataSource slave; - protected Balancer balancer = new RoundRobinBlancer(); - - private DataSourceList dataSourceList = new DataSourceList(); + protected Balancer balancer = new RoundRobinBlancer(); public HADataSource(){ @@ -35,6 +30,7 @@ public class HADataSource extends MultiDataSource implements DataSource { } public void setMaster(DruidDataSource master) { + this.getDataSources().put("master", master); this.master = master; } @@ -43,13 +39,10 @@ public class HADataSource extends MultiDataSource implements DataSource { } public void setSlave(DruidDataSource slave) { + this.getDataSources().put("slave", slave); this.slave = slave; } - public List getDataSources() { - return dataSourceList; - } - public synchronized void setDataSources(List dataSources) { throw new UnsupportedOperationException(); } @@ -77,52 +70,4 @@ public class HADataSource extends MultiDataSource implements DataSource { } } - private class DataSourceList extends AbstractList implements RandomAccess, java.io.Serializable { - - private static final long serialVersionUID = -2764017481108945198L; - - public int size() { - return 2; - } - - public Object[] toArray() { - return new DruidDataSource[] { master, slave }; - } - - public T[] toArray(T[] a) { - throw new UnsupportedOperationException(); - } - - public DruidDataSource get(int index) { - if (index == 0) { - return master; - } - - if (index == 1) { - return slave; - } - - throw new IllegalArgumentException("index : " + index); - } - - public DruidDataSource set(int index, DruidDataSource element) { - throw new UnsupportedOperationException(); - } - - public int indexOf(Object o) { - if (o == master) { - return 0; - } - - if (o == slave) { - return 1; - } - - return -1; - } - - public boolean contains(Object o) { - return o == master || o == slave; - } - } } diff --git a/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java index 8958045d70..eb5b614af4 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/MultiDataSource.java @@ -2,8 +2,10 @@ package com.alibaba.druid.pool.ha; import java.sql.Connection; import java.sql.SQLException; -import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -32,6 +34,8 @@ public abstract class MultiDataSource extends DataSourceAdapter { private boolean inited = false; private final Lock lock = new ReentrantLock(); + + private ConcurrentMap dataSources = new ConcurrentHashMap(); public MultiDataSource(){ @@ -94,7 +98,9 @@ public abstract class MultiDataSource extends DataSourceAdapter { return statementIdSeed.incrementAndGet(); } - public abstract List getDataSources(); + public Map getDataSources() { + return dataSources; + } public Properties getProperties() { return properties; @@ -114,7 +120,7 @@ public abstract class MultiDataSource extends DataSourceAdapter { @Override public void run() { - for (DruidDataSource dataSource : getDataSources()) { + for (DruidDataSource dataSource : getDataSources().values()) { boolean isValid = validDataSourceChecker.isValid(dataSource); if (isValid) { handleNotAwailableDatasource(dataSource); diff --git a/src/main/java/com/alibaba/druid/pool/ha/config/DruidDataSourceConfig.java b/src/main/java/com/alibaba/druid/pool/ha/config/DruidDataSourceConfig.java index c9a1012416..1270346ccc 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/config/DruidDataSourceConfig.java +++ b/src/main/java/com/alibaba/druid/pool/ha/config/DruidDataSourceConfig.java @@ -2,10 +2,48 @@ package com.alibaba.druid.pool.ha.config; public class DruidDataSourceConfig { + private String name; + private String url; - private String user; + private String username; private String password; + private int initialSize; + protected int maxActive; + private int minIdle; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getInitialSize() { + return initialSize; + } + + public void setInitialSize(int initialSize) { + this.initialSize = initialSize; + } + + public int getMaxActive() { + return maxActive; + } + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + public int getMinIdle() { + return minIdle; + } + + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + public String getUrl() { return url; } @@ -14,12 +52,12 @@ public class DruidDataSourceConfig { this.url = url; } - public String getUser() { - return user; + public String getUsername() { + return username; } - public void setUser(String user) { - this.user = user; + public void setUsername(String username) { + this.username = username; } public String getPassword() { diff --git a/src/main/java/com/alibaba/druid/pool/ha/config/MultiDataSourceConfig.java b/src/main/java/com/alibaba/druid/pool/ha/config/MultiDataSourceConfig.java index 46886955b6..4a3dcf7972 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/config/MultiDataSourceConfig.java +++ b/src/main/java/com/alibaba/druid/pool/ha/config/MultiDataSourceConfig.java @@ -5,8 +5,18 @@ import java.util.List; public class MultiDataSourceConfig { + private String name; + private List dataSources = new ArrayList(); + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + public List getDataSources() { return dataSources; } diff --git a/src/main/java/com/alibaba/druid/pool/ha/config/URLConnectionConfigLoader.java b/src/main/java/com/alibaba/druid/pool/ha/config/URLConnectionConfigLoader.java index 464321fa07..8c4cb7c068 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/config/URLConnectionConfigLoader.java +++ b/src/main/java/com/alibaba/druid/pool/ha/config/URLConnectionConfigLoader.java @@ -1,17 +1,84 @@ package com.alibaba.druid.pool.ha.config; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; -public class URLConnectionConfigLoader { +import com.alibaba.druid.DruidRuntimeException; +import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.fastjson.JSON; - private final URL configServerURL; +public class URLConnectionConfigLoader implements ConfigLoader { + + private URL url; + private int connectTimeout = 1000 * 3; + private int readTimeout; public URLConnectionConfigLoader(URL configServerURL){ - this.configServerURL = configServerURL; + this.url = configServerURL; } - public URL getConfigServerURL() { - return configServerURL; + public URLConnectionConfigLoader(String url) throws MalformedURLException{ + this.url = new URL(url); + } + + public URL getURL() { + return url; + } + + public void setURL(URL url) { + this.url = url; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getReadTimeout() { + return readTimeout; + } + + public void setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + } + + @Override + public MultiDataSourceConfig load() { + if (url == null) { + throw new IllegalStateException("configServerURL is null"); + } + + String responseMessage; + + { + HttpURLConnection conn = null; + Reader reader = null; + try { + conn = (HttpURLConnection) url.openConnection(); + + conn.setConnectTimeout(connectTimeout); + conn.setReadTimeout(readTimeout); + + conn.connect(); + + reader = new InputStreamReader(conn.getInputStream()); + responseMessage = JdbcUtils.read(reader); + } catch (Exception e) { + throw new DruidRuntimeException("load config error, url : " + url.toString()); + } finally { + JdbcUtils.close(reader); + conn.disconnect(); + } + } + + MultiDataSourceConfig config = JSON.parseObject(responseMessage, MultiDataSourceConfig.class); + return config; } } diff --git a/src/test/java/com/alibaba/druid/pool/CobarTest.java b/src/test/java/com/alibaba/druid/pool/CobarTest.java new file mode 100644 index 0000000000..0c27db26b1 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/CobarTest.java @@ -0,0 +1,44 @@ +package com.alibaba.druid.pool; + +import java.sql.Connection; + +import com.alibaba.druid.pool.vendor.MySqlExceptionSorter; +import com.alibaba.druid.util.JdbcUtils; + +import junit.framework.TestCase; + + +public class CobarTest extends TestCase { + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + jdbcUrl = "jdbc:mysql://10.20.146.88:8066/pt_dragoon_masterdb_test?useUnicode=true&characterEncoding=UTF-8"; + user = "pt_dragoon_test"; + password = "pt_dragoon_test"; + driverClass = "com.mysql.jdbc.Driver"; + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_0() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setDriverClassName(driverClass); + dataSource.setUrl(jdbcUrl); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setFilters("stat"); + dataSource.setExceptionSorter(MySqlExceptionSorter.class.getName()); + + Connection conn = dataSource.getConnection(); + + conn.close(); + + dataSource.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/pool/URLConfigerLoaderTest.java b/src/test/java/com/alibaba/druid/pool/URLConfigerLoaderTest.java new file mode 100644 index 0000000000..c67cf03aa0 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/URLConfigerLoaderTest.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.pool; + +import junit.framework.TestCase; + +import com.alibaba.druid.pool.ha.config.URLConnectionConfigLoader; + + +public class URLConfigerLoaderTest extends TestCase { + public void test_0 () throws Exception { + String url = "http://www.baidu.com/"; + + URLConnectionConfigLoader loader = new URLConnectionConfigLoader(url); + loader.load(); + } +} diff --git a/src/test/java/com/alibaba/druid/pool/benckmark/Case_Concurrent_50.java b/src/test/java/com/alibaba/druid/pool/benckmark/Case_Concurrent_50.java new file mode 100644 index 0000000000..609d69c735 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/benckmark/Case_Concurrent_50.java @@ -0,0 +1,149 @@ +/* + * 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.benckmark; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.NumberFormat; +import java.util.concurrent.CountDownLatch; + +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.apache.commons.dbcp.BasicDataSource; + +import com.alibaba.druid.TestUtil; +import com.alibaba.druid.pool.DruidDataSource; + +public class Case_Concurrent_50 extends TestCase { + + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + private int initialSize = 0; + private int minIdle = 3; + private int maxIdle = 5; + private int maxActive = 10; + private String validationQuery = "SELECT 1"; + private boolean testOnBorrow = false; + + private long minEvictableIdleTimeMillis = 3000; + public final int LOOP_COUNT = 5; + public final int COUNT = 1000 * 10; + + private final int THREAD_COUNT = 50; + + protected void setUp() throws Exception { + jdbcUrl = "jdbc:fake:dragoon_v25masterdb"; + user = "dragoon25"; + password = "dragoon25"; + driverClass = "com.alibaba.druid.mock.MockDriver"; + } + + public void test_0() throws Exception { + final DruidDataSource dataSource = new DruidDataSource(); + + dataSource.setInitialSize(initialSize); + dataSource.setMaxActive(maxActive); + dataSource.setMinIdle(minIdle); + dataSource.setMaxIdle(maxIdle); + dataSource.setPoolPreparedStatements(true); + dataSource.setDriverClassName(driverClass); + dataSource.setUrl(jdbcUrl); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxWait(6000); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setValidationQuery(validationQuery); + dataSource.setTestOnBorrow(testOnBorrow); + dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + + for (int i = 0; i < LOOP_COUNT; ++i) { + p0(dataSource, "druid"); + } + + System.out.println(); + } + + public void test_1() throws Exception { + final BasicDataSource dataSource = new BasicDataSource(); + + dataSource.setInitialSize(initialSize); + dataSource.setMaxActive(maxActive); + dataSource.setMinIdle(minIdle); + dataSource.setMaxIdle(maxIdle); + dataSource.setPoolPreparedStatements(true); + dataSource.setDriverClassName(driverClass); + dataSource.setUrl(jdbcUrl); + dataSource.setPoolPreparedStatements(true); + dataSource.setUsername(user); + dataSource.setPassword(password); + dataSource.setValidationQuery(validationQuery); + dataSource.setTestOnBorrow(testOnBorrow); + dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + + for (int i = 0; i < LOOP_COUNT; ++i) { + p0(dataSource, "dbcp"); + } + + System.out.println(); + } + + private void p0(final DataSource dataSource, String name) throws Exception { + long startMillis = System.currentTimeMillis(); + long startYGC = TestUtil.getYoungGC(); + long startFullGC = TestUtil.getFullGC(); + + final CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); + for (int i = 0; i < THREAD_COUNT; ++i) { + Thread thread = new Thread() { + + public void run() { + try { + + for (int i = 0; i < COUNT; ++i) { + Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT 1"); + Thread.sleep(0, 1000 * 100); + rs.close(); + stmt.close(); + conn.close(); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + endLatch.countDown(); + } + } + }; + thread.start(); + } + endLatch.await(); + + long millis = System.currentTimeMillis() - startMillis; + long ygc = TestUtil.getYoungGC() - startYGC; + long fullGC = TestUtil.getFullGC() - startFullGC; + + System.out.println(name + " millis : " + NumberFormat.getInstance().format(millis) + ", YGC " + ygc + " FGC " + + fullGC); + } +}