This is an automated email from the ASF dual-hosted git repository.

zhaojinchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 3250821747f Add ResourceSwitchManager and SwitchingResource to 
decouple resource change logic (#18836)
3250821747f is described below

commit 3250821747fb4ccab731c1baf0d7292e6e4a0696
Author: Liang Zhang <[email protected]>
AuthorDate: Tue Jul 5 00:14:29 2022 +0800

    Add ResourceSwitchManager and SwitchingResource to decouple resource change 
logic (#18836)
    
    * Add ResourceSwitchManager and SwitchingResource to decouple resource 
change logic
    
    * Refactor
    
    * Fix test case
    
    * Fix test cases
    
    * Fix test cases
    
    * Fix ResourceSwitchManager
---
 .../mysql/constant/MySQLServerErrorCode.java       |  2 +-
 .../metadata/database/ShardingSphereDatabase.java  |  6 +-
 .../database/resource/ShardingSphereResource.java  |  9 ---
 .../jdbc/adapter/AbstractDataSourceAdapter.java    |  2 +-
 .../mode/manager/ContextManager.java               | 53 +++++++++----
 .../manager/switcher/ResourceSwitchManager.java    | 89 ++++++++++++++++++++++
 .../mode/manager/switcher/SwitchingResource.java   | 30 +++++---
 .../mode/manager/ContextManagerTest.java           |  3 +
 .../ClusterContextManagerCoordinatorTest.java      |  2 +
 .../executor/AbstractDatabaseMetadataExecutor.java |  2 +-
 .../admin/mysql/MySQLAdminExecutorCreator.java     |  2 +-
 .../executor/UnicastResourceShowExecutor.java      |  4 +-
 .../impl/SchemaAssignedDatabaseBackendHandler.java |  2 +-
 .../data/impl/UnicastDatabaseBackendHandler.java   |  6 +-
 .../TextProtocolBackendHandlerFactoryTest.java     |  4 +-
 .../SchemaAssignedDatabaseBackendHandlerTest.java  |  2 +-
 .../impl/UnicastDatabaseBackendHandlerTest.java    |  2 +-
 .../protocol/FrontDatabaseProtocolTypeFactory.java |  2 +-
 18 files changed, 167 insertions(+), 55 deletions(-)

diff --git 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
index 2580c41ff85..d0da0e258fe 100644
--- 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
+++ 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
@@ -52,7 +52,7 @@ public enum MySQLServerErrorCode implements SQLErrorCode {
     
     ER_NOT_SUPPORTED_YET(1235, "42000", "This version of ShardingSphere-Proxy 
doesn't yet support this SQL. '%s'"),
     
-    ER_SP_DOES_NOT_EXIST(1305, "42000", "Message: Datasource or ShardingSphere 
rule does not exist"),
+    ER_SP_DOES_NOT_EXIST(1305, "42000", "Message: Data Source or 
ShardingSphere rule does not exist"),
     
     ER_CON_COUNT_ERROR(1040, "HY000", "Too many connections"),
     
diff --git 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabase.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabase.java
index 834811e0d60..9b38b511101 100644
--- 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabase.java
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/ShardingSphereDatabase.java
@@ -113,11 +113,11 @@ public final class ShardingSphereDatabase {
     }
     
     /**
-     * Determine whether there is a data source.
+     * Judge whether contains data source.
      *
-     * @return has datasource or not
+     * @return contains data source or not
      */
-    public boolean hasDataSource() {
+    public boolean containsDataSource() {
         return !resource.getDataSources().isEmpty();
     }
     
diff --git 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/resource/ShardingSphereResource.java
 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/resource/ShardingSphereResource.java
index bb7d815a016..39ae8a29434 100644
--- 
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/resource/ShardingSphereResource.java
+++ 
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/metadata/database/resource/ShardingSphereResource.java
@@ -65,15 +65,6 @@ public final class ShardingSphereResource {
         return result;
     }
     
-    /**
-     * Get all instance data sources.
-     *
-     * @return all instance data sources
-     */
-    public Collection<DataSource> getAllInstanceDataSources() {
-        return dataSources.entrySet().stream().filter(entry -> 
getAllInstanceDataSourceNames().contains(entry.getKey())).map(Entry::getValue).collect(Collectors.toSet());
-    }
-    
     /**
      * Get all instance data source names.
      *
diff --git 
a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
 
b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
index be1072c868a..dee048011db 100644
--- 
a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
+++ 
b/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
@@ -25,7 +25,7 @@ import java.io.PrintWriter;
 import java.util.logging.Logger;
 
 /**
- * Adapter for {@code Datasource}.
+ * Adapter for {@code DataSource}.
  */
 @Getter
 @Setter
diff --git 
a/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
index 32af1998fdf..1d1bf3f4268 100644
--- 
a/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
+++ 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/ContextManager.java
@@ -46,6 +46,8 @@ import 
org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.
 import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
 import 
org.apache.shardingsphere.infra.rule.identifier.type.MutableDataNodeRule;
 import org.apache.shardingsphere.infra.rule.identifier.type.ResourceHeldRule;
+import org.apache.shardingsphere.mode.manager.switcher.ResourceSwitchManager;
+import org.apache.shardingsphere.mode.manager.switcher.SwitchingResource;
 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 
 import javax.sql.DataSource;
@@ -245,7 +247,7 @@ public final class ContextManager implements AutoCloseable {
     @SuppressWarnings("rawtypes")
     public void alterRuleConfiguration(final String databaseName, final 
Collection<RuleConfiguration> ruleConfigs) {
         try {
-            Collection<ResourceHeldRule> staleResourceHeldRules = 
metaDataContexts.getMetaData().getDatabases().get(databaseName).getRuleMetaData().findRules(ResourceHeldRule.class);
+            Collection<ResourceHeldRule> staleResourceHeldRules = 
getStaleResourceHeldRules(databaseName);
             metaDataContexts = 
createMetaDataContextsWithAlteredDatabaseRules(databaseName, ruleConfigs);
             persistMetaData(metaDataContexts);
             
staleResourceHeldRules.forEach(ResourceHeldRule::closeStaleResources);
@@ -254,8 +256,16 @@ public final class ContextManager implements AutoCloseable 
{
         }
     }
     
+    @SuppressWarnings("rawtypes")
+    private Collection<ResourceHeldRule> getStaleResourceHeldRules(final 
String databaseName) {
+        Collection<ResourceHeldRule> result = new LinkedList<>();
+        
result.addAll(metaDataContexts.getMetaData().getDatabases().get(databaseName).getRuleMetaData().findRules(ResourceHeldRule.class));
+        
result.addAll(metaDataContexts.getMetaData().getGlobalRuleMetaData().findRules(ResourceHeldRule.class));
+        return result;
+    }
+    
     private MetaDataContexts 
createMetaDataContextsWithAlteredDatabaseRules(final String databaseName, final 
Collection<RuleConfiguration> ruleConfigs) throws SQLException {
-        Map<String, ShardingSphereDatabase> changedDatabases = 
createChangedDatabases(databaseName, ruleConfigs);
+        Map<String, ShardingSphereDatabase> changedDatabases = 
createChangedDatabasesWithAlteredDatabaseRules(databaseName, ruleConfigs);
         ShardingSphereRuleMetaData changedGlobalMetaData = new 
ShardingSphereRuleMetaData(
                 
GlobalRulesBuilder.buildRules(metaDataContexts.getMetaData().getGlobalRuleMetaData().getConfigurations(),
 changedDatabases, instanceContext));
         return new 
MetaDataContexts(metaDataContexts.getPersistService().orElse(null),
@@ -263,7 +273,7 @@ public final class ContextManager implements AutoCloseable {
                 OptimizerContextFactory.create(changedDatabases, 
changedGlobalMetaData));
     }
     
-    private Map<String, ShardingSphereDatabase> createChangedDatabases(final 
String databaseName, final Collection<RuleConfiguration> ruleConfigs) throws 
SQLException {
+    private Map<String, ShardingSphereDatabase> 
createChangedDatabasesWithAlteredDatabaseRules(final String databaseName, final 
Collection<RuleConfiguration> ruleConfigs) throws SQLException {
         ShardingSphereDatabase changedDatabase = 
ShardingSphereDatabasesFactory.create(databaseName,
                 new 
DataSourceProvidedDatabaseConfiguration(metaDataContexts.getMetaData().getDatabases().get(databaseName).getResource().getDataSources(),
 ruleConfigs),
                 metaDataContexts.getMetaData().getProps(), instanceContext);
@@ -278,25 +288,36 @@ public final class ContextManager implements 
AutoCloseable {
      * @param databaseName database name
      * @param dataSourcePropsMap altered data source properties map
      */
+    @SuppressWarnings("rawtypes")
     public void alterDataSourceConfiguration(final String databaseName, final 
Map<String, DataSourceProperties> dataSourcePropsMap) {
         try {
-            MetaDataContexts changedMetaDataContext = 
createMetaDataContextsWithAlteredResources(databaseName, dataSourcePropsMap);
-            persistMetaData(changedMetaDataContext);
-            refreshMetaDataContext(databaseName, changedMetaDataContext, 
dataSourcePropsMap);
+            Collection<ResourceHeldRule> staleResourceHeldRules = 
getStaleResourceHeldRules(databaseName);
+            SwitchingResource switchingResource = new 
ResourceSwitchManager().create(metaDataContexts.getMetaData().getDatabases().get(databaseName).getResource(),
 dataSourcePropsMap);
+            metaDataContexts = 
createMetaDataContextsWithAlteredResources(databaseName, switchingResource);
+            persistMetaData(metaDataContexts);
+            
staleResourceHeldRules.forEach(ResourceHeldRule::closeStaleResources);
+            switchingResource.closeStaleDataSources();
         } catch (final SQLException ex) {
-            log.error("Alter database:{} data source configuration failed", 
databaseName, ex);
+            log.error("Alter database: {} data source configuration failed", 
databaseName, ex);
         }
     }
     
-    private MetaDataContexts createMetaDataContextsWithAlteredResources(final 
String databaseName, final Map<String, DataSourceProperties> dataSourceProps) 
throws SQLException {
-        ShardingSphereDatabase database = 
metaDataContexts.getMetaData().getDatabases().get(databaseName);
-        DatabaseConfiguration databaseConfig = new 
DataSourceProvidedDatabaseConfiguration(getNewDataSources(database, 
dataSourceProps), database.getRuleMetaData().getConfigurations());
-        ConfigurationProperties props = 
metaDataContexts.getMetaData().getProps();
-        Map<String, ShardingSphereDatabase> databases = 
ShardingSphereDatabasesFactory.create(Collections.singletonMap(database.getName(),
 databaseConfig), props, instanceContext);
-        ShardingSphereRuleMetaData globalMetaData = new 
ShardingSphereRuleMetaData(
-                
GlobalRulesBuilder.buildRules(metaDataContexts.getMetaData().getGlobalRuleMetaData().getConfigurations(),
 databases, instanceContext));
-        ShardingSphereMetaData metaData = new 
ShardingSphereMetaData(databases, globalMetaData, props);
-        return new 
MetaDataContexts(metaDataContexts.getPersistService().orElse(null), metaData, 
OptimizerContextFactory.create(databases, globalMetaData));
+    private MetaDataContexts createMetaDataContextsWithAlteredResources(final 
String databaseName, final SwitchingResource switchingResource) throws 
SQLException {
+        Map<String, ShardingSphereDatabase> changedDatabases = 
createChangedDatabasesWithAlteredResources(databaseName, switchingResource);
+        ShardingSphereRuleMetaData changedGlobalMetaData = new 
ShardingSphereRuleMetaData(
+                
GlobalRulesBuilder.buildRules(metaDataContexts.getMetaData().getGlobalRuleMetaData().getConfigurations(),
 changedDatabases, instanceContext));
+        return new 
MetaDataContexts(metaDataContexts.getPersistService().orElse(null),
+                new ShardingSphereMetaData(changedDatabases, 
changedGlobalMetaData, metaDataContexts.getMetaData().getProps()),
+                OptimizerContextFactory.create(changedDatabases, 
changedGlobalMetaData));
+    }
+    
+    private Map<String, ShardingSphereDatabase> 
createChangedDatabasesWithAlteredResources(final String databaseName, final 
SwitchingResource switchingResource) throws SQLException {
+        DatabaseConfiguration databaseConfig = new 
DataSourceProvidedDatabaseConfiguration(
+                switchingResource.getNewDataSources(), 
metaDataContexts.getMetaData().getDatabases().get(databaseName).getRuleMetaData().getConfigurations());
+        ShardingSphereDatabase changedDatabase = 
ShardingSphereDatabasesFactory.create(databaseName, databaseConfig, 
metaDataContexts.getMetaData().getProps(), instanceContext);
+        Map<String, ShardingSphereDatabase> result = new 
LinkedHashMap<>(metaDataContexts.getMetaData().getDatabases());
+        result.put(databaseName, changedDatabase);
+        return result;
     }
     
     /**
diff --git 
a/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/ResourceSwitchManager.java
 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/ResourceSwitchManager.java
new file mode 100644
index 00000000000..92e7aa8ea96
--- /dev/null
+++ 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/ResourceSwitchManager.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.mode.manager.switcher;
+
+import 
org.apache.shardingsphere.infra.datasource.pool.creator.DataSourcePoolCreator;
+import org.apache.shardingsphere.infra.datasource.props.DataSourceProperties;
+import 
org.apache.shardingsphere.infra.datasource.props.DataSourcePropertiesCreator;
+import 
org.apache.shardingsphere.infra.metadata.database.resource.ShardingSphereResource;
+
+import javax.sql.DataSource;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+/**
+ * Resource switch manager.
+ */
+public final class ResourceSwitchManager {
+    
+    /**
+     * Create switching resource.
+     * 
+     * @param resource resource
+     * @param toBeChangedDataSourceProps to be changed data source properties 
map
+     * @return created switching resource
+     */
+    public SwitchingResource create(final ShardingSphereResource resource, 
final Map<String, DataSourceProperties> toBeChangedDataSourceProps) {
+        return new SwitchingResource(resource, createNewDataSources(resource, 
toBeChangedDataSourceProps), getStaleDataSources(resource, 
toBeChangedDataSourceProps));
+    }
+    
+    private Map<String, DataSource> createNewDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        Map<String, DataSource> result = new 
LinkedHashMap<>(resource.getDataSources());
+        result.keySet().removeAll(getToBeDeletedDataSources(resource, 
toBeChangedDataSourceProps).keySet());
+        result.putAll(createToBeChangedDataSources(resource, 
toBeChangedDataSourceProps));
+        result.putAll(createToBeAddedDataSources(resource, 
toBeChangedDataSourceProps));
+        return result;
+    }
+    
+    private Map<String, DataSource> createToBeChangedDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        return 
DataSourcePoolCreator.create(getChangedDataSourceProperties(resource, 
toBeChangedDataSourceProps));
+    }
+    
+    private Map<String, DataSourceProperties> 
getChangedDataSourceProperties(final ShardingSphereResource resource, final 
Map<String, DataSourceProperties> toBeChangedDataSourceProps) {
+        return toBeChangedDataSourceProps.entrySet().stream().filter(entry -> 
isModifiedDataSource(resource.getDataSources(), entry.getKey(), 
entry.getValue()))
+                .collect(Collectors.toMap(Entry::getKey, Entry::getValue, 
(oldValue, currentValue) -> oldValue, LinkedHashMap::new));
+    }
+    
+    private boolean isModifiedDataSource(final Map<String, DataSource> 
originalDataSources, final String dataSourceName, final DataSourceProperties 
dataSourceProps) {
+        return originalDataSources.containsKey(dataSourceName) && 
!dataSourceProps.equals(DataSourcePropertiesCreator.create(originalDataSources.get(dataSourceName)));
+    }
+    
+    private Map<String, DataSource> createToBeAddedDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        Map<String, DataSourceProperties> toBeAddedDataSourceProps = 
toBeChangedDataSourceProps.entrySet().stream()
+                .filter(entry -> 
!resource.getDataSources().containsKey(entry.getKey())).collect(Collectors.toMap(Entry::getKey,
 Entry::getValue));
+        return DataSourcePoolCreator.create(toBeAddedDataSourceProps);
+    }
+    
+    private Map<String, DataSource> getStaleDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        Map<String, DataSource> result = new 
LinkedHashMap<>(resource.getDataSources().size(), 1);
+        result.putAll(getToBeDeletedDataSources(resource, 
toBeChangedDataSourceProps));
+        result.putAll(getToBeChangedDataSources(resource, 
toBeChangedDataSourceProps));
+        return result;
+    }
+    
+    private Map<String, DataSource> getToBeDeletedDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        return resource.getDataSources().entrySet().stream().filter(entry -> 
!toBeChangedDataSourceProps.containsKey(entry.getKey())).collect(Collectors.toMap(Entry::getKey,
 Entry::getValue));
+    }
+    
+    private Map<String, DataSource> getToBeChangedDataSources(final 
ShardingSphereResource resource, final Map<String, DataSourceProperties> 
toBeChangedDataSourceProps) {
+        Map<String, DataSourceProperties> changedDataSourceProps = 
getChangedDataSourceProperties(resource, toBeChangedDataSourceProps);
+        return resource.getDataSources().entrySet().stream().filter(entry -> 
changedDataSourceProps.containsKey(entry.getKey())).collect(Collectors.toMap(Entry::getKey,
 Entry::getValue));
+    }
+}
diff --git 
a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/SwitchingResource.java
similarity index 58%
copy from 
shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
copy to 
shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/SwitchingResource.java
index be1072c868a..93e585ee46a 100644
--- 
a/shardingsphere-jdbc/shardingsphere-jdbc-core/src/main/java/org/apache/shardingsphere/driver/jdbc/adapter/AbstractDataSourceAdapter.java
+++ 
b/shardingsphere-mode/shardingsphere-mode-core/src/main/java/org/apache/shardingsphere/mode/manager/switcher/SwitchingResource.java
@@ -15,26 +15,32 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.driver.jdbc.adapter;
+package org.apache.shardingsphere.mode.manager.switcher;
 
 import lombok.Getter;
-import lombok.Setter;
+import lombok.RequiredArgsConstructor;
+import 
org.apache.shardingsphere.infra.metadata.database.resource.ShardingSphereResource;
 
 import javax.sql.DataSource;
-import java.io.PrintWriter;
-import java.util.logging.Logger;
+import java.util.Map;
 
 /**
- * Adapter for {@code Datasource}.
+ * Switching resource.
  */
-@Getter
-@Setter
-public abstract class AbstractDataSourceAdapter extends WrapperAdapter 
implements DataSource {
+@RequiredArgsConstructor
+public final class SwitchingResource {
     
-    private PrintWriter logWriter = new PrintWriter(System.out);
+    private final ShardingSphereResource resource;
     
-    @Override
-    public final Logger getParentLogger() {
-        return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+    @Getter
+    private final Map<String, DataSource> newDataSources;
+    
+    private final Map<String, DataSource> staleDataSources;
+    
+    /**
+     * Close stale data sources.
+     */
+    public void closeStaleDataSources() {
+        staleDataSources.values().forEach(resource::close);
     }
 }
diff --git 
a/shardingsphere-mode/shardingsphere-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
 
b/shardingsphere-mode/shardingsphere-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
index f1950338a93..bba6a26dfc1 100644
--- 
a/shardingsphere-mode/shardingsphere-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
+++ 
b/shardingsphere-mode/shardingsphere-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/ContextManagerTest.java
@@ -206,7 +206,9 @@ public final class ContextManagerTest {
         Map<String, ShardingSphereDatabase> databases = new HashMap<>();
         databases.put("foo_db", new ShardingSphereDatabase("foo_db", new 
MySQLDatabaseType(), resource, mock(ShardingSphereRuleMetaData.class), 
Collections.emptyMap()));
         
when(metaDataContexts.getMetaData().getDatabases()).thenReturn(databases);
+        
when(metaDataContexts.getMetaData().getGlobalRuleMetaData()).thenReturn(new 
ShardingSphereRuleMetaData(Collections.emptyList()));
         
when(metaDataContexts.getPersistService()).thenReturn(Optional.of(mock(MetaDataPersistService.class,
 RETURNS_DEEP_STUBS)));
+        // TODO TransactionRule is global rule, do not use it in database rule 
test
         RuleConfiguration ruleConfig = new 
TransactionRuleConfiguration("LOCAL", null, new Properties());
         contextManager.alterRuleConfiguration("foo_db", 
Collections.singleton(ruleConfig));
         // TODO create DistributedRuleFixture to assert alter rule
@@ -218,6 +220,7 @@ public final class ContextManagerTest {
         ShardingSphereDatabase originalDatabaseMetaData = new 
ShardingSphereDatabase(
                 "foo_db", new MySQLDatabaseType(), createOriginalResource(), 
createOriginalRuleMetaData(), Collections.emptyMap());
         
when(metaDataContexts.getMetaData().getDatabases()).thenReturn(Collections.singletonMap("foo_db",
 originalDatabaseMetaData));
+        
when(metaDataContexts.getMetaData().getGlobalRuleMetaData()).thenReturn(new 
ShardingSphereRuleMetaData(Collections.emptyList()));
         contextManager.alterDataSourceConfiguration("foo_db", 
Collections.singletonMap("foo_ds", new 
DataSourceProperties(MockedDataSource.class.getName(), createProperties("test", 
"test"))));
         
assertThat(contextManager.getMetaDataContexts().getMetaData().getDatabases().get("foo_db").getResource().getDataSources().size(),
 is(1));
         assertAlteredDataSource((MockedDataSource) 
contextManager.getMetaDataContexts().getMetaData().getDatabases().get("foo_db").getResource().getDataSources().get("foo_ds"));
diff --git 
a/shardingsphere-mode/shardingsphere-mode-type/shardingsphere-cluster-mode/shardingsphere-cluster-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/ClusterContextManagerCoordinatorTest.java
 
b/shardingsphere-mode/shardingsphere-mode-type/shardingsphere-cluster-mode/shardingsphere-cluster-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/ClusterContextManagerCoordinatorTest.java
index 653fbc31659..490463a275f 100644
--- 
a/shardingsphere-mode/shardingsphere-mode-type/shardingsphere-cluster-mode/shardingsphere-cluster-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/ClusterContextManagerCoordinatorTest.java
+++ 
b/shardingsphere-mode/shardingsphere-mode-type/shardingsphere-cluster-mode/shardingsphere-cluster-mode-core/src/test/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/ClusterContextManagerCoordinatorTest.java
@@ -44,6 +44,7 @@ import 
org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.
 import 
org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereTable;
 import org.apache.shardingsphere.infra.metadata.user.ShardingSphereUser;
 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.rule.identifier.type.ResourceHeldRule;
 import 
org.apache.shardingsphere.infra.rule.identifier.type.StatusContainedRule;
 import org.apache.shardingsphere.infra.state.StateType;
 import org.apache.shardingsphere.mode.manager.ContextManager;
@@ -158,6 +159,7 @@ public final class ClusterContextManagerCoordinatorTest {
         
when(database.getSchemas().get(DefaultDatabase.LOGIC_NAME)).thenReturn(mock(ShardingSphereSchema.class));
         when(database.getRuleMetaData().getRules()).thenReturn(new 
LinkedList<>());
         
when(database.getRuleMetaData().getConfigurations()).thenReturn(Collections.emptyList());
+        
when(database.getRuleMetaData().findRules(ResourceHeldRule.class)).thenReturn(Collections.emptyList());
         return new HashMap<>(Collections.singletonMap("db", database));
     }
     
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
index 47a8a89e1f2..ffc5078ac30 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/executor/AbstractDatabaseMetadataExecutor.java
@@ -152,7 +152,7 @@ public abstract class AbstractDatabaseMetadataExecutor 
implements DatabaseAdminQ
      * @return has datasource or not
      */
     protected static Boolean hasDatasource(final String databaseName) {
-        return 
ProxyContext.getInstance().getDatabase(databaseName).hasDataSource();
+        return 
ProxyContext.getInstance().getDatabase(databaseName).containsDataSource();
     }
     
     /**
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
index fb969cb982f..829b24e061f 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/MySQLAdminExecutorCreator.java
@@ -174,7 +174,7 @@ public final class MySQLAdminExecutorCreator implements 
DatabaseAdminExecutorCre
     }
     
     private boolean hasResources() {
-        return 
ProxyContext.getInstance().getAllDatabaseNames().stream().anyMatch(each -> 
ProxyContext.getInstance().getDatabase(each).hasDataSource());
+        return 
ProxyContext.getInstance().getAllDatabaseNames().stream().anyMatch(each -> 
ProxyContext.getInstance().getDatabase(each).containsDataSource());
     }
     
     private boolean isSetClientEncoding(final SetStatement setStatement) {
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/UnicastResourceShowExecutor.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/UnicastResourceShowExecutor.java
index 857d42a1c6d..aa29c269b92 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/UnicastResourceShowExecutor.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/admin/mysql/executor/UnicastResourceShowExecutor.java
@@ -72,7 +72,7 @@ public final class UnicastResourceShowExecutor implements 
DatabaseAdminQueryExec
     public void execute(final ConnectionSession connectionSession) throws 
SQLException {
         String originDatabase = connectionSession.getDatabaseName();
         String databaseName = null == originDatabase ? getFirstDatabaseName() 
: originDatabase;
-        if 
(!ProxyContext.getInstance().getDatabase(databaseName).hasDataSource()) {
+        if 
(!ProxyContext.getInstance().getDatabase(databaseName).containsDataSource()) {
             throw new RuleNotExistedException();
         }
         try {
@@ -93,7 +93,7 @@ public final class UnicastResourceShowExecutor implements 
DatabaseAdminQueryExec
         if (databaseNames.isEmpty()) {
             throw new NoDatabaseSelectedException();
         }
-        Optional<String> result = databaseNames.stream().filter(each -> 
ProxyContext.getInstance().getDatabase(each).hasDataSource()).findFirst();
+        Optional<String> result = databaseNames.stream().filter(each -> 
ProxyContext.getInstance().getDatabase(each).containsDataSource()).findFirst();
         if (!result.isPresent()) {
             throw new RuleNotExistedException();
         }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandler.java
index 96d4159e2b2..fa5188696c8 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandler.java
@@ -78,7 +78,7 @@ public final class SchemaAssignedDatabaseBackendHandler 
implements DatabaseBacke
     private void prepareDatabaseCommunicationEngine() throws 
RequiredResourceMissedException {
         ShardingSphereDatabase database = 
ProxyContext.getInstance().getDatabase(connectionSession.getDatabaseName());
         boolean isSystemSchema = 
SystemSchemaUtil.containsSystemSchema(sqlStatementContext.getDatabaseType(), 
sqlStatementContext.getTablesContext().getSchemaNames(), database);
-        if (!isSystemSchema && !database.hasDataSource()) {
+        if (!isSystemSchema && !database.containsDataSource()) {
             throw new 
RequiredResourceMissedException(connectionSession.getDatabaseName());
         }
         if (!isSystemSchema && !database.isComplete()) {
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandler.java
index 041a7a8bec2..d8399db07ad 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/main/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandler.java
@@ -55,7 +55,7 @@ public final class UnicastDatabaseBackendHandler implements 
DatabaseBackendHandl
     public Future<ResponseHeader> executeFuture() {
         String originDatabase = connectionSession.getDatabaseName();
         String databaseName = null == originDatabase ? getFirstDatabaseName() 
: originDatabase;
-        if 
(!ProxyContext.getInstance().getDatabase(databaseName).hasDataSource()) {
+        if 
(!ProxyContext.getInstance().getDatabase(databaseName).containsDataSource()) {
             throw new RuleNotExistedException();
         }
         connectionSession.setCurrentDatabase(databaseName);
@@ -70,7 +70,7 @@ public final class UnicastDatabaseBackendHandler implements 
DatabaseBackendHandl
     public ResponseHeader execute() throws SQLException {
         String originDatabase = connectionSession.getDefaultDatabaseName();
         String databaseName = null == originDatabase ? getFirstDatabaseName() 
: originDatabase;
-        if 
(!ProxyContext.getInstance().getDatabase(databaseName).hasDataSource()) {
+        if 
(!ProxyContext.getInstance().getDatabase(databaseName).containsDataSource()) {
             throw new RuleNotExistedException();
         }
         try {
@@ -87,7 +87,7 @@ public final class UnicastDatabaseBackendHandler implements 
DatabaseBackendHandl
         if (databaseNames.isEmpty()) {
             throw new NoDatabaseSelectedException();
         }
-        Optional<String> result = databaseNames.stream().filter(each -> 
ProxyContext.getInstance().getDatabase(each).hasDataSource()).findFirst();
+        Optional<String> result = databaseNames.stream().filter(each -> 
ProxyContext.getInstance().getDatabase(each).containsDataSource()).findFirst();
         if (!result.isPresent()) {
             throw new RuleNotExistedException();
         }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
index 2e1643cf73f..73e3c561e64 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/TextProtocolBackendHandlerFactoryTest.java
@@ -189,7 +189,7 @@ public final class TextProtocolBackendHandlerFactoryTest 
extends ProxyContextRes
         ProxyContext proxyContext = ProxyContext.getInstance();
         when(proxyContext.getAllDatabaseNames()).thenReturn(new 
HashSet<>(Collections.singletonList("schema")));
         
when(proxyContext.getContextManager().getMetaDataContexts().getMetaData().getDatabases().containsKey("schema")).thenReturn(true);
-        
when(proxyContext.getDatabase("schema").hasDataSource()).thenReturn(true);
+        
when(proxyContext.getDatabase("schema").containsDataSource()).thenReturn(true);
         TextProtocolBackendHandler actual = 
TextProtocolBackendHandlerFactory.newInstance(databaseType, sql, 
Optional::empty, connectionSession);
         assertThat(actual, instanceOf(DatabaseBackendHandler.class));
     }
@@ -222,7 +222,7 @@ public final class TextProtocolBackendHandlerFactoryTest 
extends ProxyContextRes
         String sql = "select * from t_order limit 1";
         ProxyContext proxyContext = ProxyContext.getInstance();
         when(proxyContext.getAllDatabaseNames()).thenReturn(new 
HashSet<>(Collections.singletonList("db")));
-        when(proxyContext.getDatabase("db").hasDataSource()).thenReturn(true);
+        
when(proxyContext.getDatabase("db").containsDataSource()).thenReturn(true);
         TextProtocolBackendHandler actual = 
TextProtocolBackendHandlerFactory.newInstance(databaseType, sql, 
Optional::empty, connectionSession);
         assertThat(actual, 
instanceOf(SchemaAssignedDatabaseBackendHandler.class));
         sql = "select * from information_schema.schemata limit 1";
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandlerTest.java
index 1882b7d29cc..a2208f89610 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandlerTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/SchemaAssignedDatabaseBackendHandlerTest.java
@@ -99,7 +99,7 @@ public final class SchemaAssignedDatabaseBackendHandlerTest 
extends ProxyContext
         for (int i = 0; i < 10; i++) {
             ShardingSphereDatabase database = 
mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS);
             when(database.isComplete()).thenReturn(true);
-            when(database.hasDataSource()).thenReturn(true);
+            when(database.containsDataSource()).thenReturn(true);
             when(database.getResource().getDatabaseType()).thenReturn(new 
H2DatabaseType());
             result.put(String.format(DATABASE_PATTERN, i), database);
         }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandlerTest.java
index dc10ca4bb48..6974bcdfd74 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandlerTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-backend/src/test/java/org/apache/shardingsphere/proxy/backend/text/data/impl/UnicastDatabaseBackendHandlerTest.java
@@ -93,7 +93,7 @@ public final class UnicastDatabaseBackendHandlerTest extends 
ProxyContextRestore
         Map<String, ShardingSphereDatabase> result = new HashMap<>(10, 1);
         for (int i = 0; i < 10; i++) {
             ShardingSphereDatabase database = 
mock(ShardingSphereDatabase.class, RETURNS_DEEP_STUBS);
-            when(database.hasDataSource()).thenReturn(true);
+            when(database.containsDataSource()).thenReturn(true);
             when(database.getResource().getDatabaseType()).thenReturn(new 
H2DatabaseType());
             result.put(String.format(DATABASE_PATTERN, i), database);
         }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-core/src/main/java/org/apache/shardingsphere/proxy/frontend/protocol/FrontDatabaseProtocolTypeFactory.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-core/src/main/java/org/apache/shardingsphere/proxy/frontend/protocol/FrontDatabaseProtocolTypeFactory.java
index 3a9aabc41a8..f871320805e 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-core/src/main/java/org/apache/shardingsphere/proxy/frontend/protocol/FrontDatabaseProtocolTypeFactory.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-core/src/main/java/org/apache/shardingsphere/proxy/frontend/protocol/FrontDatabaseProtocolTypeFactory.java
@@ -50,7 +50,7 @@ public final class FrontDatabaseProtocolTypeFactory {
         if (metaDataContexts.getMetaData().getDatabases().isEmpty()) {
             return 
DatabaseTypeEngine.getTrunkDatabaseType(DEFAULT_FRONTEND_DATABASE_PROTOCOL_TYPE);
         }
-        Optional<ShardingSphereDatabase> database = 
metaDataContexts.getMetaData().getDatabases().values().stream().filter(ShardingSphereDatabase::hasDataSource).findFirst();
+        Optional<ShardingSphereDatabase> database = 
metaDataContexts.getMetaData().getDatabases().values().stream().filter(ShardingSphereDatabase::containsDataSource).findFirst();
         return database.isPresent() ? 
database.get().getResource().getDatabaseType() : 
DatabaseTypeEngine.getTrunkDatabaseType(DEFAULT_FRONTEND_DATABASE_PROTOCOL_TYPE);
     }
     

Reply via email to