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.metadata;
19  
20  import com.google.common.base.Preconditions;
21  import com.google.common.base.Splitter;
22  import lombok.AccessLevel;
23  import lombok.NoArgsConstructor;
24  import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration;
25  import org.apache.shardingsphere.infra.config.database.impl.DataSourceGeneratedDatabaseConfiguration;
26  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
27  import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
28  import org.apache.shardingsphere.infra.datasource.pool.config.DataSourceConfiguration;
29  import org.apache.shardingsphere.infra.datasource.pool.destroyer.DataSourcePoolDestroyer;
30  import org.apache.shardingsphere.infra.instance.InstanceContext;
31  import org.apache.shardingsphere.infra.instance.metadata.jdbc.JDBCInstanceMetaData;
32  import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
33  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
34  import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
35  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
36  import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
37  import org.apache.shardingsphere.infra.state.datasource.DataSourceState;
38  import org.apache.shardingsphere.infra.state.datasource.DataSourceStateManager;
39  import org.apache.shardingsphere.metadata.factory.ExternalMetaDataFactory;
40  import org.apache.shardingsphere.metadata.factory.InternalMetaDataFactory;
41  import org.apache.shardingsphere.metadata.persist.MetaDataPersistService;
42  import org.apache.shardingsphere.mode.event.storage.StorageNodeDataSource;
43  import org.apache.shardingsphere.mode.manager.ContextManagerBuilderParameter;
44  
45  import javax.sql.DataSource;
46  import java.sql.SQLException;
47  import java.util.Collection;
48  import java.util.Collections;
49  import java.util.HashMap;
50  import java.util.LinkedHashMap;
51  import java.util.List;
52  import java.util.Map;
53  import java.util.Map.Entry;
54  import java.util.stream.Collectors;
55  
56  /**
57   * Meta data contexts factory.
58   */
59  @NoArgsConstructor(access = AccessLevel.PRIVATE)
60  public final class MetaDataContextsFactory {
61      
62      /**
63       * Create meta data contexts.
64       *
65       * @param persistService persist service
66       * @param param context manager builder parameter
67       * @param instanceContext instance context
68       * @return meta data contexts
69       * @throws SQLException SQL exception
70       */
71      public static MetaDataContexts create(final MetaDataPersistService persistService, final ContextManagerBuilderParameter param, final InstanceContext instanceContext) throws SQLException {
72          return create(persistService, param, instanceContext, Collections.emptyMap());
73      }
74      
75      /**
76       * Create meta data contexts.
77       * 
78       * @param persistService persist service
79       * @param param context manager builder parameter
80       * @param instanceContext instance context
81       * @param storageNodes storage nodes
82       * @return meta data contexts
83       * @throws SQLException SQL exception
84       */
85      public static MetaDataContexts create(final MetaDataPersistService persistService, final ContextManagerBuilderParameter param,
86                                            final InstanceContext instanceContext, final Map<String, StorageNodeDataSource> storageNodes) throws SQLException {
87          boolean isDatabaseMetaDataExisted = !persistService.getDatabaseMetaDataService().loadAllDatabaseNames().isEmpty();
88          Map<String, DatabaseConfiguration> effectiveDatabaseConfigs = isDatabaseMetaDataExisted
89                  ? createEffectiveDatabaseConfigurations(getDatabaseNames(instanceContext, param.getDatabaseConfigs(), persistService), param.getDatabaseConfigs(), persistService)
90                  : param.getDatabaseConfigs();
91          checkDataSourceStates(effectiveDatabaseConfigs, storageNodes, param.isForce());
92          // TODO load global data sources from persist service
93          Map<String, DataSource> globalDataSources = param.getGlobalDataSources();
94          Collection<RuleConfiguration> globalRuleConfigs = isDatabaseMetaDataExisted ? persistService.getGlobalRuleService().load() : param.getGlobalRuleConfigs();
95          ConfigurationProperties props = isDatabaseMetaDataExisted ? new ConfigurationProperties(persistService.getPropsService().load()) : new ConfigurationProperties(param.getProps());
96          Map<String, ShardingSphereDatabase> databases = isDatabaseMetaDataExisted
97                  ? InternalMetaDataFactory.create(persistService, effectiveDatabaseConfigs, props, instanceContext)
98                  : ExternalMetaDataFactory.create(effectiveDatabaseConfigs, props, instanceContext);
99          ResourceMetaData globalResourceMetaData = new ResourceMetaData(globalDataSources);
100         RuleMetaData globalRuleMetaData = new RuleMetaData(GlobalRulesBuilder.buildRules(globalRuleConfigs, databases, props));
101         MetaDataContexts result = new MetaDataContexts(persistService, new ShardingSphereMetaData(databases, globalResourceMetaData, globalRuleMetaData, props));
102         if (!isDatabaseMetaDataExisted) {
103             persistDatabaseConfigurations(result, param);
104             persistMetaData(result);
105         }
106         return result;
107     }
108     
109     private static Collection<String> getDatabaseNames(final InstanceContext instanceContext,
110                                                        final Map<String, DatabaseConfiguration> databaseConfigs, final MetaDataPersistService persistService) {
111         return instanceContext.getInstance().getMetaData() instanceof JDBCInstanceMetaData ? databaseConfigs.keySet() : persistService.getDatabaseMetaDataService().loadAllDatabaseNames();
112     }
113     
114     private static Map<String, DatabaseConfiguration> createEffectiveDatabaseConfigurations(final Collection<String> databaseNames,
115                                                                                             final Map<String, DatabaseConfiguration> databaseConfigs, final MetaDataPersistService persistService) {
116         return databaseNames.stream().collect(Collectors.toMap(each -> each, each -> createEffectiveDatabaseConfiguration(each, databaseConfigs, persistService)));
117     }
118     
119     private static DatabaseConfiguration createEffectiveDatabaseConfiguration(final String databaseName,
120                                                                               final Map<String, DatabaseConfiguration> databaseConfigs, final MetaDataPersistService persistService) {
121         closeGeneratedDataSources(databaseName, databaseConfigs);
122         Map<String, DataSourceConfiguration> dataSources = persistService.loadDataSourceConfigurations(databaseName);
123         Collection<RuleConfiguration> databaseRuleConfigs = persistService.getDatabaseRulePersistService().load(databaseName);
124         return new DataSourceGeneratedDatabaseConfiguration(dataSources, databaseRuleConfigs);
125     }
126     
127     private static void closeGeneratedDataSources(final String databaseName, final Map<String, ? extends DatabaseConfiguration> databaseConfigs) {
128         if (databaseConfigs.containsKey(databaseName) && !databaseConfigs.get(databaseName).getStorageUnits().isEmpty()) {
129             databaseConfigs.get(databaseName).getDataSources().values().forEach(each -> new DataSourcePoolDestroyer(each).asyncDestroy());
130         }
131     }
132     
133     private static void checkDataSourceStates(final Map<String, DatabaseConfiguration> databaseConfigs, final Map<String, StorageNodeDataSource> storageNodes, final boolean force) {
134         Map<String, DataSourceState> storageDataSourceStates = getStorageDataSourceStates(storageNodes);
135         databaseConfigs.forEach((key, value) -> {
136             if (!value.getStorageUnits().isEmpty()) {
137                 DataSourceStateManager.getInstance().initStates(key, value.getStorageUnits(), storageDataSourceStates, force);
138             }
139         });
140     }
141     
142     private static Map<String, DataSourceState> getStorageDataSourceStates(final Map<String, StorageNodeDataSource> storageDataSourceStates) {
143         Map<String, DataSourceState> result = new HashMap<>(storageDataSourceStates.size(), 1F);
144         storageDataSourceStates.forEach((key, value) -> {
145             List<String> values = Splitter.on(".").splitToList(key);
146             Preconditions.checkArgument(3 == values.size(), "Illegal data source of storage node.");
147             String databaseName = values.get(0);
148             String dataSourceName = values.get(2);
149             result.put(databaseName + "." + dataSourceName, DataSourceState.valueOf(value.getStatus().name()));
150         });
151         return result;
152     }
153     
154     private static void persistDatabaseConfigurations(final MetaDataContexts metadataContexts, final ContextManagerBuilderParameter param) {
155         metadataContexts.getPersistService().persistGlobalRuleConfiguration(param.getGlobalRuleConfigs(), param.getProps());
156         for (Entry<String, ? extends DatabaseConfiguration> entry : param.getDatabaseConfigs().entrySet()) {
157             String databaseName = entry.getKey();
158             metadataContexts.getPersistService().persistConfigurations(entry.getKey(), entry.getValue(),
159                     metadataContexts.getMetaData().getDatabase(databaseName).getResourceMetaData().getStorageUnits().entrySet().stream()
160                             .collect(Collectors.toMap(Entry::getKey, each -> each.getValue().getDataSource(), (oldValue, currentValue) -> oldValue, LinkedHashMap::new)),
161                     metadataContexts.getMetaData().getDatabase(databaseName).getRuleMetaData().getRules());
162         }
163     }
164     
165     private static void persistMetaData(final MetaDataContexts metaDataContexts) {
166         metaDataContexts.getMetaData().getDatabases().values().forEach(each -> each.getSchemas()
167                 .forEach((schemaName, schema) -> metaDataContexts.getPersistService().getDatabaseMetaDataService().persistByAlterConfiguration(each.getName(), schemaName, schema)));
168         metaDataContexts.getStatistics().getDatabaseData().forEach((databaseName, databaseData) -> databaseData.getSchemaData().forEach((schemaName, schemaData) -> metaDataContexts
169                 .getPersistService().getShardingSphereDataPersistService().persist(databaseName, schemaName, schemaData, metaDataContexts.getMetaData().getDatabases())));
170     }
171 }