1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.sharding.route.engine.type.standard;
19
20 import com.cedarsoftware.util.CaseInsensitiveSet;
21 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
22 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
23 import org.apache.shardingsphere.infra.datanode.DataNode;
24 import org.apache.shardingsphere.infra.hint.HintManager;
25 import org.apache.shardingsphere.infra.hint.HintValueContext;
26 import org.apache.shardingsphere.infra.route.context.RouteContext;
27 import org.apache.shardingsphere.infra.route.context.RouteMapper;
28 import org.apache.shardingsphere.infra.route.context.RouteUnit;
29 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
30 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.HintShardingStrategyConfiguration;
31 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
32 import org.apache.shardingsphere.sharding.exception.algorithm.MismatchedShardingDataSourceRouteInfoException;
33 import org.apache.shardingsphere.sharding.exception.algorithm.NoShardingDatabaseRouteInfoException;
34 import org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
35 import org.apache.shardingsphere.sharding.route.engine.condition.ShardingConditions;
36 import org.apache.shardingsphere.sharding.route.engine.condition.value.ListShardingConditionValue;
37 import org.apache.shardingsphere.sharding.route.engine.condition.value.ShardingConditionValue;
38 import org.apache.shardingsphere.sharding.route.engine.type.ShardingRouteEngine;
39 import org.apache.shardingsphere.sharding.route.strategy.ShardingStrategy;
40 import org.apache.shardingsphere.sharding.route.strategy.ShardingStrategyFactory;
41 import org.apache.shardingsphere.sharding.route.strategy.type.hint.HintShardingStrategy;
42 import org.apache.shardingsphere.sharding.route.strategy.type.none.NoneShardingStrategy;
43 import org.apache.shardingsphere.sharding.rule.BindingTableRule;
44 import org.apache.shardingsphere.sharding.rule.ShardingRule;
45 import org.apache.shardingsphere.sharding.rule.ShardingTable;
46 import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
47
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Collections;
51 import java.util.LinkedList;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Optional;
55
56
57
58
59 public final class ShardingStandardRoutingEngine implements ShardingRouteEngine {
60
61 private final String logicTableName;
62
63 private final ShardingConditions shardingConditions;
64
65 private final SQLStatementContext sqlStatementContext;
66
67 private final ConfigurationProperties props;
68
69 private final Collection<Collection<DataNode>> originalDataNodes = new LinkedList<>();
70
71 private final HintValueContext hintValueContext;
72
73 public ShardingStandardRoutingEngine(final String logicTableName, final ShardingConditions shardingConditions, final SQLStatementContext sqlStatementContext,
74 final HintValueContext hintValueContext, final ConfigurationProperties props) {
75 this.logicTableName = logicTableName;
76 this.shardingConditions = shardingConditions;
77 this.sqlStatementContext = sqlStatementContext;
78 this.props = props;
79 this.hintValueContext = hintValueContext;
80 }
81
82 @Override
83 public RouteContext route(final ShardingRule shardingRule) {
84 RouteContext result = new RouteContext();
85 Collection<DataNode> dataNodes = getDataNodes(shardingRule, shardingRule.getShardingTable(logicTableName));
86 result.getOriginalDataNodes().addAll(originalDataNodes);
87 for (DataNode each : dataNodes) {
88 result.getRouteUnits().add(
89 new RouteUnit(new RouteMapper(each.getDataSourceName(), each.getDataSourceName()), Collections.singleton(new RouteMapper(logicTableName, each.getTableName()))));
90 }
91 return result;
92 }
93
94 private Collection<DataNode> getDataNodes(final ShardingRule shardingRule, final ShardingTable shardingTable) {
95 ShardingStrategy databaseShardingStrategy = createShardingStrategy(shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable),
96 shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn());
97 ShardingStrategy tableShardingStrategy = createShardingStrategy(shardingRule.getTableShardingStrategyConfiguration(shardingTable),
98 shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn());
99 if (isRoutingByHint(shardingRule, shardingTable)) {
100 return routeByHint(shardingTable, databaseShardingStrategy, tableShardingStrategy);
101 }
102 if (isRoutingByShardingConditions(shardingRule, shardingTable)) {
103 return routeByShardingConditions(shardingRule, shardingTable, databaseShardingStrategy, tableShardingStrategy);
104 }
105 return routeByMixedConditions(shardingRule, shardingTable, databaseShardingStrategy, tableShardingStrategy);
106 }
107
108 private boolean isRoutingByHint(final ShardingRule shardingRule, final ShardingTable shardingTable) {
109 return shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable) instanceof HintShardingStrategyConfiguration
110 && shardingRule.getTableShardingStrategyConfiguration(shardingTable) instanceof HintShardingStrategyConfiguration;
111 }
112
113 private boolean isRoutingBySQLHint() {
114 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
115 for (String each : tableNames) {
116 if (hintValueContext.containsHintShardingValue(each)) {
117 return true;
118 }
119 }
120 return false;
121 }
122
123 private Collection<DataNode> routeByHint(final ShardingTable shardingTable, final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
124 return route0(shardingTable, databaseShardingStrategy, getDatabaseShardingValuesFromHint(), tableShardingStrategy, getTableShardingValuesFromHint());
125 }
126
127 private boolean isRoutingByShardingConditions(final ShardingRule shardingRule, final ShardingTable shardingTable) {
128 return !(shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable) instanceof HintShardingStrategyConfiguration
129 || shardingRule.getTableShardingStrategyConfiguration(shardingTable) instanceof HintShardingStrategyConfiguration);
130 }
131
132 private Collection<DataNode> routeByShardingConditions(final ShardingRule shardingRule, final ShardingTable shardingTable,
133 final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
134 return shardingConditions.getConditions().isEmpty()
135 ? route0(shardingTable, databaseShardingStrategy, Collections.emptyList(), tableShardingStrategy, Collections.emptyList())
136 : routeByShardingConditionsWithCondition(shardingRule, shardingTable, databaseShardingStrategy, tableShardingStrategy);
137 }
138
139 private Collection<DataNode> routeByShardingConditionsWithCondition(final ShardingRule shardingRule, final ShardingTable shardingTable,
140 final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
141 Collection<DataNode> result = new LinkedList<>();
142 for (ShardingCondition each : shardingConditions.getConditions()) {
143 Collection<DataNode> dataNodes = route0(shardingTable,
144 databaseShardingStrategy, getShardingValuesFromShardingConditions(shardingRule, databaseShardingStrategy.getShardingColumns(), each),
145 tableShardingStrategy, getShardingValuesFromShardingConditions(shardingRule, tableShardingStrategy.getShardingColumns(), each));
146 result.addAll(dataNodes);
147 originalDataNodes.add(dataNodes);
148 }
149 return result;
150 }
151
152 private Collection<DataNode> routeByMixedConditions(final ShardingRule shardingRule, final ShardingTable shardingTable,
153 final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
154 return shardingConditions.getConditions().isEmpty()
155 ? routeByMixedConditionsWithHint(shardingRule, shardingTable, databaseShardingStrategy, tableShardingStrategy)
156 : routeByMixedConditionsWithCondition(shardingRule, shardingTable, databaseShardingStrategy, tableShardingStrategy);
157 }
158
159 private Collection<DataNode> routeByMixedConditionsWithCondition(final ShardingRule shardingRule, final ShardingTable shardingTable,
160 final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
161 Collection<DataNode> result = new LinkedList<>();
162 for (ShardingCondition each : shardingConditions.getConditions()) {
163 Collection<DataNode> dataNodes = route0(shardingTable, databaseShardingStrategy,
164 getDatabaseShardingValues(shardingRule, databaseShardingStrategy, each), tableShardingStrategy, getTableShardingValues(shardingRule, tableShardingStrategy, each));
165 result.addAll(dataNodes);
166 originalDataNodes.add(dataNodes);
167 }
168 return result;
169 }
170
171 private Collection<DataNode> routeByMixedConditionsWithHint(final ShardingRule shardingRule, final ShardingTable shardingTable,
172 final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {
173 if (shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable) instanceof HintShardingStrategyConfiguration) {
174 return route0(shardingTable, databaseShardingStrategy, getDatabaseShardingValuesFromHint(), tableShardingStrategy, Collections.emptyList());
175 }
176 return route0(shardingTable, databaseShardingStrategy, Collections.emptyList(), tableShardingStrategy, getTableShardingValuesFromHint());
177 }
178
179 private List<ShardingConditionValue> getDatabaseShardingValues(final ShardingRule shardingRule, final ShardingStrategy databaseShardingStrategy, final ShardingCondition shardingCondition) {
180 return isGettingShardingValuesFromHint(databaseShardingStrategy)
181 ? getDatabaseShardingValuesFromHint()
182 : getShardingValuesFromShardingConditions(shardingRule, databaseShardingStrategy.getShardingColumns(), shardingCondition);
183 }
184
185 private List<ShardingConditionValue> getTableShardingValues(final ShardingRule shardingRule, final ShardingStrategy tableShardingStrategy, final ShardingCondition shardingCondition) {
186 return isGettingShardingValuesFromHint(tableShardingStrategy)
187 ? getTableShardingValuesFromHint()
188 : getShardingValuesFromShardingConditions(shardingRule, tableShardingStrategy.getShardingColumns(), shardingCondition);
189 }
190
191 private boolean isGettingShardingValuesFromHint(final ShardingStrategy shardingStrategy) {
192 return shardingStrategy instanceof HintShardingStrategy;
193 }
194
195 private List<ShardingConditionValue> getDatabaseShardingValuesFromHint() {
196 if (isRoutingBySQLHint()) {
197 return getDatabaseShardingValuesFromSQLHint();
198 }
199 return getShardingConditions(HintManager.isDatabaseShardingOnly() ? HintManager.getDatabaseShardingValues() : HintManager.getDatabaseShardingValues(logicTableName));
200 }
201
202 private List<ShardingConditionValue> getDatabaseShardingValuesFromSQLHint() {
203 Collection<Comparable<?>> shardingValues = new LinkedList<>();
204 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
205 for (String each : tableNames) {
206 if (each.equals(logicTableName) && hintValueContext.containsHintShardingDatabaseValue(each)) {
207 shardingValues.addAll(hintValueContext.getHintShardingDatabaseValue(each));
208 }
209 }
210 return getShardingConditions(shardingValues);
211 }
212
213 private List<ShardingConditionValue> getTableShardingValuesFromHint() {
214 if (isRoutingBySQLHint()) {
215 return getTableShardingValuesFromSQLHint();
216 }
217 return getShardingConditions(HintManager.getTableShardingValues(logicTableName));
218 }
219
220 private List<ShardingConditionValue> getTableShardingValuesFromSQLHint() {
221 Collection<Comparable<?>> shardingValues = new LinkedList<>();
222 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
223 for (String each : tableNames) {
224 if (each.equals(logicTableName) && hintValueContext.containsHintShardingTableValue(each)) {
225 shardingValues.addAll(hintValueContext.getHintShardingTableValue(each));
226 }
227 }
228 return getShardingConditions(shardingValues);
229 }
230
231 private List<ShardingConditionValue> getShardingConditions(final Collection<Comparable<?>> shardingValue) {
232 return shardingValue.isEmpty() ? Collections.emptyList() : Collections.singletonList(new ListShardingConditionValue<>("", logicTableName, shardingValue));
233 }
234
235 private List<ShardingConditionValue> getShardingValuesFromShardingConditions(final ShardingRule shardingRule, final Collection<String> shardingColumns, final ShardingCondition shardingCondition) {
236 List<ShardingConditionValue> result = new ArrayList<>(shardingColumns.size());
237 for (ShardingConditionValue each : shardingCondition.getValues()) {
238 Optional<BindingTableRule> bindingTableRule = shardingRule.findBindingTableRule(each.getTableName());
239 if ((logicTableName.equalsIgnoreCase(each.getTableName()) || bindingTableRule.isPresent() && bindingTableRule.get().hasLogicTable(logicTableName))
240 && new CaseInsensitiveSet<>(shardingColumns).contains(each.getColumnName())) {
241 result.add(each);
242 }
243 }
244 return result;
245 }
246
247 private Collection<DataNode> route0(final ShardingTable shardingTable,
248 final ShardingStrategy databaseShardingStrategy, final List<ShardingConditionValue> databaseShardingValues,
249 final ShardingStrategy tableShardingStrategy, final List<ShardingConditionValue> tableShardingValues) {
250 Collection<String> routedDataSources = routeDataSources(shardingTable, databaseShardingStrategy, databaseShardingValues);
251 Collection<DataNode> result = new LinkedList<>();
252 for (String each : routedDataSources) {
253 result.addAll(routeTables(shardingTable, each, tableShardingStrategy, tableShardingValues));
254 }
255 return result;
256 }
257
258 private Collection<String> routeDataSources(final ShardingTable shardingTable, final ShardingStrategy databaseShardingStrategy, final List<ShardingConditionValue> databaseShardingValues) {
259 if (databaseShardingValues.isEmpty()) {
260 return shardingTable.getActualDataSourceNames();
261 }
262 Collection<String> result = databaseShardingStrategy.doSharding(shardingTable.getActualDataSourceNames(), databaseShardingValues, shardingTable.getDataSourceDataNode(), props);
263 ShardingSpherePreconditions.checkNotEmpty(result, NoShardingDatabaseRouteInfoException::new);
264 ShardingSpherePreconditions.checkState(shardingTable.getActualDataSourceNames().containsAll(result),
265 () -> new MismatchedShardingDataSourceRouteInfoException(result, shardingTable.getActualDataSourceNames()));
266 return result;
267 }
268
269 private Collection<DataNode> routeTables(final ShardingTable shardingTable, final String routedDataSource,
270 final ShardingStrategy tableShardingStrategy, final List<ShardingConditionValue> tableShardingValues) {
271 Collection<String> availableTargetTables = shardingTable.getActualTableNames(routedDataSource);
272 Collection<String> routedTables = tableShardingValues.isEmpty()
273 ? availableTargetTables
274 : tableShardingStrategy.doSharding(availableTargetTables, tableShardingValues, shardingTable.getTableDataNode(), props);
275 Collection<DataNode> result = new LinkedList<>();
276 for (String each : routedTables) {
277 result.add(new DataNode(routedDataSource, each));
278 }
279 return result;
280 }
281
282 private ShardingStrategy createShardingStrategy(final ShardingStrategyConfiguration shardingStrategyConfig, final Map<String, ShardingAlgorithm> shardingAlgorithms,
283 final String defaultShardingColumn) {
284 return null == shardingStrategyConfig ? new NoneShardingStrategy()
285 : ShardingStrategyFactory.newInstance(shardingStrategyConfig, shardingAlgorithms.get(shardingStrategyConfig.getShardingAlgorithmName()), defaultShardingColumn);
286 }
287 }