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;
19  
20  import lombok.Getter;
21  import lombok.extern.slf4j.Slf4j;
22  import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
23  import org.apache.shardingsphere.database.exception.core.exception.syntax.database.NoDatabaseSelectedException;
24  import org.apache.shardingsphere.database.exception.core.exception.syntax.database.UnknownDatabaseException;
25  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
26  import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
27  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
28  import org.apache.shardingsphere.infra.database.DatabaseTypeEngine;
29  import org.apache.shardingsphere.infra.datasource.pool.props.domain.DataSourcePoolProperties;
30  import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
31  import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
32  import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
33  import org.apache.shardingsphere.infra.instance.metadata.InstanceType;
34  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
35  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
36  import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
37  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
38  import org.apache.shardingsphere.infra.metadata.database.schema.builder.GenericSchemaBuilder;
39  import org.apache.shardingsphere.infra.metadata.database.schema.builder.GenericSchemaBuilderMaterial;
40  import org.apache.shardingsphere.infra.metadata.database.schema.manager.GenericSchemaManager;
41  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
42  import org.apache.shardingsphere.infra.metadata.statistics.builder.ShardingSphereStatisticsFactory;
43  import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
44  import org.apache.shardingsphere.mode.exclusive.ExclusiveOperatorEngine;
45  import org.apache.shardingsphere.mode.manager.listener.ContextManagerLifecycleListenerFactory;
46  import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
47  import org.apache.shardingsphere.mode.metadata.factory.MetaDataContextsFactory;
48  import org.apache.shardingsphere.mode.metadata.manager.MetaDataContextManager;
49  import org.apache.shardingsphere.mode.metadata.manager.resource.SwitchingResource;
50  import org.apache.shardingsphere.mode.persist.PersistServiceFacade;
51  import org.apache.shardingsphere.mode.spi.repository.PersistRepository;
52  import org.apache.shardingsphere.mode.state.StateContext;
53  
54  import java.sql.SQLException;
55  import java.util.Collection;
56  import java.util.Collections;
57  import java.util.Map;
58  import java.util.stream.Collectors;
59  
60  /**
61   * Context manager.
62   */
63  @Getter
64  @Slf4j
65  public final class ContextManager implements AutoCloseable {
66      
67      private final MetaDataContexts metaDataContexts;
68      
69      private final ComputeNodeInstanceContext computeNodeInstanceContext;
70      
71      private final ExclusiveOperatorEngine exclusiveOperatorEngine;
72      
73      private final ExecutorEngine executorEngine;
74      
75      private final MetaDataContextManager metaDataContextManager;
76      
77      private final PersistServiceFacade persistServiceFacade;
78      
79      private final StateContext stateContext;
80      
81      public ContextManager(final MetaDataContexts metaDataContexts, final ComputeNodeInstanceContext computeNodeInstanceContext, final ExclusiveOperatorEngine exclusiveOperatorEngine,
82                            final PersistRepository repository) {
83          this.metaDataContexts = metaDataContexts;
84          this.computeNodeInstanceContext = computeNodeInstanceContext;
85          this.exclusiveOperatorEngine = exclusiveOperatorEngine;
86          executorEngine = ExecutorEngine.createExecutorEngineWithSize(metaDataContexts.getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
87          metaDataContextManager = new MetaDataContextManager(metaDataContexts, computeNodeInstanceContext, repository);
88          persistServiceFacade = new PersistServiceFacade(repository, computeNodeInstanceContext.getModeConfiguration(), metaDataContextManager);
89          stateContext = new StateContext(persistServiceFacade.getStateService().load());
90          ContextManagerLifecycleListenerFactory.getListeners(this).forEach(each -> each.onInitialized(this));
91      }
92      
93      /**
94       * Get database type.
95       *
96       * @return database type
97       */
98      public DatabaseType getDatabaseType() {
99          Collection<ShardingSphereDatabase> databases = metaDataContexts.getMetaData().getAllDatabases();
100         return databases.stream().flatMap(each -> each.getResourceMetaData().getStorageUnits().values().stream()).findFirst().map(StorageUnit::getStorageType)
101                 .orElseGet(DatabaseTypeEngine::getDefaultStorageType);
102     }
103     
104     /**
105      * Get all database names.
106      *
107      * @return all database names
108      */
109     public Collection<String> getAllDatabaseNames() {
110         return metaDataContexts.getMetaData().getAllDatabases().stream().map(ShardingSphereDatabase::getName).collect(Collectors.toList());
111     }
112     
113     /**
114      * Get database.
115      *
116      * @param name database name
117      * @return got database
118      */
119     public ShardingSphereDatabase getDatabase(final String name) {
120         ShardingSpherePreconditions.checkNotEmpty(name, NoDatabaseSelectedException::new);
121         ShardingSphereMetaData metaData = metaDataContexts.getMetaData();
122         ShardingSpherePreconditions.checkState(metaData.containsDatabase(name), () -> new UnknownDatabaseException(name));
123         return metaData.getDatabase(name);
124     }
125     
126     /**
127      * Get storage units.
128      *
129      * @param databaseName database name
130      * @return storage units
131      */
132     public Map<String, StorageUnit> getStorageUnits(final String databaseName) {
133         return getDatabase(databaseName).getResourceMetaData().getStorageUnits();
134     }
135     
136     /**
137      * Reload database.
138      *
139      * @param database to be reloaded database
140      */
141     public void reloadDatabase(final ShardingSphereDatabase database) {
142         try {
143             MetaDataContexts reloadedMetaDataContexts = createMetaDataContexts(database);
144             dropSchemas(database.getName(), reloadedMetaDataContexts.getMetaData().getDatabase(database.getName()), database);
145             metaDataContexts.update(reloadedMetaDataContexts);
146             metaDataContexts.getMetaData().getDatabase(database.getName()).getAllSchemas()
147                     .forEach(each -> persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getSchema().alterByRefresh(database.getName(), each));
148         } catch (final SQLException ex) {
149             log.error("Refresh database meta data: {} failed", database.getName(), ex);
150         }
151     }
152     
153     private MetaDataContexts createMetaDataContexts(final ShardingSphereDatabase database) throws SQLException {
154         Map<String, DataSourcePoolProperties> dataSourcePoolProps = persistServiceFacade.getMetaDataFacade().getDataSourceUnitService().load(database.getName());
155         SwitchingResource switchingResource = metaDataContextManager.getResourceSwitchManager().switchByAlterStorageUnit(database.getResourceMetaData(), dataSourcePoolProps);
156         Collection<RuleConfiguration> ruleConfigs = persistServiceFacade.getMetaDataFacade().getDatabaseRuleService().load(database.getName());
157         ShardingSphereDatabase changedDatabase = new MetaDataContextsFactory(persistServiceFacade.getMetaDataFacade(), computeNodeInstanceContext)
158                 .createChangedDatabase(database.getName(), false, switchingResource, ruleConfigs, metaDataContexts);
159         metaDataContexts.getMetaData().putDatabase(changedDatabase);
160         ConfigurationProperties props = new ConfigurationProperties(persistServiceFacade.getMetaDataFacade().getPropsService().load());
161         Collection<RuleConfiguration> globalRuleConfigs = persistServiceFacade.getMetaDataFacade().getGlobalRuleService().load();
162         RuleMetaData changedGlobalMetaData = new RuleMetaData(GlobalRulesBuilder.buildRules(globalRuleConfigs, metaDataContexts.getMetaData().getAllDatabases(), props));
163         ShardingSphereMetaData metaData = new ShardingSphereMetaData(
164                 metaDataContexts.getMetaData().getAllDatabases(), metaDataContexts.getMetaData().getGlobalResourceMetaData(), changedGlobalMetaData, props);
165         MetaDataContexts result =
166                 new MetaDataContexts(metaData, ShardingSphereStatisticsFactory.create(metaData, persistServiceFacade.getMetaDataFacade().getStatisticsService().load(metaData)));
167         switchingResource.closeStaleDataSources();
168         return result;
169     }
170     
171     private void dropSchemas(final String databaseName, final ShardingSphereDatabase reloadDatabase, final ShardingSphereDatabase currentDatabase) {
172         GenericSchemaManager.getToBeDroppedSchemaNames(reloadDatabase, currentDatabase)
173                 .forEach(each -> persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getSchema().drop(databaseName, each));
174     }
175     
176     /**
177      * Reload schema.
178      *
179      * @param database database
180      * @param schemaName to be reloaded schema name
181      * @param dataSourceName data source name
182      */
183     public void reloadSchema(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName) {
184         try {
185             ShardingSphereSchema reloadedSchema = loadSchema(database, schemaName, dataSourceName);
186             if (reloadedSchema.getAllTables().isEmpty()) {
187                 database.dropSchema(schemaName);
188                 persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getSchema().drop(database.getName(), schemaName);
189             } else {
190                 database.addSchema(reloadedSchema);
191                 persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getSchema().alterByRefresh(database.getName(), reloadedSchema);
192             }
193         } catch (final SQLException ex) {
194             log.error("Reload meta data of database: {} schema: {} with data source: {} failed", database.getName(), schemaName, dataSourceName, ex);
195         }
196     }
197     
198     private ShardingSphereSchema loadSchema(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName) throws SQLException {
199         database.reloadRules();
200         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(Collections.singletonMap(dataSourceName, database.getResourceMetaData().getStorageUnits().get(dataSourceName)),
201                 database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName);
202         ShardingSphereSchema result = GenericSchemaBuilder.build(database.getProtocolType(), material).get(schemaName);
203         persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getView().load(database.getName(), schemaName).forEach(result::putView);
204         return result;
205     }
206     
207     /**
208      * Reload table.
209      *
210      * @param database database
211      * @param schemaName schema name
212      * @param tableName to be reloaded table name
213      */
214     public void reloadTable(final ShardingSphereDatabase database, final String schemaName, final String tableName) {
215         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(
216                 database.getResourceMetaData().getStorageUnits(), database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName);
217         try {
218             persistTable(database, schemaName, tableName, material);
219         } catch (final SQLException ex) {
220             log.error("Reload table: {} meta data of database: {} schema: {} failed", tableName, database.getName(), schemaName, ex);
221         }
222     }
223     
224     /**
225      * Reload table from single data source.
226      *
227      * @param database database
228      * @param schemaName schema name
229      * @param dataSourceName data source name
230      * @param tableName to be reloaded table name
231      */
232     public void reloadTable(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName, final String tableName) {
233         StorageUnit storageUnit = database.getResourceMetaData().getStorageUnits().get(dataSourceName);
234         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(
235                 Collections.singletonMap(dataSourceName, storageUnit), database.getRuleMetaData().getRules(), metaDataContexts.getMetaData().getProps(), schemaName);
236         try {
237             persistTable(database, schemaName, tableName, material);
238         } catch (final SQLException ex) {
239             log.error("Reload table: {} meta data of database: {} schema: {} with data source: {} failed", tableName, database.getName(), schemaName, dataSourceName, ex);
240         }
241     }
242     
243     private void persistTable(final ShardingSphereDatabase database, final String schemaName, final String tableName, final GenericSchemaBuilderMaterial material) throws SQLException {
244         ShardingSphereSchema schema = GenericSchemaBuilder.build(Collections.singleton(tableName), database.getProtocolType(), material).getOrDefault(schemaName, new ShardingSphereSchema(schemaName));
245         if (schema.containsTable(tableName)) {
246             persistServiceFacade.getMetaDataFacade().getDatabaseMetaDataFacade().getTable().persist(database.getName(), schemaName, Collections.singleton(schema.getTable(tableName)));
247         } else {
248             persistServiceFacade.getModeFacade().getMetaDataManagerService().dropTables(database, schemaName, Collections.singleton(tableName));
249         }
250     }
251     
252     /**
253      * Get pre-selected database name.
254      *
255      * @return pre-selected database name
256      */
257     public String getPreSelectedDatabaseName() {
258         return InstanceType.JDBC == computeNodeInstanceContext.getInstance().getMetaData().getType() ? metaDataContexts.getMetaData().getAllDatabases().iterator().next().getName() : null;
259     }
260     
261     @Override
262     public void close() {
263         ContextManagerLifecycleListenerFactory.getListeners(this).forEach(each -> each.onDestroyed(this));
264         executorEngine.close();
265         metaDataContexts.getMetaData().close();
266         persistServiceFacade.close();
267     }
268 }