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.datanode.DataNode;
23 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
24 import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
25 import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
26 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ComplexShardingStrategyConfiguration;
27 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
28 import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
29 import org.apache.shardingsphere.sharding.exception.metadata.DuplicateShardingActualDataNodeException;
30 import org.apache.shardingsphere.sharding.exception.metadata.InvalidBindingTablesException;
31 import org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
32 import org.apache.shardingsphere.sharding.rule.BindingTableCheckedConfiguration;
33 import org.apache.shardingsphere.sharding.rule.ShardingRule;
34 import org.apache.shardingsphere.sharding.rule.ShardingTable;
35 import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
36
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.Map;
42 import java.util.Optional;
43 import java.util.stream.Collectors;
44
45 @RequiredArgsConstructor
46 public class ShardingRuleChecker {
47
48 private final ShardingRule shardingRule;
49
50
51
52
53
54
55 public void check(final ShardingRuleConfiguration ruleConfig) {
56 checkUniqueActualDataNodesInTableRules();
57 checkBindingTableConfiguration(ruleConfig);
58 }
59
60 private void checkUniqueActualDataNodesInTableRules() {
61 Collection<DataNode> uniqueActualDataNodes = new HashSet<>(shardingRule.getShardingTables().size(), 1F);
62 shardingRule.getShardingTables().forEach((key, value) -> checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.getActualDataNodes().iterator().next()));
63 }
64
65 private void checkUniqueActualDataNodes(final Collection<DataNode> uniqueActualDataNodes, final String logicTable, final DataNode sampleActualDataNode) {
66 ShardingSpherePreconditions.checkNotContains(uniqueActualDataNodes, sampleActualDataNode,
67 () -> new DuplicateShardingActualDataNodeException(logicTable, sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
68 uniqueActualDataNodes.add(sampleActualDataNode);
69 }
70
71 private void checkBindingTableConfiguration(final ShardingRuleConfiguration ruleConfig) {
72 checkBindingTablesNumericSuffix(ruleConfig.getBindingTableGroups(), shardingRule.getShardingTables());
73 BindingTableCheckedConfiguration checkedConfig = new BindingTableCheckedConfiguration(shardingRule.getDataSourceNames(), shardingRule.getShardingAlgorithms(),
74 ruleConfig.getBindingTableGroups(), shardingRule.getDefaultDatabaseShardingStrategyConfig(), shardingRule.getDefaultTableShardingStrategyConfig(),
75 shardingRule.getDefaultShardingColumn());
76 ShardingSpherePreconditions.checkState(isValidBindingTableConfiguration(shardingRule.getShardingTables(), checkedConfig),
77 () -> new InvalidBindingTablesException("Invalid binding table configuration."));
78 }
79
80 private void checkBindingTablesNumericSuffix(final Collection<ShardingTableReferenceRuleConfiguration> bindingTableGroups, final Map<String, ShardingTable> shardingTables) {
81 for (ShardingTableReferenceRuleConfiguration each : bindingTableGroups) {
82 Collection<String> bindingTables = Splitter.on(",").trimResults().splitToList(each.getReference());
83 if (bindingTables.size() <= 1) {
84 continue;
85 }
86 for (String logicTable : bindingTables) {
87 ShardingSpherePreconditions.checkState(hasValidNumericSuffix(getShardingTable(logicTable, shardingTables)),
88 () -> new InvalidBindingTablesException(String.format("Alphabetical table suffixes are not supported in binding tables '%s'.", each.getReference())));
89 }
90 }
91 }
92
93 private boolean hasValidNumericSuffix(final ShardingTable shardingTable) {
94 String logicTable = shardingTable.getLogicTable();
95 int logicTableLength = logicTable.length();
96 for (DataNode each : shardingTable.getActualDataNodes()) {
97 String tableName = each.getTableName();
98 if (tableName.equalsIgnoreCase(logicTable)) {
99 continue;
100 }
101 if (tableName.length() > logicTableLength && tableName.regionMatches(true, 0, logicTable, 0, logicTableLength) && !Character.isDigit(tableName.charAt(tableName.length() - 1))) {
102 return false;
103 }
104 }
105 return true;
106 }
107
108 private boolean isValidBindingTableConfiguration(final Map<String, ShardingTable> shardingTables, final BindingTableCheckedConfiguration checkedConfig) {
109 for (ShardingTableReferenceRuleConfiguration each : checkedConfig.getBindingTableGroups()) {
110 Collection<String> bindingTables = Splitter.on(",").trimResults().splitToList(each.getReference());
111 if (bindingTables.size() <= 1) {
112 continue;
113 }
114 Iterator<String> iterator = bindingTables.iterator();
115 ShardingTable sampleShardingTable = getShardingTable(iterator.next(), shardingTables);
116 while (iterator.hasNext()) {
117 ShardingTable shardingTable = getShardingTable(iterator.next(), shardingTables);
118 if (!isValidActualDataSourceName(sampleShardingTable, shardingTable) || !isValidActualTableName(sampleShardingTable, shardingTable)) {
119 return false;
120 }
121 if (!isBindingShardingAlgorithm(sampleShardingTable, shardingTable, true, checkedConfig) || !isBindingShardingAlgorithm(sampleShardingTable, shardingTable, false, checkedConfig)) {
122 return false;
123 }
124 }
125 }
126 return true;
127 }
128
129 private ShardingTable getShardingTable(final String logicTableName, final Map<String, ShardingTable> shardingTables) {
130 ShardingTable result = shardingTables.get(logicTableName);
131 ShardingSpherePreconditions.checkNotNull(result, () -> new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName)));
132 return result;
133 }
134
135 private boolean isValidActualDataSourceName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
136 return sampleShardingTable.getActualDataSourceNames().equals(shardingTable.getActualDataSourceNames());
137 }
138
139 private boolean isValidActualTableName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
140 for (String each : sampleShardingTable.getActualDataSourceNames()) {
141 Collection<String> sampleActualTableNames = sampleShardingTable.getActualTableNames(each).stream()
142 .map(actualTableName -> actualTableName.replace(sampleShardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
143 Collection<String> actualTableNames =
144 shardingTable.getActualTableNames(each).stream().map(optional -> optional.replace(shardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
145 if (!sampleActualTableNames.equals(actualTableNames)) {
146 return false;
147 }
148 }
149 return true;
150 }
151
152 private boolean isBindingShardingAlgorithm(final ShardingTable sampleShardingTable, final ShardingTable shardingTable, final boolean databaseAlgorithm,
153 final BindingTableCheckedConfiguration checkedConfig) {
154 return getAlgorithmExpression(sampleShardingTable, databaseAlgorithm, checkedConfig).equals(getAlgorithmExpression(shardingTable, databaseAlgorithm, checkedConfig));
155 }
156
157 private Optional<String> getAlgorithmExpression(final ShardingTable shardingTable, final boolean databaseAlgorithm, final BindingTableCheckedConfiguration checkedConfig) {
158 ShardingStrategyConfiguration shardingStrategyConfig = databaseAlgorithm
159 ? shardingRule.getDatabaseShardingStrategyConfiguration(shardingTable)
160 : shardingRule.getTableShardingStrategyConfiguration(shardingTable);
161 ShardingAlgorithm shardingAlgorithm = checkedConfig.getShardingAlgorithms().get(shardingStrategyConfig.getShardingAlgorithmName());
162 String dataNodePrefix = databaseAlgorithm ? shardingTable.getDataSourceDataNode().getPrefix() : shardingTable.getTableDataNode().getPrefix();
163 String shardingColumn = getShardingColumn(shardingStrategyConfig, shardingRule.getDefaultShardingColumn());
164 return null == shardingAlgorithm ? Optional.empty() : shardingAlgorithm.getAlgorithmStructure(dataNodePrefix, shardingColumn);
165 }
166
167 private String getShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String defaultShardingColumn) {
168 String shardingColumn = defaultShardingColumn;
169 if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
170 shardingColumn = ((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns();
171 }
172 if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
173 shardingColumn = ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
174 }
175 return null == shardingColumn ? "" : shardingColumn;
176 }
177
178
179
180
181
182
183
184 public void checkToBeAddedDataNodes(final Map<String, Collection<DataNode>> toBeAddedDataNodes, final boolean isAlteration) {
185 Collection<DataNode> uniqueActualDataNodes = new HashSet<>(shardingRule.getShardingTables().size() + toBeAddedDataNodes.size(), 1F);
186 shardingRule.getShardingTables().forEach((key, value) -> {
187 if (isAlteration && toBeAddedDataNodes.containsKey(key)) {
188 return;
189 }
190 checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.getActualDataNodes().iterator().next());
191 });
192 toBeAddedDataNodes.forEach((key, value) -> checkUniqueActualDataNodes(uniqueActualDataNodes, key, value.iterator().next()));
193 }
194 }