mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
some small refactors & add tests
This commit is contained in:
@@ -37,7 +37,6 @@ public class FileNodeListener extends NodeListener {
|
||||
|
||||
private Lock lock = new ReentrantLock();
|
||||
private String file = null;
|
||||
private String prefix = "";
|
||||
private int intervalSeconds = 60;
|
||||
private ScheduledExecutorService executor;
|
||||
|
||||
@@ -81,7 +80,7 @@ public class FileNodeListener extends NodeListener {
|
||||
@Override
|
||||
public List<NodeEvent> refresh() {
|
||||
Properties originalProperties = PropertiesUtils.loadProperties(file);
|
||||
List<String> nameList = PropertiesUtils.loadNameList(originalProperties, prefix);
|
||||
List<String> nameList = PropertiesUtils.loadNameList(originalProperties, getPrefix());
|
||||
Properties properties = new Properties();
|
||||
for (String n : nameList) {
|
||||
String url = originalProperties.getProperty(n + ".url");
|
||||
@@ -143,12 +142,4 @@ public class FileNodeListener extends NodeListener {
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
public abstract class NodeListener extends Observable {
|
||||
private final static Log LOG = LogFactory.getLog(NodeListener.class);
|
||||
|
||||
private String prefix = "";
|
||||
private Properties properties = new Properties();
|
||||
private Date lastUpdateTime = null;
|
||||
private Observer observer = null;
|
||||
@@ -111,4 +112,12 @@ public abstract class NodeListener extends Observable {
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ public class PoolUpdater implements Observer {
|
||||
}
|
||||
|
||||
private void blacklistNode(String nodeName) {
|
||||
LOG.info("Deleting Node " + nodeName + ", just add into blacklist.");
|
||||
LOG.info("Deleting Node " + nodeName + ", just add it into blacklist.");
|
||||
nodesToDel.add(nodeName);
|
||||
highAvailableDataSource.addBlackList(nodeName);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@ public class ZookeeperNodeInfo {
|
||||
private String prefix = "";
|
||||
private String host;
|
||||
private Integer port;
|
||||
/**
|
||||
* Database can be the following ones:
|
||||
* 1. Database in MySQL and PostgreSQL JDBC URL
|
||||
* 2. ServiceName or SID in Oracle JDBC URL
|
||||
* etc.
|
||||
*/
|
||||
private String database;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
@@ -71,4 +78,12 @@ public class ZookeeperNodeInfo {
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public void setDatabase(String database) {
|
||||
this.database = database;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* bar.port=3309
|
||||
* bar.username=bar
|
||||
* bar.password=bar_password
|
||||
* bar.database=bar_database
|
||||
* </pre>
|
||||
*
|
||||
* @author DigitalSonic
|
||||
@@ -65,15 +66,14 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
private final static Log LOG = LogFactory.getLog(ZookeeperNodeListener.class);
|
||||
private String zkConnectString;
|
||||
private String path = "/ha-druid-datasources";
|
||||
private String dataPrefix = "";
|
||||
private Lock lock = new ReentrantLock();
|
||||
private boolean privateZkClient = false; // Should I close the client?
|
||||
private PathChildrenCache cache;
|
||||
private CuratorFramework client;
|
||||
/**
|
||||
* Template Format:
|
||||
* jdbc:mysql://${host}:${port}/foo?useUnicode=true
|
||||
* ${host} and ${port} will be replaced by values in ZK
|
||||
* URL Template, e.g.
|
||||
* jdbc:mysql://${host}:${port}/${database}?useUnicode=true
|
||||
* ${host}, ${port} and ${database} will be replaced by values in ZK
|
||||
*/
|
||||
private String urlTemplate;
|
||||
|
||||
@@ -183,7 +183,7 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
ChildData data = event.getData();
|
||||
String nodeName = getNodeName(data);
|
||||
List<String> names = new ArrayList<String>();
|
||||
names.add(dataPrefix + "." + nodeName);
|
||||
names.add(getPrefix() + "." + nodeName);
|
||||
Properties properties = getPropertiesFromChildData(data);
|
||||
List<NodeEvent> events = NodeEvent.generateEvents(properties, names, type);
|
||||
|
||||
@@ -228,6 +228,7 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
}
|
||||
|
||||
private Properties getPropertiesFromChildData(ChildData data) {
|
||||
String dataPrefix = getPrefix();
|
||||
Properties properties = new Properties();
|
||||
if (data == null) {
|
||||
return properties;
|
||||
@@ -243,7 +244,7 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
Properties filtered = PropertiesUtils.filterPrefix(full, dataPrefix);
|
||||
for (String n : filtered.stringPropertyNames()) {
|
||||
properties.setProperty(
|
||||
n.replaceFirst(dataPrefix, dataPrefix + "." + nodeName),
|
||||
n.replaceFirst(dataPrefix, dataPrefix + "\\." + nodeName),
|
||||
filtered.getProperty(n));
|
||||
}
|
||||
if (!properties.containsKey(dataPrefix + "." + nodeName + ".url")) {
|
||||
@@ -254,12 +255,16 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
|
||||
private String formatUrl(Properties properties) {
|
||||
String url = urlTemplate;
|
||||
String dataPrefix = getPrefix();
|
||||
if (properties.containsKey(dataPrefix + ".host")) {
|
||||
url = url.replace("${host}", properties.getProperty(dataPrefix + ".host"));
|
||||
}
|
||||
if (properties.containsKey(dataPrefix + ".port")) {
|
||||
url = url.replace("${port}", properties.getProperty(dataPrefix + ".port"));
|
||||
}
|
||||
if (properties.containsKey(dataPrefix + ".database")) {
|
||||
url = url.replace("${database}", properties.getProperty(dataPrefix + ".database"));
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -299,14 +304,6 @@ public class ZookeeperNodeListener extends NodeListener {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getDataPrefix() {
|
||||
return dataPrefix;
|
||||
}
|
||||
|
||||
public void setDataPrefix(String dataPrefix) {
|
||||
this.dataPrefix = dataPrefix;
|
||||
}
|
||||
|
||||
public String getUrlTemplate() {
|
||||
return urlTemplate;
|
||||
}
|
||||
|
||||
@@ -131,6 +131,9 @@ public class ZookeeperNodeRegister {
|
||||
if (n.getPort() != null) {
|
||||
properties.setProperty(n.getPrefix() + "port", n.getPort().toString());
|
||||
}
|
||||
if (n.getDatabase() != null) {
|
||||
properties.setProperty(n.getPrefix() + "database", n.getDatabase());
|
||||
}
|
||||
if (n.getUsername() != null) {
|
||||
properties.setProperty(n.getPrefix() + "username", n.getUsername());
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import org.junit.Test;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class NodeEventTest {
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class PoolUpdaterTest {
|
||||
private HighAvailableDataSource haDataSource;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.alibaba.druid.pool.ha.node;
|
||||
|
||||
import com.alibaba.druid.DruidRuntimeException;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.pool.ha.HighAvailableDataSource;
|
||||
import com.alibaba.druid.support.logging.Log;
|
||||
import com.alibaba.druid.support.logging.LogFactory;
|
||||
import org.apache.curator.test.TestingServer;
|
||||
@@ -17,6 +19,9 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@@ -35,6 +40,48 @@ public class ZookeeperNodeListenerTest {
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHaWithZk() throws Exception {
|
||||
// 1. Init HighAvailableDataSource
|
||||
ZookeeperNodeListener listener = new ZookeeperNodeListener();
|
||||
listener.setZkConnectString(server.getConnectString());
|
||||
listener.setPrefix("foo");
|
||||
listener.setPath(PATH);
|
||||
listener.setUrlTemplate("jdbc:derby:memory:${database};create=true");
|
||||
HighAvailableDataSource dataSource = new HighAvailableDataSource();
|
||||
dataSource.setNodeListener(listener);
|
||||
dataSource.setPoolPurgeIntervalSeconds(10);
|
||||
dataSource.init();
|
||||
assertTrue(dataSource.getDataSourceMap().isEmpty());
|
||||
|
||||
// 2. Register one Node
|
||||
ZookeeperNodeRegister register = registerNodeAndReturnRegister();
|
||||
|
||||
Thread.sleep(3000); // Wait for the Node to be created.
|
||||
assertFalse(dataSource.getDataSourceMap().isEmpty());
|
||||
assertEquals(1, dataSource.getAvailableDataSourceMap().size());
|
||||
DruidDataSource ds = (DruidDataSource) dataSource.getAvailableDataSourceMap().get("foo.test-foo");
|
||||
assertEquals("jdbc:derby:memory:foo;create=true", ds.getUrl());
|
||||
assertNotNull(dataSource.getConnection());
|
||||
|
||||
// 3. Delete one Node
|
||||
register.destroy();
|
||||
boolean checkBlackList = false;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Thread.sleep(500);
|
||||
if (dataSource.isInBlackList("foo.test-foo")) {
|
||||
assertTrue(dataSource.getAvailableDataSourceMap().isEmpty());
|
||||
assertFalse(dataSource.getDataSourceMap().isEmpty());
|
||||
assertNull(dataSource.getConnection());
|
||||
checkBlackList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(checkBlackList);
|
||||
|
||||
dataSource.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddOneNode() throws Exception {
|
||||
CountDownLatch cdl = new CountDownLatch(1);
|
||||
@@ -42,7 +89,7 @@ public class ZookeeperNodeListenerTest {
|
||||
listener.setZkConnectString(server.getConnectString());
|
||||
listener.setPath(PATH);
|
||||
listener.setUrlTemplate("jdbc:mysql://${host}:${port}/foo");
|
||||
listener.setDataPrefix("foo");
|
||||
listener.setPrefix("foo");
|
||||
listener.setObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
@@ -51,8 +98,8 @@ public class ZookeeperNodeListenerTest {
|
||||
NodeEvent event = events[0];
|
||||
LOG.info("NodeEvent received: " + event);
|
||||
if (NodeEventTypeEnum.ADD == event.getType()) {
|
||||
assertEquals("foo", event.getUsername());
|
||||
assertEquals("password", event.getPassword());
|
||||
assertEquals("sa", event.getUsername());
|
||||
assertEquals("", event.getPassword());
|
||||
assertEquals("foo.test-foo", event.getNodeName());
|
||||
assertEquals("jdbc:mysql://127.0.0.1:1234/foo",
|
||||
event.getUrl());
|
||||
@@ -67,9 +114,9 @@ public class ZookeeperNodeListenerTest {
|
||||
|
||||
cdl.await(10, TimeUnit.SECONDS);
|
||||
Properties properties = listener.getProperties();
|
||||
assertEquals(5, properties.size());
|
||||
assertEquals("foo", properties.getProperty("foo.test-foo.username"));
|
||||
assertEquals("password", properties.getProperty("foo.test-foo.password"));
|
||||
assertEquals(6, properties.size());
|
||||
assertEquals("sa", properties.getProperty("foo.test-foo.username"));
|
||||
assertEquals("", properties.getProperty("foo.test-foo.password"));
|
||||
assertEquals("127.0.0.1", properties.getProperty("foo.test-foo.host"));
|
||||
assertEquals("1234", properties.getProperty("foo.test-foo.port"));
|
||||
assertEquals("jdbc:mysql://127.0.0.1:1234/foo",
|
||||
@@ -89,7 +136,7 @@ public class ZookeeperNodeListenerTest {
|
||||
listener.setZkConnectString(server.getConnectString());
|
||||
listener.setPath(PATH);
|
||||
listener.setUrlTemplate("jdbc:mysql://${host}:${port}/foo");
|
||||
listener.setDataPrefix("foo");
|
||||
listener.setPrefix("foo");
|
||||
listener.setObserver(new Observer() {
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
@@ -98,8 +145,8 @@ public class ZookeeperNodeListenerTest {
|
||||
NodeEvent event = events[0];
|
||||
LOG.info("NodeEvent received: " + event);
|
||||
if (NodeEventTypeEnum.DELETE == event.getType()) {
|
||||
assertEquals("foo", event.getUsername());
|
||||
assertEquals("password", event.getPassword());
|
||||
assertEquals("sa", event.getUsername());
|
||||
assertEquals("", event.getPassword());
|
||||
assertEquals("foo.test-foo", event.getNodeName());
|
||||
assertEquals("jdbc:mysql://127.0.0.1:1234/foo",
|
||||
event.getUrl());
|
||||
@@ -113,7 +160,7 @@ public class ZookeeperNodeListenerTest {
|
||||
listener.update();
|
||||
addCDL.await(10, TimeUnit.SECONDS);
|
||||
Properties properties = listener.getProperties();
|
||||
assertEquals(5, properties.size());
|
||||
assertEquals(6, properties.size());
|
||||
|
||||
register.destroy();
|
||||
removeCDL.await(10, TimeUnit.SECONDS);
|
||||
@@ -132,8 +179,9 @@ public class ZookeeperNodeListenerTest {
|
||||
node.setPrefix("foo");
|
||||
node.setHost("127.0.0.1");
|
||||
node.setPort(1234);
|
||||
node.setUsername("foo");
|
||||
node.setPassword("password");
|
||||
node.setDatabase("foo");
|
||||
node.setUsername("sa");
|
||||
node.setPassword("");
|
||||
payload.add(node);
|
||||
register.register("test-foo", payload);
|
||||
return register;
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.alibaba.druid.pool.ha.node;
|
||||
import com.alibaba.druid.support.logging.Log;
|
||||
import com.alibaba.druid.support.logging.LogFactory;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
import org.apache.curator.retry.ExponentialBackoffRetry;
|
||||
import org.apache.curator.test.TestingServer;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
@@ -17,12 +15,14 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ZookeeperNodeRegisterTest {
|
||||
private final static Log LOG = LogFactory.getLog(ZookeeperNodeRegisterTest.class);
|
||||
private final String PATH = "/ha-druid-datasource";
|
||||
private static TestingServer server;
|
||||
private final String PATH = "/ha-druid-datasource";
|
||||
private ZookeeperNodeRegister register;
|
||||
|
||||
@BeforeClass
|
||||
@@ -56,6 +56,7 @@ public class ZookeeperNodeRegisterTest {
|
||||
node1.setPrefix("foo");
|
||||
node1.setHost("127.0.0.1");
|
||||
node1.setPort(1234);
|
||||
node1.setDatabase("foo_db");
|
||||
node1.setUsername("foo");
|
||||
node1.setPassword("password");
|
||||
payload.add(node1);
|
||||
@@ -87,6 +88,9 @@ public class ZookeeperNodeRegisterTest {
|
||||
properties.load(new StringReader(str));
|
||||
validateNodeProperties(node1, properties);
|
||||
validateNodeProperties(node2, properties);
|
||||
assertTrue(properties.containsKey("foo.database"));
|
||||
assertFalse(properties.containsKey("bar.database"));
|
||||
assertEquals("foo_db", properties.getProperty("foo.database"));
|
||||
}
|
||||
|
||||
private void validateNodeProperties(ZookeeperNodeInfo node, Properties properties) {
|
||||
|
||||
Reference in New Issue
Block a user