From 9207dd46a714b73f3739529c53aca112463e29f2 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 23 Dec 2011 16:51:11 +0800 Subject: [PATCH] ha --- .../druid/pool/ha/DataSourceHolder.java | 12 ++- .../alibaba/druid/pool/ha/HADataSource.java | 20 ++++- .../druid/pool/ha/config/HAConfigLoader.java | 22 +++++ .../bvt/pool/ha/CobarDataSourceTest.java | 83 +++++++++++++++++-- 4 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/pool/ha/config/HAConfigLoader.java diff --git a/src/main/java/com/alibaba/druid/pool/ha/DataSourceHolder.java b/src/main/java/com/alibaba/druid/pool/ha/DataSourceHolder.java index 8af209aa23..06b883211f 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/DataSourceHolder.java +++ b/src/main/java/com/alibaba/druid/pool/ha/DataSourceHolder.java @@ -22,6 +22,16 @@ public class DataSourceHolder implements Closeable { private transient int weightRegionEnd; + private boolean writable = true; + + public boolean isWritable() { + return writable; + } + + public void setWritable(boolean writable) { + this.writable = writable; + } + public int getWeightRegionBegin() { return weightRegionBegin; } @@ -93,7 +103,7 @@ public class DataSourceHolder implements Closeable { connectCount.incrementAndGet(); try { Connection conn = dataSource.getConnection(); - + return new MultiConnectionHolder(this, conn); } catch (SQLException ex) { connectErrorCount.incrementAndGet(); 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 9a06e01470..943badae68 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HADataSource.java @@ -24,6 +24,14 @@ public class HADataSource extends MultiDataSource implements HADataSourceMBean, master.resetState(); slave.resetState(); } + + public boolean isMasterWritable() { + return master != null && master.isWritable(); + } + + public boolean isSlaveWritable() { + return slave != null && slave.isWritable(); + } public long getMasterConnectCount() { return master.getConnectCount(); @@ -45,8 +53,10 @@ public class HADataSource extends MultiDataSource implements HADataSourceMBean, this.restartDataSource("slave"); } - public void setMaster(DruidDataSource master) { - this.setMaster(new DataSourceHolder(master)); + public DataSourceHolder setMaster(DruidDataSource master) { + DataSourceHolder holder = new DataSourceHolder(master); + this.setMaster(holder); + return holder; } public void setMaster(DataSourceHolder master) { @@ -58,8 +68,10 @@ public class HADataSource extends MultiDataSource implements HADataSourceMBean, return slave; } - public void setSlave(DruidDataSource slave) { - this.setSlave(new DataSourceHolder(slave)); + public DataSourceHolder setSlave(DruidDataSource slave) { + DataSourceHolder holder = new DataSourceHolder(slave); + this.setSlave(holder); + return holder; } public void setSlave(DataSourceHolder slave) { diff --git a/src/main/java/com/alibaba/druid/pool/ha/config/HAConfigLoader.java b/src/main/java/com/alibaba/druid/pool/ha/config/HAConfigLoader.java new file mode 100644 index 0000000000..11fc84b4d1 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/ha/config/HAConfigLoader.java @@ -0,0 +1,22 @@ +package com.alibaba.druid.pool.ha.config; + +import java.net.URL; +import java.sql.SQLException; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; + + +public class HAConfigLoader extends URLConnectionConfigLoader { + + public HAConfigLoader(URL configServerURL){ + super(configServerURL); + } + + @Override + protected void handleResponseMessage() throws SQLException { + JSONObject json = JSON.parseObject(this.getResponseMessage()); + json.get("serverList"); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ha/CobarDataSourceTest.java b/src/test/java/com/alibaba/druid/bvt/pool/ha/CobarDataSourceTest.java index 5bc4b46eb3..4a5869dbfd 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/ha/CobarDataSourceTest.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/ha/CobarDataSourceTest.java @@ -4,14 +4,17 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; - -import org.junit.Assert; +import java.util.concurrent.atomic.AtomicBoolean; import junit.framework.TestCase; +import org.junit.Assert; + import com.alibaba.druid.mock.MockConnection; +import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.ha.cobar.CobarConfigLoader; import com.alibaba.druid.pool.ha.cobar.CobarDataSource; +import com.alibaba.druid.pool.ha.cobar.CobarFailureDetecter; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -40,8 +43,11 @@ public class CobarDataSourceTest extends TestCase { cobarList.add(cobarB); - String mockUrlA = "jdbc:mock://mock:80/cobarA"; - String mockUrlB = "jdbc:mock://mock:81/cobarB"; + final String mockUrlA = "jdbc:mock://mock:80/cobarA"; + final String mockUrlB = "jdbc:mock://mock:81/cobarB"; + + final AtomicBoolean statusA = new AtomicBoolean(true); + final AtomicBoolean statusB = new AtomicBoolean(true); config.put("cobarList", cobarList); @@ -50,7 +56,8 @@ public class CobarDataSourceTest extends TestCase { dataSource.setUsername("test"); dataSource.setPassword(""); dataSource.setMaxWait(1); - dataSource.setConfigLoadPeriodMillis(3); + dataSource.setConfigLoadPeriodMillis(10); + dataSource.setFailureDetectPeriodMillis(1); CobarConfigLoader configLoader = new CobarConfigLoader(dataSource) { @@ -65,6 +72,23 @@ public class CobarDataSourceTest extends TestCase { } }; dataSource.setConfigLoader(configLoader); + + CobarFailureDetecter failureDetector = new CobarFailureDetecter() { + public boolean isValidConnection(DruidDataSource dataSource, Connection conn) { + MockConnection mockConn; + try { + mockConn = conn.unwrap(MockConnection.class); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + if (mockConn.getUrl().equals(mockUrlA)) { + return statusA.get(); + } + return statusB.get(); + } + }; + dataSource.setFailureDetector(failureDetector); { Connection conn = dataSource.getConnection(); @@ -113,6 +137,55 @@ public class CobarDataSourceTest extends TestCase { stmt.close(); conn.close(); } + + cobarList.add(cobarA); + Assert.assertEquals(2, cobarList.size()); + Thread.sleep(dataSource.getConfigLoadPeriodMillis() * 2); + for (int i = 0; i < 100; ++i) { + Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("select 1"); + + rs.next(); + rs.close(); + stmt.close(); + conn.close(); + } + + statusA.set(false); + Thread.sleep(dataSource.getFailureDetectPeriodMillis() * 2); + for (int i = 0; i < 100; ++i) { + Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("select 1"); + + MockConnection mockConn = conn.unwrap(MockConnection.class); + Assert.assertNotNull(mockConn); + Assert.assertEquals(mockUrlB, mockConn.getUrl()); + + rs.next(); + rs.close(); + stmt.close(); + conn.close(); + } + + statusA.set(true); + statusB.set(false); + Thread.sleep(dataSource.getFailureDetectPeriodMillis() * 2); + for (int i = 0; i < 100; ++i) { + Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("select 1"); + + MockConnection mockConn = conn.unwrap(MockConnection.class); + Assert.assertNotNull(mockConn); + Assert.assertEquals(mockUrlA, mockConn.getUrl()); + + rs.next(); + rs.close(); + stmt.close(); + conn.close(); + } } }