1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.infra.route.engine;
19
20 import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
21 import org.apache.shardingsphere.infra.binder.context.extractor.SQLStatementContextExtractor;
22 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
23 import org.apache.shardingsphere.infra.exception.kernel.syntax.hint.DataSourceHintNotExistsException;
24 import org.apache.shardingsphere.infra.hint.HintManager;
25 import org.apache.shardingsphere.infra.hint.HintValueContext;
26 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
27 import org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
28 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
29 import org.apache.shardingsphere.infra.route.SQLRouter;
30 import org.apache.shardingsphere.infra.route.SQLRouter.Type;
31 import org.apache.shardingsphere.infra.route.context.RouteContext;
32 import org.apache.shardingsphere.infra.route.context.RouteMapper;
33 import org.apache.shardingsphere.infra.route.context.RouteUnit;
34 import org.apache.shardingsphere.infra.route.engine.tableless.router.TablelessSQLRouter;
35 import org.apache.shardingsphere.infra.route.lifecycle.DecorateSQLRouter;
36 import org.apache.shardingsphere.infra.route.lifecycle.EntranceSQLRouter;
37 import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
38 import org.apache.shardingsphere.infra.session.query.QueryContext;
39 import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
40
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.LinkedHashMap;
44 import java.util.Map;
45 import java.util.Map.Entry;
46 import java.util.Optional;
47
48
49
50
51 @HighFrequencyInvocation
52 public final class SQLRouteEngine {
53
54 private final ConfigurationProperties props;
55
56 @SuppressWarnings("rawtypes")
57 private final Map<ShardingSphereRule, SQLRouter> dataNodeRouters;
58
59 @SuppressWarnings("rawtypes")
60 private final Map<ShardingSphereRule, SQLRouter> dataSourceRouters;
61
62 @SuppressWarnings("rawtypes")
63 public SQLRouteEngine(final Collection<ShardingSphereRule> rules, final ConfigurationProperties props) {
64 this.props = props;
65 Map<ShardingSphereRule, SQLRouter> routers = OrderedSPILoader.getServices(SQLRouter.class, rules);
66 dataNodeRouters = filterRouters(routers, Type.DATA_NODE);
67 dataSourceRouters = filterRouters(routers, Type.DATA_SOURCE);
68 }
69
70 @SuppressWarnings("rawtypes")
71 private Map<ShardingSphereRule, SQLRouter> filterRouters(final Map<ShardingSphereRule, SQLRouter> routers, final Type type) {
72 Map<ShardingSphereRule, SQLRouter> result = new LinkedHashMap<>();
73 for (Entry<ShardingSphereRule, SQLRouter> entry : routers.entrySet()) {
74 if (type == entry.getValue().getType()) {
75 result.put(entry.getKey(), entry.getValue());
76 }
77 }
78 return result;
79 }
80
81
82
83
84
85
86
87
88
89 public RouteContext route(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database) {
90 RouteContext result = new RouteContext();
91 Optional<String> dataSourceName = findDataSourceByHint(queryContext.getHintValueContext(), database.getResourceMetaData().getStorageUnits());
92 if (dataSourceName.isPresent()) {
93 result.getRouteUnits().add(new RouteUnit(new RouteMapper(dataSourceName.get(), dataSourceName.get()), Collections.emptyList()));
94 return result;
95 }
96 Collection<String> tableNames = SQLStatementContextExtractor.getTableNames(database, queryContext.getSqlStatementContext());
97 result = route(queryContext, globalRuleMetaData, database, dataNodeRouters, tableNames, result);
98 result = new TablelessSQLRouter().route(queryContext, globalRuleMetaData, database, tableNames, result);
99 result = route(queryContext, globalRuleMetaData, database, dataSourceRouters, tableNames, result);
100 if (result.getRouteUnits().isEmpty() && 1 == database.getResourceMetaData().getStorageUnits().size()) {
101 String singleDataSourceName = database.getResourceMetaData().getStorageUnits().keySet().iterator().next();
102 result.getRouteUnits().add(new RouteUnit(new RouteMapper(singleDataSourceName, singleDataSourceName), Collections.emptyList()));
103 }
104 return result;
105 }
106
107 @SuppressWarnings({"unchecked", "rawtypes"})
108 private RouteContext route(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database,
109 final Map<ShardingSphereRule, SQLRouter> routers, final Collection<String> tableNames, final RouteContext routeContext) {
110 RouteContext result = routeContext;
111 for (Entry<ShardingSphereRule, SQLRouter> entry : routers.entrySet()) {
112 if (result.getRouteUnits().isEmpty() && entry.getValue() instanceof EntranceSQLRouter) {
113 result = ((EntranceSQLRouter) entry.getValue()).createRouteContext(queryContext, globalRuleMetaData, database, entry.getKey(), tableNames, props);
114 } else if (entry.getValue() instanceof DecorateSQLRouter) {
115 ((DecorateSQLRouter) entry.getValue()).decorateRouteContext(result, queryContext, database, entry.getKey(), tableNames, props);
116 }
117 }
118 return result;
119 }
120
121 private Optional<String> findDataSourceByHint(final HintValueContext hintValueContext, final Map<String, StorageUnit> storageUnits) {
122 Optional<String> result = HintManager.isInstantiated() && HintManager.getDataSourceName().isPresent() ? HintManager.getDataSourceName() : hintValueContext.findHintDataSourceName();
123 if (result.isPresent() && !storageUnits.containsKey(result.get())) {
124 throw new DataSourceHintNotExistsException(result.get());
125 }
126 return result;
127 }
128 }