From 65fafdb67aeb546e55c7f1f158a450e714de97b8 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Thu, 13 Dec 2018 00:15:47 +0800 Subject: [PATCH 01/14] add a special prefix into ha-datasource properties file In order to put HA Datasource properties and other properties altogether into one properties file, HighAvailableDataSource add a new field named propertyPrefix. --- .../druid/pool/ha/DataSourceCreator.java | 18 ++++++++-- .../pool/ha/HighAvailableDataSource.java | 11 +++++- .../druid/pool/ha/DataSourceCreatorTest.java | 35 +++++++++++++++++++ .../ha/ha-with-prefix-datasource.properties | 4 +++ 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/test/resources/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties diff --git a/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java b/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java index be1e9b69f1..72eed4c98f 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java +++ b/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java @@ -44,8 +44,12 @@ public class DataSourceCreator { private List nameList = new ArrayList(); public DataSourceCreator(String file) { + this(file, ""); + } + + public DataSourceCreator(String file, String propertyPrefix) { loadProperties(file); - loadNameList(); + loadNameList(propertyPrefix); } public Map createMap(HighAvailableDataSource haDataSource) throws SQLException { @@ -119,10 +123,14 @@ public class DataSourceCreator { return dataSource; } - private void loadNameList() { + private void loadNameList(String propertyPrefix) { Set names = new HashSet(); for (String n : properties.stringPropertyNames()) { - if (n.contains(".url")) { + if (propertyPrefix != null && !propertyPrefix.isEmpty() + && !n.startsWith(propertyPrefix)) { + continue; + } + if (n.endsWith(".url")) { names.add(n.split("\\.url")[0]); } } @@ -167,4 +175,8 @@ public class DataSourceCreator { LOG.warn("File " + file + " can't be loaded!"); } } + + public List getNameList() { + return nameList; + } } diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index b347944293..fc6fa583e7 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -88,6 +88,7 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc private Map dataSourceMap = new ConcurrentHashMap(); private DataSourceSelector selector = new RandomDataSourceSelector(this); private String dataSourceFile = DEFAULT_DATA_SOURCE_FILE; + private String propertyPrefix = ""; private boolean inited = false; @@ -100,7 +101,7 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc return; } if (dataSourceMap == null || dataSourceMap.isEmpty()) { - dataSourceMap = new DataSourceCreator(dataSourceFile).createMap(this); + dataSourceMap = new DataSourceCreator(dataSourceFile, propertyPrefix).createMap(this); } if (selector == null) { selector = new RandomDataSourceSelector(this); @@ -146,6 +147,14 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc this.dataSourceFile = dataSourceFile; } + public String getPropertyPrefix() { + return propertyPrefix; + } + + public void setPropertyPrefix(String propertyPrefix) { + this.propertyPrefix = propertyPrefix; + } + public void setDataSourceMap(Map dataSourceMap) { if (dataSourceMap != null) { this.dataSourceMap = dataSourceMap; diff --git a/src/test/java/com/alibaba/druid/pool/ha/DataSourceCreatorTest.java b/src/test/java/com/alibaba/druid/pool/ha/DataSourceCreatorTest.java index f3052702b6..76a4dfc08d 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/DataSourceCreatorTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/DataSourceCreatorTest.java @@ -3,11 +3,29 @@ package com.alibaba.druid.pool.ha; import org.junit.Test; import javax.sql.DataSource; +import java.util.List; import java.util.Map; import static org.junit.Assert.*; public class DataSourceCreatorTest { + @Test + public void testNameList() { + String file = "/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties"; + DataSourceCreator creator = new DataSourceCreator(file, "prefix1"); + List list = creator.getNameList(); + assertFalse(list.isEmpty()); + assertEquals(1, list.size()); + assertEquals("prefix1.foo", list.get(0)); + + creator = new DataSourceCreator(file); + list = creator.getNameList(); + assertEquals(3, list.size()); + for (String k : list) { + assertNotEquals("bar", k); + } + } + @Test public void createMap() throws Exception { HighAvailableDataSource highAvailableDataSource = new HighAvailableDataSource(); @@ -19,4 +37,21 @@ public class DataSourceCreatorTest { assertNotNull(map.get("bar")); } + @Test + public void createMapWithPrefix() throws Exception { + HighAvailableDataSource highAvailableDataSource = new HighAvailableDataSource(); + String file = "/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties"; + DataSourceCreator creator = new DataSourceCreator(file, "prefix1"); + Map map = creator.createMap(highAvailableDataSource); + assertEquals(1, map.size()); + assertNotNull(map.get("prefix1.foo")); + assertNull(map.get("prefix2.foo")); + + creator = new DataSourceCreator(file, "prefix2"); + map = creator.createMap(highAvailableDataSource); + assertEquals(1, map.size()); + assertNull(map.get("prefix1.foo")); + assertNotNull(map.get("prefix2.foo")); + } + } \ No newline at end of file diff --git a/src/test/resources/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties b/src/test/resources/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties new file mode 100644 index 0000000000..b008c63d9f --- /dev/null +++ b/src/test/resources/com/alibaba/druid/pool/ha/ha-with-prefix-datasource.properties @@ -0,0 +1,4 @@ +prefix1.foo.url=jdbc:derby:memory:foo1;create=true +prefix2.foo.url=jdbc:derby:memory:foo2;create=true +foo.url=jdbc:derby:memory:foo3;create=true +bar=jdbc:derby:memory:bar;create=true From b6c90db170a29e8218887f8eccff259446818185 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Fri, 1 Feb 2019 18:21:16 +0800 Subject: [PATCH 02/14] Enhance RandomDataSourceSelector 1. shorten the checking interval when validate failed 2. provide some parameters in higher level 3. add a sleep before validation (default 0) 4. validate the DataSource concurrently --- .../pool/ha/HighAvailableDataSource.java | 1 + .../pool/ha/selector/DataSourceSelector.java | 1 + .../ha/selector/NamedDataSourceSelector.java | 4 + .../ha/selector/RandomDataSourceSelector.java | 65 ++++++++++++- .../RandomDataSourceValidateThread.java | 95 ++++++++++++++----- ...mDataSourceSelectorWithValidationTest.java | 8 +- 6 files changed, 147 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index fc6fa583e7..0c34795751 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -105,6 +105,7 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc } if (selector == null) { selector = new RandomDataSourceSelector(this); + selector.init(); } if (dataSourceMap == null || dataSourceMap.isEmpty()) { LOG.warn("There is NO DataSource available!!! Please check your configuration."); diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java index d6646a2cd2..5db261fa33 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java @@ -29,4 +29,5 @@ public interface DataSourceSelector { void setTarget(String name); boolean isSame(String name); String getName(); + void init(); } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java index 11cbf293bf..515468ca8b 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java @@ -35,6 +35,10 @@ public class NamedDataSourceSelector implements DataSourceSelector { this.highAvailableDataSource = highAvailableDataSource; } + @Override + public void init() { + } + @Override public boolean isSame(String name) { return getName().equalsIgnoreCase(name); diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java index f5434d391a..8a0a13a0f4 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java @@ -43,12 +43,31 @@ public class RandomDataSourceSelector implements DataSourceSelector { private RandomDataSourceValidateThread validateThread; private RandomDataSourceRecoverThread recoverThread; + private int checkingIntervalSeconds = 15; + private int recoveryIntervalSeconds = 30; + private int validationSleepSeconds = 0; + private int blacklistThreshold = 3; + public RandomDataSourceSelector(HighAvailableDataSource highAvailableDataSource) { this.highAvailableDataSource = highAvailableDataSource; + } + + @Override + public void init() { + if (highAvailableDataSource == null) { + LOG.warn("highAvailableDataSource is NULL!"); + return; + } + if (!highAvailableDataSource.isTestOnBorrow() && !highAvailableDataSource.isTestOnReturn()) { validateThread = new RandomDataSourceValidateThread(this); + validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds); + validateThread.setValidationSleepSeconds(validationSleepSeconds); + validateThread.setBlacklistThreshold(blacklistThreshold); + new Thread(validateThread, "RandomDataSourceSelector-isValid-thread").start(); + recoverThread = new RandomDataSourceRecoverThread(this); - new Thread(validateThread, "RandomDataSourceSelector-validate-thread").start(); + recoverThread.setSleepSeconds(recoveryIntervalSeconds); new Thread(recoverThread, "RandomDataSourceSelector-recover-thread").start(); } else { LOG.info("testOnBorrow or testOnReturn has been set to true, ignore validateThread"); @@ -123,11 +142,55 @@ public class RandomDataSourceSelector implements DataSourceSelector { } } + public HighAvailableDataSource getHighAvailableDataSource() { + return highAvailableDataSource; + } + public RandomDataSourceValidateThread getValidateThread() { return validateThread; } + public void setValidateThread(RandomDataSourceValidateThread validateThread) { + this.validateThread = validateThread; + } + public RandomDataSourceRecoverThread getRecoverThread() { return recoverThread; } + + public void setRecoverThread(RandomDataSourceRecoverThread recoverThread) { + this.recoverThread = recoverThread; + } + + public int getCheckingIntervalSeconds() { + return checkingIntervalSeconds; + } + + public void setCheckingIntervalSeconds(int checkingIntervalSeconds) { + this.checkingIntervalSeconds = checkingIntervalSeconds; + } + + public int getRecoveryIntervalSeconds() { + return recoveryIntervalSeconds; + } + + public void setRecoveryIntervalSeconds(int recoveryIntervalSeconds) { + this.recoveryIntervalSeconds = recoveryIntervalSeconds; + } + + public int getValidationSleepSeconds() { + return validationSleepSeconds; + } + + public void setValidationSleepSeconds(int validationSleepSeconds) { + this.validationSleepSeconds = validationSleepSeconds; + } + + public int getBlacklistThreshold() { + return blacklistThreshold; + } + + public void setBlacklistThreshold(int blacklistThreshold) { + this.blacklistThreshold = blacklistThreshold; + } } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java index e2887fe349..45c7a3a4d0 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java @@ -24,22 +24,22 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import java.util.*; +import java.util.concurrent.*; /** * A Thread trying to test all DataSource provided by HADataSource. - * If a DataSource failed this test for 3 times, it will be put into a blacklist. + * If a DataSource failed this test for 3 times (default value), it will be put into a blacklist. * * @author DigitalSonic */ public class RandomDataSourceValidateThread implements Runnable { private final static Log LOG = LogFactory.getLog(RandomDataSourceValidateThread.class); - private int sleepSeconds = 30; + private int checkingIntervalSeconds = 15; + private int validationSleepSeconds = 0; private int blacklistThreshold = 3; - private RandomDataSourceSelector selector; + private ExecutorService checkExecutor = Executors.newFixedThreadPool(5); private Map errorCounts = new HashMap(); public RandomDataSourceValidateThread(RandomDataSourceSelector selector) { @@ -53,12 +53,29 @@ public class RandomDataSourceValidateThread implements Runnable { checkAllDataSources(); maintainBlacklist(); } - try { - Thread.sleep(sleepSeconds * 1000); - } catch (InterruptedException e) { - // ignore + sleepForNextValidation(); + } + } + + private void sleepForNextValidation() { + int errorCountBelowThreshold = 0; + + for (int count : errorCounts.values()) { + if (count > 0 && count < blacklistThreshold && count > errorCountBelowThreshold) { + errorCountBelowThreshold = count; } } + + int newSleepSeconds = checkingIntervalSeconds / (errorCountBelowThreshold + 1); + if (newSleepSeconds < 1) { + newSleepSeconds = 1; + } + try { + LOG.debug("Sleep " + newSleepSeconds + " second(s) until next checking."); + Thread.sleep(newSleepSeconds * 1000); + } catch (InterruptedException e) { + // ignore + } } private void maintainBlacklist() { @@ -75,21 +92,36 @@ public class RandomDataSourceValidateThread implements Runnable { private void checkAllDataSources() { Map dataSourceMap = selector.getDataSourceMap(); - for (Map.Entry e : dataSourceMap.entrySet()) { + List> tasks = new ArrayList>(); + + for (final Map.Entry e : dataSourceMap.entrySet()) { if (!(e.getValue() instanceof DruidDataSource)) { continue; } - boolean flag = check(e.getKey(), (DruidDataSource) e.getValue()); - if (flag) { - errorCounts.put(e.getKey(), 0); - } else { - if (!errorCounts.containsKey(e.getKey())) { - errorCounts.put(e.getKey(), 0); + tasks.add(new Callable() { + @Override + public Boolean call() { + boolean flag = check(e.getKey(), (DruidDataSource) e.getValue()); + + if (flag) { + errorCounts.put(e.getKey(), 0); + } else { + if (!errorCounts.containsKey(e.getKey())) { + errorCounts.put(e.getKey(), 0); + } + int count = errorCounts.get(e.getKey()); + errorCounts.put(e.getKey(), count + 1); + } + + return flag; } - int count = errorCounts.get(e.getKey()); - errorCounts.put(e.getKey(), count + 1); - } + }); + } + try { + checkExecutor.invokeAll(tasks); + } catch (Exception e) { + LOG.warn("Exception occurred while checking DataSource.", e); } } @@ -109,8 +141,9 @@ public class RandomDataSourceValidateThread implements Runnable { info.setProperty("password", password); } try { - LOG.debug("Validating " + name + " every " + sleepSeconds + " seconds."); + LOG.debug("Validating " + name + " every " + checkingIntervalSeconds + " seconds."); conn = driver.connect(url, info); + sleepBeforeValidation(); dataSource.validateConnection(conn); } catch (SQLException e) { LOG.warn("Validation FAILED for " + name + " with url [" + url + "] and username [" @@ -123,8 +156,24 @@ public class RandomDataSourceValidateThread implements Runnable { return result; } - public void setSleepSeconds(int sleepSeconds) { - this.sleepSeconds = sleepSeconds; + private void sleepBeforeValidation() { + if (validationSleepSeconds <= 0) { + return; + } + try { + LOG.debug("Sleep " + validationSleepSeconds + " second(s) before validation."); + Thread.sleep(validationSleepSeconds * 1000L); + } catch (InterruptedException e) { + // ignore + } + } + + public void setCheckingIntervalSeconds(int checkingIntervalSeconds) { + this.checkingIntervalSeconds = checkingIntervalSeconds; + } + + public void setValidationSleepSeconds(int validationSleepSeconds) { + this.validationSleepSeconds = validationSleepSeconds; } public void setBlacklistThreshold(int blacklistThreshold) { diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java index a38cf40f4b..f082f8d7f2 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java @@ -30,8 +30,10 @@ public class RandomDataSourceSelectorWithValidationTest { @Test public void testOneDataSourceFailAndRecover() throws Exception { - ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getValidateThread().setSleepSeconds(3); - ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getRecoverThread().setSleepSeconds(3); + RandomDataSourceSelector selector = ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()); + selector.setCheckingIntervalSeconds(3); + selector.getRecoverThread().setSleepSeconds(3); + selector.init(); Thread.sleep(30 * 1000); @@ -57,7 +59,7 @@ public class RandomDataSourceSelectorWithValidationTest { @Test public void testAllDataSourceFail() throws Exception { - ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getValidateThread().setSleepSeconds(3); + ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getValidateThread().setCheckingIntervalSeconds(3); ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getRecoverThread().setSleepSeconds(3); Thread.sleep(30 * 1000); From 6b7eccb063bf132f46fe81461fdbd0980e14a435 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Fri, 1 Feb 2019 18:22:12 +0800 Subject: [PATCH 03/14] Add an enhanced StickyRandomDataSourceSelector This selector can stick a DataSource to a Thread in a short time. --- .../ha/selector/StickyDataSourceHolder.java | 40 +++++++++++++ .../StickyRandomDataSourceSelector.java | 57 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/main/java/com/alibaba/druid/pool/ha/selector/StickyDataSourceHolder.java create mode 100644 src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyDataSourceHolder.java b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyDataSourceHolder.java new file mode 100644 index 0000000000..e69659e85d --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyDataSourceHolder.java @@ -0,0 +1,40 @@ +package com.alibaba.druid.pool.ha.selector; + +import javax.sql.DataSource; + +/** + * A class holding DataSource reference and retrieving time. + * + * @author DigitalSonic + */ +public class StickyDataSourceHolder { + private long retrievingTime = System.currentTimeMillis(); + private DataSource dataSource; + + public StickyDataSourceHolder() { + } + + public StickyDataSourceHolder(DataSource dataSource) { + this.dataSource = dataSource; + } + + public boolean isValid() { + return retrievingTime > 0 && dataSource != null; + } + + public long getRetrievingTime() { + return retrievingTime; + } + + public void setRetrievingTime(long retrievingTime) { + this.retrievingTime = retrievingTime; + } + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } +} diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java new file mode 100644 index 0000000000..bd871a9a3b --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java @@ -0,0 +1,57 @@ +package com.alibaba.druid.pool.ha.selector; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.ha.HighAvailableDataSource; + +import javax.sql.DataSource; + +/** + * An extend selector based on RandomDataSourceSelector which can stick a DataSource to a Thread in a while. + * + * @author DigitalSonic + * @see RandomDataSourceSelector + * @see StickyDataSourceHolder + */ +public class StickyRandomDataSourceSelector extends RandomDataSourceSelector { + private ThreadLocal holders = new ThreadLocal(); + + private int expireSeconds = 5; + + public StickyRandomDataSourceSelector(HighAvailableDataSource highAvailableDataSource) { + super(highAvailableDataSource); + } + + @Override + public DataSource get() { + StickyDataSourceHolder holder = holders.get(); + if (holder != null && isValid(holder) && !isExpired(holder)) { + return holder.getDataSource(); + } + DataSource dataSource = super.get(); + holder = new StickyDataSourceHolder(dataSource); + holders.remove(); + holders.set(holder); + return dataSource; + } + + private boolean isValid(StickyDataSourceHolder holder) { + boolean flag = holder.isValid() && !getBlacklist().contains(holder.getDataSource()); + if (!(holder.getDataSource() instanceof DruidDataSource) || !flag) { + return flag; + } + DruidDataSource dataSource = (DruidDataSource) holder.getDataSource(); + return flag && dataSource.getActiveCount() < dataSource.getMaxActive(); + } + + private boolean isExpired(StickyDataSourceHolder holder) { + return System.currentTimeMillis() - holder.getRetrievingTime() > expireSeconds * 1000; + } + + public int getExpireSeconds() { + return expireSeconds; + } + + public void setExpireSeconds(int expireSeconds) { + this.expireSeconds = expireSeconds; + } +} From c7715b7ec3ccd20e2a00e4cafc37cfe5e0dfbeb2 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 10:25:59 +0800 Subject: [PATCH 04/14] add default validationQueryTimeout when given 0 --- .../alibaba/druid/pool/vendor/MySqlValidConnectionChecker.java | 2 +- .../alibaba/druid/pool/vendor/OracleValidConnectionChecker.java | 2 +- .../com/alibaba/druid/pool/vendor/PGValidConnectionChecker.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/vendor/MySqlValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/MySqlValidConnectionChecker.java index cb90043513..a22e627e4c 100644 --- a/src/main/java/com/alibaba/druid/pool/vendor/MySqlValidConnectionChecker.java +++ b/src/main/java/com/alibaba/druid/pool/vendor/MySqlValidConnectionChecker.java @@ -99,7 +99,7 @@ public class MySqlValidConnectionChecker extends ValidConnectionCheckerAdapter i } if (clazz.isAssignableFrom(conn.getClass())) { - if (validationQueryTimeout < 0) { + if (validationQueryTimeout <= 0) { validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT; } diff --git a/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java index da7e93ff31..c3138fa947 100644 --- a/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java +++ b/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java @@ -74,7 +74,7 @@ public class OracleValidConnectionChecker extends ValidConnectionCheckerAdapter return true; } - int queryTimeout = validationQueryTimeout < 0 ? timeout : validationQueryTimeout; + int queryTimeout = validationQueryTimeout <= 0 ? timeout : validationQueryTimeout; Statement stmt = null; ResultSet rs = null; diff --git a/src/main/java/com/alibaba/druid/pool/vendor/PGValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/PGValidConnectionChecker.java index df8b9f5cbe..73f00c7577 100644 --- a/src/main/java/com/alibaba/druid/pool/vendor/PGValidConnectionChecker.java +++ b/src/main/java/com/alibaba/druid/pool/vendor/PGValidConnectionChecker.java @@ -55,7 +55,7 @@ public class PGValidConnectionChecker extends ValidConnectionCheckerAdapter impl conn = ((ConnectionProxy) conn).getRawObject(); } - int queryTimeout = validationQueryTimeout < 0 ? defaultQueryTimeout : validationQueryTimeout; + int queryTimeout = validationQueryTimeout <= 0 ? defaultQueryTimeout : validationQueryTimeout; Statement stmt = null; ResultSet rs = null; From 851eb966736a9e182ab02b13fbb1c75833f1f481 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 16:12:23 +0800 Subject: [PATCH 05/14] slightly modify Use ConcurrentHashMap instead of HashMap in RandomDataSourceValidateThread. Add some Log in StickyRandomDataSourceSelector. Add some test cases for StickyRandomDataSourceSelect. --- .../RandomDataSourceValidateThread.java | 12 +++-- .../StickyRandomDataSourceSelector.java | 6 +++ .../BaseRandomDataSourceSelectorTest.java | 31 +++++++++++ .../RandomDataSourceSelectorTest.java | 36 +------------ .../StickyRandomDataSourceSelectorTest.java | 51 +++++++++++++++++++ 5 files changed, 99 insertions(+), 37 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/pool/ha/selector/BaseRandomDataSourceSelectorTest.java create mode 100644 src/test/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelectorTest.java diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java index 45c7a3a4d0..9f5430f1de 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java @@ -24,8 +24,14 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * A Thread trying to test all DataSource provided by HADataSource. @@ -40,7 +46,7 @@ public class RandomDataSourceValidateThread implements Runnable { private int blacklistThreshold = 3; private RandomDataSourceSelector selector; private ExecutorService checkExecutor = Executors.newFixedThreadPool(5); - private Map errorCounts = new HashMap(); + private Map errorCounts = new ConcurrentHashMap(); public RandomDataSourceValidateThread(RandomDataSourceSelector selector) { this.selector = selector; diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java index bd871a9a3b..ccc4153e40 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java @@ -2,6 +2,8 @@ package com.alibaba.druid.pool.ha.selector; 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 javax.sql.DataSource; @@ -13,6 +15,8 @@ import javax.sql.DataSource; * @see StickyDataSourceHolder */ public class StickyRandomDataSourceSelector extends RandomDataSourceSelector { + private final static Log LOG = LogFactory.getLog(StickyRandomDataSourceSelector.class); + private ThreadLocal holders = new ThreadLocal(); private int expireSeconds = 5; @@ -25,8 +29,10 @@ public class StickyRandomDataSourceSelector extends RandomDataSourceSelector { public DataSource get() { StickyDataSourceHolder holder = holders.get(); if (holder != null && isValid(holder) && !isExpired(holder)) { + LOG.debug("Return the sticky DataSource " + holder.getDataSource().toString() + " directly."); return holder.getDataSource(); } + LOG.debug("Return a random DataSource."); DataSource dataSource = super.get(); holder = new StickyDataSourceHolder(dataSource); holders.remove(); diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/BaseRandomDataSourceSelectorTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/BaseRandomDataSourceSelectorTest.java new file mode 100644 index 0000000000..78a6ae9e38 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/BaseRandomDataSourceSelectorTest.java @@ -0,0 +1,31 @@ +package com.alibaba.druid.pool.ha.selector; + +import com.alibaba.druid.pool.ha.HighAvailableDataSource; +import com.alibaba.druid.pool.ha.MockDataSource; +import org.junit.After; +import org.junit.Before; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +public class BaseRandomDataSourceSelectorTest { + protected Map dataSourceMap; + protected HighAvailableDataSource dataSource; + + @Before + public void setUp() { + dataSourceMap = new HashMap(); + for (int i = 0; i < 10; i++) { + dataSourceMap.put(Integer.toString(i), new MockDataSource(Integer.toString(i))); + } + dataSource = new HighAvailableDataSource(); + dataSource.setDataSourceMap(dataSourceMap); + } + + @After + public void tearDown() { + dataSourceMap = null; + dataSource = null; + } +} diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java index 0421ef3c40..cad11e45da 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java @@ -1,39 +1,13 @@ package com.alibaba.druid.pool.ha.selector; -import com.alibaba.druid.pool.ha.HighAvailableDataSource; import com.alibaba.druid.pool.ha.MockDataSource; -import org.junit.After; -import org.junit.Before; import org.junit.Test; -import javax.sql.DataSource; -import java.util.HashMap; -import java.util.Map; - import static org.junit.Assert.assertTrue; -public class RandomDataSourceSelectorTest { - private Map dataSourceMap; - private HighAvailableDataSource dataSource; - - @Before - public void setUp() { - dataSourceMap = new HashMap(); - for (int i = 0; i < 10; i++) { - dataSourceMap.put(Integer.toString(i), new MockDataSource(Integer.toString(i))); - } - dataSource = new HighAvailableDataSource(); - dataSource.setDataSourceMap(dataSourceMap); - } - - @After - public void tearDown() { - dataSourceMap = null; - dataSource = null; - } - +public class RandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTest { @Test - public void testRandomGet() throws Exception { + public void testRandomGet() { RandomDataSourceSelector selector = new RandomDataSourceSelector(dataSource); int[] count = new int[10]; @@ -46,10 +20,4 @@ public class RandomDataSourceSelectorTest { assertTrue(i > 0); } } - - @Test - public void testOneDataSourceFail() { - - } - } \ No newline at end of file diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelectorTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelectorTest.java new file mode 100644 index 0000000000..b58b1d9578 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelectorTest.java @@ -0,0 +1,51 @@ +package com.alibaba.druid.pool.ha.selector; + +import com.alibaba.druid.pool.ha.MockDataSource; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +public class StickyRandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTest { + @Test + public void testGetSameDataSourceInFiveSeconds() throws InterruptedException { + StickyRandomDataSourceSelector selector = new StickyRandomDataSourceSelector(dataSource); + int lastHashCode = selector.get().hashCode(); + for (int i = 0; i < 4; i++) { + assertEquals(lastHashCode, selector.get().hashCode()); + Thread.sleep(1000); + } + } + + @Test + public void testGetDifferentDataSource() throws InterruptedException { + StickyRandomDataSourceSelector selector = new StickyRandomDataSourceSelector(dataSource); + selector.setExpireSeconds(1); + int lastHashCode = selector.get().hashCode(); + boolean hasDifferentDataSource = false; + for (int i = 0; i < 20; i++) { + hasDifferentDataSource = selector.get().hashCode() != lastHashCode; + Thread.sleep(500); + } + assertTrue(hasDifferentDataSource); + } + + @Test + public void testIgnoreForbiddenDataSource() throws InterruptedException { + MockDataSource normal = new MockDataSource("Normal"); + MockDataSource forbidden = new MockDataSource("Forbidden"); + dataSourceMap.put("N", normal); + dataSourceMap.put("F", forbidden); + dataSource.setDataSourceMap(dataSourceMap); + + StickyRandomDataSourceSelector selector = new StickyRandomDataSourceSelector(dataSource); + selector.setExpireSeconds(1); + selector.getBlacklist().add(forbidden); + + for (int i = 0; i < 20; i++) { + assertNotEquals(forbidden, selector.get()); + Thread.sleep(500); + } + } +} From dfcc16107ac83181be99d848704d5a7110a3fb35 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 16:46:32 +0800 Subject: [PATCH 06/14] fix failed testcase --- .../pool/ha/HighAvailableDataSource.java | 4 ++-- ...mDataSourceSelectorWithValidationTest.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index 0c34795751..e6e45879d8 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -86,11 +86,11 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc // Properties copied from DruidAbstractDataSource END private Map dataSourceMap = new ConcurrentHashMap(); - private DataSourceSelector selector = new RandomDataSourceSelector(this); + private DataSourceSelector selector; private String dataSourceFile = DEFAULT_DATA_SOURCE_FILE; private String propertyPrefix = ""; - private boolean inited = false; + private volatile boolean inited = false; public void init() throws SQLException { if (inited) { diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java index f082f8d7f2..13a7a5421c 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java @@ -35,14 +35,12 @@ public class RandomDataSourceSelectorWithValidationTest { selector.getRecoverThread().setSleepSeconds(3); selector.init(); - Thread.sleep(30 * 1000); - DruidDataSource dataSource = (DruidDataSource) highAvailableDataSource.getDataSourceMap().get("foo"); dataSource.setValidationQuery("select xxx from yyy"); - Thread.sleep(10 * 1000); + Thread.sleep(6 * 1000); assertTrue(dataSource.isTestOnReturn()); for (int i = 0; i < 100; i++) { - assertNotEquals(dataSource, highAvailableDataSource.getDataSourceSelector().get()); + assertNotEquals(dataSource, selector.get()); } dataSource.setValidationQuery(null); @@ -50,7 +48,7 @@ public class RandomDataSourceSelectorWithValidationTest { assertFalse(dataSource.isTestOnReturn()); int count = 0; for (int i = 0; i < 100; i++) { - if (dataSource == highAvailableDataSource.getDataSourceSelector().get()) { + if (dataSource == selector.get()) { count++; } } @@ -59,23 +57,23 @@ public class RandomDataSourceSelectorWithValidationTest { @Test public void testAllDataSourceFail() throws Exception { - ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getValidateThread().setCheckingIntervalSeconds(3); - ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()).getRecoverThread().setSleepSeconds(3); - - Thread.sleep(30 * 1000); + RandomDataSourceSelector selector = (RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector(); + selector.setCheckingIntervalSeconds(3); + selector.setRecoveryIntervalSeconds(3); + selector.init(); DruidDataSource foo = (DruidDataSource) highAvailableDataSource.getDataSourceMap().get("foo"); DruidDataSource bar = (DruidDataSource) highAvailableDataSource.getDataSourceMap().get("bar"); foo.setValidationQuery("select xxx from yyy"); bar.setValidationQuery("select xxx from yyy"); - Thread.sleep(10 * 1000); + Thread.sleep(6 * 1000); assertTrue(foo.isTestOnReturn()); assertTrue(bar.isTestOnReturn()); int[] count = new int[2]; for (int i = 0; i < 100; i++) { - DataSource dataSource = highAvailableDataSource.getDataSourceSelector().get(); + DataSource dataSource = selector.get(); if (foo == dataSource) { count[0]++; } else if (bar == dataSource) { From bd87a038be118fdb88b374c220eafc187fb901c2 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 17:23:13 +0800 Subject: [PATCH 07/14] refactor the codes related to DataSourceSelector --- .../pool/ha/HighAvailableDataSource.java | 4 +- .../pool/ha/selector/DataSourceSelector.java | 1 - .../ha/selector/DataSourceSelectorEnum.java | 53 +++++++++++++++++++ .../selector/DataSourceSelectorFactory.java | 13 +++-- .../ha/selector/NamedDataSourceSelector.java | 7 +-- .../ha/selector/RandomDataSourceSelector.java | 7 +-- .../StickyRandomDataSourceSelector.java | 5 ++ 7 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorEnum.java diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index e6e45879d8..899c4a1350 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -167,11 +167,9 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc } public void setSelector(String name) { - if (name != null && this.selector != null && this.selector.isSame(name)) { - return; - } DataSourceSelector selector = DataSourceSelectorFactory.getSelector(name, this); if (selector != null) { + selector.init(); setDataSourceSelector(selector); } } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java index 5db261fa33..301ab7e654 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelector.java @@ -27,7 +27,6 @@ import java.util.Map; public interface DataSourceSelector { DataSource get(); void setTarget(String name); - boolean isSame(String name); String getName(); void init(); } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorEnum.java b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorEnum.java new file mode 100644 index 0000000000..6337716629 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorEnum.java @@ -0,0 +1,53 @@ +package com.alibaba.druid.pool.ha.selector; + +import com.alibaba.druid.pool.ha.HighAvailableDataSource; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + +/** + * An enum holding the names and classes of DataSourceSelector. + * + * @author DigitalSonic + */ +public enum DataSourceSelectorEnum { + BY_NAME("byName", NamedDataSourceSelector.class), + RANDOM("random", RandomDataSourceSelector.class), + STICKY_RANDOM("stickyRandom", StickyRandomDataSourceSelector.class); + + private final static Log LOG = LogFactory.getLog(DataSourceSelectorEnum.class); + private String name; + private Class clazz; + + DataSourceSelectorEnum(String name, Class clazz) { + this.name = name; + this.clazz = clazz; + } + + /** + * Create a new instance of the DataSourceSelector represented by this enum. + * + * @return null if dataSource is not given or exception occurred while creating new instance + */ + public DataSourceSelector newInstance(HighAvailableDataSource dataSource) { + if (dataSource == null) { + LOG.warn("You should provide an instance of HighAvailableDataSource!"); + return null; + } + + DataSourceSelector selector = null; + try { + selector = clazz.getDeclaredConstructor(HighAvailableDataSource.class).newInstance(dataSource); + } catch (Exception e) { + LOG.error("Can not create new instance of " + clazz.getName(), e); + } + return selector; + } + + public String getName() { + return name; + } + + public Class getClazz() { + return clazz; + } +} diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorFactory.java b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorFactory.java index 5ba620400e..4054ab6920 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorFactory.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/DataSourceSelectorFactory.java @@ -23,11 +23,16 @@ import com.alibaba.druid.pool.ha.HighAvailableDataSource; * @author DigitalSonic */ public class DataSourceSelectorFactory { + /** + * Get a new instance of the given selector name. + * + * @return null if the given name do not represent a DataSourceSelector + */ public static DataSourceSelector getSelector(String name, HighAvailableDataSource highAvailableDataSource) { - if ("random".equalsIgnoreCase(name)) { - return new RandomDataSourceSelector(highAvailableDataSource); - } else if ("byName".equalsIgnoreCase(name)) { - return new NamedDataSourceSelector(highAvailableDataSource); + for (DataSourceSelectorEnum e : DataSourceSelectorEnum.values()) { + if (e.getName().equalsIgnoreCase(name)) { + return e.newInstance(highAvailableDataSource); + } } return null; } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java index 515468ca8b..1ce27a2144 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/NamedDataSourceSelector.java @@ -39,14 +39,9 @@ public class NamedDataSourceSelector implements DataSourceSelector { public void init() { } - @Override - public boolean isSame(String name) { - return getName().equalsIgnoreCase(name); - } - @Override public String getName() { - return "byName"; + return DataSourceSelectorEnum.BY_NAME.getName(); } @Override diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java index 8a0a13a0f4..faa520f905 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java @@ -74,14 +74,9 @@ public class RandomDataSourceSelector implements DataSourceSelector { } } - @Override - public boolean isSame(String name) { - return getName().equalsIgnoreCase(name); - } - @Override public String getName() { - return "random"; + return DataSourceSelectorEnum.RANDOM.getName(); } @Override diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java index ccc4153e40..b4ebf7de55 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/StickyRandomDataSourceSelector.java @@ -25,6 +25,11 @@ public class StickyRandomDataSourceSelector extends RandomDataSourceSelector { super(highAvailableDataSource); } + @Override + public String getName() { + return DataSourceSelectorEnum.STICKY_RANDOM.getName(); + } + @Override public DataSource get() { StickyDataSourceHolder holder = holders.get(); From 65085548975141d4e48df021f5924b8f97609155 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 18:23:56 +0800 Subject: [PATCH 08/14] Fix a creation bug Ignore the failure while creating DruidDataSource. --- .../java/com/alibaba/druid/pool/ha/DataSourceCreator.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java b/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java index 72eed4c98f..23b21cef8c 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java +++ b/src/main/java/com/alibaba/druid/pool/ha/DataSourceCreator.java @@ -65,8 +65,12 @@ public class DataSourceCreator { String username = properties.getProperty(n + ".username"); String password = properties.getProperty(n + ".password"); LOG.info("Creating " + n + " with url[" + url + "] and username[" + username + "]."); - DruidDataSource dataSource = create(n, url, username, password, haDataSource); - map.put(n, dataSource); + try { + DruidDataSource dataSource = create(n, url, username, password, haDataSource); + map.put(n, dataSource); + } catch(Exception e) { + LOG.error("Can NOT create DruidDataSource for " + n, e); + } } LOG.info(map.size() + " DruidDataSource(s) created. "); return map; From f681871e49ed1f61916ff81f001e81b5176d0490 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 2 Feb 2019 18:30:56 +0800 Subject: [PATCH 09/14] RandomDataSourceSelector can load some parameters from Properties now --- .../pool/ha/HighAvailableDataSource.java | 42 ++++++++++++-- .../RandomDataSourceRecoverThread.java | 4 ++ .../ha/selector/RandomDataSourceSelector.java | 55 +++++++++++++++---- .../RandomDataSourceValidateThread.java | 12 ++++ .../RandomDataSourceSelectorTest.java | 26 ++++++++- 5 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index 899c4a1350..0b305f8395 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -20,6 +20,7 @@ import com.alibaba.druid.pool.DruidAbstractDataSource; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.WrapperAdapter; import com.alibaba.druid.pool.ha.selector.DataSourceSelector; +import com.alibaba.druid.pool.ha.selector.DataSourceSelectorEnum; import com.alibaba.druid.pool.ha.selector.DataSourceSelectorFactory; import com.alibaba.druid.pool.ha.selector.RandomDataSourceSelector; import com.alibaba.druid.support.logging.Log; @@ -104,8 +105,7 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc dataSourceMap = new DataSourceCreator(dataSourceFile, propertyPrefix).createMap(this); } if (selector == null) { - selector = new RandomDataSourceSelector(this); - selector.init(); + setSelector(DataSourceSelectorEnum.RANDOM.getName()); } if (dataSourceMap == null || dataSourceMap.isEmpty()) { LOG.warn("There is NO DataSource available!!! Please check your configuration."); @@ -188,7 +188,7 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc @Override public Connection getConnection(String username, String password) throws SQLException { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); + throw new UnsupportedOperationException("Not supported by HighAvailableDataSource."); } @Override @@ -228,7 +228,15 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc } public void setConnectProperties(Properties connectProperties) { - this.connectProperties = connectProperties; + if (connectProperties == null) { + connectProperties = new Properties(); + } + + if (this.connectProperties != null) { + this.connectProperties.putAll(connectProperties); + } else { + this.connectProperties = connectProperties; + } } public int getInitialSize() { @@ -413,6 +421,32 @@ public class HighAvailableDataSource extends WrapperAdapter implements DataSourc public void setConnectionProperties(String connectionProperties) { this.connectionProperties = connectionProperties; + + // COPIED FROM DruidAbstractDataSource.setConnectionProperties() + + if (connectionProperties == null || connectionProperties.trim().length() == 0) { + setConnectProperties(null); + return; + } + + String[] entries = connectionProperties.split(";"); + Properties properties = new Properties(); + for (int i = 0; i < entries.length; i++) { + String entry = entries[i]; + if (entry.length() > 0) { + int index = entry.indexOf('='); + if (index > 0) { + String name = entry.substring(0, index); + String value = entry.substring(index + 1); + properties.setProperty(name, value); + } else { + // no value is empty string which is how java.util.Properties works + properties.setProperty(entry, ""); + } + } + } + + setConnectProperties(properties); } public String getFilters() { diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java index 0ab3ed67b5..38249e024e 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java @@ -83,6 +83,10 @@ public class RandomDataSourceRecoverThread implements Runnable { } } + public int getSleepSeconds() { + return sleepSeconds; + } + public void setSleepSeconds(int sleepSeconds) { this.sleepSeconds = sleepSeconds; } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java index faa520f905..fac6ba65a2 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Random; import java.util.concurrent.CopyOnWriteArrayList; @@ -35,6 +36,12 @@ import java.util.concurrent.CopyOnWriteArrayList; * @author DigitalSonic */ public class RandomDataSourceSelector implements DataSourceSelector { + private static final String PROP_PREFIX = "druid.ha.random."; + public static final String PROP_CHECKING_INTERVAL = PROP_PREFIX + "checkingIntervalSeconds"; + public static final String PROP_RECOVERY_INTERVAL = PROP_PREFIX + "recoveryIntervalSeconds"; + public static final String PROP_VALIDATION_SLEEP = PROP_PREFIX + "validationSleepSeconds"; + public static final String PROP_BLACKLIST_THRESHOLD = PROP_PREFIX + "blacklistThreshold"; + private final static Log LOG = LogFactory.getLog(RandomDataSourceSelector.class); private Random random = new Random(); @@ -58,17 +65,9 @@ public class RandomDataSourceSelector implements DataSourceSelector { LOG.warn("highAvailableDataSource is NULL!"); return; } - if (!highAvailableDataSource.isTestOnBorrow() && !highAvailableDataSource.isTestOnReturn()) { - validateThread = new RandomDataSourceValidateThread(this); - validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds); - validateThread.setValidationSleepSeconds(validationSleepSeconds); - validateThread.setBlacklistThreshold(blacklistThreshold); - new Thread(validateThread, "RandomDataSourceSelector-isValid-thread").start(); - - recoverThread = new RandomDataSourceRecoverThread(this); - recoverThread.setSleepSeconds(recoveryIntervalSeconds); - new Thread(recoverThread, "RandomDataSourceSelector-recover-thread").start(); + loadProperties(); + initThreads(); } else { LOG.info("testOnBorrow or testOnReturn has been set to true, ignore validateThread"); } @@ -137,6 +136,42 @@ public class RandomDataSourceSelector implements DataSourceSelector { } } + private void loadProperties() { + checkingIntervalSeconds = loadInteger(PROP_CHECKING_INTERVAL, checkingIntervalSeconds); + recoveryIntervalSeconds = loadInteger(PROP_RECOVERY_INTERVAL, recoveryIntervalSeconds); + validationSleepSeconds = loadInteger(PROP_VALIDATION_SLEEP, validationSleepSeconds); + blacklistThreshold = loadInteger(PROP_BLACKLIST_THRESHOLD, blacklistThreshold); + } + + private int loadInteger(String name, int defaultValue) { + if (name == null) { + return defaultValue; + } + + Properties properties = highAvailableDataSource.getConnectProperties(); + int value = defaultValue; + try { + if (properties.containsKey(name)) { + value = Integer.parseInt(properties.getProperty(name)); + } + } catch (Exception e) { + LOG.error("Exception occurred while parsing " + name, e); + } + return value; + } + + private void initThreads() { + validateThread = new RandomDataSourceValidateThread(this); + validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds); + validateThread.setValidationSleepSeconds(validationSleepSeconds); + validateThread.setBlacklistThreshold(blacklistThreshold); + new Thread(validateThread, "RandomDataSourceSelector-isValid-thread").start(); + + recoverThread = new RandomDataSourceRecoverThread(this); + recoverThread.setSleepSeconds(recoveryIntervalSeconds); + new Thread(recoverThread, "RandomDataSourceSelector-recover-thread").start(); + } + public HighAvailableDataSource getHighAvailableDataSource() { return highAvailableDataSource; } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java index 9f5430f1de..9beca1e65d 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java @@ -174,14 +174,26 @@ public class RandomDataSourceValidateThread implements Runnable { } } + public int getCheckingIntervalSeconds() { + return checkingIntervalSeconds; + } + public void setCheckingIntervalSeconds(int checkingIntervalSeconds) { this.checkingIntervalSeconds = checkingIntervalSeconds; } + public int getValidationSleepSeconds() { + return validationSleepSeconds; + } + public void setValidationSleepSeconds(int validationSleepSeconds) { this.validationSleepSeconds = validationSleepSeconds; } + public int getBlacklistThreshold() { + return blacklistThreshold; + } + public void setBlacklistThreshold(int blacklistThreshold) { this.blacklistThreshold = blacklistThreshold; } diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java index cad11e45da..c37b2337b6 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java @@ -3,6 +3,7 @@ package com.alibaba.druid.pool.ha.selector; import com.alibaba.druid.pool.ha.MockDataSource; import org.junit.Test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class RandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTest { @@ -20,4 +21,27 @@ public class RandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTe assertTrue(i > 0); } } -} \ No newline at end of file + + @Test + public void testCreateSelectorWithProperties() { + String props = "druid.ha.random.checkingIntervalSeconds=60;"; + props += "druid.ha.random.recoveryIntervalSeconds=120;"; + props += "druid.ha.random.validationSleepSeconds=10;"; + props += "druid.ha.random.blacklistThreshold=5;"; + dataSource.setConnectionProperties(props); + + RandomDataSourceSelector selector = new RandomDataSourceSelector(dataSource); + selector.init(); + assertEquals(60, selector.getCheckingIntervalSeconds()); + assertEquals(60, selector.getValidateThread().getCheckingIntervalSeconds()); + + assertEquals(120, selector.getRecoveryIntervalSeconds()); + assertEquals(120, selector.getRecoverThread().getSleepSeconds()); + + assertEquals(10, selector.getValidationSleepSeconds()); + assertEquals(10, selector.getValidateThread().getValidationSleepSeconds()); + + assertEquals(5, selector.getBlacklistThreshold()); + assertEquals(5, selector.getValidateThread().getBlacklistThreshold()); + } +} From c1e73f2fa916b23fa122cf44a26118eee8429950 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Mon, 25 Feb 2019 14:49:45 +0800 Subject: [PATCH 10/14] Optimize the logic in HA Validation. --- .../RandomDataSourceRecoverThread.java | 23 +++++++++++++++- .../ha/selector/RandomDataSourceSelector.java | 27 ++++++++++++------- .../RandomDataSourceValidateThread.java | 8 +++++- .../RandomDataSourceSelectorTest.java | 1 + ...mDataSourceSelectorWithValidationTest.java | 4 +-- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java index 38249e024e..7ea818ae77 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java @@ -31,7 +31,8 @@ import java.sql.Connection; public class RandomDataSourceRecoverThread implements Runnable { private final static Log LOG = LogFactory.getLog(RandomDataSourceRecoverThread.class); private RandomDataSourceSelector selector; - private int sleepSeconds = 30; + private int sleepSeconds = 60; + private int validationSleepSeconds = 0; public RandomDataSourceRecoverThread(RandomDataSourceSelector selector) { this.selector = selector; @@ -61,6 +62,7 @@ public class RandomDataSourceRecoverThread implements Runnable { Connection connection = null; try { connection = dataSource.getConnection(); + sleepBeforeValidation(); dataSource.validateConnection(connection); LOG.info(dataSource.getName() + " is available now."); selector.removeBlacklist(dataSource); @@ -75,6 +77,17 @@ public class RandomDataSourceRecoverThread implements Runnable { } } + private void sleepBeforeValidation() { + if (validationSleepSeconds > 0) { + try { + LOG.debug("Sleep " + validationSleepSeconds + " second(s) before validation."); + Thread.sleep(validationSleepSeconds * 1000); + } catch (InterruptedException e) { + // ignore + } + } + } + private void sleep() { try { Thread.sleep(sleepSeconds * 1000); @@ -90,4 +103,12 @@ public class RandomDataSourceRecoverThread implements Runnable { public void setSleepSeconds(int sleepSeconds) { this.sleepSeconds = sleepSeconds; } + + public int getValidationSleepSeconds() { + return validationSleepSeconds; + } + + public void setValidationSleepSeconds(int validationSleepSeconds) { + this.validationSleepSeconds = validationSleepSeconds; + } } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java index fac6ba65a2..434e30cfbe 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java @@ -51,7 +51,7 @@ public class RandomDataSourceSelector implements DataSourceSelector { private RandomDataSourceRecoverThread recoverThread; private int checkingIntervalSeconds = 15; - private int recoveryIntervalSeconds = 30; + private int recoveryIntervalSeconds = 60; private int validationSleepSeconds = 0; private int blacklistThreshold = 3; @@ -118,6 +118,10 @@ public class RandomDataSourceSelector implements DataSourceSelector { return blacklist; } + public boolean containInBlacklist(DataSource dataSource) { + return dataSource != null && blacklist.contains(dataSource); + } + public void addBlacklist(DataSource dataSource) { if (dataSource != null && !blacklist.contains(dataSource)) { blacklist.add(dataSource); @@ -128,7 +132,7 @@ public class RandomDataSourceSelector implements DataSourceSelector { } public void removeBlacklist(DataSource dataSource) { - if (dataSource != null && blacklist.contains(dataSource)) { + if (containInBlacklist(dataSource)) { blacklist.remove(dataSource); if (dataSource instanceof DruidDataSource) { ((DruidDataSource) dataSource).setTestOnReturn(highAvailableDataSource.isTestOnReturn()); @@ -161,14 +165,19 @@ public class RandomDataSourceSelector implements DataSourceSelector { } private void initThreads() { - validateThread = new RandomDataSourceValidateThread(this); - validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds); - validateThread.setValidationSleepSeconds(validationSleepSeconds); - validateThread.setBlacklistThreshold(blacklistThreshold); - new Thread(validateThread, "RandomDataSourceSelector-isValid-thread").start(); + if (validateThread == null) { + validateThread = new RandomDataSourceValidateThread(this); + validateThread.setCheckingIntervalSeconds(checkingIntervalSeconds); + validateThread.setValidationSleepSeconds(validationSleepSeconds); + validateThread.setBlacklistThreshold(blacklistThreshold); + } + new Thread(validateThread, "RandomDataSourceSelector-validate-thread").start(); - recoverThread = new RandomDataSourceRecoverThread(this); - recoverThread.setSleepSeconds(recoveryIntervalSeconds); + if (recoverThread == null) { + recoverThread = new RandomDataSourceRecoverThread(this); + recoverThread.setSleepSeconds(recoveryIntervalSeconds); + recoverThread.setValidationSleepSeconds(validationSleepSeconds); + } new Thread(recoverThread, "RandomDataSourceSelector-recover-thread").start(); } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java index 9beca1e65d..8a11096c93 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceValidateThread.java @@ -89,7 +89,8 @@ public class RandomDataSourceValidateThread implements Runnable { for (Map.Entry e : errorCounts.entrySet()) { if (e.getValue() <= 0) { selector.removeBlacklist(dataSourceMap.get(e.getKey())); - } else if (e.getValue() >= blacklistThreshold) { + } else if (e.getValue() >= blacklistThreshold + && !selector.containInBlacklist(dataSourceMap.get(e.getKey()))) { LOG.warn("Adding " + e.getKey() + " to blacklist."); selector.addBlacklist(dataSourceMap.get(e.getKey())); } @@ -105,6 +106,11 @@ public class RandomDataSourceValidateThread implements Runnable { continue; } + if (selector.containInBlacklist(e.getValue())) { + LOG.debug(e.getKey() + " is already in blacklist, skip."); + continue; + } + tasks.add(new Callable() { @Override public Boolean call() { diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java index c37b2337b6..a2b88d7468 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorTest.java @@ -40,6 +40,7 @@ public class RandomDataSourceSelectorTest extends BaseRandomDataSourceSelectorTe assertEquals(10, selector.getValidationSleepSeconds()); assertEquals(10, selector.getValidateThread().getValidationSleepSeconds()); + assertEquals(10, selector.getRecoverThread().getValidationSleepSeconds()); assertEquals(5, selector.getBlacklistThreshold()); assertEquals(5, selector.getValidateThread().getBlacklistThreshold()); diff --git a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java index 13a7a5421c..50c284818f 100644 --- a/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java +++ b/src/test/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelectorWithValidationTest.java @@ -31,13 +31,13 @@ public class RandomDataSourceSelectorWithValidationTest { @Test public void testOneDataSourceFailAndRecover() throws Exception { RandomDataSourceSelector selector = ((RandomDataSourceSelector) highAvailableDataSource.getDataSourceSelector()); - selector.setCheckingIntervalSeconds(3); + selector.getValidateThread().setCheckingIntervalSeconds(3); selector.getRecoverThread().setSleepSeconds(3); selector.init(); DruidDataSource dataSource = (DruidDataSource) highAvailableDataSource.getDataSourceMap().get("foo"); dataSource.setValidationQuery("select xxx from yyy"); - Thread.sleep(6 * 1000); + Thread.sleep(10 * 1000); assertTrue(dataSource.isTestOnReturn()); for (int i = 0; i < 100; i++) { assertNotEquals(dataSource, selector.get()); From 3dc254a6c369a63290d585c25ff3f514fb81d213 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Thu, 28 Feb 2019 23:03:58 +0800 Subject: [PATCH 11/14] remove the discard operation after validation failure --- .../pool/ha/selector/RandomDataSourceRecoverThread.java | 5 +---- .../druid/pool/ha/selector/RandomDataSourceSelector.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java index 7ea818ae77..9d8b447fae 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceRecoverThread.java @@ -31,7 +31,7 @@ import java.sql.Connection; public class RandomDataSourceRecoverThread implements Runnable { private final static Log LOG = LogFactory.getLog(RandomDataSourceRecoverThread.class); private RandomDataSourceSelector selector; - private int sleepSeconds = 60; + private int sleepSeconds = 120; private int validationSleepSeconds = 0; public RandomDataSourceRecoverThread(RandomDataSourceSelector selector) { @@ -69,9 +69,6 @@ public class RandomDataSourceRecoverThread implements Runnable { } catch(Exception e) { LOG.warn("DataSource[" + dataSource.getName() + "] is still unavailable. Exception: " + e.getMessage()); - if (connection != null) { - dataSource.discardConnection(connection); - } } finally { JdbcUtils.close(connection); } diff --git a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java index 434e30cfbe..137d461cdd 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java +++ b/src/main/java/com/alibaba/druid/pool/ha/selector/RandomDataSourceSelector.java @@ -51,7 +51,7 @@ public class RandomDataSourceSelector implements DataSourceSelector { private RandomDataSourceRecoverThread recoverThread; private int checkingIntervalSeconds = 15; - private int recoveryIntervalSeconds = 60; + private int recoveryIntervalSeconds = 120; private int validationSleepSeconds = 0; private int blacklistThreshold = 3; From 07bcb98c99c326177843aa8f595847123409d1fb Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Tue, 9 Apr 2019 00:59:48 +0800 Subject: [PATCH 12/14] fix import error --- .../java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java index 5390b51a98..380501e030 100644 --- a/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/ha/HighAvailableDataSource.java @@ -34,8 +34,8 @@ import com.alibaba.druid.pool.DruidAbstractDataSource; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.WrapperAdapter; import com.alibaba.druid.pool.ha.selector.DataSourceSelector; +import com.alibaba.druid.pool.ha.selector.DataSourceSelectorEnum; import com.alibaba.druid.pool.ha.selector.DataSourceSelectorFactory; -import com.alibaba.druid.pool.ha.selector.RandomDataSourceSelector; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; From ce2e7a017930b411996db5e2d2a78aaf23fd3074 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Thu, 18 Apr 2019 17:06:27 +0800 Subject: [PATCH 13/14] add ER_ERROR_ON_CLOSE(1023) to MySqlExceptionSorter --- .../druid/pool/vendor/MySqlExceptionSorter.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/alibaba/druid/pool/vendor/MySqlExceptionSorter.java b/src/main/java/com/alibaba/druid/pool/vendor/MySqlExceptionSorter.java index 6cf7cc8e29..1a1c444fb8 100644 --- a/src/main/java/com/alibaba/druid/pool/vendor/MySqlExceptionSorter.java +++ b/src/main/java/com/alibaba/druid/pool/vendor/MySqlExceptionSorter.java @@ -38,7 +38,7 @@ public class MySqlExceptionSorter implements ExceptionSorter { } switch (errorCode) { - // Communications Errors + // Communications Errors case 1040: // ER_CON_COUNT_ERROR case 1042: // ER_BAD_HOST_ERROR case 1043: // ER_HANDSHAKE_ERROR @@ -46,21 +46,23 @@ public class MySqlExceptionSorter implements ExceptionSorter { case 1081: // ER_IPSOCK_ERROR case 1129: // ER_HOST_IS_BLOCKED case 1130: // ER_HOST_NOT_PRIVILEGED - // Authentication Errors + // Authentication Errors case 1045: // ER_ACCESS_DENIED_ERROR - // Resource errors + // Resource errors case 1004: // ER_CANT_CREATE_FILE case 1005: // ER_CANT_CREATE_TABLE case 1015: // ER_CANT_LOCK case 1021: // ER_DISK_FULL case 1041: // ER_OUT_OF_RESOURCES - // Out-of-memory errors + // Out-of-memory errors case 1037: // ER_OUTOFMEMORY case 1038: // ER_OUT_OF_SORTMEMORY - // Access denied + // Access denied case 1142: // ER_TABLEACCESS_DENIED_ERROR case 1227: // ER_SPECIFIC_ACCESS_DENIED_ERROR + case 1023: // ER_ERROR_ON_CLOSE + case 1290: // ER_OPTION_PREVENTS_STATEMENT return true; default: From 0eed60eff7379e6120b63d466efdc6b61938b5b9 Mon Sep 17 00:00:00 2001 From: taoyu <1255803549@qq.com> Date: Fri, 19 Apr 2019 16:51:39 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E5=88=AB=E5=AD=97=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/alibaba/druid/util/JdbcUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/alibaba/druid/util/JdbcUtils.java b/src/main/java/com/alibaba/druid/util/JdbcUtils.java index d863121c3f..20a895093e 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcUtils.java +++ b/src/main/java/com/alibaba/druid/util/JdbcUtils.java @@ -489,7 +489,7 @@ public final class JdbcUtils implements JdbcConstants { } else if(rawUrl.startsWith("jdbc:presto:")) { return JdbcConstants.PRESTO_DRIVER; }else { - throw new SQLException("unkow jdbc driver : " + rawUrl); + throw new SQLException("unknown jdbc driver : " + rawUrl); } }