View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.mode.manager.standalone;
19  
20  import com.google.common.base.Strings;
21  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
22  import org.apache.shardingsphere.infra.connection.refresher.util.TableRefreshUtils;
23  import org.apache.shardingsphere.infra.datasource.pool.props.domain.DataSourcePoolProperties;
24  import org.apache.shardingsphere.infra.instance.mode.ModeContextManager;
25  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
26  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
27  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
28  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
29  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereView;
30  import org.apache.shardingsphere.infra.metadata.database.schema.pojo.AlterSchemaMetaDataPOJO;
31  import org.apache.shardingsphere.infra.metadata.database.schema.pojo.AlterSchemaPOJO;
32  import org.apache.shardingsphere.infra.metadata.version.MetaDataVersion;
33  import org.apache.shardingsphere.infra.rule.attribute.datanode.MutableDataNodeRuleAttribute;
34  import org.apache.shardingsphere.infra.rule.scope.GlobalRule;
35  import org.apache.shardingsphere.infra.rule.scope.GlobalRule.GlobalRuleChangedType;
36  import org.apache.shardingsphere.infra.spi.type.ordered.cache.OrderedServicesCache;
37  import org.apache.shardingsphere.metadata.persist.service.config.database.DatabaseBasedPersistService;
38  import org.apache.shardingsphere.metadata.persist.service.database.DatabaseMetaDataBasedPersistService;
39  import org.apache.shardingsphere.mode.event.DataChangedEvent;
40  import org.apache.shardingsphere.mode.event.DataChangedEvent.Type;
41  import org.apache.shardingsphere.mode.manager.ContextManager;
42  import org.apache.shardingsphere.mode.manager.ContextManagerAware;
43  import org.apache.shardingsphere.mode.manager.switcher.ResourceSwitchManager;
44  import org.apache.shardingsphere.mode.manager.switcher.SwitchingResource;
45  import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
46  import org.apache.shardingsphere.mode.metadata.builder.RuleConfigurationEventBuilder;
47  import org.apache.shardingsphere.single.api.config.SingleRuleConfiguration;
48  
49  import java.sql.SQLException;
50  import java.util.Collection;
51  import java.util.Collections;
52  import java.util.LinkedHashSet;
53  import java.util.Map;
54  import java.util.Map.Entry;
55  import java.util.Optional;
56  import java.util.Properties;
57  import java.util.stream.Collectors;
58  
59  /**
60   * Standalone mode context manager.
61   */
62  public final class StandaloneModeContextManager implements ModeContextManager, ContextManagerAware {
63      
64      private final RuleConfigurationEventBuilder ruleConfigurationEventBuilder = new RuleConfigurationEventBuilder();
65      
66      private ContextManager contextManager;
67      
68      @Override
69      public void createDatabase(final String databaseName) {
70          contextManager.getResourceMetaDataContextManager().addDatabase(databaseName);
71          contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService().addDatabase(databaseName);
72          clearServiceCache();
73      }
74      
75      @Override
76      public void dropDatabase(final String databaseName) {
77          contextManager.getResourceMetaDataContextManager().dropDatabase(databaseName);
78          contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService().dropDatabase(databaseName);
79          clearServiceCache();
80      }
81      
82      @Override
83      public void createSchema(final String databaseName, final String schemaName) {
84          ShardingSphereSchema schema = new ShardingSphereSchema();
85          ShardingSphereMetaData metaData = contextManager.getMetaDataContexts().getMetaData();
86          ShardingSphereDatabase database = metaData.getDatabase(databaseName);
87          database.addSchema(schemaName, schema);
88          metaData.getGlobalRuleMetaData().getRules().forEach(each -> ((GlobalRule) each).refresh(metaData.getDatabases(), GlobalRuleChangedType.SCHEMA_CHANGED));
89          contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService().persistByAlterConfiguration(databaseName, schemaName, schema);
90      }
91      
92      @Override
93      public void alterSchema(final AlterSchemaPOJO alterSchemaPOJO) {
94          ShardingSphereMetaData metaData = contextManager.getMetaDataContexts().getMetaData();
95          ShardingSphereDatabase database = metaData.getDatabase(alterSchemaPOJO.getDatabaseName());
96          putSchemaMetaData(database, alterSchemaPOJO.getSchemaName(), alterSchemaPOJO.getRenameSchemaName(), alterSchemaPOJO.getLogicDataSourceName());
97          removeSchemaMetaData(database, alterSchemaPOJO.getSchemaName());
98          metaData.getGlobalRuleMetaData().getRules().forEach(each -> ((GlobalRule) each).refresh(metaData.getDatabases(), GlobalRuleChangedType.SCHEMA_CHANGED));
99          DatabaseMetaDataBasedPersistService databaseMetaDataService = contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService();
100         databaseMetaDataService.persistByAlterConfiguration(alterSchemaPOJO.getDatabaseName(), alterSchemaPOJO.getRenameSchemaName(), database.getSchema(alterSchemaPOJO.getRenameSchemaName()));
101         databaseMetaDataService.getViewMetaDataPersistService().persist(alterSchemaPOJO.getDatabaseName(), alterSchemaPOJO.getRenameSchemaName(),
102                 database.getSchema(alterSchemaPOJO.getRenameSchemaName()).getViews());
103         databaseMetaDataService.dropSchema(alterSchemaPOJO.getDatabaseName(), alterSchemaPOJO.getSchemaName());
104     }
105     
106     private void putSchemaMetaData(final ShardingSphereDatabase database, final String schemaName, final String renameSchemaName, final String logicDataSourceName) {
107         ShardingSphereSchema schema = database.getSchema(schemaName);
108         database.addSchema(renameSchemaName, schema);
109         addDataNode(database, logicDataSourceName, schemaName, schema.getAllTableNames());
110     }
111     
112     private void addDataNode(final ShardingSphereDatabase database, final String logicDataSourceName, final String schemaName, final Collection<String> tobeAddedTableNames) {
113         tobeAddedTableNames.forEach(each -> {
114             if (!Strings.isNullOrEmpty(logicDataSourceName) && TableRefreshUtils.isSingleTable(each, database)) {
115                 database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class).forEach(rule -> rule.put(logicDataSourceName, schemaName, each));
116             }
117         });
118     }
119     
120     private void addDataNode(final ShardingSphereDatabase database, final String logicDataSourceName, final String schemaName, final Map<String, ShardingSphereTable> toBeAddedTables,
121                              final Map<String, ShardingSphereView> toBeAddedViews) {
122         addTablesToDataNode(database, schemaName, logicDataSourceName, toBeAddedTables);
123         addViewsToDataNode(database, schemaName, logicDataSourceName, toBeAddedTables, toBeAddedViews);
124     }
125     
126     private void addTablesToDataNode(final ShardingSphereDatabase database, final String schemaName, final String logicDataSourceName, final Map<String, ShardingSphereTable> toBeAddedTables) {
127         for (Entry<String, ShardingSphereTable> entry : toBeAddedTables.entrySet()) {
128             if (!Strings.isNullOrEmpty(logicDataSourceName) && TableRefreshUtils.isSingleTable(entry.getKey(), database)) {
129                 database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class).forEach(rule -> rule.put(logicDataSourceName, schemaName, entry.getKey()));
130             }
131             database.getSchema(schemaName).putTable(entry.getKey(), entry.getValue());
132         }
133     }
134     
135     private void addViewsToDataNode(final ShardingSphereDatabase database, final String schemaName, final String logicDataSourceName,
136                                     final Map<String, ShardingSphereTable> toBeAddedTables, final Map<String, ShardingSphereView> toBeAddedViews) {
137         for (Entry<String, ShardingSphereView> entry : toBeAddedViews.entrySet()) {
138             if (!Strings.isNullOrEmpty(logicDataSourceName) && TableRefreshUtils.isSingleTable(entry.getKey(), database)) {
139                 database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class).forEach(each -> each.put(logicDataSourceName, schemaName, entry.getKey()));
140             }
141             database.getSchema(schemaName).putTable(entry.getKey(), toBeAddedTables.get(entry.getKey().toLowerCase()));
142             database.getSchema(schemaName).putView(entry.getKey(), entry.getValue());
143         }
144     }
145     
146     private void removeSchemaMetaData(final ShardingSphereDatabase database, final String schemaName) {
147         ShardingSphereSchema schema = new ShardingSphereSchema(database.getSchema(schemaName).getTables(), database.getSchema(schemaName).getViews());
148         database.dropSchema(schemaName);
149         removeDataNode(database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class), Collections.singletonList(schemaName), schema.getAllTableNames());
150     }
151     
152     private void removeDataNode(final Collection<MutableDataNodeRuleAttribute> ruleAttributes, final Collection<String> schemaNames, final Collection<String> tobeRemovedTables) {
153         tobeRemovedTables.forEach(each -> ruleAttributes.forEach(rule -> rule.remove(schemaNames, each)));
154     }
155     
156     private void removeDataNode(final ShardingSphereDatabase database, final String schemaName, final Collection<String> tobeRemovedTables, final Collection<String> tobeRemovedViews) {
157         removeTablesToDataNode(database, schemaName, tobeRemovedTables);
158         removeViewsToDataNode(database, schemaName, tobeRemovedTables, tobeRemovedViews);
159     }
160     
161     private void removeDataNode(final Collection<MutableDataNodeRuleAttribute> ruleAttributes, final String schemaName, final Collection<String> tobeRemovedTables) {
162         tobeRemovedTables.forEach(each -> ruleAttributes.forEach(rule -> rule.remove(schemaName, each)));
163     }
164     
165     private void removeTablesToDataNode(final ShardingSphereDatabase database, final String schemaName, final Collection<String> toBeDroppedTables) {
166         removeDataNode(database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class), schemaName, toBeDroppedTables);
167         toBeDroppedTables.forEach(each -> database.getSchema(schemaName).removeTable(each));
168     }
169     
170     private void removeViewsToDataNode(final ShardingSphereDatabase database, final String schemaName, final Collection<String> toBeDroppedTables, final Collection<String> toBeDroppedViews) {
171         removeDataNode(database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class), schemaName, toBeDroppedViews);
172         ShardingSphereSchema schema = database.getSchema(schemaName);
173         toBeDroppedTables.forEach(schema::removeTable);
174         toBeDroppedViews.forEach(schema::removeView);
175     }
176     
177     @Override
178     public void dropSchema(final String databaseName, final Collection<String> schemaNames) {
179         Collection<String> tobeRemovedTables = new LinkedHashSet<>();
180         Collection<String> tobeRemovedSchemas = new LinkedHashSet<>();
181         ShardingSphereMetaData metaData = contextManager.getMetaDataContexts().getMetaData();
182         ShardingSphereDatabase database = metaData.getDatabase(databaseName);
183         for (String each : schemaNames) {
184             ShardingSphereSchema schema = new ShardingSphereSchema(database.getSchema(each).getTables(), database.getSchema(each).getViews());
185             database.dropSchema(each);
186             Optional.of(schema).ifPresent(optional -> tobeRemovedTables.addAll(optional.getAllTableNames()));
187             tobeRemovedSchemas.add(each.toLowerCase());
188         }
189         removeDataNode(database.getRuleMetaData().getAttributes(MutableDataNodeRuleAttribute.class), tobeRemovedSchemas, tobeRemovedTables);
190         metaData.getGlobalRuleMetaData().getRules().forEach(each -> ((GlobalRule) each).refresh(metaData.getDatabases(), GlobalRuleChangedType.SCHEMA_CHANGED));
191     }
192     
193     @Override
194     public void alterSchemaMetaData(final AlterSchemaMetaDataPOJO alterSchemaMetaDataPOJO) {
195         String databaseName = alterSchemaMetaDataPOJO.getDatabaseName();
196         String schemaName = alterSchemaMetaDataPOJO.getSchemaName();
197         ShardingSphereMetaData metaData = contextManager.getMetaDataContexts().getMetaData();
198         ShardingSphereDatabase database = metaData.getDatabase(databaseName);
199         Map<String, ShardingSphereTable> tables = alterSchemaMetaDataPOJO.getAlteredTables().stream().collect(Collectors.toMap(ShardingSphereTable::getName, table -> table));
200         Map<String, ShardingSphereView> views = alterSchemaMetaDataPOJO.getAlteredViews().stream().collect(Collectors.toMap(ShardingSphereView::getName, view -> view));
201         addDataNode(database, alterSchemaMetaDataPOJO.getLogicDataSourceName(), schemaName, tables, views);
202         removeDataNode(database, schemaName, alterSchemaMetaDataPOJO.getDroppedTables(), alterSchemaMetaDataPOJO.getDroppedViews());
203         metaData.getGlobalRuleMetaData().getRules().forEach(each -> ((GlobalRule) each).refresh(metaData.getDatabases(), GlobalRuleChangedType.SCHEMA_CHANGED));
204         DatabaseMetaDataBasedPersistService databaseMetaDataService = contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService();
205         databaseMetaDataService.getTableMetaDataPersistService().persist(databaseName, schemaName, tables);
206         databaseMetaDataService.getViewMetaDataPersistService().persist(databaseName, schemaName, views);
207         alterSchemaMetaDataPOJO.getDroppedTables().forEach(each -> databaseMetaDataService.getTableMetaDataPersistService().delete(databaseName, schemaName, each));
208         alterSchemaMetaDataPOJO.getDroppedViews().forEach(each -> databaseMetaDataService.getViewMetaDataPersistService().delete(databaseName, schemaName, each));
209     }
210     
211     @Override
212     public void registerStorageUnits(final String databaseName, final Map<String, DataSourcePoolProperties> toBeRegisteredProps) throws SQLException {
213         SwitchingResource switchingResource =
214                 new ResourceSwitchManager().registerStorageUnit(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getResourceMetaData(), toBeRegisteredProps);
215         contextManager.getMetaDataContexts().getMetaData().getDatabases().putAll(contextManager.getConfigurationContextManager().createChangedDatabases(databaseName, false, switchingResource, null));
216         contextManager.getMetaDataContexts().getMetaData().getGlobalRuleMetaData().getRules()
217                 .forEach(each -> ((GlobalRule) each).refresh(contextManager.getMetaDataContexts().getMetaData().getDatabases(), GlobalRuleChangedType.DATABASE_CHANGED));
218         contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getSchemas()
219                 .forEach((schemaName, schema) -> contextManager.getMetaDataContexts().getPersistService().getDatabaseMetaDataService()
220                         .persistByAlterConfiguration(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getName(), schemaName, schema));
221         DatabaseBasedPersistService<Map<String, DataSourcePoolProperties>> dataSourceService = contextManager.getMetaDataContexts().getPersistService().getDataSourceUnitService();
222         contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().switchActiveVersion(dataSourceService.persistConfigurations(databaseName, toBeRegisteredProps));
223         clearServiceCache();
224     }
225     
226     @Override
227     public void alterStorageUnits(final String databaseName, final Map<String, DataSourcePoolProperties> toBeUpdatedProps) throws SQLException {
228         SwitchingResource switchingResource =
229                 new ResourceSwitchManager().alterStorageUnit(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getResourceMetaData(), toBeUpdatedProps);
230         contextManager.getMetaDataContexts().getMetaData().getDatabases().putAll(contextManager.getConfigurationContextManager().createChangedDatabases(databaseName, true, switchingResource, null));
231         contextManager.getMetaDataContexts().getMetaData().getGlobalRuleMetaData().getRules()
232                 .forEach(each -> ((GlobalRule) each).refresh(contextManager.getMetaDataContexts().getMetaData().getDatabases(), GlobalRuleChangedType.DATABASE_CHANGED));
233         DatabaseBasedPersistService<Map<String, DataSourcePoolProperties>> dataSourceService = contextManager.getMetaDataContexts().getPersistService().getDataSourceUnitService();
234         contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().switchActiveVersion(dataSourceService.persistConfigurations(databaseName, toBeUpdatedProps));
235         switchingResource.closeStaleDataSources();
236         clearServiceCache();
237     }
238     
239     @Override
240     public void unregisterStorageUnits(final String databaseName, final Collection<String> toBeDroppedStorageUnitNames) throws SQLException {
241         SwitchingResource switchingResource =
242                 new ResourceSwitchManager().unregisterStorageUnit(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getResourceMetaData(), toBeDroppedStorageUnitNames);
243         contextManager.getMetaDataContexts().getMetaData().getDatabases()
244                 .putAll(contextManager.getConfigurationContextManager().renewDatabase(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName), switchingResource));
245         MetaDataContexts reloadMetaDataContexts = contextManager.getConfigurationContextManager().createMetaDataContexts(databaseName, false, switchingResource, null);
246         contextManager.getConfigurationContextManager().alterSchemaMetaData(databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName),
247                 contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName), true);
248         contextManager.deletedSchemaNames(databaseName, reloadMetaDataContexts.getMetaData().getDatabase(databaseName), contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName));
249         contextManager.renewMetaDataContexts(reloadMetaDataContexts);
250         switchingResource.closeStaleDataSources();
251         clearServiceCache();
252     }
253     
254     @Override
255     public void alterSingleRuleConfiguration(final String databaseName, final Collection<RuleConfiguration> ruleConfigs) {
256         ruleConfigs.removeIf(each -> !each.getClass().isAssignableFrom(SingleRuleConfiguration.class));
257         Collection<MetaDataVersion> metaDataVersions = contextManager.getMetaDataContexts().getPersistService().getDatabaseRulePersistService()
258                 .persistConfigurations(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getName(), ruleConfigs);
259         contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().switchActiveVersion(metaDataVersions);
260         contextManager.getConfigurationContextManager().alterRuleConfiguration(databaseName, ruleConfigs.iterator().next());
261         clearServiceCache();
262     }
263     
264     @Override
265     public Collection<MetaDataVersion> alterRuleConfiguration(final String databaseName, final RuleConfiguration toBeAlteredRuleConfig) {
266         if (null != toBeAlteredRuleConfig) {
267             Collection<MetaDataVersion> metaDataVersions = contextManager.getMetaDataContexts().getPersistService().getDatabaseRulePersistService()
268                     .persistConfigurations(contextManager.getMetaDataContexts().getMetaData().getDatabase(databaseName).getName(), Collections.singletonList(toBeAlteredRuleConfig));
269             contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().switchActiveVersion(metaDataVersions);
270             sendDatabaseRuleChangedEvent(databaseName, metaDataVersions);
271             clearServiceCache();
272         }
273         return Collections.emptyList();
274     }
275     
276     private void sendDatabaseRuleChangedEvent(final String databaseName, final Collection<MetaDataVersion> metaDataVersions) {
277         for (MetaDataVersion each : metaDataVersions) {
278             sendDatabaseRuleChangedEvent(databaseName, each);
279         }
280     }
281     
282     private void sendDatabaseRuleChangedEvent(final String databaseName, final MetaDataVersion metaDataVersion) {
283         for (String each : metaDataVersion.getActiveVersionKeys()) {
284             ruleConfigurationEventBuilder.build(databaseName, new DataChangedEvent(each, metaDataVersion.getNextActiveVersion(), Type.UPDATED))
285                     .ifPresent(optional -> contextManager.getInstanceContext().getEventBusContext().post(optional));
286         }
287     }
288     
289     @Override
290     public void removeRuleConfigurationItem(final String databaseName, final RuleConfiguration toBeRemovedRuleConfig) {
291         if (null != toBeRemovedRuleConfig) {
292             sendDatabaseRuleChangedEvent(databaseName,
293                     contextManager.getMetaDataContexts().getPersistService().getDatabaseRulePersistService().deleteConfigurations(databaseName, Collections.singleton(toBeRemovedRuleConfig)));
294             clearServiceCache();
295         }
296     }
297     
298     @Override
299     public void removeRuleConfiguration(final String databaseName, final String ruleName) {
300         contextManager.getMetaDataContexts().getPersistService().getDatabaseRulePersistService().delete(databaseName, ruleName);
301         clearServiceCache();
302     }
303     
304     @Override
305     public void alterGlobalRuleConfiguration(final RuleConfiguration toBeAlteredRuleConfig) {
306         contextManager.getConfigurationContextManager().alterGlobalRuleConfiguration(toBeAlteredRuleConfig);
307         contextManager.getMetaDataContexts().getPersistService().getGlobalRuleService().persist(Collections.singleton(toBeAlteredRuleConfig));
308         clearServiceCache();
309     }
310     
311     @Override
312     public void alterProperties(final Properties props) {
313         contextManager.getConfigurationContextManager().alterProperties(props);
314         contextManager.getMetaDataContexts().getPersistService().getPropsService().persist(props);
315         clearServiceCache();
316     }
317     
318     private void clearServiceCache() {
319         OrderedServicesCache.clearCache();
320     }
321     
322     @Override
323     public void setContextManagerAware(final ContextManager contextManager) {
324         this.contextManager = contextManager;
325     }
326 }