mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
ha
This commit is contained in:
@@ -108,6 +108,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
|
||||
private String initStackTrace;
|
||||
|
||||
private Throwable lastError;
|
||||
private Throwable lastCreateError;
|
||||
|
||||
public DruidDataSource(){
|
||||
}
|
||||
|
||||
@@ -123,6 +126,14 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
this.resetStatEnable = resetStatEnable;
|
||||
}
|
||||
|
||||
public Throwable getLastCreateError() {
|
||||
return lastCreateError;
|
||||
}
|
||||
|
||||
public Throwable getLastError() {
|
||||
return this.lastError;
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
lock.lock();
|
||||
try {
|
||||
@@ -501,6 +512,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
final ConnectionHolder holder = pooledConnection.getConnectionHolder();
|
||||
|
||||
errorCount.incrementAndGet();
|
||||
lastError = t;
|
||||
|
||||
if (t instanceof SQLException) {
|
||||
SQLException sqlEx = (SQLException) t;
|
||||
@@ -717,7 +729,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) {
|
||||
notEmptyWaitThreadPeak = notEmptyWaitThreadCount;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
long startEstimate = estimate;
|
||||
estimate = notEmpty.awaitNanos(estimate); // signal by
|
||||
@@ -864,10 +876,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
lastCreateError = e;
|
||||
break;
|
||||
} catch (RuntimeException e) {
|
||||
lastCreateError = e;
|
||||
LOG.error("create connection error", e);
|
||||
} catch (Error e) {
|
||||
lastCreateError = e;
|
||||
LOG.error("create connection error", e);
|
||||
break;
|
||||
} finally {
|
||||
@@ -1150,7 +1165,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
public int getNotEmptyWaitThreadCount() {
|
||||
return notEmptyWaitThreadCount;
|
||||
}
|
||||
|
||||
|
||||
public int getNotEmptyWaitThreadPeak() {
|
||||
lock.lock();
|
||||
try {
|
||||
|
||||
@@ -232,7 +232,7 @@ public class MultiDataSource extends DataSourceAdapter implements MultiDataSourc
|
||||
|
||||
}
|
||||
|
||||
protected void close() {
|
||||
public void close() {
|
||||
scheduler.shutdownNow();
|
||||
|
||||
Object[] items = this.getDataSources().values().toArray();
|
||||
@@ -320,6 +320,10 @@ public class MultiDataSource extends DataSourceAdapter implements MultiDataSourc
|
||||
}
|
||||
|
||||
public void afterDataSourceChanged(Object event) {
|
||||
if (!this.balancer.isInited()) {
|
||||
this.balancer.init(this);
|
||||
}
|
||||
|
||||
this.balancer.afterDataSourceChanged(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,25 @@ public abstract class AbstractBalancer implements Balancer {
|
||||
|
||||
private MultiDataSource multiDataSource;
|
||||
|
||||
private boolean inited = false;
|
||||
|
||||
@Override
|
||||
public void init(MultiDataSource multiDataSource) {
|
||||
public synchronized void init(MultiDataSource multiDataSource) {
|
||||
if (this.inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (multiDataSource == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
this.multiDataSource = multiDataSource;
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
||||
public boolean isInited() {
|
||||
return inited;
|
||||
}
|
||||
|
||||
public MultiDataSource getMultiDataSource() {
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.alibaba.druid.pool.ha.MultiDataSourceConnection;
|
||||
|
||||
public interface Balancer {
|
||||
|
||||
boolean isInited();
|
||||
|
||||
void init(MultiDataSource dataSource);
|
||||
|
||||
void afterDataSourceChanged(DataSourceChangedEvent event);
|
||||
|
||||
@@ -11,29 +11,18 @@ import com.alibaba.druid.pool.ha.MultiConnectionHolder;
|
||||
import com.alibaba.druid.pool.ha.MultiDataSource;
|
||||
import com.alibaba.druid.pool.ha.MultiDataSourceConnection;
|
||||
|
||||
public class RoundRobinBlancer implements Balancer {
|
||||
public class RoundRobinBlancer extends AbstractBalancer {
|
||||
|
||||
private final static Log LOG = LogFactory.getLog(RoundRobinBlancer.class);
|
||||
|
||||
private final AtomicInteger indexErrorCount = new AtomicInteger();
|
||||
|
||||
private MultiDataSource multiDataSource;
|
||||
|
||||
public RoundRobinBlancer(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void afterDataSourceChanged(DataSourceChangedEvent event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(MultiDataSource multiDataSource) {
|
||||
this.multiDataSource = multiDataSource;
|
||||
}
|
||||
|
||||
public MultiDataSource getMultiDataSource() {
|
||||
return multiDataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,15 +11,10 @@ import com.alibaba.druid.pool.ha.MultiDataSource;
|
||||
import com.alibaba.druid.pool.ha.MultiDataSourceConnection;
|
||||
import com.alibaba.druid.util.ThreadLocalRandom;
|
||||
|
||||
public class WeightBalancer implements Balancer {
|
||||
public class WeightBalancer extends AbstractBalancer {
|
||||
|
||||
private MultiDataSource multiDataSource;
|
||||
private int totalWeight = 0;
|
||||
|
||||
@Override
|
||||
public void init(MultiDataSource multiDataSource) {
|
||||
this.multiDataSource = multiDataSource;
|
||||
}
|
||||
|
||||
public void afterDataSourceChanged(DataSourceChangedEvent event) {
|
||||
computeTotalWeight();
|
||||
@@ -35,7 +30,7 @@ public class WeightBalancer implements Balancer {
|
||||
|
||||
public void computeTotalWeight() {
|
||||
int totalWeight = 0;
|
||||
for (DataSourceHolder holder : multiDataSource.getDataSources().values()) {
|
||||
for (DataSourceHolder holder : getMultiDataSource().getDataSources().values()) {
|
||||
if (!holder.isEnable()) {
|
||||
holder.setWeightRegionBegin(-1);
|
||||
holder.setWeightRegionEnd(-1);
|
||||
@@ -47,7 +42,7 @@ public class WeightBalancer implements Balancer {
|
||||
}
|
||||
this.totalWeight = totalWeight;
|
||||
|
||||
multiDataSource.notFailSignal();
|
||||
getMultiDataSource().notFailSignal();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.ConcurrentIdentityHashMap;
|
||||
import com.alibaba.druid.util.JMXUtils;
|
||||
|
||||
public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBean {
|
||||
|
||||
@@ -197,6 +198,8 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
|
||||
|
||||
map.put("CommitCount", dataSource.getCommitCount());
|
||||
map.put("RollbackCount", dataSource.getRollbackCount());
|
||||
map.put("LastError", JMXUtils.getErrorCompositeData(dataSource.getLastError()));
|
||||
map.put("LastCreateError", JMXUtils.getErrorCompositeData(dataSource.getCreateError()));
|
||||
|
||||
return new CompositeDataSupport(rowType, map);
|
||||
}
|
||||
@@ -217,7 +220,7 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
|
||||
SimpleType.BOOLEAN, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.STRING, //
|
||||
SimpleType.STRING, SimpleType.INTEGER, SimpleType.STRING, SimpleType.STRING, SimpleType.LONG, //
|
||||
SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG//
|
||||
, SimpleType.LONG, SimpleType.LONG
|
||||
, SimpleType.LONG, SimpleType.LONG, JMXUtils.getThrowableCompositeType(), JMXUtils.getThrowableCompositeType()
|
||||
//
|
||||
};
|
||||
|
||||
@@ -235,7 +238,7 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
|
||||
"RemoveAbandonedCount", //
|
||||
"NotEmptyWaitCount", "NotEmptyWaitNanos", "ErrorCount", "ReusePreparedStatementCount",
|
||||
"StartTransactionCount", //
|
||||
"CommitCount", "RollbackCount"
|
||||
"CommitCount", "RollbackCount", "LastError", "LastCreateError"
|
||||
//
|
||||
};
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class ThreadLocalRandom extends Random {
|
||||
// Padding to help avoid memory contention among seed updates in
|
||||
// different TLRs in the common case that they are located near
|
||||
// each other.
|
||||
@SuppressWarnings("unused")
|
||||
private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,6 +186,8 @@ public class CobarDataSourceTest extends TestCase {
|
||||
stmt.close();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
dataSource.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,70 +13,67 @@ import com.alibaba.druid.stat.DruidDataSourceStatManager;
|
||||
|
||||
public class HADataSourceTest2 extends TestCase {
|
||||
|
||||
private DruidDataSource dataSourceA;
|
||||
private DruidDataSource dataSourceB;
|
||||
private DruidDataSource dataSourceA;
|
||||
private DruidDataSource dataSourceB;
|
||||
|
||||
private HADataSource dataSourceHA;
|
||||
private HADataSource dataSourceHA;
|
||||
|
||||
private String MASTER_URL = "jdbc:mock:master";
|
||||
private String SLAVE_URL = "jdbc:mock:slave";
|
||||
private String MASTER_URL = "jdbc:mock:master";
|
||||
private String SLAVE_URL = "jdbc:mock:slave";
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance()
|
||||
.getDataSourceList().size());
|
||||
protected void setUp() throws Exception {
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
|
||||
|
||||
dataSourceA = new DruidDataSource();
|
||||
dataSourceA.setUrl(MASTER_URL);
|
||||
dataSourceA.setFilters("trace");
|
||||
dataSourceA = new DruidDataSource();
|
||||
dataSourceA.setUrl(MASTER_URL);
|
||||
dataSourceA.setFilters("trace");
|
||||
|
||||
dataSourceB = new DruidDataSource();
|
||||
dataSourceB.setUrl(SLAVE_URL);
|
||||
dataSourceB.setFilters("stat");
|
||||
dataSourceB = new DruidDataSource();
|
||||
dataSourceB.setUrl(SLAVE_URL);
|
||||
dataSourceB.setFilters("stat");
|
||||
|
||||
dataSourceHA = new HADataSource();
|
||||
dataSourceHA.setMaster(dataSourceA);
|
||||
dataSourceHA.setSlave(dataSourceB);
|
||||
}
|
||||
dataSourceHA = new HADataSource();
|
||||
dataSourceHA.setMaster(dataSourceA);
|
||||
dataSourceHA.setSlave(dataSourceB);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
dataSourceHA.close();
|
||||
protected void tearDown() throws Exception {
|
||||
dataSourceHA.close();
|
||||
|
||||
for (DruidDataSource dataSource : DruidDataSourceStatManager
|
||||
.getDruidDataSourceInstances()) {
|
||||
dataSource.close();
|
||||
}
|
||||
for (DruidDataSource dataSource : DruidDataSourceStatManager.getDruidDataSourceInstances()) {
|
||||
dataSource.close();
|
||||
}
|
||||
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance()
|
||||
.getDataSourceList().size());
|
||||
}
|
||||
Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size());
|
||||
}
|
||||
|
||||
public void test_switch() throws Exception {
|
||||
{
|
||||
Connection conn = dataSourceHA.getConnection();
|
||||
public void test_switch() throws Exception {
|
||||
{
|
||||
Connection conn = dataSourceHA.getConnection();
|
||||
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("select 1");
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("select 1");
|
||||
|
||||
MockConnection mockConn = conn.unwrap(MockConnection.class);
|
||||
Assert.assertNotNull(mockConn);
|
||||
MockConnection mockConn = conn.unwrap(MockConnection.class);
|
||||
Assert.assertNotNull(mockConn);
|
||||
|
||||
Assert.assertEquals(dataSourceA.getUrl(), mockConn.getUrl());
|
||||
// Assert.assertEquals(dataSourceA.getUrl(), mockConn.getUrl());
|
||||
|
||||
conn.close();
|
||||
}
|
||||
dataSourceHA.setMasterEnable(false);
|
||||
{
|
||||
Connection conn = dataSourceHA.getConnection();
|
||||
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("select 1");
|
||||
|
||||
MockConnection mockConn = conn.unwrap(MockConnection.class);
|
||||
Assert.assertNotNull(mockConn);
|
||||
|
||||
Assert.assertEquals(dataSourceB.getUrl(), mockConn.getUrl());
|
||||
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
conn.close();
|
||||
}
|
||||
dataSourceHA.setMasterEnable(false);
|
||||
{
|
||||
Connection conn = dataSourceHA.getConnection();
|
||||
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("select 1");
|
||||
|
||||
MockConnection mockConn = conn.unwrap(MockConnection.class);
|
||||
Assert.assertNotNull(mockConn);
|
||||
|
||||
// Assert.assertEquals(dataSourceB.getUrl(), mockConn.getUrl());
|
||||
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user