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.infra.config.props.ConfigurationProperties;
23  import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
24  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
25  import org.apache.shardingsphere.infra.datasource.pool.props.domain.DataSourcePoolProperties;
26  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
27  import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.NoDatabaseSelectedException;
28  import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.database.UnknownDatabaseException;
29  import org.apache.shardingsphere.infra.executor.kernel.ExecutorEngine;
30  import org.apache.shardingsphere.infra.instance.InstanceContext;
31  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
32  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
33  import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
34  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
35  import org.apache.shardingsphere.infra.metadata.database.schema.builder.GenericSchemaBuilder;
36  import org.apache.shardingsphere.infra.metadata.database.schema.builder.GenericSchemaBuilderMaterial;
37  import org.apache.shardingsphere.infra.metadata.database.schema.manager.GenericSchemaManager;
38  import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
39  import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
40  import org.apache.shardingsphere.infra.state.cluster.ClusterState;
41  import org.apache.shardingsphere.metadata.persist.MetaDataBasedPersistService;
42  import org.apache.shardingsphere.mode.manager.context.ConfigurationContextManager;
43  import org.apache.shardingsphere.mode.manager.context.ResourceMetaDataContextManager;
44  import org.apache.shardingsphere.mode.manager.context.ShardingSphereDatabaseContextManager;
45  import org.apache.shardingsphere.mode.manager.switcher.ResourceSwitchManager;
46  import org.apache.shardingsphere.mode.manager.switcher.SwitchingResource;
47  import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
48  import org.apache.shardingsphere.mode.state.StateContext;
49  import org.apache.shardingsphere.mode.state.StateService;
50  
51  import java.sql.SQLException;
52  import java.util.Collection;
53  import java.util.Collections;
54  import java.util.Map;
55  import java.util.concurrent.atomic.AtomicReference;
56  
57  /**
58   * Context manager.
59   */
60  @Getter
61  @Slf4j
62  public final class ContextManager implements AutoCloseable {
63      
64      private final AtomicReference<MetaDataContexts> metaDataContexts;
65      
66      private final InstanceContext instanceContext;
67      
68      private final ShardingSphereDatabaseContextManager shardingSphereDatabaseContextManager;
69      
70      private final ConfigurationContextManager configurationContextManager;
71      
72      private final ResourceMetaDataContextManager resourceMetaDataContextManager;
73      
74      private final ExecutorEngine executorEngine;
75      
76      private final StateContext stateContext;
77      
78      public ContextManager(final MetaDataContexts metaDataContexts, final InstanceContext instanceContext) {
79          this.metaDataContexts = new AtomicReference<>(metaDataContexts);
80          this.instanceContext = instanceContext;
81          shardingSphereDatabaseContextManager = new ShardingSphereDatabaseContextManager(this.metaDataContexts);
82          configurationContextManager = new ConfigurationContextManager(this.metaDataContexts, instanceContext);
83          resourceMetaDataContextManager = new ResourceMetaDataContextManager(this.metaDataContexts);
84          executorEngine = ExecutorEngine.createExecutorEngineWithSize(metaDataContexts.getMetaData().getProps().<Integer>getValue(ConfigurationPropertyKey.KERNEL_EXECUTOR_SIZE));
85          stateContext = new StateContext(new StateService(metaDataContexts.getPersistService().getRepository()));
86      }
87      
88      /**
89       * Get meta data contexts.
90       * 
91       * @return meta data contexts
92       */
93      public MetaDataContexts getMetaDataContexts() {
94          return metaDataContexts.get();
95      }
96      
97      /**
98       * Renew meta data contexts.
99       * 
100      * @param metaDataContexts meta data contexts
101      */
102     public void renewMetaDataContexts(final MetaDataContexts metaDataContexts) {
103         this.metaDataContexts.set(metaDataContexts);
104     }
105     
106     /**
107      * Get database.
108      *
109      * @param name database name
110      * @return got database
111      */
112     public ShardingSphereDatabase getDatabase(final String name) {
113         ShardingSpherePreconditions.checkNotEmpty(name, NoDatabaseSelectedException::new);
114         ShardingSphereMetaData metaData = getMetaDataContexts().getMetaData();
115         ShardingSpherePreconditions.checkState(metaData.containsDatabase(name), () -> new UnknownDatabaseException(name));
116         return metaData.getDatabase(name);
117     }
118     
119     /**
120      * Get storage units.
121      *
122      * @param databaseName database name
123      * @return storage units
124      */
125     public Map<String, StorageUnit> getStorageUnits(final String databaseName) {
126         return getDatabase(databaseName).getResourceMetaData().getStorageUnits();
127     }
128     
129     /**
130      * Reload database meta data.
131      *
132      * @param database to be reloaded database
133      * @param force whether to force refresh table metadata
134      */
135     public void refreshDatabaseMetaData(final ShardingSphereDatabase database, final boolean force) {
136         try {
137             MetaDataContexts reloadedMetaDataContexts = createMetaDataContexts(database);
138             MetaDataBasedPersistService persistService = metaDataContexts.get().getPersistService();
139             if (force) {
140                 metaDataContexts.set(reloadedMetaDataContexts);
141                 metaDataContexts.get().getMetaData().getDatabase(database.getName()).getSchemas()
142                         .forEach((schemaName, schema) -> persistService.getDatabaseMetaDataService().persistByAlterConfiguration(database.getName(), schemaName, schema));
143             } else {
144                 deletedSchemaNames(database.getName(), reloadedMetaDataContexts.getMetaData().getDatabase(database.getName()), database);
145                 metaDataContexts.set(reloadedMetaDataContexts);
146                 metaDataContexts.get().getMetaData().getDatabase(database.getName()).getSchemas()
147                         .forEach((schemaName, schema) -> persistService.getDatabaseMetaDataService().compareAndPersist(database.getName(), schemaName, schema));
148             }
149         } catch (final SQLException ex) {
150             log.error("Refresh database meta data: {} failed", database.getName(), ex);
151         }
152     }
153     
154     /**
155      * Reload table meta data.
156      * 
157      * @param database to be reloaded database
158      */
159     public void refreshTableMetaData(final ShardingSphereDatabase database) {
160         try {
161             MetaDataContexts reloadedMetaDataContexts = createMetaDataContexts(database);
162             deletedSchemaNames(database.getName(), reloadedMetaDataContexts.getMetaData().getDatabase(database.getName()), database);
163             metaDataContexts.set(reloadedMetaDataContexts);
164             metaDataContexts.get().getMetaData().getDatabase(database.getName()).getSchemas()
165                     .forEach((schemaName, schema) -> metaDataContexts.get().getPersistService().getDatabaseMetaDataService().compareAndPersist(database.getName(), schemaName, schema));
166         } catch (final SQLException ex) {
167             log.error("Refresh table meta data: {} failed", database.getName(), ex);
168         }
169     }
170     
171     private MetaDataContexts createMetaDataContexts(final ShardingSphereDatabase database) throws SQLException {
172         MetaDataBasedPersistService metaDataPersistService = metaDataContexts.get().getPersistService();
173         Map<String, DataSourcePoolProperties> dataSourcePoolPropsFromRegCenter = metaDataPersistService.getDataSourceUnitService().load(database.getName());
174         SwitchingResource switchingResource = new ResourceSwitchManager().alterStorageUnit(database.getResourceMetaData(), dataSourcePoolPropsFromRegCenter);
175         metaDataContexts.get().getMetaData().getDatabases().putAll(configurationContextManager.renewDatabase(database, switchingResource));
176         Collection<RuleConfiguration> ruleConfigs = metaDataPersistService.getDatabaseRulePersistService().load(database.getName());
177         Map<String, ShardingSphereDatabase> changedDatabases = configurationContextManager.createChangedDatabases(database.getName(), false, switchingResource, ruleConfigs);
178         ConfigurationProperties props = new ConfigurationProperties(metaDataPersistService.getPropsService().load());
179         Collection<RuleConfiguration> globalRuleConfigs = metaDataPersistService.getGlobalRuleService().load();
180         RuleMetaData changedGlobalMetaData = new RuleMetaData(GlobalRulesBuilder.buildRules(globalRuleConfigs, changedDatabases, props));
181         MetaDataContexts result = new MetaDataContexts(metaDataPersistService,
182                 new ShardingSphereMetaData(changedDatabases, metaDataContexts.get().getMetaData().getGlobalResourceMetaData(), changedGlobalMetaData, props));
183         switchingResource.closeStaleDataSources();
184         return result;
185     }
186     
187     /**
188      * Delete schema names.
189      * 
190      * @param databaseName database name
191      * @param reloadDatabase reload database
192      * @param currentDatabase current database
193      */
194     public void deletedSchemaNames(final String databaseName, final ShardingSphereDatabase reloadDatabase, final ShardingSphereDatabase currentDatabase) {
195         GenericSchemaManager.getToBeDeletedSchemaNames(reloadDatabase.getSchemas(), currentDatabase.getSchemas()).keySet()
196                 .forEach(each -> metaDataContexts.get().getPersistService().getDatabaseMetaDataService().dropSchema(databaseName, each));
197     }
198     
199     /**
200      * Reload schema.
201      * 
202      * @param database database
203      * @param schemaName to be reloaded schema name
204      * @param dataSourceName data source name
205      */
206     public void reloadSchema(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName) {
207         try {
208             ShardingSphereSchema reloadedSchema = loadSchema(database, schemaName, dataSourceName);
209             if (reloadedSchema.getTables().isEmpty()) {
210                 database.dropSchema(schemaName);
211                 metaDataContexts.get().getPersistService().getDatabaseMetaDataService().dropSchema(database.getName(),
212                         schemaName);
213             } else {
214                 database.addSchema(schemaName, reloadedSchema);
215                 metaDataContexts.get().getPersistService().getDatabaseMetaDataService()
216                         .compareAndPersist(database.getName(), schemaName, reloadedSchema);
217             }
218         } catch (final SQLException ex) {
219             log.error("Reload meta data of database: {} schema: {} with data source: {} failed", database.getName(), schemaName, dataSourceName, ex);
220         }
221     }
222     
223     private ShardingSphereSchema loadSchema(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName) throws SQLException {
224         database.reloadRules();
225         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getProtocolType(),
226                 Collections.singletonMap(dataSourceName, database.getResourceMetaData().getStorageUnits().get(dataSourceName).getStorageType()),
227                 Collections.singletonMap(dataSourceName, database.getResourceMetaData().getStorageUnits().get(dataSourceName).getDataSource()),
228                 database.getRuleMetaData().getRules(), metaDataContexts.get().getMetaData().getProps(), schemaName);
229         ShardingSphereSchema result = GenericSchemaBuilder.build(material).get(schemaName);
230         result.getViews().putAll(metaDataContexts.get().getPersistService().getDatabaseMetaDataService().getViewMetaDataPersistService().load(database.getName(), schemaName));
231         return result;
232     }
233     
234     /**
235      * Reload table.
236      * 
237      * @param database database
238      * @param schemaName schema name
239      * @param tableName to be reloaded table name
240      */
241     public void reloadTable(final ShardingSphereDatabase database, final String schemaName, final String tableName) {
242         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getProtocolType(),
243                 database.getResourceMetaData().getStorageUnits(), database.getRuleMetaData().getRules(), metaDataContexts.get().getMetaData().getProps(), schemaName);
244         try {
245             persistTable(database, schemaName, tableName, material);
246         } catch (final SQLException ex) {
247             log.error("Reload table: {} meta data of database: {} schema: {} failed", tableName, database.getName(), schemaName, ex);
248         }
249     }
250     
251     /**
252      * Reload table from single data source.
253      * 
254      * @param database database
255      * @param schemaName schema name
256      * @param dataSourceName data source name
257      * @param tableName to be reloaded table name
258      */
259     public void reloadTable(final ShardingSphereDatabase database, final String schemaName, final String dataSourceName, final String tableName) {
260         StorageUnit storageUnit = database.getResourceMetaData().getStorageUnits().get(dataSourceName);
261         GenericSchemaBuilderMaterial material = new GenericSchemaBuilderMaterial(database.getProtocolType(),
262                 Collections.singletonMap(dataSourceName, storageUnit.getStorageType()), Collections.singletonMap(dataSourceName, storageUnit.getDataSource()),
263                 database.getRuleMetaData().getRules(), metaDataContexts.get().getMetaData().getProps(), schemaName);
264         try {
265             persistTable(database, schemaName, tableName, material);
266         } catch (final SQLException ex) {
267             log.error("Reload table: {} meta data of database: {} schema: {} with data source: {} failed", tableName, database.getName(), schemaName, dataSourceName, ex);
268         }
269     }
270     
271     private void persistTable(final ShardingSphereDatabase database, final String schemaName, final String tableName, final GenericSchemaBuilderMaterial material) throws SQLException {
272         ShardingSphereSchema schema = GenericSchemaBuilder.build(Collections.singleton(tableName), material).getOrDefault(schemaName, new ShardingSphereSchema());
273         metaDataContexts.get().getPersistService().getDatabaseMetaDataService().getTableMetaDataPersistService()
274                 .persist(database.getName(), schemaName, Collections.singletonMap(tableName, schema.getTable(tableName)));
275     }
276     
277     /**
278      * Update cluster state.
279      * 
280      * @param clusterState cluster state
281      */
282     public void updateClusterState(final ClusterState clusterState) {
283         stateContext.switchState(clusterState);
284     }
285     
286     @Override
287     public void close() {
288         executorEngine.close();
289         metaDataContexts.get().close();
290     }
291 }