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.DuplicateShardingActualDataNodeException;
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.stream.Collectors;
48
49 @RequiredArgsConstructor
50 public class ShardingRuleChecker {
51
52 private final ShardingRule shardingRule;
53
54
55
56
57
58
59 public void check(final ShardingRuleConfiguration ruleConfig) {
60 checkUniqueActualDataNodesInTableRules();
61 checkBindingTableConfiguration(ruleConfig);
62 checkInlineShardingAlgorithmsInTableRules();
63 }
64
65 private void checkUniqueActualDataNodesInTableRules() {
66 Collection<DataNode> uniqueActualDataNodes = new HashSet<>(shardingRule.getShardingTables().size(), 1F);
67 shardingRule.getShardingTables().forEach((key, value) -> checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.getActualDataNodes().iterator().next()));
68 }
69
70 private void checkUniqueActualDataNodes(final Collection<DataNode> uniqueActualDataNodes, final String logicTable, final DataNode sampleActualDataNode) {
71 ShardingSpherePreconditions.checkNotContains(uniqueActualDataNodes, sampleActualDataNode,
72 () -> new DuplicateShardingActualDataNodeException(logicTable, sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
73 uniqueActualDataNodes.add(sampleActualDataNode);
74 }
75
76 private void checkBindingTableConfiguration(final ShardingRuleConfiguration ruleConfig) {
77 ShardingSpherePreconditions.checkState(
78 isValidBindingTableConfiguration(shardingRule.getShardingTables(),
79 new BindingTableCheckedConfiguration(shardingRule.getDataSourceNames(), shardingRule.getShardingAlgorithms(), ruleConfig.getBindingTableGroups(),
80 shardingRule.getDefaultDatabaseShardingStrategyConfig(), shardingRule.getDefaultTableShardingStrategyConfig(), 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 ShardingSpherePreconditions.checkNotNull(result, () -> new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName)));
108 return result;
109 }
110
111 private boolean isValidActualDataSourceName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
112 return sampleShardingTable.getActualDataSourceNames().equals(shardingTable.getActualDataSourceNames());
113 }
114
115 private boolean isValidActualTableName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
116 for (String each : sampleShardingTable.getActualDataSourceNames()) {
117 Collection<String> sampleActualTableNames = sampleShardingTable.getActualTableNames(each).stream()
118 .map(actualTableName -> actualTableName.replace(sampleShardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
119 Collection<String> actualTableNames =
120 shardingTable.getActualTableNames(each).stream().map(optional -> optional.replace(shardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
121 if (!sampleActualTableNames.equals(actualTableNames)) {
122 return false;
123 }
124 }
125 return true;
126 }
127
128 private boolean isBindingShardingAlgorithm(final ShardingTable sampleShardingTable, final ShardingTable shardingTable, final boolean databaseAlgorithm,
129 final BindingTableCheckedConfiguration checkedConfig) {
130 return getAlgorithmExpression(sampleShardingTable, databaseAlgorithm, checkedConfig).equals(getAlgorithmExpression(shardingTable, databaseAlgorithm, checkedConfig));
131 }
132
133 private Optional<String> getAlgorithmExpression(final ShardingTable shardingTable, final boolean databaseAlgorithm, final BindingTableCheckedConfiguration checkedConfig) {
134 ShardingStrategyConfiguration shardingStrategyConfig = databaseAlgorithm
135 ? shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable)
136 : shardingRule.getTableShardingStrategyConfiguration(shardingTable);
137 ShardingAlgorithm shardingAlgorithm = checkedConfig.getShardingAlgorithms().get(shardingStrategyConfig.getShardingAlgorithmName());
138 String dataNodePrefix = databaseAlgorithm ? shardingTable.getDataSourceDataNode().getPrefix() : shardingTable.getTableDataNode().getPrefix();
139 String shardingColumn = getShardingColumn(shardingStrategyConfig, shardingRule.getDefaultShardingColumn());
140 return null == shardingAlgorithm ? Optional.empty() : shardingAlgorithm.getAlgorithmStructure(dataNodePrefix, shardingColumn);
141 }
142
143 private String getShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String defaultShardingColumn) {
144 String shardingColumn = defaultShardingColumn;
145 if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
146 shardingColumn = ((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns();
147 }
148 if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
149 shardingColumn = ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
150 }
151 return null == shardingColumn ? "" : shardingColumn;
152 }
153
154 private void checkInlineShardingAlgorithmsInTableRules() {
155 shardingRule.getShardingTables().forEach((key, value) -> {
156 validateInlineShardingAlgorithm(value, shardingRule.getTableShardingStrategyConfiguration(value), value.getTableDataNode());
157 validateInlineShardingAlgorithm(value, shardingRule.getDatabaseShardingStrategyConfiguration(value), value.getDataSourceDataNode());
158 });
159 }
160
161 private void validateInlineShardingAlgorithm(final ShardingTable shardingTable, final ShardingStrategyConfiguration shardingStrategy, final DataNodeInfo dataNodeInfo) {
162 if (null == shardingStrategy) {
163 return;
164 }
165 ShardingAlgorithm shardingAlgorithm = shardingRule.getShardingAlgorithms().get(shardingStrategy.getShardingAlgorithmName());
166 if (shardingAlgorithm instanceof InlineShardingAlgorithm) {
167 String shardingColumn = null == ((StandardShardingStrategyConfiguration) shardingStrategy).getShardingColumn() ? shardingRule.getDefaultShardingColumn()
168 : ((StandardShardingStrategyConfiguration) shardingStrategy).getShardingColumn();
169 String result = null;
170 try {
171 result = ((InlineShardingAlgorithm) shardingAlgorithm).doSharding(Collections.emptySet(), new PreciseShardingValue<>(shardingTable.getLogicTable(), shardingColumn, dataNodeInfo, 1));
172
173 } catch (final Exception ignored) {
174
175 }
176 ShardingSpherePreconditions.checkState(null == result || result.startsWith(dataNodeInfo.getPrefix()),
177 () -> new AlgorithmInitializationException(shardingAlgorithm, "`%s` sharding algorithm configuration of `%s` does not match the actual data nodes",
178 shardingStrategy.getShardingAlgorithmName(), shardingTable.getLogicTable()));
179 }
180 }
181
182
183
184
185
186
187
188 public void checkToBeAddedDataNodes(final Map<String, Collection<DataNode>> toBeAddedDataNodes, final boolean isAlteration) {
189 Collection<DataNode> uniqueActualDataNodes = new HashSet<>(shardingRule.getShardingTables().size() + toBeAddedDataNodes.size(), 1F);
190 shardingRule.getShardingTables().forEach((key, value) -> {
191 if (isAlteration && toBeAddedDataNodes.containsKey(key)) {
192 return;
193 }
194 checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.getActualDataNodes().iterator().next());
195 });
196 toBeAddedDataNodes.forEach((key, value) -> checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.iterator().next()));
197 }
198 }