You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by pa...@apache.org on 2022/09/28 10:39:08 UTC
[shardingsphere] branch master updated: Add sharding cache plugin (#21240)
This is an automated email from the ASF dual-hosted git repository.
panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 018d69b5de0 Add sharding cache plugin (#21240)
018d69b5de0 is described below
commit 018d69b5de0e636df4cc3159ab4b7155ecb76e4a
Author: 吴伟杰 <wu...@apache.org>
AuthorDate: Wed Sep 28 18:38:57 2022 +0800
Add sharding cache plugin (#21240)
* Implements sharding route cache
* Complete ShardingRouteCacheableChecker
* Add Yaml swapper for sharding cache
* Complete javadoc
* Formatting codes
* Merge CachedShardingSQLRouter
* Simplify ShardingRouteCacheValue
* Add SuppressWarnings
* Refactor packages in cache module
* Checking length of SQL
* Complete CachedShardingSQLRouter
* Add CachedShardingSQLRouterTest
* Add TODO into CachedShardingSQLRouter
* Complete select checking in ShardingRouteCacheableChecker
* Add ShardingRouteCacheableCheckerTest
* Add ShardingCacheRuleBuilderTest
* Add ShardingRouteCacheTest
* Add tests for YAML swappers
* Add shardingsphere-sharding-cache plugin JDBC and Proxy
* Format codes
---
.../shardingsphere-sharding-plugin/pom.xml | 1 +
.../{ => shardingsphere-sharding-cache}/pom.xml | 23 ++-
.../sharding/cache/api/ShardingCacheOptions.java | 37 ++++
.../cache/api/ShardingCacheRuleConfiguration.java | 37 ++++
.../checker/ShardingRouteCacheableCheckResult.java | 35 ++++
.../checker/ShardingRouteCacheableChecker.java | 228 +++++++++++++++++++++
.../CacheableShardingAlgorithmChecker.java | 55 +++++
.../CacheableShardingAlgorithmClassProvider.java | 35 ++++
...tInCacheableShardingAlgorithmClassProvider.java | 39 ++++
.../cache/route/CachedShardingSQLRouter.java | 88 ++++++++
.../cache/route/cache/ShardingRouteCache.java | 64 ++++++
.../cache/route/cache/ShardingRouteCacheKey.java | 37 ++++
.../cache/route/cache/ShardingRouteCacheValue.java | 91 ++++++++
.../sharding/cache/rule/ShardingCacheRule.java | 52 +++++
.../rule/builder/ShardingCacheRuleBuilder.java | 55 +++++
.../YamlShardingCacheOptionsConfiguration.java | 36 ++++
.../yaml/YamlShardingCacheRuleConfiguration.java | 41 ++++
...mlShardingCacheOptionsConfigurationSwapper.java | 42 ++++
.../YamlShardingCacheRuleConfigurationSwapper.java | 59 ++++++
...org.apache.shardingsphere.infra.route.SQLRouter | 18 ++
...infra.rule.builder.database.DatabaseRuleBuilder | 18 ++
...onfig.swapper.rule.YamlRuleConfigurationSwapper | 18 ++
...gorithm.CacheableShardingAlgorithmClassProvider | 18 ++
.../checker/ShardingRouteCacheableCheckerTest.java | 180 ++++++++++++++++
.../cache/route/CachedShardingSQLRouterTest.java | 170 +++++++++++++++
.../cache/route/cache/ShardingRouteCacheTest.java | 39 ++++
.../rule/builder/ShardingCacheRuleBuilderTest.java | 62 ++++++
...ardingCacheOptionsConfigurationSwapperTest.java | 49 +++++
...lShardingCacheRuleConfigurationSwapperTest.java | 75 +++++++
.../shardingsphere-jdbc-core/pom.xml | 5 +
.../shardingsphere-proxy-bootstrap/pom.xml | 5 +
31 files changed, 1705 insertions(+), 7 deletions(-)
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml
index 96b0e711863..1eda9ca9134 100644
--- a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml
@@ -31,5 +31,6 @@
<modules>
<module>shardingsphere-sharding-cosid</module>
<module>shardingsphere-sharding-nanoid</module>
+ <module>shardingsphere-sharding-cache</module>
</modules>
</project>
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/pom.xml
similarity index 66%
copy from shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml
copy to shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/pom.xml
index 96b0e711863..3c4c588cf34 100644
--- a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/pom.xml
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/pom.xml
@@ -21,15 +21,24 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.shardingsphere</groupId>
- <artifactId>shardingsphere-sharding</artifactId>
+ <artifactId>shardingsphere-sharding-plugin</artifactId>
<version>5.2.1-SNAPSHOT</version>
</parent>
- <artifactId>shardingsphere-sharding-plugin</artifactId>
- <packaging>pom</packaging>
+ <artifactId>shardingsphere-sharding-cache</artifactId>
<name>${project.artifactId}</name>
- <modules>
- <module>shardingsphere-sharding-cosid</module>
- <module>shardingsphere-sharding-nanoid</module>
- </modules>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.shardingsphere</groupId>
+ <artifactId>shardingsphere-sharding-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.shardingsphere</groupId>
+ <artifactId>shardingsphere-sql-parser-postgresql</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheOptions.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheOptions.java
new file mode 100644
index 00000000000..ce27310a5f0
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheOptions.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.api;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+
+/**
+ * Options of sharding cache.
+ */
+@RequiredArgsConstructor
+@Getter
+@ToString
+public final class ShardingCacheOptions {
+
+ private final boolean softValues;
+
+ private final int initialCapacity;
+
+ private final int maximumSize;
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheRuleConfiguration.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheRuleConfiguration.java
new file mode 100644
index 00000000000..92c6b43c8d8
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/api/ShardingCacheRuleConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.api;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+import org.apache.shardingsphere.infra.config.rule.function.EnhancedRuleConfiguration;
+import org.apache.shardingsphere.infra.config.rule.scope.DatabaseRuleConfiguration;
+
+/**
+ * Configuration for sharding cache rule.
+ */
+@RequiredArgsConstructor
+@Getter
+@ToString
+public final class ShardingCacheRuleConfiguration implements DatabaseRuleConfiguration, EnhancedRuleConfiguration {
+
+ private final int allowedMaxSqlLength;
+
+ private final ShardingCacheOptions routeCache;
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckResult.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckResult.java
new file mode 100644
index 00000000000..6a1c9edebb3
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckResult.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Route cacheable check result.
+ */
+@RequiredArgsConstructor
+@Getter
+public class ShardingRouteCacheableCheckResult {
+
+ private final boolean probablyCacheable;
+
+ private final List<Integer> shardingConditionParameterMarkerIndexes;
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableChecker.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableChecker.java
new file mode 100644
index 00000000000..0a0b9465c8c
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableChecker.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import com.google.common.collect.Range;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import org.apache.shardingsphere.infra.binder.QueryContext;
+import org.apache.shardingsphere.infra.binder.segment.insert.keygen.GeneratedKeyContext;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.binder.statement.dml.DeleteStatementContext;
+import org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementContext;
+import org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
+import org.apache.shardingsphere.infra.binder.statement.dml.UpdateStatementContext;
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.sharding.cache.checker.algorithm.CacheableShardingAlgorithmChecker;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
+import org.apache.shardingsphere.sharding.route.engine.condition.engine.impl.InsertClauseShardingConditionEngine;
+import org.apache.shardingsphere.sharding.route.engine.condition.engine.impl.WhereClauseShardingConditionEngine;
+import org.apache.shardingsphere.sharding.route.engine.condition.value.ListShardingConditionValue;
+import org.apache.shardingsphere.sharding.route.engine.condition.value.RangeShardingConditionValue;
+import org.apache.shardingsphere.sharding.route.engine.condition.value.ShardingConditionValue;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.rule.TableRule;
+import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.InsertValuesSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Sharding route cacheable checker.
+ */
+public final class ShardingRouteCacheableChecker {
+
+ private final ShardingRule shardingRule;
+
+ private final LoadingCache<Key, ShardingRouteCacheableCheckResult> checkingCache;
+
+ public ShardingRouteCacheableChecker(final ShardingCacheRule shardingCacheRule) {
+ shardingRule = shardingCacheRule.getShardingRule();
+ checkingCache = buildCache(shardingCacheRule.getConfiguration().getRouteCache());
+ }
+
+ private LoadingCache<Key, ShardingRouteCacheableCheckResult> buildCache(final ShardingCacheOptions cacheOptions) {
+ Caffeine<Object, Object> result = Caffeine.newBuilder().initialCapacity(cacheOptions.getInitialCapacity()).maximumSize(cacheOptions.getMaximumSize());
+ if (cacheOptions.isSoftValues()) {
+ result.softValues();
+ }
+ return result.build(this::load);
+ }
+
+ private ShardingRouteCacheableCheckResult load(final Key key) {
+ SQLStatementContext<?> sqlStatementContext = key.getSqlStatementContext();
+ ShardingRouteCacheableCheckResult result;
+ if (sqlStatementContext instanceof SelectStatementContext) {
+ result = checkSelectCacheable((SelectStatementContext) sqlStatementContext, key.getParameters(), key.getDatabase());
+ } else if (sqlStatementContext instanceof UpdateStatementContext) {
+ result = checkUpdateCacheable((UpdateStatementContext) sqlStatementContext, key.getParameters(), key.getDatabase());
+ } else if (sqlStatementContext instanceof InsertStatementContext) {
+ result = checkInsertCacheable((InsertStatementContext) sqlStatementContext, key.getParameters(), key.getDatabase());
+ } else if (sqlStatementContext instanceof DeleteStatementContext) {
+ result = checkDeleteCacheable((DeleteStatementContext) sqlStatementContext, key.getParameters(), key.getDatabase());
+ } else {
+ result = new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ key.getParameters().clear();
+ return result;
+ }
+
+ private ShardingRouteCacheableCheckResult checkSelectCacheable(final SelectStatementContext statementContext, final List<Object> parameters, final ShardingSphereDatabase database) {
+ Collection<String> tableNames = new HashSet<>(statementContext.getTablesContext().getTableNames());
+ if (!shardingRule.isAllShardingTables(tableNames) || shardingRule.isAllBroadcastTables(tableNames)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ tableNames.removeAll(shardingRule.getBroadcastTables());
+ if (1 != tableNames.size() && !shardingRule.isAllBindingTables(tableNames) || containsNonCacheableShardingAlgorithm(tableNames)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ List<ShardingCondition> shardingConditions = new WhereClauseShardingConditionEngine(shardingRule, database).createShardingConditions(statementContext, parameters);
+ return checkShardingConditionsCacheable(shardingConditions);
+ }
+
+ private ShardingRouteCacheableCheckResult checkUpdateCacheable(final UpdateStatementContext statementContext, final List<Object> parameters, final ShardingSphereDatabase database) {
+ return checkUpdateOrDeleteCacheable(statementContext, parameters, database);
+ }
+
+ private ShardingRouteCacheableCheckResult checkInsertCacheable(final InsertStatementContext statementContext, final List<Object> parameters, final ShardingSphereDatabase database) {
+ Collection<String> tableNames = statementContext.getTablesContext().getTableNames();
+ boolean isShardingTable;
+ if (1 != tableNames.size() || null != statementContext.getInsertSelectContext() || null != statementContext.getOnDuplicateKeyUpdateValueContext()
+ || statementContext.getGeneratedKeyContext().map(GeneratedKeyContext::isGenerated).orElse(false)
+ || (isShardingTable = shardingRule.isAllShardingTables(tableNames)) && containsNonCacheableShardingAlgorithm(tableNames)
+ || !isShardingTable && !shardingRule.isAllBroadcastTables(tableNames)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ Collection<InsertValuesSegment> values = statementContext.getSqlStatement().getValues();
+ if (1 != values.size()) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ InsertValuesSegment valueSegment = values.iterator().next();
+ for (ExpressionSegment each : valueSegment.getValues()) {
+ if (!(each instanceof ParameterMarkerExpressionSegment || each instanceof LiteralExpressionSegment)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ }
+ List<ShardingCondition> shardingConditions = new InsertClauseShardingConditionEngine(shardingRule, database).createShardingConditions(statementContext, parameters);
+ return checkShardingConditionsCacheable(shardingConditions);
+ }
+
+ private ShardingRouteCacheableCheckResult checkDeleteCacheable(final DeleteStatementContext statementContext, final List<Object> parameters, final ShardingSphereDatabase database) {
+ return checkUpdateOrDeleteCacheable(statementContext, parameters, database);
+ }
+
+ private ShardingRouteCacheableCheckResult checkUpdateOrDeleteCacheable(final SQLStatementContext<?> statementContext, final List<Object> parameters, final ShardingSphereDatabase database) {
+ Collection<String> tableNames = statementContext.getTablesContext().getTableNames();
+ boolean isShardingTable;
+ if (1 != tableNames.size() || (isShardingTable = shardingRule.isAllShardingTables(tableNames)) && containsNonCacheableShardingAlgorithm(tableNames)
+ || !isShardingTable && !shardingRule.isAllBroadcastTables(tableNames)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ List<ShardingCondition> shardingConditions = new WhereClauseShardingConditionEngine(shardingRule, database).createShardingConditions(statementContext, parameters);
+ return checkShardingConditionsCacheable(shardingConditions);
+ }
+
+ private boolean containsNonCacheableShardingAlgorithm(final Collection<String> logicTables) {
+ for (String each : logicTables) {
+ TableRule tableRule = shardingRule.getTableRule(each);
+ String databaseShardingAlgorithmName = shardingRule.getDatabaseShardingStrategyConfiguration(tableRule).getShardingAlgorithmName();
+ ShardingAlgorithm databaseShardingAlgorithm = shardingRule.getShardingAlgorithms().get(databaseShardingAlgorithmName);
+ if (null != databaseShardingAlgorithm && !CacheableShardingAlgorithmChecker.isCacheableShardingAlgorithm(databaseShardingAlgorithm)) {
+ return true;
+ }
+ String tableShardingAlgorithmName = shardingRule.getTableShardingStrategyConfiguration(tableRule).getShardingAlgorithmName();
+ ShardingAlgorithm tableShardingAlgorithm = shardingRule.getShardingAlgorithms().get(tableShardingAlgorithmName);
+ if (null != tableShardingAlgorithm && !CacheableShardingAlgorithmChecker.isCacheableShardingAlgorithm(tableShardingAlgorithm)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static ShardingRouteCacheableCheckResult checkShardingConditionsCacheable(final List<ShardingCondition> shardingConditions) {
+ Set<Integer> result = new TreeSet<>();
+ for (ShardingCondition each : shardingConditions) {
+ for (ShardingConditionValue conditionValue : each.getValues()) {
+ if (!isConditionTypeCacheable(conditionValue)) {
+ return new ShardingRouteCacheableCheckResult(false, Collections.emptyList());
+ }
+ result.addAll(conditionValue.getParameterMarkerIndexes());
+ }
+ }
+ return new ShardingRouteCacheableCheckResult(true, new ArrayList<>(result));
+ }
+
+ private static boolean isConditionTypeCacheable(final ShardingConditionValue conditionValue) {
+ if (conditionValue instanceof ListShardingConditionValue<?>) {
+ for (Comparable<?> eachValue : ((ListShardingConditionValue<?>) conditionValue).getValues()) {
+ if (!(eachValue instanceof Number)) {
+ return false;
+ }
+ }
+ }
+ if (conditionValue instanceof RangeShardingConditionValue<?>) {
+ Range<?> range = ((RangeShardingConditionValue<?>) conditionValue).getValueRange();
+ return range.lowerEndpoint() instanceof Number && range.upperEndpoint() instanceof Number;
+ }
+ return true;
+ }
+
+ /**
+ * Check if query is cacheable.
+ *
+ * @param database database
+ * @param queryContext query context
+ * @return is cacheable
+ */
+ public ShardingRouteCacheableCheckResult check(final ShardingSphereDatabase database, final QueryContext queryContext) {
+ return checkingCache.get(new Key(database, queryContext.getSql(), queryContext.getSqlStatementContext(), queryContext.getParameters()));
+ }
+
+ @EqualsAndHashCode(of = "sql")
+ @Getter
+ private static class Key {
+
+ private final ShardingSphereDatabase database;
+
+ private final String sql;
+
+ private final SQLStatementContext<?> sqlStatementContext;
+
+ private final List<Object> parameters;
+
+ Key(final ShardingSphereDatabase database, final String sql, final SQLStatementContext<?> sqlStatementContext, final List<Object> parameters) {
+ this.database = database;
+ this.sql = sql;
+ this.sqlStatementContext = sqlStatementContext;
+ this.parameters = new ArrayList<>(parameters);
+ }
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmChecker.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmChecker.java
new file mode 100644
index 00000000000..02de8fbc8d0
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmChecker.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker.algorithm;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.util.spi.ShardingSphereServiceLoader;
+import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Cacheable sharding algorithm checker.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class CacheableShardingAlgorithmChecker {
+
+ static {
+ Collection<Class<? extends ShardingAlgorithm>> result = new HashSet<>();
+ ShardingSphereServiceLoader.register(CacheableShardingAlgorithmClassProvider.class);
+ for (CacheableShardingAlgorithmClassProvider each : ShardingSphereServiceLoader.getServiceInstances(CacheableShardingAlgorithmClassProvider.class)) {
+ result.addAll(each.getCacheableShardingAlgorithmClasses());
+ }
+ CACHEABLE_SHARDING_ALGORITHM_CLASSES = result;
+ }
+
+ private static final Collection<Class<? extends ShardingAlgorithm>> CACHEABLE_SHARDING_ALGORITHM_CLASSES;
+
+ /**
+ * Check if sharding algorithm is cacheable.
+ *
+ * @param shardingAlgorithm instance of sharding algorithm
+ * @return is sharding algorithm cacheable
+ */
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public static boolean isCacheableShardingAlgorithm(final ShardingAlgorithm shardingAlgorithm) {
+ return CACHEABLE_SHARDING_ALGORITHM_CLASSES.contains(shardingAlgorithm.getClass());
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmClassProvider.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmClassProvider.java
new file mode 100644
index 00000000000..1e553aeb380
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/CacheableShardingAlgorithmClassProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker.algorithm;
+
+import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
+
+import java.util.Collection;
+
+/**
+ * Cacheable sharding algorithm class provider.
+ */
+public interface CacheableShardingAlgorithmClassProvider {
+
+ /**
+ * Get classes of cacheable sharding algorithm.
+ *
+ * @return classes of cacheable sharding algorithm.
+ */
+ Collection<Class<? extends ShardingAlgorithm>> getCacheableShardingAlgorithmClasses();
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/impl/BuiltInCacheableShardingAlgorithmClassProvider.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/impl/BuiltInCacheableShardingAlgorithmClassProvider.java
new file mode 100644
index 00000000000..0072a5f1b83
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/checker/algorithm/impl/BuiltInCacheableShardingAlgorithmClassProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker.algorithm.impl;
+
+import org.apache.shardingsphere.sharding.algorithm.sharding.mod.HashModShardingAlgorithm;
+import org.apache.shardingsphere.sharding.algorithm.sharding.mod.ModShardingAlgorithm;
+import org.apache.shardingsphere.sharding.algorithm.sharding.range.BoundaryBasedRangeShardingAlgorithm;
+import org.apache.shardingsphere.sharding.algorithm.sharding.range.VolumeBasedRangeShardingAlgorithm;
+import org.apache.shardingsphere.sharding.cache.checker.algorithm.CacheableShardingAlgorithmClassProvider;
+import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Built-in cacheable sharding algorithm class provider.
+ */
+public final class BuiltInCacheableShardingAlgorithmClassProvider implements CacheableShardingAlgorithmClassProvider {
+
+ @Override
+ public Collection<Class<? extends ShardingAlgorithm>> getCacheableShardingAlgorithmClasses() {
+ return Arrays.asList(ModShardingAlgorithm.class, HashModShardingAlgorithm.class, VolumeBasedRangeShardingAlgorithm.class, BoundaryBasedRangeShardingAlgorithm.class);
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouter.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouter.java
new file mode 100644
index 00000000000..25a6e20af74
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouter.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route;
+
+import org.apache.shardingsphere.infra.binder.QueryContext;
+import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.context.ConnectionContext;
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.route.SQLRouter;
+import org.apache.shardingsphere.infra.route.context.RouteContext;
+import org.apache.shardingsphere.sharding.cache.checker.ShardingRouteCacheableCheckResult;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheKey;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheValue;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.constant.ShardingOrder;
+import org.apache.shardingsphere.sharding.route.engine.ShardingSQLRouter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * TODO Design a cache layer interface in kernel.
+ * Cached sharding SQL router.
+ */
+public final class CachedShardingSQLRouter implements SQLRouter<ShardingCacheRule> {
+
+ @Override
+ public RouteContext createRouteContext(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingCacheRule rule, final ConfigurationProperties props,
+ final ConnectionContext connectionContext) {
+ if (queryContext.getSql().length() > rule.getConfiguration().getAllowedMaxSqlLength()) {
+ return new RouteContext();
+ }
+ ShardingRouteCacheableCheckResult cacheableCheckResult = rule.getRouteCacheableChecker().check(database, queryContext);
+ if (!cacheableCheckResult.isProbablyCacheable()) {
+ return new RouteContext();
+ }
+ List<Object> shardingConditionParameters = new ArrayList<>(cacheableCheckResult.getShardingConditionParameterMarkerIndexes().size());
+ for (int each : cacheableCheckResult.getShardingConditionParameterMarkerIndexes()) {
+ if (each >= queryContext.getParameters().size()) {
+ return new RouteContext();
+ }
+ shardingConditionParameters.add(queryContext.getParameters().get(each));
+ }
+ Optional<RouteContext> cachedRouteContext = rule.getRouteCache().get(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParameters))
+ .flatMap(ShardingRouteCacheValue::getCachedRouteContext);
+ RouteContext result = cachedRouteContext.orElseGet(() -> new ShardingSQLRouter().createRouteContext(queryContext, database, rule.getShardingRule(), props, connectionContext));
+ if (!cachedRouteContext.isPresent() && hitOneShardOnly(result)) {
+ rule.getRouteCache().put(new ShardingRouteCacheKey(queryContext.getSql(), shardingConditionParameters), new ShardingRouteCacheValue(result));
+ }
+ return result;
+ }
+
+ private boolean hitOneShardOnly(final RouteContext routeContext) {
+ return 1 == routeContext.getRouteUnits().size() && 1 == routeContext.getRouteUnits().iterator().next().getTableMappers().size()
+ && 1 == routeContext.getOriginalDataNodes().size() && 1 == routeContext.getOriginalDataNodes().iterator().next().size();
+ }
+
+ @Override
+ public void decorateRouteContext(final RouteContext routeContext, final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingCacheRule rule,
+ final ConfigurationProperties props, final ConnectionContext connectionContext) {
+ }
+
+ @Override
+ public int getOrder() {
+ return ShardingOrder.ORDER - 1;
+ }
+
+ @Override
+ public Class<ShardingCacheRule> getTypeClass() {
+ return ShardingCacheRule.class;
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCache.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCache.java
new file mode 100644
index 00000000000..2be40ea2c29
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCache.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route.cache;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+
+import java.util.Optional;
+
+/**
+ * Cache for sharding route.
+ */
+public final class ShardingRouteCache {
+
+ private final Cache<ShardingRouteCacheKey, ShardingRouteCacheValue> cache;
+
+ public ShardingRouteCache(final ShardingCacheOptions cacheOptions) {
+ cache = buildRouteCache(cacheOptions);
+ }
+
+ private Cache<ShardingRouteCacheKey, ShardingRouteCacheValue> buildRouteCache(final ShardingCacheOptions cacheOptions) {
+ Caffeine<Object, Object> result = Caffeine.newBuilder().initialCapacity(cacheOptions.getInitialCapacity()).maximumSize(cacheOptions.getMaximumSize());
+ if (cacheOptions.isSoftValues()) {
+ result.softValues();
+ }
+ return result.build();
+ }
+
+ /**
+ * Cache route result.
+ *
+ * @param key cache key
+ * @param value cache value
+ */
+ public void put(final ShardingRouteCacheKey key, final ShardingRouteCacheValue value) {
+ cache.put(key, value);
+ }
+
+ /**
+ * Get cached route result.
+ *
+ * @param key cache key
+ * @return optional cached route result
+ */
+ public Optional<ShardingRouteCacheValue> get(final ShardingRouteCacheKey key) {
+ return Optional.ofNullable(cache.getIfPresent(key));
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheKey.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheKey.java
new file mode 100644
index 00000000000..d7f0e712586
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheKey.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route.cache;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Key of sharding route cache.
+ */
+@RequiredArgsConstructor
+@Getter
+@EqualsAndHashCode
+public final class ShardingRouteCacheKey {
+
+ private final String sql;
+
+ private final List<Object> shardingConditionParameters;
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheValue.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheValue.java
new file mode 100644
index 00000000000..97686083c9f
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheValue.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route.cache;
+
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.route.context.RouteContext;
+import org.apache.shardingsphere.infra.route.context.RouteStageContext;
+import org.apache.shardingsphere.infra.route.context.RouteUnit;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Value of sharding route cache.
+ */
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ShardingRouteCacheValue {
+
+ private final boolean cacheable;
+
+ private final RouteContext cachedRouteContext;
+
+ public ShardingRouteCacheValue(final RouteContext routeContext) {
+ this(null != routeContext, routeContext);
+ }
+
+ /**
+ * Get cached route context.
+ *
+ * @return optional cached route context
+ */
+ public Optional<RouteContext> getCachedRouteContext() {
+ return cacheable ? Optional.of(deepCopyRouteContext()) : Optional.empty();
+ }
+
+ private RouteContext deepCopyRouteContext() {
+ RouteContext result = new RouteContext();
+ result.getOriginalDataNodes().addAll(deepCopyOriginalDataNodes());
+ result.getRouteUnits().addAll(deepCopyRouteUnits());
+ result.getRouteStageContexts().putAll(deepCopyRouteStageContext());
+ return result;
+ }
+
+ private Collection<Collection<DataNode>> deepCopyOriginalDataNodes() {
+ Collection<Collection<DataNode>> result = new ArrayList<>(cachedRouteContext.getOriginalDataNodes().size());
+ for (Collection<DataNode> eachDataNodes : cachedRouteContext.getOriginalDataNodes()) {
+ Collection<DataNode> eachResult = new ArrayList<>(eachDataNodes.size());
+ // TODO This could be simplified if all fields of DataNode were immutable
+ for (DataNode each : eachDataNodes) {
+ DataNode copiedDataNode = new DataNode(each.getDataSourceName(), each.getTableName());
+ copiedDataNode.setSchemaName(each.getSchemaName());
+ eachResult.add(copiedDataNode);
+ }
+ result.add(eachResult);
+ }
+ return result;
+ }
+
+ private Collection<RouteUnit> deepCopyRouteUnits() {
+ Collection<RouteUnit> result = new ArrayList<>(cachedRouteContext.getRouteUnits().size());
+ for (RouteUnit each : cachedRouteContext.getRouteUnits()) {
+ result.add(new RouteUnit(each.getDataSourceMapper(), new ArrayList<>(each.getTableMappers())));
+ }
+ return result;
+ }
+
+ private Map<Class<? extends ShardingSphereRule>, ? extends RouteStageContext> deepCopyRouteStageContext() {
+ // TODO Implements deep copy for route stage contexts
+ return cachedRouteContext.getRouteStageContexts();
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/ShardingCacheRule.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/ShardingCacheRule.java
new file mode 100644
index 00000000000..d49e978278f
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/ShardingCacheRule.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.rule;
+
+import lombok.Getter;
+import org.apache.shardingsphere.infra.rule.identifier.scope.DatabaseRule;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCache;
+import org.apache.shardingsphere.sharding.cache.checker.ShardingRouteCacheableChecker;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+
+/**
+ * Sharding cache rule.
+ */
+@Getter
+public final class ShardingCacheRule implements DatabaseRule {
+
+ private final ShardingCacheRuleConfiguration configuration;
+
+ private final ShardingRule shardingRule;
+
+ private final ShardingRouteCacheableChecker routeCacheableChecker;
+
+ private final ShardingRouteCache routeCache;
+
+ public ShardingCacheRule(final ShardingCacheRuleConfiguration configuration, final ShardingRule shardingRule) {
+ this.configuration = configuration;
+ this.shardingRule = shardingRule;
+ routeCacheableChecker = new ShardingRouteCacheableChecker(this);
+ routeCache = new ShardingRouteCache(configuration.getRouteCache());
+ }
+
+ @Override
+ public String getType() {
+ return ShardingCacheRule.class.getSimpleName();
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilder.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilder.java
new file mode 100644
index 00000000000..3ecfc9251ab
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilder.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.rule.builder;
+
+import org.apache.shardingsphere.infra.instance.InstanceContext;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.rule.builder.database.DatabaseRuleBuilder;
+import org.apache.shardingsphere.infra.rule.identifier.scope.DatabaseRule;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.constant.ShardingOrder;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+
+import javax.sql.DataSource;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Builder for Sharding cache rule.
+ */
+public final class ShardingCacheRuleBuilder implements DatabaseRuleBuilder<ShardingCacheRuleConfiguration> {
+
+ @Override
+ public DatabaseRule build(final ShardingCacheRuleConfiguration config, final String databaseName, final Map<String, DataSource> dataSources, final Collection<ShardingSphereRule> builtRules,
+ final InstanceContext instanceContext) {
+ ShardingRule shardingRule = (ShardingRule) builtRules.stream().filter(ShardingRule.class::isInstance).findFirst()
+ .orElseThrow(() -> new IllegalStateException("ShardingCacheRule requires ShardingRule"));
+ return new ShardingCacheRule(config, shardingRule);
+ }
+
+ @Override
+ public int getOrder() {
+ return ShardingOrder.ALGORITHM_PROVIDER_ORDER + 1;
+ }
+
+ @Override
+ public Class<ShardingCacheRuleConfiguration> getTypeClass() {
+ return ShardingCacheRuleConfiguration.class;
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheOptionsConfiguration.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheOptionsConfiguration.java
new file mode 100644
index 00000000000..ea3c11385e8
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheOptionsConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.shardingsphere.infra.util.yaml.YamlConfiguration;
+
+/**
+ * Sharding cache options configuration for YAML.
+ */
+@Getter
+@Setter
+public final class YamlShardingCacheOptionsConfiguration implements YamlConfiguration {
+
+ private boolean softValues;
+
+ private int initialCapacity;
+
+ private int maximumSize;
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheRuleConfiguration.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheRuleConfiguration.java
new file mode 100644
index 00000000000..67a4054e32f
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/YamlShardingCacheRuleConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import org.apache.shardingsphere.infra.yaml.config.pojo.rule.YamlRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+
+/**
+ * Sharding cache rule configuration for YAML.
+ */
+@Getter
+@Setter
+public final class YamlShardingCacheRuleConfiguration implements YamlRuleConfiguration {
+
+ private int allowedMaxSqlLength;
+
+ private YamlShardingCacheOptionsConfiguration routeCache;
+
+ @Override
+ public Class<? extends RuleConfiguration> getRuleConfigurationType() {
+ return ShardingCacheRuleConfiguration.class;
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapper.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapper.java
new file mode 100644
index 00000000000..d016deca3ce
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapper.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml.swapper;
+
+import org.apache.shardingsphere.infra.util.yaml.swapper.YamlConfigurationSwapper;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.yaml.YamlShardingCacheOptionsConfiguration;
+
+/**
+ * YAML sharding cache options configuration swapper.
+ */
+public final class YamlShardingCacheOptionsConfigurationSwapper implements YamlConfigurationSwapper<YamlShardingCacheOptionsConfiguration, ShardingCacheOptions> {
+
+ @Override
+ public YamlShardingCacheOptionsConfiguration swapToYamlConfiguration(final ShardingCacheOptions data) {
+ YamlShardingCacheOptionsConfiguration result = new YamlShardingCacheOptionsConfiguration();
+ result.setSoftValues(data.isSoftValues());
+ result.setInitialCapacity(data.getInitialCapacity());
+ result.setMaximumSize(data.getMaximumSize());
+ return result;
+ }
+
+ @Override
+ public ShardingCacheOptions swapToObject(final YamlShardingCacheOptionsConfiguration yamlConfig) {
+ return new ShardingCacheOptions(yamlConfig.isSoftValues(), yamlConfig.getInitialCapacity(), yamlConfig.getMaximumSize());
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapper.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapper.java
new file mode 100644
index 00000000000..b4fcdd0b085
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapper.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml.swapper;
+
+import org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapper;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.yaml.YamlShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.constant.ShardingOrder;
+
+/**
+ * YAML sharding cache rule configuration swapper.
+ */
+public final class YamlShardingCacheRuleConfigurationSwapper implements YamlRuleConfigurationSwapper<YamlShardingCacheRuleConfiguration, ShardingCacheRuleConfiguration> {
+
+ private final YamlShardingCacheOptionsConfigurationSwapper cacheOptionsConfigurationSwapper = new YamlShardingCacheOptionsConfigurationSwapper();
+
+ @Override
+ public YamlShardingCacheRuleConfiguration swapToYamlConfiguration(final ShardingCacheRuleConfiguration data) {
+ YamlShardingCacheRuleConfiguration result = new YamlShardingCacheRuleConfiguration();
+ result.setAllowedMaxSqlLength(data.getAllowedMaxSqlLength());
+ result.setRouteCache(cacheOptionsConfigurationSwapper.swapToYamlConfiguration(data.getRouteCache()));
+ return result;
+ }
+
+ @Override
+ public ShardingCacheRuleConfiguration swapToObject(final YamlShardingCacheRuleConfiguration yamlConfig) {
+ return new ShardingCacheRuleConfiguration(yamlConfig.getAllowedMaxSqlLength(), cacheOptionsConfigurationSwapper.swapToObject(yamlConfig.getRouteCache()));
+ }
+
+ @Override
+ public Class<ShardingCacheRuleConfiguration> getTypeClass() {
+ return ShardingCacheRuleConfiguration.class;
+ }
+
+ @Override
+ public String getRuleTagName() {
+ return "SHARDING_CACHE";
+ }
+
+ @Override
+ public int getOrder() {
+ return ShardingOrder.ALGORITHM_PROVIDER_ORDER + 1;
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.route.SQLRouter b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.route.SQLRouter
new file mode 100644
index 00000000000..567ac2e893b
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.route.SQLRouter
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.apache.shardingsphere.sharding.cache.route.CachedShardingSQLRouter
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.rule.builder.database.DatabaseRuleBuilder b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.rule.builder.database.DatabaseRuleBuilder
new file mode 100644
index 00000000000..e90e2b61a25
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.rule.builder.database.DatabaseRuleBuilder
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.apache.shardingsphere.sharding.cache.rule.builder.ShardingCacheRuleBuilder
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapper b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapper
new file mode 100644
index 00000000000..ec866c01061
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapper
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.apache.shardingsphere.sharding.cache.yaml.swapper.YamlShardingCacheRuleConfigurationSwapper
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.sharding.cache.checker.algorithm.CacheableShardingAlgorithmClassProvider b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.sharding.cache.checker.algorithm.CacheableShardingAlgorithmCl [...]
new file mode 100644
index 00000000000..b733daceea9
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/main/resources/META-INF/services/org.apache.shardingsphere.sharding.cache.checker.algorithm.CacheableShardingAlgorithmClassProvider
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+org.apache.shardingsphere.sharding.cache.checker.algorithm.impl.BuiltInCacheableShardingAlgorithmClassProvider
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
new file mode 100644
index 00000000000..a4a99e12671
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/checker/ShardingRouteCacheableCheckerTest.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.checker;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.infra.binder.QueryContext;
+import org.apache.shardingsphere.infra.binder.SQLStatementContextFactory;
+import org.apache.shardingsphere.infra.binder.statement.SQLStatementContext;
+import org.apache.shardingsphere.infra.config.algorithm.AlgorithmConfiguration;
+import org.apache.shardingsphere.infra.database.type.DatabaseTypeFactory;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstance;
+import org.apache.shardingsphere.infra.instance.InstanceContext;
+import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.metadata.database.resource.ShardingSphereResource;
+import org.apache.shardingsphere.infra.metadata.database.rule.ShardingSphereRuleMetaData;
+import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereColumn;
+import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.metadata.database.schema.decorator.model.ShardingSphereTable;
+import org.apache.shardingsphere.infra.parser.sql.SQLStatementParserEngine;
+import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
+import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
+import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sql.parser.api.CacheOption;
+import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+@RunWith(Parameterized.class)
+@RequiredArgsConstructor
+public final class ShardingRouteCacheableCheckerTest {
+
+ private static final String DATABASE_NAME = "sharding_db";
+
+ private static final String SCHEMA_NAME = "public";
+
+ private final String sql;
+
+ private final List<Object> parameters;
+
+ private final boolean expectedProbablyCacheable;
+
+ private final List<Integer> expectedShardingConditionParameterMarkerIndexes;
+
+ @Parameters(name = "probably cacheable: {2}, SQL: {0}")
+ public static Iterable<Object[]> parameters() {
+ Collection<Object[]> probablyCacheableCases = Arrays.asList(
+ new Object[]{"insert into t_broadcast_table (broadcast_table_id, broadcast_table_col1) values (?, ?)", Arrays.asList(1, "foo"), true, Collections.emptyList()},
+ new Object[]{"insert into t_warehouse (id) values (?)", Collections.singletonList(1), true, Collections.singletonList(0)},
+ new Object[]{"select * from t_warehouse where id = ?", Collections.singletonList(1), true, Collections.singletonList(0)},
+ new Object[]{"select * from t_warehouse where id in (?, ?, ?)", Arrays.asList(1, 2, 3), true, Arrays.asList(0, 1, 2)},
+ new Object[]{"select * from t_warehouse where id between ? and ?", Arrays.asList(1, 10), true, Arrays.asList(0, 1)},
+ new Object[]{"select * from t_warehouse where id between ? and ? limit ? offset ?", Arrays.asList(1, 10, 100, 50), true, Arrays.asList(0, 1)},
+ new Object[]{"update t_broadcast_table set broadcast_table_col1 = ?", Collections.singletonList(0), true, Collections.emptyList()},
+ new Object[]{"update t_broadcast_table set broadcast_table_col1 = ? where broadcast_table_id = ?", Arrays.asList(0, 1), true, Collections.emptyList()},
+ new Object[]{"update t_warehouse set warehouse_name = ? where id = ?", Arrays.asList("foo", 1), true, Collections.singletonList(1)},
+ new Object[]{"delete from t_broadcast_table", Collections.emptyList(), true, Collections.emptyList()},
+ new Object[]{"delete from t_warehouse where id = ?", Collections.singletonList(1), true, Collections.singletonList(0)});
+ Collection<Object[]> nonCacheableCases = Arrays.asList(
+ new Object[]{"create table t_warehouse (id int4 not null primary key)", Collections.emptyList(), false, Collections.emptyList()},
+ new Object[]{"insert into t_warehouse (id) select warehouse_id from t_order", Collections.emptyList(), false, Collections.emptyList()},
+ new Object[]{"insert into t_broadcast_table (broadcast_table_id, broadcast_table_col1) values (?, ?), (?, ?)", Arrays.asList(1, "foo", 2, "bar"), false, Collections.emptyList()},
+ new Object[]{"insert into t_warehouse (id) values (?), (?)", Arrays.asList(1, 2), false, Collections.emptyList()},
+ new Object[]{"insert into t_non_sharding_table (id) values (?)", Collections.singletonList(1), false, Collections.emptyList()},
+ new Object[]{"insert into t_non_cacheable_database_sharding (id) values (?)", Collections.singletonList(1), false, Collections.emptyList()},
+ new Object[]{"insert into t_non_cacheable_table_sharding (id) values (?)", Collections.singletonList(1), false, Collections.emptyList()},
+ new Object[]{"insert into t_warehouse (id) values (now())", Collections.emptyList(), false, Collections.emptyList()},
+ new Object[]{"select * from t_broadcast_table where broadcast_table_id = ?", Collections.singletonList(1), false, Collections.emptyList()},
+ new Object[]{"select * from t_warehouse w join t_order o on w.id = o.warehouse_id where w.id = ?", Collections.singletonList(1), false, Collections.emptyList()},
+ new Object[]{"update t_warehouse set warehouse_name = ? where id = (select max(warehouse_id) from t_order)", Collections.singletonList("foo"), false, Collections.emptyList()},
+ new Object[]{"delete from t_order where warehouse_id in (1, 2, now())", Collections.emptyList(), false, Collections.emptyList()},
+ new Object[]{"delete from t_order where warehouse_id between now() and now()", Collections.emptyList(), false, Collections.emptyList()},
+ new Object[]{"delete from t_order o where o.warehouse_id in (select w.id from t_warehouse w)", Collections.emptyList(), false, Collections.emptyList()});
+ return Stream.of(probablyCacheableCases.stream(), nonCacheableCases.stream()).flatMap(Function.identity()).collect(Collectors.toList());
+ }
+
+ @Test
+ public void assertCheckCacheable() {
+ ShardingRule shardingRule = prepareShardingRule();
+ ShardingCacheRule shardingCacheRule = prepareShardingCacheRule(shardingRule);
+ ShardingSphereDatabase database = prepareDatabase(shardingRule, shardingCacheRule);
+ ShardingRouteCacheableCheckResult actual = new ShardingRouteCacheableChecker(shardingCacheRule).check(database, prepareQueryContext(database, sql, parameters));
+ assertThat(actual.isProbablyCacheable(), is(expectedProbablyCacheable));
+ assertThat(actual.getShardingConditionParameterMarkerIndexes(), is(expectedShardingConditionParameterMarkerIndexes));
+ }
+
+ private ShardingRule prepareShardingRule() {
+ ShardingRuleConfiguration configuration = new ShardingRuleConfiguration();
+ configuration.getBroadcastTables().add("t_broadcast_table");
+ configuration.getBindingTableGroups().add("t_order,t_order_item");
+ Properties modShardingAlgorithmProps = new Properties();
+ modShardingAlgorithmProps.setProperty("sharding-count", "2");
+ configuration.getShardingAlgorithms().put("mod", new AlgorithmConfiguration("MOD", modShardingAlgorithmProps));
+ Properties inlineShardingAlgorithmProps = new Properties();
+ inlineShardingAlgorithmProps.setProperty("algorithm-expression", "ds_${id % 2}");
+ configuration.getShardingAlgorithms().put("inline", new AlgorithmConfiguration("INLINE", inlineShardingAlgorithmProps));
+ configuration.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("warehouse_id", "mod"));
+ ShardingTableRuleConfiguration warehouse = new ShardingTableRuleConfiguration("t_warehouse", "ds_${0..1}.t_warehouse");
+ warehouse.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("id", "mod"));
+ configuration.getTables().add(warehouse);
+ configuration.getTables().add(new ShardingTableRuleConfiguration("t_order", "ds_${0..1}.t_order"));
+ configuration.getTables().add(new ShardingTableRuleConfiguration("t_order_item", "ds_${0..1}.t_order_item"));
+ ShardingTableRuleConfiguration nonCacheableDatabaseSharding = new ShardingTableRuleConfiguration("t_non_cacheable_database_sharding", "ds_${0..1}.t_non_cacheable_database_sharding");
+ nonCacheableDatabaseSharding.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("id", "inline"));
+ configuration.getTables().add(nonCacheableDatabaseSharding);
+ ShardingTableRuleConfiguration nonCacheableTableSharding = new ShardingTableRuleConfiguration("t_non_cacheable_table_sharding", "ds_0.t_non_cacheable_table_sharding_${0..1}");
+ nonCacheableTableSharding.setTableShardingStrategy(new StandardShardingStrategyConfiguration("id", "inline"));
+ configuration.getTables().add(nonCacheableTableSharding);
+ return new ShardingRule(configuration, Arrays.asList("ds_0", "ds_1"), new InstanceContext(mock(ComputeNodeInstance.class), props -> 0, null, null, null, null));
+ }
+
+ private ShardingCacheRule prepareShardingCacheRule(final ShardingRule shardingRule) {
+ return new ShardingCacheRule(new ShardingCacheRuleConfiguration(100, new ShardingCacheOptions(true, 0, 0)), shardingRule);
+ }
+
+ private ShardingSphereDatabase prepareDatabase(final ShardingRule shardingRule, final ShardingCacheRule shardingCacheRule) {
+ ShardingSphereSchema schema = new ShardingSphereSchema();
+ schema.getTables().put("t_broadcast_table", new ShardingSphereTable("t_broadcast_table", Arrays.asList(
+ new ShardingSphereColumn("broadcast_table_id", Types.INTEGER, true, false, false, true),
+ new ShardingSphereColumn("broadcast_table_col1", Types.VARCHAR, false, false, false, true)),
+ Collections.emptyList(), Collections.emptyList()));
+ schema.getTables().put("t_warehouse", new ShardingSphereTable("t_warehouse",
+ Collections.singletonList(new ShardingSphereColumn("id", Types.INTEGER, true, false, false, true)),
+ Collections.emptyList(), Collections.emptyList()));
+ schema.getTables().put("t_order", new ShardingSphereTable("t_order", Arrays.asList(
+ new ShardingSphereColumn("warehouse_id", Types.INTEGER, false, false, false, true),
+ new ShardingSphereColumn("order_id", Types.INTEGER, true, false, false, true)),
+ Collections.emptyList(), Collections.emptyList()));
+ schema.getTables().put("t_order_item", new ShardingSphereTable("t_order_item", Arrays.asList(
+ new ShardingSphereColumn("warehouse_id", Types.INTEGER, false, false, false, true),
+ new ShardingSphereColumn("order_broadcast_table_id", Types.INTEGER, true, false, false, true)),
+ Collections.emptyList(), Collections.emptyList()));
+ return new ShardingSphereDatabase(DATABASE_NAME, DatabaseTypeFactory.getInstance("PostgreSQL"), new ShardingSphereResource(DATABASE_NAME, Collections.emptyMap()),
+ new ShardingSphereRuleMetaData(Arrays.asList(shardingRule, shardingCacheRule)), Collections.singletonMap(SCHEMA_NAME, schema));
+ }
+
+ private QueryContext prepareQueryContext(final ShardingSphereDatabase database, final String sql, final List<Object> parameters) {
+ SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(Collections.singletonMap(DATABASE_NAME, database), parameters, parse(sql), DATABASE_NAME);
+ return new QueryContext(sqlStatementContext, sql, parameters);
+ }
+
+ private SQLStatement parse(final String sql) {
+ CacheOption cacheOption = new CacheOption(0, 0);
+ return new SQLStatementParserEngine("PostgreSQL", cacheOption, cacheOption, false).parse(sql, false);
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouterTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouterTest.java
new file mode 100644
index 00000000000..39ca51e78d9
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/CachedShardingSQLRouterTest.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route;
+
+import org.apache.shardingsphere.infra.binder.QueryContext;
+import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.route.context.RouteContext;
+import org.apache.shardingsphere.infra.route.context.RouteMapper;
+import org.apache.shardingsphere.infra.route.context.RouteUnit;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.checker.ShardingRouteCacheableCheckResult;
+import org.apache.shardingsphere.sharding.cache.checker.ShardingRouteCacheableChecker;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCache;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheKey;
+import org.apache.shardingsphere.sharding.cache.route.cache.ShardingRouteCacheValue;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.route.engine.ShardingSQLRouter;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public final class CachedShardingSQLRouterTest {
+
+ @Mock
+ private ShardingCacheRule shardingCacheRule;
+
+ @Test
+ public void assertCreateRouteContextWithSQLExceedMaxAllowedLength() {
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(1, null));
+ QueryContext queryContext = new QueryContext(null, "select 1", Collections.emptyList());
+ RouteContext actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ assertRouteContextIsEmpty(actual);
+ }
+
+ @Test
+ public void assertCreateRouteContextWithNotCacheableQuery() {
+ QueryContext queryContext = new QueryContext(null, "insert into t values (?), (?)", Collections.emptyList());
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(100, null));
+ when(shardingCacheRule.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
+ when(shardingCacheRule.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(false, Collections.emptyList()));
+ RouteContext actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ assertRouteContextIsEmpty(actual);
+ }
+
+ @Test
+ public void assertCreateRouteContextWithUnmatchedActualParameterSize() {
+ QueryContext queryContext = new QueryContext(null, "insert into t values (?, ?)", Collections.singletonList(0));
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(100, null));
+ when(shardingCacheRule.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
+ when(shardingCacheRule.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(true, Collections.singletonList(1)));
+ RouteContext actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ assertRouteContextIsEmpty(actual);
+ }
+
+ private static void assertRouteContextIsEmpty(final RouteContext actual) {
+ assertTrue(actual.getRouteUnits().isEmpty());
+ assertTrue(actual.getOriginalDataNodes().isEmpty());
+ assertTrue(actual.getRouteStageContexts().isEmpty());
+ }
+
+ @Test
+ public void assertCreateRouteContextWithCacheableQueryButCacheMissed() {
+ QueryContext queryContext = new QueryContext(null, "insert into t values (?, ?)", Arrays.asList(0, 1));
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(100, null));
+ when(shardingCacheRule.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
+ when(shardingCacheRule.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(true, Collections.singletonList(1)));
+ when(shardingCacheRule.getRouteCache()).thenReturn(mock(ShardingRouteCache.class));
+ RouteContext expected = new RouteContext();
+ expected.getRouteUnits().add(new RouteUnit(new RouteMapper("ds_0", "ds_0"), Collections.singletonList(new RouteMapper("t", "t"))));
+ expected.getOriginalDataNodes().add(Collections.singletonList(new DataNode("ds_0", "t")));
+ when(shardingCacheRule.getRouteCache().get(any(ShardingRouteCacheKey.class))).thenReturn(Optional.empty());
+ RouteContext actual;
+ try (
+ MockedConstruction<ShardingSQLRouter> ignored = mockConstruction(ShardingSQLRouter.class,
+ (mock, context) -> when(mock.createRouteContext(queryContext, null, shardingCacheRule.getShardingRule(), null, null)).thenReturn(expected))) {
+ actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ }
+ assertThat(actual, is(expected));
+ verify(shardingCacheRule.getRouteCache()).put(any(ShardingRouteCacheKey.class), any(ShardingRouteCacheValue.class));
+ }
+
+ @Test
+ public void assertCreateRouteContextWithCacheHit() {
+ QueryContext queryContext = new QueryContext(null, "insert into t values (?, ?)", Arrays.asList(0, 1));
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(100, null));
+ when(shardingCacheRule.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
+ when(shardingCacheRule.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(true, Collections.singletonList(1)));
+ when(shardingCacheRule.getRouteCache()).thenReturn(mock(ShardingRouteCache.class));
+ RouteContext expected = new RouteContext();
+ expected.getRouteUnits().add(new RouteUnit(new RouteMapper("ds_0", "ds_0"), Collections.singletonList(new RouteMapper("t", "t"))));
+ expected.getOriginalDataNodes().add(Collections.singletonList(new DataNode("ds_0", "t")));
+ when(shardingCacheRule.getRouteCache().get(any(ShardingRouteCacheKey.class))).thenReturn(Optional.of(new ShardingRouteCacheValue(expected)));
+ RouteContext actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ assertThat(actual, not(expected));
+ assertThat(actual.getOriginalDataNodes(), is(expected.getOriginalDataNodes()));
+ assertThat(actual.getRouteUnits(), is(expected.getRouteUnits()));
+ }
+
+ @Test
+ public void assertCreateRouteContextWithQueryRoutedToMultiDataNodes() {
+ QueryContext queryContext = new QueryContext(null, "select * from t", Collections.emptyList());
+ when(shardingCacheRule.getConfiguration()).thenReturn(new ShardingCacheRuleConfiguration(100, null));
+ when(shardingCacheRule.getRouteCacheableChecker()).thenReturn(mock(ShardingRouteCacheableChecker.class));
+ when(shardingCacheRule.getRouteCacheableChecker().check(null, queryContext)).thenReturn(new ShardingRouteCacheableCheckResult(true, Collections.emptyList()));
+ when(shardingCacheRule.getRouteCache()).thenReturn(mock(ShardingRouteCache.class));
+ RouteContext expected = new RouteContext();
+ expected.getRouteUnits().add(new RouteUnit(new RouteMapper("ds_0", "ds_0"), Arrays.asList(new RouteMapper("t", "t_0"), new RouteMapper("t", "t_1"))));
+ expected.getOriginalDataNodes().add(Collections.singletonList(new DataNode("ds_0", "t_0")));
+ RouteContext actual;
+ try (
+ MockedConstruction<ShardingSQLRouter> ignored = mockConstruction(ShardingSQLRouter.class,
+ (mock, context) -> when(mock.createRouteContext(queryContext, null, shardingCacheRule.getShardingRule(), null, null)).thenReturn(expected))) {
+ actual = new CachedShardingSQLRouter().createRouteContext(queryContext, null, shardingCacheRule, null, null);
+ }
+ assertThat(actual, is(expected));
+ verify(shardingCacheRule.getRouteCache(), never()).put(any(ShardingRouteCacheKey.class), any(ShardingRouteCacheValue.class));
+ }
+
+ @Test
+ public void assertDecorateRouteContext() {
+ RouteContext routeContext = mock(RouteContext.class);
+ new CachedShardingSQLRouter().decorateRouteContext(routeContext, null, null, null, null, null);
+ verifyNoInteractions(routeContext);
+ }
+
+ @Test
+ public void assertGetOrder() {
+ assertThat(new CachedShardingSQLRouter().getOrder(), is(-11));
+ }
+
+ @Test
+ public void assertGetTypeClass() {
+ assertThat(new CachedShardingSQLRouter().getTypeClass(), CoreMatchers.<Class<ShardingCacheRule>>is(ShardingCacheRule.class));
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheTest.java
new file mode 100644
index 00000000000..1f82eef5b05
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/route/cache/ShardingRouteCacheTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.route.cache;
+
+import org.apache.shardingsphere.infra.route.context.RouteContext;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public final class ShardingRouteCacheTest {
+
+ @Test
+ public void assertPutAndGet() {
+ ShardingRouteCache cache = new ShardingRouteCache(new ShardingCacheOptions(true, 1, 1));
+ ShardingRouteCacheKey key = new ShardingRouteCacheKey("select name from t where id = ?", Collections.singletonList(1));
+ assertFalse(cache.get(key).isPresent());
+ cache.put(key, new ShardingRouteCacheValue(new RouteContext()));
+ assertTrue(cache.get(key).isPresent());
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilderTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilderTest.java
new file mode 100644
index 00000000000..409ab0aa628
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/rule/builder/ShardingCacheRuleBuilderTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.rule.builder;
+
+import org.apache.shardingsphere.infra.rule.identifier.scope.DatabaseRule;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.rule.ShardingCacheRule;
+import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+
+public final class ShardingCacheRuleBuilderTest {
+
+ @Test
+ public void assertBuildShardingCacheRule() {
+ ShardingRule expectedShardingRule = mock(ShardingRule.class);
+ ShardingCacheRuleConfiguration expectedConfiguration = new ShardingCacheRuleConfiguration(100, new ShardingCacheOptions(true, 1, 1));
+ DatabaseRule actual = new ShardingCacheRuleBuilder().build(expectedConfiguration, "", Collections.emptyMap(), Collections.singletonList(expectedShardingRule), null);
+ assertThat(actual, instanceOf(ShardingCacheRule.class));
+ ShardingCacheRule actualShardingCacheRule = (ShardingCacheRule) actual;
+ assertThat(actualShardingCacheRule.getConfiguration(), is(expectedConfiguration));
+ assertThat(actualShardingCacheRule.getShardingRule(), is(expectedShardingRule));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void assertBuildShardingCacheRuleWithoutShardingRule() {
+ new ShardingCacheRuleBuilder().build(null, "", Collections.emptyMap(), Collections.emptyList(), null);
+ }
+
+ @Test
+ public void assertGetOrder() {
+ assertThat(new ShardingCacheRuleBuilder().getOrder(), is(-8));
+ }
+
+ @Test
+ public void assertGetTypeClass() {
+ assertThat(new ShardingCacheRuleBuilder().getTypeClass(), CoreMatchers.<Class<ShardingCacheRuleConfiguration>>is(ShardingCacheRuleConfiguration.class));
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapperTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapperTest.java
new file mode 100644
index 00000000000..36e49246143
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheOptionsConfigurationSwapperTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml.swapper;
+
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.yaml.YamlShardingCacheOptionsConfiguration;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public final class YamlShardingCacheOptionsConfigurationSwapperTest {
+
+ @Test
+ public void assertSwapToYamlConfiguration() {
+ YamlShardingCacheOptionsConfiguration actual = new YamlShardingCacheOptionsConfigurationSwapper().swapToYamlConfiguration(new ShardingCacheOptions(true, 128, 1024));
+ assertTrue(actual.isSoftValues());
+ assertThat(actual.getInitialCapacity(), is(128));
+ assertThat(actual.getMaximumSize(), is(1024));
+ }
+
+ @Test
+ public void assertSwapToObject() {
+ YamlShardingCacheOptionsConfiguration input = new YamlShardingCacheOptionsConfiguration();
+ input.setSoftValues(true);
+ input.setInitialCapacity(256);
+ input.setMaximumSize(4096);
+ ShardingCacheOptions actual = new YamlShardingCacheOptionsConfigurationSwapper().swapToObject(input);
+ assertTrue(actual.isSoftValues());
+ assertThat(actual.getInitialCapacity(), is(256));
+ assertThat(actual.getMaximumSize(), is(4096));
+ }
+}
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapperTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapperTest.java
new file mode 100644
index 00000000000..7b3a9d5f16f
--- /dev/null
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-plugin/shardingsphere-sharding-cache/src/test/java/org/apache/shardingsphere/sharding/cache/yaml/swapper/YamlShardingCacheRuleConfigurationSwapperTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.sharding.cache.yaml.swapper;
+
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheOptions;
+import org.apache.shardingsphere.sharding.cache.api.ShardingCacheRuleConfiguration;
+import org.apache.shardingsphere.sharding.cache.yaml.YamlShardingCacheOptionsConfiguration;
+import org.apache.shardingsphere.sharding.cache.yaml.YamlShardingCacheRuleConfiguration;
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public final class YamlShardingCacheRuleConfigurationSwapperTest {
+
+ @Test
+ public void assertSwapToYamlConfiguration() {
+ YamlShardingCacheRuleConfiguration actual = new YamlShardingCacheRuleConfigurationSwapper()
+ .swapToYamlConfiguration(new ShardingCacheRuleConfiguration(100, new ShardingCacheOptions(true, 128, 1024)));
+ assertThat(actual.getAllowedMaxSqlLength(), is(100));
+ YamlShardingCacheOptionsConfiguration actualRouteCache = actual.getRouteCache();
+ assertTrue(actualRouteCache.isSoftValues());
+ assertThat(actualRouteCache.getInitialCapacity(), is(128));
+ assertThat(actualRouteCache.getMaximumSize(), is(1024));
+ }
+
+ @Test
+ public void assertSwapToObject() {
+ YamlShardingCacheRuleConfiguration input = new YamlShardingCacheRuleConfiguration();
+ input.setAllowedMaxSqlLength(200);
+ YamlShardingCacheOptionsConfiguration configuration = new YamlShardingCacheOptionsConfiguration();
+ configuration.setSoftValues(true);
+ configuration.setInitialCapacity(256);
+ configuration.setMaximumSize(4096);
+ input.setRouteCache(configuration);
+ ShardingCacheRuleConfiguration actual = new YamlShardingCacheRuleConfigurationSwapper().swapToObject(input);
+ assertThat(actual.getAllowedMaxSqlLength(), is(200));
+ ShardingCacheOptions actualOptions = actual.getRouteCache();
+ assertTrue(actualOptions.isSoftValues());
+ assertThat(actualOptions.getInitialCapacity(), is(256));
+ assertThat(actualOptions.getMaximumSize(), is(4096));
+ }
+
+ @Test
+ public void assertGetTypeClass() {
+ assertThat(new YamlShardingCacheRuleConfigurationSwapper().getTypeClass(), CoreMatchers.<Class<ShardingCacheRuleConfiguration>>is(ShardingCacheRuleConfiguration.class));
+ }
+
+ @Test
+ public void assertGetRuleTagName() {
+ assertThat(new YamlShardingCacheRuleConfigurationSwapper().getRuleTagName(), is("SHARDING_CACHE"));
+ }
+
+ @Test
+ public void assertGetOrder() {
+ assertThat(new YamlShardingCacheRuleConfigurationSwapper().getOrder(), is(-8));
+ }
+}
diff --git a/shardingsphere-jdbc/shardingsphere-jdbc-core/pom.xml b/shardingsphere-jdbc/shardingsphere-jdbc-core/pom.xml
index 0eb282a40f6..1d225580175 100644
--- a/shardingsphere-jdbc/shardingsphere-jdbc-core/pom.xml
+++ b/shardingsphere-jdbc/shardingsphere-jdbc-core/pom.xml
@@ -115,6 +115,11 @@
<artifactId>shardingsphere-sharding-core</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.shardingsphere</groupId>
+ <artifactId>shardingsphere-sharding-cache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-readwrite-splitting-core</artifactId>
diff --git a/shardingsphere-proxy/shardingsphere-proxy-bootstrap/pom.xml b/shardingsphere-proxy/shardingsphere-proxy-bootstrap/pom.xml
index a746d406e71..ef5f2775c8e 100644
--- a/shardingsphere-proxy/shardingsphere-proxy-bootstrap/pom.xml
+++ b/shardingsphere-proxy/shardingsphere-proxy-bootstrap/pom.xml
@@ -98,6 +98,11 @@
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.shardingsphere</groupId>
+ <artifactId>shardingsphere-sharding-cache</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>