/* * Copyright 1999-2015 dangdang.com. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *

*/ package com.dangdang.ddframe.rdb.sharding.routing.type.simple; import com.dangdang.ddframe.rdb.sharding.api.BaseShardingValue; import com.dangdang.ddframe.rdb.sharding.api.ShardingValue; import com.dangdang.ddframe.rdb.sharding.api.rule.DataNode; import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule; import com.dangdang.ddframe.rdb.sharding.api.rule.TableRule; import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy; import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy; import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder; import com.dangdang.ddframe.rdb.sharding.hint.ShardingKey; import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Column; import com.dangdang.ddframe.rdb.sharding.parsing.parser.context.condition.Condition; import com.dangdang.ddframe.rdb.sharding.parsing.parser.sql.SQLStatement; import com.dangdang.ddframe.rdb.sharding.routing.strategy.ShardingStrategy; import com.dangdang.ddframe.rdb.sharding.routing.strategy.SingleKeyShardingAlgorithm; import com.dangdang.ddframe.rdb.sharding.routing.type.RoutingEngine; import com.dangdang.ddframe.rdb.sharding.routing.type.RoutingResult; import com.dangdang.ddframe.rdb.sharding.routing.type.TableUnit; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * Simple routing engine. * * @author zhangliang */ @RequiredArgsConstructor public final class SimpleRoutingEngine implements RoutingEngine { private final ShardingRule shardingRule; private final List parameters; private final String logicTableName; private final SQLStatement sqlStatement; @Override public RoutingResult route() { TableRule tableRule = shardingRule.getTableRule(logicTableName); List databaseShardingValues = getDatabaseShardingValues(tableRule); List tableShardingValues = getTableShardingValues(tableRule); Collection routedDataSources = routeDataSources(tableRule, databaseShardingValues); Map> routedMap = new LinkedHashMap<>(routedDataSources.size()); for (String each : routedDataSources) { routedMap.put(each, routeTables(tableRule, each, tableShardingValues)); } return generateRoutingResult(tableRule, routedMap); } private List getDatabaseShardingValues(final TableRule tableRule) { DatabaseShardingStrategy strategy = shardingRule.getDatabaseShardingStrategy(tableRule); return HintManagerHolder.isUseShardingHint() ? getDatabaseShardingValuesFromHint(strategy.getShardingColumns()) : getShardingValues(strategy.getShardingColumns()); } private List getTableShardingValues(final TableRule tableRule) { TableShardingStrategy strategy = shardingRule.getTableShardingStrategy(tableRule); return HintManagerHolder.isUseShardingHint() ? getTableShardingValuesFromHint(strategy.getShardingColumns()) : getShardingValues(strategy.getShardingColumns()); } private List getDatabaseShardingValuesFromHint(final Collection shardingColumns) { List result = new ArrayList<>(shardingColumns.size()); for (String each : shardingColumns) { Optional shardingValue = HintManagerHolder.getDatabaseShardingValue(new ShardingKey(logicTableName, each)); if (shardingValue.isPresent()) { result.add(shardingValue.get()); } } return result; } private List getTableShardingValuesFromHint(final Collection shardingColumns) { List result = new ArrayList<>(shardingColumns.size()); for (String each : shardingColumns) { Optional shardingValue = HintManagerHolder.getTableShardingValue(new ShardingKey(logicTableName, each)); if (shardingValue.isPresent()) { result.add(shardingValue.get()); } } return result; } private List getShardingValues(final Collection shardingColumns) { List result = new ArrayList<>(shardingColumns.size()); for (String each : shardingColumns) { Optional condition = sqlStatement.getConditions().find(new Column(each, logicTableName)); if (condition.isPresent()) { result.add(condition.get().getShardingValue(parameters)); } } return result; } private Collection routeDataSources(final TableRule tableRule, final List databaseShardingValues) { DatabaseShardingStrategy strategy = shardingRule.getDatabaseShardingStrategy(tableRule); if (isAccurateSharding(databaseShardingValues, strategy)) { Collection result = new LinkedList<>(); Collection accurateDatabaseShardingValues = transferToShardingValues((ShardingValue) databaseShardingValues.get(0)); for (ShardingValue eachDatabaseShardingValue : accurateDatabaseShardingValues) { result.add(strategy.doAccurateSharding(tableRule.getActualDatasourceNames(), eachDatabaseShardingValue)); } return result; } Collection result = shardingRule.getDatabaseShardingStrategy(tableRule).doStaticSharding(tableRule.getActualDatasourceNames(), databaseShardingValues); Preconditions.checkState(!result.isEmpty(), "no database route info"); return result; } private Collection routeTables(final TableRule tableRule, final String routedDataSource, final List tableShardingValues) { TableShardingStrategy strategy = shardingRule.getTableShardingStrategy(tableRule); if (isAccurateSharding(tableShardingValues, strategy)) { Collection result = new HashSet<>(); Collection accurateTableShardingValues = transferToShardingValues((ShardingValue) tableShardingValues.get(0)); for (ShardingValue eachTableShardingValue : accurateTableShardingValues) { result.add(shardingRule.getTableShardingStrategy(tableRule).doAccurateSharding( tableRule.isDynamic() ? Collections.emptyList() : tableRule.getActualTableNames(routedDataSource), eachTableShardingValue)); } return result; } Collection result = tableRule.isDynamic() ? strategy.doDynamicSharding(tableShardingValues) : strategy.doStaticSharding(tableRule.getActualTableNames(routedDataSource), tableShardingValues); Preconditions.checkState(!result.isEmpty(), "no table route info"); return result; } private boolean isAccurateSharding(final List shardingValues, final ShardingStrategy shardingStrategy) { return 1 == shardingValues.size() && shardingStrategy.getShardingAlgorithm() instanceof SingleKeyShardingAlgorithm && ShardingValue.ShardingValueType.RANGE != shardingValues.get(0).getType(); } @SuppressWarnings("unchecked") private List transferToShardingValues(final ShardingValue shardingValue) { if (ShardingValue.ShardingValueType.SINGLE == shardingValue.getType()) { return Collections.singletonList(shardingValue); } List result = new ArrayList<>(shardingValue.getValues().size()); for (Comparable each : shardingValue.getValues()) { result.add(new ShardingValue(shardingValue.getLogicTableName(), shardingValue.getColumnName(), each)); } return result; } private RoutingResult generateRoutingResult(final TableRule tableRule, final Map> routedMap) { RoutingResult result = new RoutingResult(); for (Entry> entry : routedMap.entrySet()) { Collection dataNodes = tableRule.getActualDataNodes(entry.getKey(), entry.getValue()); for (DataNode each : dataNodes) { result.getTableUnits().getTableUnits().add(new TableUnit(each.getDataSourceName(), logicTableName, each.getTableName())); } } return result; } }