From 2849b62ae77a182306b1cefe726c22e54c5e4e6f Mon Sep 17 00:00:00 2001 From: Haoran Meng Date: Fri, 3 Jan 2025 16:27:09 +0800 Subject: [PATCH] Get reloaded metadata asynchronously after rule configuration altered (#34236) --- .../mode/metadata/MetaDataContextHolder.java | 62 +++++++++++++++++++ .../mode/metadata/MetaDataContextManager.java | 5 +- .../DatabaseRuleConfigurationManager.java | 16 ++--- .../metadata/MetaDataContextHolderTest.java | 46 ++++++++++++++ .../ClusterMetaDataManagerPersistService.java | 16 +++-- 5 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolder.java create mode 100644 mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolderTest.java diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolder.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolder.java new file mode 100644 index 0000000000000..9a8a86852e15f --- /dev/null +++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolder.java @@ -0,0 +1,62 @@ +/* + * 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.metadata; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Meta data context holder. + */ +@AllArgsConstructor +@Slf4j +public final class MetaDataContextHolder { + + @Getter + private final AtomicReference metaDataContexts; + + private final CompletableFuture future = new CompletableFuture<>(); + + /** + * Get meta data contexts. + * + * @return meta data contexts + */ + public MetaDataContexts getMetaDataContextsAsync() { + try { + return future.get(5, TimeUnit.SECONDS); + } catch (final InterruptedException | java.util.concurrent.ExecutionException | java.util.concurrent.TimeoutException ex) { + return metaDataContexts.get(); + } + } + + /** + * Update meta data contexts. + * + * @param reloadMetaDataContexts reload meta data contexts + */ + public void updateMetaDataContextsAsync(final MetaDataContexts reloadMetaDataContexts) { + metaDataContexts.set(reloadMetaDataContexts); + future.complete(reloadMetaDataContexts); + } +} diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextManager.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextManager.java index 7da1734731d5d..4dee15f38ee0d 100644 --- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextManager.java +++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextManager.java @@ -74,13 +74,16 @@ public class MetaDataContextManager { private final RuleConfigurationPersistDecorateEngine ruleConfigPersistDecorateEngine; + private final MetaDataContextHolder metaDataContextHolder; + public MetaDataContextManager(final AtomicReference metaDataContexts, final ComputeNodeInstanceContext computeNodeInstanceContext, final PersistRepository repository) { this.metaDataContexts = metaDataContexts; this.computeNodeInstanceContext = computeNodeInstanceContext; + metaDataContextHolder = new MetaDataContextHolder(metaDataContexts); resourceSwitchManager = new ResourceSwitchManager(); databaseManager = new ShardingSphereDatabaseDataManager(metaDataContexts); storageUnitManager = new StorageUnitManager(metaDataContexts, computeNodeInstanceContext, repository, resourceSwitchManager); - databaseRuleConfigurationManager = new DatabaseRuleConfigurationManager(metaDataContexts, computeNodeInstanceContext, repository); + databaseRuleConfigurationManager = new DatabaseRuleConfigurationManager(metaDataContextHolder, computeNodeInstanceContext, repository); schemaMetaDataManager = new SchemaMetaDataManager(metaDataContexts, repository); ruleItemManager = new RuleItemManager(metaDataContexts, repository, databaseRuleConfigurationManager); globalConfigurationManager = new GlobalConfigurationManager(metaDataContexts, repository); diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/manager/DatabaseRuleConfigurationManager.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/manager/DatabaseRuleConfigurationManager.java index 50361e42ecd85..da56fddff540c 100644 --- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/manager/DatabaseRuleConfigurationManager.java +++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/manager/DatabaseRuleConfigurationManager.java @@ -27,6 +27,7 @@ import org.apache.shardingsphere.infra.rule.builder.database.DatabaseRulesBuilder; import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; import org.apache.shardingsphere.metadata.persist.MetaDataPersistService; +import org.apache.shardingsphere.mode.metadata.MetaDataContextHolder; import org.apache.shardingsphere.mode.metadata.MetaDataContexts; import org.apache.shardingsphere.mode.metadata.MetaDataContextsFactory; import org.apache.shardingsphere.mode.spi.PersistRepository; @@ -35,7 +36,6 @@ import java.util.Collection; import java.util.LinkedList; import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** @@ -43,15 +43,15 @@ */ public final class DatabaseRuleConfigurationManager { - private final AtomicReference metaDataContexts; + private final MetaDataContextHolder metaDataContextHolder; private final ComputeNodeInstanceContext computeNodeInstanceContext; private final MetaDataPersistService metaDataPersistService; - public DatabaseRuleConfigurationManager(final AtomicReference metaDataContexts, final ComputeNodeInstanceContext computeNodeInstanceContext, + public DatabaseRuleConfigurationManager(final MetaDataContextHolder metaDataContextHolder, final ComputeNodeInstanceContext computeNodeInstanceContext, final PersistRepository repository) { - this.metaDataContexts = metaDataContexts; + this.metaDataContextHolder = metaDataContextHolder; this.computeNodeInstanceContext = computeNodeInstanceContext; metaDataPersistService = new MetaDataPersistService(repository); } @@ -65,7 +65,7 @@ public DatabaseRuleConfigurationManager(final AtomicReference */ @SuppressWarnings({"unchecked", "rawtypes"}) public synchronized void alterRuleConfiguration(final String databaseName, final RuleConfiguration ruleConfig) throws SQLException { - ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName); + ShardingSphereDatabase database = metaDataContextHolder.getMetaDataContexts().get().getMetaData().getDatabase(databaseName); Collection rules = new LinkedList<>(database.getRuleMetaData().getRules()); Optional toBeChangedRule = rules.stream().filter(each -> each.getConfiguration().getClass().equals(ruleConfig.getClass())).findFirst(); if (toBeChangedRule.isPresent() && toBeChangedRule.get() instanceof PartialRuleUpdateSupported && ((PartialRuleUpdateSupported) toBeChangedRule.get()).partialUpdate(ruleConfig)) { @@ -87,7 +87,7 @@ public synchronized void alterRuleConfiguration(final String databaseName, final */ @SuppressWarnings({"unchecked", "rawtypes"}) public synchronized void dropRuleConfiguration(final String databaseName, final RuleConfiguration ruleConfig) throws SQLException { - ShardingSphereDatabase database = metaDataContexts.get().getMetaData().getDatabase(databaseName); + ShardingSphereDatabase database = metaDataContextHolder.getMetaDataContexts().get().getMetaData().getDatabase(databaseName); Collection rules = new LinkedList<>(database.getRuleMetaData().getRules()); Optional toBeChangedRule = rules.stream().filter(each -> each.getConfiguration().getClass().equals(ruleConfig.getClass())).findFirst(); if (toBeChangedRule.isPresent() && toBeChangedRule.get() instanceof PartialRuleUpdateSupported && ((PartialRuleUpdateSupported) toBeChangedRule.get()).partialUpdate(ruleConfig)) { @@ -104,8 +104,8 @@ public synchronized void dropRuleConfiguration(final String databaseName, final private void refreshMetadata(final String databaseName, final Collection ruleConfigurations) throws SQLException { MetaDataContexts reloadMetaDataContexts = MetaDataContextsFactory.createByAlterRule(databaseName, false, - ruleConfigurations, metaDataContexts.get(), metaDataPersistService, computeNodeInstanceContext); - metaDataContexts.set(reloadMetaDataContexts); + ruleConfigurations, metaDataContextHolder.getMetaDataContexts().get(), metaDataPersistService, computeNodeInstanceContext); + metaDataContextHolder.updateMetaDataContextsAsync(reloadMetaDataContexts); } private Collection getRuleConfigurations(final Collection rules) { diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolderTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolderTest.java new file mode 100644 index 0000000000000..da176b16f1b72 --- /dev/null +++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/MetaDataContextHolderTest.java @@ -0,0 +1,46 @@ +/* + * 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.metadata; + +import org.junit.jupiter.api.Test; + +import java.util.concurrent.atomic.AtomicReference; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.mockito.Mockito.mock; + +class MetaDataContextHolderTest { + + private final MetaDataContexts metaDataContexts = mock(MetaDataContexts.class); + + private final MetaDataContextHolder metaDataContextHolder = new MetaDataContextHolder(new AtomicReference<>(metaDataContexts)); + + @Test + void assertGetMetaDataContextsAsync() { + assertThat(metaDataContextHolder.getMetaDataContextsAsync(), is(metaDataContexts)); + } + + @Test + void assertUpdateMetaDataContextsAsync() { + assertThat(metaDataContextHolder.getMetaDataContextsAsync(), is(metaDataContexts)); + metaDataContextHolder.updateMetaDataContextsAsync(mock(MetaDataContexts.class)); + assertNotEquals(metaDataContextHolder.getMetaDataContextsAsync(), metaDataContexts); + } +} diff --git a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java index 421ea385b9bc9..f6f9635da24f3 100644 --- a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java +++ b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/persist/service/ClusterMetaDataManagerPersistService.java @@ -215,9 +215,11 @@ public void alterRuleConfiguration(final String databaseName, final RuleConfigur } private void afterRuleConfigurationAltered(final String databaseName, final MetaDataContexts originalMetaDataContexts) { - MetaDataContexts reloadMetaDataContexts = metaDataContextManager.getMetaDataContexts().get(); - metaDataPersistService.persistReloadDatabaseByAlter( - databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName), originalMetaDataContexts.getMetaData().getDatabase(databaseName)); + MetaDataContexts reloadMetaDataContexts = metaDataContextManager.getMetaDataContextHolder().getMetaDataContextsAsync(); + if (!reloadMetaDataContexts.equals(originalMetaDataContexts)) { + metaDataPersistService.persistReloadDatabaseByAlter( + databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName), originalMetaDataContexts.getMetaData().getDatabase(databaseName)); + } } @Override @@ -235,9 +237,11 @@ public void removeRuleConfiguration(final String databaseName, final String rule } private void afterRuleConfigurationDropped(final String databaseName, final MetaDataContexts originalMetaDataContexts) { - MetaDataContexts reloadMetaDataContexts = metaDataContextManager.getMetaDataContexts().get(); - metaDataPersistService.persistReloadDatabaseByDrop( - databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName), originalMetaDataContexts.getMetaData().getDatabase(databaseName)); + MetaDataContexts reloadMetaDataContexts = metaDataContextManager.getMetaDataContextHolder().getMetaDataContextsAsync(); + if (!reloadMetaDataContexts.equals(originalMetaDataContexts)) { + metaDataPersistService.persistReloadDatabaseByDrop( + databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName), originalMetaDataContexts.getMetaData().getDatabase(databaseName)); + } } @Override