Skip to content

Commit

Permalink
Pick #30917, #33138, Check duplicate actual data nodes when create or…
Browse files Browse the repository at this point in the history
… alter sharding table rule (#12)
  • Loading branch information
RaigorJiang authored Oct 8, 2024
1 parent e939037 commit f52df84
Show file tree
Hide file tree
Showing 12 changed files with 523 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
/**
* Duplicate sharding actual data node exception.
*/
public final class DuplicateSharingActualDataNodeException extends ShardingSQLException {
public final class DuplicateShardingActualDataNodeException extends ShardingSQLException {

private static final long serialVersionUID = 3503761639898230998L;

public DuplicateSharingActualDataNodeException(final String logicalTableName, final String dataSourceName, final String tableName) {
public DuplicateShardingActualDataNodeException(final String logicalTableName, final String dataSourceName, final String tableName) {
super(XOpenSQLState.DUPLICATE, 12,
"Same actual data node cannot be configured in multiple logic tables in same database, logical table '%s', actual data node '%s.%s'.", logicalTableName, dataSourceName, tableName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,10 @@
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
import org.apache.shardingsphere.sharding.cache.ShardingCache;
import org.apache.shardingsphere.sharding.exception.metadata.DuplicateSharingActualDataNodeException;
import org.apache.shardingsphere.sharding.exception.metadata.InvalidBindingTablesException;
import org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
import org.apache.shardingsphere.sharding.rule.attribute.ShardingDataNodeRuleAttribute;
import org.apache.shardingsphere.sharding.rule.attribute.ShardingTableNamesRuleAttribute;
import org.apache.shardingsphere.sharding.rule.checker.ShardingRuleChecker;
import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
import org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
Expand All @@ -68,15 +67,13 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand All @@ -87,8 +84,6 @@
@Getter
public final class ShardingRule implements DatabaseRule {

private static final String ALGORITHM_EXPRESSION_KEY = "algorithm-expression";

private final ShardingRuleConfiguration configuration;

private final Collection<String> dataSourceNames;
Expand Down Expand Up @@ -117,15 +112,16 @@ public final class ShardingRule implements DatabaseRule {

private final RuleAttributes attributes;

private final ShardingRuleChecker shardingRuleChecker = new ShardingRuleChecker(this);

public ShardingRule(final ShardingRuleConfiguration ruleConfig, final Map<String, DataSource> dataSources, final InstanceContext instanceContext) {
configuration = ruleConfig;
this.dataSourceNames = getDataSourceNames(ruleConfig.getTables(), ruleConfig.getAutoTables(), dataSources.keySet());
dataSourceNames = getDataSourceNames(ruleConfig.getTables(), ruleConfig.getAutoTables(), dataSources.keySet());
ruleConfig.getShardingAlgorithms().forEach((key, value) -> shardingAlgorithms.put(key, TypedSPILoader.getService(ShardingAlgorithm.class, value.getType(), value.getProps())));
ruleConfig.getKeyGenerators().forEach((key, value) -> keyGenerators.put(key, TypedSPILoader.getService(KeyGenerateAlgorithm.class, value.getType(), value.getProps())));
ruleConfig.getAuditors().forEach((key, value) -> auditors.put(key, TypedSPILoader.getService(ShardingAuditAlgorithm.class, value.getType(), value.getProps())));
shardingTables.putAll(createShardingTables(ruleConfig.getTables(), ruleConfig.getDefaultKeyGenerateStrategy()));
shardingTables.putAll(createShardingAutoTables(ruleConfig.getAutoTables(), ruleConfig.getDefaultKeyGenerateStrategy()));
validateUniqueActualDataNodesInTableRules();
bindingTableRules.putAll(createBindingTableRules(ruleConfig.getBindingTableGroups()));
defaultDatabaseShardingStrategyConfig = createDefaultDatabaseShardingStrategyConfiguration(ruleConfig);
defaultTableShardingStrategyConfig = createDefaultTableShardingStrategyConfiguration(ruleConfig);
Expand All @@ -134,25 +130,13 @@ public ShardingRule(final ShardingRuleConfiguration ruleConfig, final Map<String
? TypedSPILoader.getService(KeyGenerateAlgorithm.class, null)
: keyGenerators.get(ruleConfig.getDefaultKeyGenerateStrategy().getKeyGeneratorName());
defaultShardingColumn = ruleConfig.getDefaultShardingColumn();
ShardingSpherePreconditions.checkState(isValidBindingTableConfiguration(shardingTables, new BindingTableCheckedConfiguration(this.dataSourceNames, shardingAlgorithms,
ruleConfig.getBindingTableGroups(), defaultDatabaseShardingStrategyConfig, defaultTableShardingStrategyConfig, defaultShardingColumn)),
InvalidBindingTablesException::new);
keyGenerators.values().stream().filter(InstanceContextAware.class::isInstance).forEach(each -> ((InstanceContextAware) each).setInstanceContext(instanceContext));
if (defaultKeyGenerateAlgorithm instanceof InstanceContextAware && -1 == instanceContext.getWorkerId()) {
((InstanceContextAware) defaultKeyGenerateAlgorithm).setInstanceContext(instanceContext);
}
shardingCache = null == ruleConfig.getShardingCache() ? null : new ShardingCache(ruleConfig.getShardingCache(), this);
attributes = new RuleAttributes(new ShardingDataNodeRuleAttribute(shardingTables), new ShardingTableNamesRuleAttribute(shardingTables.values()));
}

private void validateUniqueActualDataNodesInTableRules() {
Set<DataNode> uniqueActualDataNodes = new HashSet<>(shardingTables.size(), 1L);
shardingTables.forEach((key, value) -> {
DataNode sampleActualDataNode = value.getActualDataNodes().iterator().next();
ShardingSpherePreconditions.checkState(!uniqueActualDataNodes.contains(sampleActualDataNode),
() -> new DuplicateSharingActualDataNodeException(key, sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
uniqueActualDataNodes.add(sampleActualDataNode);
});
shardingRuleChecker.check(ruleConfig);
}

private ShardingStrategyConfiguration createDefaultDatabaseShardingStrategyConfiguration(final ShardingRuleConfiguration ruleConfig) {
Expand Down Expand Up @@ -248,71 +232,6 @@ private BindingTableRule createBindingTableRule(final String bindingTableGroup)
return result;
}

private boolean isValidBindingTableConfiguration(final Map<String, ShardingTable> shardingTables, final BindingTableCheckedConfiguration checkedConfig) {
for (ShardingTableReferenceRuleConfiguration each : checkedConfig.getBindingTableGroups()) {
Collection<String> bindingTables = Splitter.on(",").trimResults().splitToList(each.getReference());
if (bindingTables.size() <= 1) {
continue;
}
Iterator<String> iterator = bindingTables.iterator();
ShardingTable sampleShardingTable = getShardingTable(iterator.next(), shardingTables);
while (iterator.hasNext()) {
ShardingTable shardingTable = getShardingTable(iterator.next(), shardingTables);
if (!isValidActualDataSourceName(sampleShardingTable, shardingTable) || !isValidActualTableName(sampleShardingTable, shardingTable)) {
return false;
}
if (!isBindingShardingAlgorithm(sampleShardingTable, shardingTable, true, checkedConfig) || !isBindingShardingAlgorithm(sampleShardingTable, shardingTable, false, checkedConfig)) {
return false;
}
}
}
return true;
}

private boolean isValidActualDataSourceName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
return sampleShardingTable.getActualDataSourceNames().equals(shardingTable.getActualDataSourceNames());
}

private boolean isValidActualTableName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
for (String each : sampleShardingTable.getActualDataSourceNames()) {
Collection<String> sampleActualTableNames =
sampleShardingTable.getActualTableNames(each).stream().map(actualTableName -> actualTableName.replace(sampleShardingTable.getTableDataNode().getPrefix(), ""))
.collect(Collectors.toSet());
Collection<String> actualTableNames =
shardingTable.getActualTableNames(each).stream().map(optional -> optional.replace(shardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
if (!sampleActualTableNames.equals(actualTableNames)) {
return false;
}
}
return true;
}

private boolean isBindingShardingAlgorithm(final ShardingTable sampleShardingTable, final ShardingTable shardingTable, final boolean databaseAlgorithm,
final BindingTableCheckedConfiguration checkedConfig) {
return getAlgorithmExpression(sampleShardingTable, databaseAlgorithm, checkedConfig).equals(getAlgorithmExpression(shardingTable, databaseAlgorithm, checkedConfig));
}

private Optional<String> getAlgorithmExpression(final ShardingTable shardingTable, final boolean databaseAlgorithm, final BindingTableCheckedConfiguration checkedConfig) {
ShardingStrategyConfiguration shardingStrategyConfig = databaseAlgorithm
? getDatabaseShardingStrategyConfiguration(shardingTable, checkedConfig.getDefaultDatabaseShardingStrategyConfig())
: getTableShardingStrategyConfiguration(shardingTable, checkedConfig.getDefaultTableShardingStrategyConfig());
ShardingAlgorithm shardingAlgorithm = checkedConfig.getShardingAlgorithms().get(shardingStrategyConfig.getShardingAlgorithmName());
String dataNodePrefix = databaseAlgorithm ? shardingTable.getDataSourceDataNode().getPrefix() : shardingTable.getTableDataNode().getPrefix();
String shardingColumn = getShardingColumn(shardingStrategyConfig, checkedConfig.getDefaultShardingColumn());
return null == shardingAlgorithm ? Optional.empty() : shardingAlgorithm.getAlgorithmStructure(dataNodePrefix, shardingColumn);
}

private String getShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String defaultShardingColumn) {
String shardingColumn = defaultShardingColumn;
if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
shardingColumn = ((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns();
}
if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
shardingColumn = ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
}
return null == shardingColumn ? "" : shardingColumn;
}

/**
* Get database sharding strategy configuration.
*
Expand Down Expand Up @@ -387,19 +306,7 @@ public Optional<ShardingTable> findShardingTableByActualTable(final String actua
* @throws ShardingTableRuleNotFoundException sharding table rule not found exception
*/
public ShardingTable getShardingTable(final String logicTableName) {
Optional<ShardingTable> shardingTable = findShardingTable(logicTableName);
if (shardingTable.isPresent()) {
return shardingTable.get();
}
throw new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName));
}

private ShardingTable getShardingTable(final String logicTableName, final Map<String, ShardingTable> shardingTables) {
ShardingTable result = shardingTables.get(logicTableName);
if (null != result) {
return result;
}
throw new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName));
return findShardingTable(logicTableName).orElseThrow(() -> new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName)));
}

/**
Expand Down Expand Up @@ -437,8 +344,8 @@ public boolean isAllBindingTables(final ShardingSphereDatabase database, final S
return false;
}
String defaultSchemaName = new DatabaseTypeRegistry(sqlStatementContext.getDatabaseType()).getDefaultSchemaName(database.getName());
ShardingSphereSchema schema = sqlStatementContext.getTablesContext().getSchemaName().map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));
SelectStatementContext select = (SelectStatementContext) sqlStatementContext;
ShardingSphereSchema schema = select.getTablesContext().getSchemaName().map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));
return isJoinConditionContainsShardingColumns(schema, select, logicTableNames, select.getWhereSegments());
}

Expand Down Expand Up @@ -555,11 +462,11 @@ private Optional<String> findShardingColumn(final ShardingStrategyConfiguration
}

/**
* Judge whether given logic table column is generate key column or not.
* Judge whether given logic table column is key generated column or not.
*
* @param columnName column name
* @param tableName table name
* @return whether given logic table column is generate key column or not
* @return whether given logic table column is key generated column or not
*/
public boolean isGenerateKeyColumn(final String columnName, final String tableName) {
return Optional.ofNullable(shardingTables.get(tableName)).filter(each -> isGenerateKeyColumn(each, columnName)).isPresent();
Expand Down Expand Up @@ -593,7 +500,7 @@ public Collection<? extends Comparable<?>> generateKeys(final AlgorithmSQLContex

/**
* Judge whether support auto increment or not.
*
*
* @param logicTableName logic table name
* @return whether support auto increment or not
*/
Expand Down
Loading

0 comments on commit f52df84

Please sign in to comment.