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());