This is an automated email from the ASF dual-hosted git repository. panjuan 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 e64dd3e527b Fix connection leak when alter resource (#18812) e64dd3e527b is described below commit e64dd3e527ba93d627dde9f2898e22c52602d2cd Author: Haoran Meng <menghaora...@gmail.com> AuthorDate: Sun Jul 3 22:35:44 2022 +0800 Fix connection leak when alter resource (#18812) --- .../mode/manager/ContextManager.java | 34 ++++++++++++++++++++-- .../mode/manager/ContextManagerTest.java | 8 +++-- 2 files changed, 37 insertions(+), 5 deletions(-) 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 09d32f63d58..0bdc6a2cace 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 @@ -205,7 +205,7 @@ public final class ContextManager implements AutoCloseable { * @throws SQLException SQL exception */ public void addResource(final String databaseName, final Map<String, DataSourceProperties> toBeAddedDataSourcePropsMap) throws SQLException { - refreshMetaDataContext(databaseName, toBeAddedDataSourcePropsMap); + refreshMetaDataContextForAddResource(databaseName, toBeAddedDataSourcePropsMap); metaDataContexts.getPersistService().ifPresent(optional -> optional.getDataSourceService().append(databaseName, toBeAddedDataSourcePropsMap)); } @@ -217,7 +217,7 @@ public final class ContextManager implements AutoCloseable { * @throws SQLException SQL exception */ public void alterResource(final String databaseName, final Map<String, DataSourceProperties> toBeAlteredDataSourcePropsMap) throws SQLException { - refreshMetaDataContext(databaseName, toBeAlteredDataSourcePropsMap); + refreshMetaDataContextForAlterResource(databaseName, toBeAlteredDataSourcePropsMap); metaDataContexts.getPersistService().ifPresent(optional -> optional.getDataSourceService().append(databaseName, toBeAlteredDataSourcePropsMap)); } @@ -493,8 +493,17 @@ public final class ContextManager implements AutoCloseable { return new MetaDataContexts(metaDataContexts.getPersistService().orElse(null), changedMetaData, metaDataContexts.getOptimizerContext()); } - private void refreshMetaDataContext(final String databaseName, final Map<String, DataSourceProperties> dataSourcePropsMap) throws SQLException { + private void refreshMetaDataContextForAddResource(final String databaseName, final Map<String, DataSourceProperties> dataSourcePropsMap) throws SQLException { MetaDataContexts changedMetaDataContexts = buildChangedMetaDataContextWithAddedDataSource(databaseName, dataSourcePropsMap); + refreshMetaDataContext(databaseName, changedMetaDataContexts); + } + + private void refreshMetaDataContextForAlterResource(final String databaseName, final Map<String, DataSourceProperties> dataSourcePropsMap) throws SQLException { + MetaDataContexts changedMetaDataContexts = buildChangedMetaDataContextWithAlteredDataSource(databaseName, dataSourcePropsMap); + refreshMetaDataContext(databaseName, changedMetaDataContexts); + } + + private void refreshMetaDataContext(final String databaseName, final MetaDataContexts changedMetaDataContexts) { metaDataContexts.getMetaData().getDatabases().putAll(changedMetaDataContexts.getMetaData().getDatabases()); metaDataContexts.getOptimizerContext().getFederationMetaData().getDatabases().putAll(changedMetaDataContexts.getOptimizerContext().getFederationMetaData().getDatabases()); metaDataContexts.getOptimizerContext().getParserContexts().putAll(changedMetaDataContexts.getOptimizerContext().getParserContexts()); @@ -530,6 +539,25 @@ public final class ContextManager implements AutoCloseable { return result; } + private MetaDataContexts buildChangedMetaDataContextWithAlteredDataSource(final String databaseName, final Map<String, DataSourceProperties> alteredDataSourceProps) throws SQLException { + ShardingSphereDatabase database = metaDataContexts.getMetaData().getDatabases().get(databaseName); + Map<String, DataSource> pendingClosedDataSources = getChangedDataSources(database, alteredDataSourceProps); + Map<String, DataSourceProperties> pendingAlteredDataSourceProps = alteredDataSourceProps.entrySet().stream().filter(entry -> pendingClosedDataSources.keySet().contains(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + pendingClosedDataSources.values().forEach(database.getResource()::close); + Map<String, DataSource> dataSourceMap = new HashMap<>(database.getResource().getDataSources()); + dataSourceMap.putAll(DataSourcePoolCreator.create(pendingAlteredDataSourceProps)); + ConfigurationProperties props = metaDataContexts.getMetaData().getProps(); + DatabaseConfiguration databaseConfig = new DataSourceProvidedDatabaseConfiguration(dataSourceMap, database.getRuleMetaData().getConfigurations()); + 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); + MetaDataContexts result = new MetaDataContexts(metaDataContexts.getPersistService().orElse(null), metaData, OptimizerContextFactory.create(databases, globalMetaData)); + persistMetaData(result); + return result; + } + private MetaDataContexts buildChangedMetaDataContextWithChangedDataSource(final ShardingSphereDatabase originalDatabase, final Map<String, DataSourceProperties> newDataSourceProps) throws SQLException { Collection<String> deletedDataSources = getDeletedDataSources(originalDatabase, newDataSourceProps).keySet(); 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 9766ea86314..b08cd395894 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 @@ -171,14 +171,18 @@ public final class ContextManagerTest { @Test public void assertAlterResource() throws SQLException { Map<String, ShardingSphereDatabase> originalDatabases = new HashMap<>(Collections.singletonMap("foo_db", createOriginalDatabaseMetaData())); + ShardingSphereResource originalResource = originalDatabases.get("foo_db").getResource(); + DataSource originalDataSource = originalResource.getDataSources().get("bar_ds"); when(metaDataContexts.getMetaData().getDatabases()).thenReturn(originalDatabases); - contextManager.alterResource("foo_db", Collections.singletonMap("bar_ds", new DataSourceProperties(MockedDataSource.class.getName(), createProperties("test", "test")))); + contextManager.alterResource("foo_db", Collections.singletonMap("bar_ds", new DataSourceProperties(MockedDataSource.class.getName(), + createProperties("test", "test")))); + verify(originalResource, times(1)).close(originalDataSource); assertAlteredDataSource((MockedDataSource) contextManager.getMetaDataContexts().getMetaData().getDatabases().get("foo_db").getResource().getDataSources().get("bar_ds")); } private ShardingSphereDatabase createOriginalDatabaseMetaData() { ShardingSphereResource resource = mock(ShardingSphereResource.class); - when(resource.getDataSources()).thenReturn(Collections.singletonMap("foo_db", new MockedDataSource())); + when(resource.getDataSources()).thenReturn(Collections.singletonMap("bar_ds", new MockedDataSource())); ShardingSphereRuleMetaData ruleMetaData = mock(ShardingSphereRuleMetaData.class); when(ruleMetaData.getConfigurations()).thenReturn(new LinkedList<>()); return new ShardingSphereDatabase("foo_db", new MySQLDatabaseType(), resource, ruleMetaData, Collections.emptyMap());