1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.sharding.rule.checker;
19
20 import com.google.common.base.Splitter;
21 import lombok.RequiredArgsConstructor;
22 import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
23 import org.apache.shardingsphere.infra.datanode.DataNode;
24 import org.apache.shardingsphere.infra.datanode.DataNodeInfo;
25 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
26 import org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm;
27 import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
28 import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
29 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ComplexShardingStrategyConfiguration;
30 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
31 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
32 import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
33 import org.apache.shardingsphere.sharding.exception.metadata.DuplicateSharingActualDataNodeException;
34 import org.apache.shardingsphere.sharding.exception.metadata.InvalidBindingTablesException;
35 import org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
36 import org.apache.shardingsphere.sharding.rule.BindingTableCheckedConfiguration;
37 import org.apache.shardingsphere.sharding.rule.ShardingRule;
38 import org.apache.shardingsphere.sharding.rule.ShardingTable;
39 import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
40
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.Map;
46 import java.util.Optional;
47 import java.util.Set;
48 import java.util.stream.Collectors;
49
50 @RequiredArgsConstructor
51 public class ShardingRuleChecker {
52
53 private final ShardingRule shardingRule;
54
55
56
57
58
59
60 public void check(final ShardingRuleConfiguration ruleConfig) {
61 checkUniqueActualDataNodesInTableRules();
62 checkBindingTableConfiguration(ruleConfig);
63 checkInlineShardingAlgorithmsInTableRules();
64 }
65
66 private void checkUniqueActualDataNodesInTableRules() {
67 Set<DataNode> uniqueActualDataNodes = new HashSet<>(shardingRule.getShardingTables().size(), 1L);
68 shardingRule.getShardingTables().forEach((key, value) -> {
69 DataNode sampleActualDataNode = value.getActualDataNodes().iterator().next();
70 ShardingSpherePreconditions.checkState(!uniqueActualDataNodes.contains(sampleActualDataNode),
71 () -> new DuplicateSharingActualDataNodeException(key, sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
72 uniqueActualDataNodes.add(sampleActualDataNode);
73 });
74 }
75
76 private void checkBindingTableConfiguration(final ShardingRuleConfiguration ruleConfig) {
77 ShardingSpherePreconditions.checkState(
78 isValidBindingTableConfiguration(shardingRule.getShardingTables(), new BindingTableCheckedConfiguration(shardingRule.getDataSourceNames(), shardingRule.getShardingAlgorithms(),
79 ruleConfig.getBindingTableGroups(), shardingRule.getDefaultDatabaseShardingStrategyConfig(), shardingRule.getDefaultTableShardingStrategyConfig(),
80 shardingRule.getDefaultShardingColumn())),
81 InvalidBindingTablesException::new);
82 }
83
84 private boolean isValidBindingTableConfiguration(final Map<String, ShardingTable> shardingTables, final BindingTableCheckedConfiguration checkedConfig) {
85 for (ShardingTableReferenceRuleConfiguration each : checkedConfig.getBindingTableGroups()) {
86 Collection<String> bindingTables = Splitter.on(",").trimResults().splitToList(each.getReference());
87 if (bindingTables.size() <= 1) {
88 continue;
89 }
90 Iterator<String> iterator = bindingTables.iterator();
91 ShardingTable sampleShardingTable = getShardingTable(iterator.next(), shardingTables);
92 while (iterator.hasNext()) {
93 ShardingTable shardingTable = getShardingTable(iterator.next(), shardingTables);
94 if (!isValidActualDataSourceName(sampleShardingTable, shardingTable) || !isValidActualTableName(sampleShardingTable, shardingTable)) {
95 return false;
96 }
97 if (!isBindingShardingAlgorithm(sampleShardingTable, shardingTable, true, checkedConfig) || !isBindingShardingAlgorithm(sampleShardingTable, shardingTable, false, checkedConfig)) {
98 return false;
99 }
100 }
101 }
102 return true;
103 }
104
105 private ShardingTable getShardingTable(final String logicTableName, final Map<String, ShardingTable> shardingTables) {
106 ShardingTable result = shardingTables.get(logicTableName);
107 if (null != result) {
108 return result;
109 }
110 throw new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName));
111 }
112
113 private boolean isValidActualDataSourceName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
114 return sampleShardingTable.getActualDataSourceNames().equals(shardingTable.getActualDataSourceNames());
115 }
116
117 private boolean isValidActualTableName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
118 for (String each : sampleShardingTable.getActualDataSourceNames()) {
119 Collection<String> sampleActualTableNames =
120 sampleShardingTable.getActualTableNames(each).stream().map(actualTableName -> actualTableName.replace(sampleShardingTable.getTableDataNode().getPrefix(), ""))
121 .collect(Collectors.toSet());
122 Collection<String> actualTableNames =
123 shardingTable.getActualTableNames(each).stream().map(optional -> optional.replace(shardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
124 if (!sampleActualTableNames.equals(actualTableNames)) {
125 return false;
126 }
127 }
128 return true;
129 }
130
131 private boolean isBindingShardingAlgorithm(final ShardingTable sampleShardingTable, final ShardingTable shardingTable, final boolean databaseAlgorithm,
132 final BindingTableCheckedConfiguration checkedConfig) {
133 return getAlgorithmExpression(sampleShardingTable, databaseAlgorithm, checkedConfig).equals(getAlgorithmExpression(shardingTable, databaseAlgorithm, checkedConfig));
134 }
135
136 private Optional<String> getAlgorithmExpression(final ShardingTable shardingTable, final boolean databaseAlgorithm, final BindingTableCheckedConfiguration checkedConfig) {
137 ShardingStrategyConfiguration shardingStrategyConfig = databaseAlgorithm
138 ? shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable)
139 : shardingRule.getTableShardingStrategyConfiguration(shardingTable);
140 ShardingAlgorithm shardingAlgorithm = checkedConfig.getShardingAlgorithms().get(shardingStrategyConfig.getShardingAlgorithmName());
141 String dataNodePrefix = databaseAlgorithm ? shardingTable.getDataSourceDataNode().getPrefix() : shardingTable.getTableDataNode().getPrefix();
142 String shardingColumn = getShardingColumn(shardingStrategyConfig, shardingRule.getDefaultShardingColumn());
143 return null == shardingAlgorithm ? Optional.empty() : shardingAlgorithm.getAlgorithmStructure(dataNodePrefix, shardingColumn);
144 }
145
146 private String getShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String defaultShardingColumn) {
147 String shardingColumn = defaultShardingColumn;
148 if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
149 shardingColumn = ((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns();
150 }
151 if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
152 shardingColumn = ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
153 }
154 return null == shardingColumn ? "" : shardingColumn;
155 }
156
157 private void checkInlineShardingAlgorithmsInTableRules() {
158 shardingRule.getShardingTables().forEach((key, value) -> {
159 validateInlineShardingAlgorithm(value, shardingRule.getTableShardingStrategyConfiguration(value), value.getTableDataNode());
160 validateInlineShardingAlgorithm(value, shardingRule.getDatabaseShardingStrategyConfiguration(value), value.getDataSourceDataNode());
161 });
162 }
163
164 private void validateInlineShardingAlgorithm(final ShardingTable shardingTable, final ShardingStrategyConfiguration shardingStrategy, final DataNodeInfo dataNodeInfo) {
165 if (null == shardingStrategy) {
166 return;
167 }
168 ShardingAlgorithm shardingAlgorithm = shardingRule.getShardingAlgorithms().get(shardingStrategy.getShardingAlgorithmName());
169 if (shardingAlgorithm instanceof InlineShardingAlgorithm) {
170 String shardingColumn = null == ((StandardShardingStrategyConfiguration) shardingStrategy).getShardingColumn() ? shardingRule.getDefaultShardingColumn()
171 : ((StandardShardingStrategyConfiguration) shardingStrategy).getShardingColumn();
172 String result = null;
173 try {
174 result = ((InlineShardingAlgorithm) shardingAlgorithm).doSharding(Collections.emptySet(), new PreciseShardingValue<>(shardingTable.getLogicTable(), shardingColumn, dataNodeInfo, 1));
175
176 } catch (final Exception ignored) {
177
178 }
179 ShardingSpherePreconditions.checkState(null == result || result.startsWith(dataNodeInfo.getPrefix()),
180 () -> new AlgorithmInitializationException(shardingAlgorithm, "`%s` sharding algorithm configuration of `%s` does not match the actual data nodes",
181 shardingStrategy.getShardingAlgorithmName(), shardingTable.getLogicTable()));
182 }
183 }
184 }