View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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   * Cached sharding SQL router.
38   */
39  public final class CachedShardingSQLRouter {
40      
41      /**
42       * Find {@link RouteContext} from cache or calculate and try caching.
43       *
44       * @param originSQLRouter origin SQL router
45       * @param queryContext query context
46       * @param globalRuleMetaData global rule meta data
47       * @param database database
48       * @param shardingCache sharding cache
49       * @param tableNames table names
50       * @param props configuration properties
51       * @return route context
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           * Create route context.
88           *
89           * @param queryContext query context
90           * @param globalRuleMetaData global rule meta data
91           * @param database database
92           * @param rule rule
93           * @param tableNames table names
94           * @param props configuration properties
95           * @return route context
96           */
97          RouteContext createRouteContext(QueryContext queryContext, RuleMetaData globalRuleMetaData, ShardingSphereDatabase database, ShardingRule rule, Collection<String> tableNames,
98                                          ConfigurationProperties props);
99      }
100 }