1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  package org.apache.shardingsphere.sharding.cache.route;
19  
20  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
21  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
22  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
23  import org.apache.shardingsphere.infra.route.context.RouteContext;
24  import org.apache.shardingsphere.infra.session.query.QueryContext;
25  import org.apache.shardingsphere.sharding.cache.ShardingCache;
26  import org.apache.shardingsphere.sharding.cache.checker.ShardingRouteCacheableCheckResult;
27  import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheKey;
28  import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheValue;
29  import org.apache.shardingsphere.sharding.rule.ShardingRule;
30  
31  import java.util.ArrayList;
32  import java.util.Collection;
33  import java.util.List;
34  import java.util.Optional;
35  
36  
37  
38  
39  public final class CachedShardingSQLRouter {
40      
41      
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53      public Optional<RouteContext> loadRouteContext(final OriginSQLRouter originSQLRouter, final QueryContext queryContext, final RuleMetaData globalRuleMetaData,
54                                                     final ShardingSphereDatabase database, final ShardingCache shardingCache, final Collection<String> tableNames, final ConfigurationProperties props) {
55          if (queryContext.getSql().length() > shardingCache.getConfiguration().getAllowedMaxSqlLength()) {
56              return Optional.empty();
57          }
58          ShardingRouteCacheableCheckResult cacheableCheckResult = shardingCache.getRouteCacheableChecker().check(database, queryContext);
59          if (!cacheableCheckResult.isProbablyCacheable()) {
60              return Optional.empty();
61          }
62          List<Object> shardingConditionParams = new ArrayList<>(cacheableCheckResult.getShardingConditionParameterMarkerIndexes().size());
63          for (int each : cacheableCheckResult.getShardingConditionParameterMarkerIndexes()) {
64              if (each >= queryContext.getParameters().size()) {
65                  return Optional.empty();
66              }
67              shardingConditionParams.add(queryContext.getParameters().get(each));
68          }
69          Optional<RouteContext> cachedResult = shardingCache.getRouteCache().get(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParams))
70                  .flatMap(ShardingRouteCacheValue::getCachedRouteContext);
71          RouteContext result = cachedResult.orElseGet(() -> originSQLRouter.createRouteContext(queryContext, globalRuleMetaData, database, shardingCache.getShardingRule(), tableNames, props));
72          if (!cachedResult.isPresent() && hitOneShardOnly(result)) {
73              shardingCache.getRouteCache().put(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParams), new ShardingRouteCacheValue(result));
74          }
75          return Optional.of(result);
76      }
77      
78      private boolean hitOneShardOnly(final RouteContext routeContext) {
79          return 1 == routeContext.getRouteUnits().size() && 1 == routeContext.getRouteUnits().iterator().next().getTableMappers().size()
80                  && 1 == routeContext.getOriginalDataNodes().size() && 1 == routeContext.getOriginalDataNodes().iterator().next().size();
81      }
82      
83      @FunctionalInterface
84      public interface OriginSQLRouter {
85          
86          
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97          RouteContext createRouteContext(QueryContext queryContext, RuleMetaData globalRuleMetaData, ShardingSphereDatabase database, ShardingRule rule, Collection<String> tableNames,
98                                          ConfigurationProperties props);
99      }
100 }