mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
ha
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.alibaba.druid.pool;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* @author wenshao<szujobs@hotmail.com>
|
||||
*/
|
||||
@@ -73,4 +75,6 @@ public interface DruidDataSourceMBean extends DruidAbstractDataSourceMBean {
|
||||
Date getPoolingPeakTime();
|
||||
|
||||
long getErrorCount();
|
||||
|
||||
ObjectName getObjectName();
|
||||
}
|
||||
|
||||
@@ -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<DruidDataSource> getDataSources() {
|
||||
return dataSourceList;
|
||||
}
|
||||
|
||||
public synchronized void setDataSources(List<DruidDataSource> dataSources) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@@ -77,52 +70,4 @@ public class HADataSource extends MultiDataSource implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
private class DataSourceList extends AbstractList<DruidDataSource> 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> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, DruidDataSource> dataSources = new ConcurrentHashMap<String, DruidDataSource>();
|
||||
|
||||
public MultiDataSource(){
|
||||
|
||||
@@ -94,7 +98,9 @@ public abstract class MultiDataSource extends DataSourceAdapter {
|
||||
return statementIdSeed.incrementAndGet();
|
||||
}
|
||||
|
||||
public abstract List<DruidDataSource> getDataSources();
|
||||
public Map<String, DruidDataSource> 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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -5,8 +5,18 @@ import java.util.List;
|
||||
|
||||
public class MultiDataSourceConfig {
|
||||
|
||||
private String name;
|
||||
|
||||
private List<DruidDataSourceConfig> dataSources = new ArrayList<DruidDataSourceConfig>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<DruidDataSourceConfig> getDataSources() {
|
||||
return dataSources;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user