some small refactors & add tests

This commit is contained in:
DigitalSonic
2020-02-06 13:53:28 +08:00
parent eb90260afe
commit 34aa0c8cd1
10 changed files with 113 additions and 43 deletions
@@ -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) {