This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new ea2a21dc751 [fix](cache) fix same sql return wrong result when switch database with `use db` and enable sql cache (#44782) ea2a21dc751 is described below commit ea2a21dc7519142ffcb4af893c88e1dfd4215556 Author: htyoung <hty551...@hotmail.com> AuthorDate: Sat Nov 30 22:48:56 2024 +0800 [fix](cache) fix same sql return wrong result when switch database with `use db` and enable sql cache (#44782) ### What problem does this PR solve? It will return wrong result when running same sql in different db with `enable_sql_cache=true` for example, the `db1` and `db2` has the same table `tbl` but the data are not equals, if execute the below sql in `db1` and cache the result, then execute it in `db2`, it will return the wrong result ```sql select count(*) from tbl ``` Co-authored-by: tongyang.han <tongyang....@jiduauto.com> --- .../doris/common/NereidsSqlCacheManager.java | 49 ++++++++------ .../cache/parse_sql_from_sql_cache.groovy | 74 ++++++++++++++++++++++ 2 files changed, 105 insertions(+), 18 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java b/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java index 1317fdaefc7..cd32b52034a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java @@ -74,9 +74,11 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -/** NereidsSqlCacheManager */ +/** + * NereidsSqlCacheManager + */ public class NereidsSqlCacheManager { - // key: <user>:<sql> + // key: <ctl.db>:<user>:<sql> // value: SqlCacheContext private volatile Cache<String, SqlCacheContext> sqlCaches; @@ -110,7 +112,7 @@ public class NereidsSqlCacheManager { // auto evict cache when jvm memory too low .softValues(); if (sqlCacheNum > 0) { - cacheBuilder = cacheBuilder.maximumSize(sqlCacheNum); + cacheBuilder.maximumSize(sqlCacheNum); } if (expireAfterAccessSeconds > 0) { cacheBuilder = cacheBuilder.expireAfterAccess(Duration.ofSeconds(expireAfterAccessSeconds)); @@ -119,7 +121,9 @@ public class NereidsSqlCacheManager { return cacheBuilder.build(); } - /** tryAddFeCache */ + /** + * tryAddFeCache + */ public void tryAddFeSqlCache(ConnectContext connectContext, String sql) { Optional<SqlCacheContext> sqlCacheContextOpt = connectContext.getStatementContext().getSqlCacheContext(); if (!sqlCacheContextOpt.isPresent()) { @@ -127,17 +131,18 @@ public class NereidsSqlCacheManager { } SqlCacheContext sqlCacheContext = sqlCacheContextOpt.get(); - UserIdentity currentUserIdentity = connectContext.getCurrentUserIdentity(); String key = sqlCacheContext.getCacheKeyType() == CacheKeyType.SQL - ? currentUserIdentity.toString() + ":" + normalizeSql(sql.trim()) - : currentUserIdentity.toString() + ":" + DebugUtil.printId(sqlCacheContext.getOrComputeCacheKeyMd5()); + ? generateCacheKey(connectContext, normalizeSql(sql)) + : generateCacheKey(connectContext, DebugUtil.printId(sqlCacheContext.getOrComputeCacheKeyMd5())); if (sqlCaches.getIfPresent(key) == null && sqlCacheContext.getOrComputeCacheKeyMd5() != null && sqlCacheContext.getResultSetInFe().isPresent()) { sqlCaches.put(key, sqlCacheContext); } } - /** tryAddBeCache */ + /** + * tryAddBeCache + */ public void tryAddBeCache(ConnectContext connectContext, String sql, CacheAnalyzer analyzer) { Optional<SqlCacheContext> sqlCacheContextOpt = connectContext.getStatementContext().getSqlCacheContext(); if (!sqlCacheContextOpt.isPresent()) { @@ -147,10 +152,9 @@ public class NereidsSqlCacheManager { return; } SqlCacheContext sqlCacheContext = sqlCacheContextOpt.get(); - UserIdentity currentUserIdentity = connectContext.getCurrentUserIdentity(); String key = sqlCacheContext.getCacheKeyType() == CacheKeyType.SQL - ? currentUserIdentity.toString() + ":" + normalizeSql(sql.trim()) - : currentUserIdentity.toString() + ":" + DebugUtil.printId(sqlCacheContext.getOrComputeCacheKeyMd5()); + ? generateCacheKey(connectContext, normalizeSql(sql)) + : generateCacheKey(connectContext, DebugUtil.printId(sqlCacheContext.getOrComputeCacheKeyMd5())); if (sqlCaches.getIfPresent(key) == null && sqlCacheContext.getOrComputeCacheKeyMd5() != null) { SqlCache cache = (SqlCache) analyzer.getCache(); sqlCacheContext.setSumOfPartitionNum(cache.getSumOfPartitionNum()); @@ -167,23 +171,23 @@ public class NereidsSqlCacheManager { } } - /** tryParseSql */ + /** + * tryParseSql + */ public Optional<LogicalSqlCache> tryParseSql(ConnectContext connectContext, String sql) { - UserIdentity currentUserIdentity = connectContext.getCurrentUserIdentity(); - String key = currentUserIdentity + ":" + normalizeSql(sql.trim()); + String key = generateCacheKey(connectContext, normalizeSql(sql.trim())); SqlCacheContext sqlCacheContext = sqlCaches.getIfPresent(key); if (sqlCacheContext == null) { return Optional.empty(); } // LOG.info("Total size: " + GraphLayout.parseInstance(sqlCacheContext).totalSize()); - + UserIdentity currentUserIdentity = connectContext.getCurrentUserIdentity(); List<Variable> currentVariables = resolveUserVariables(sqlCacheContext); if (usedVariablesChanged(currentVariables, sqlCacheContext)) { String md5 = DebugUtil.printId( sqlCacheContext.doComputeCacheKeyMd5(Utils.fastToImmutableSet(currentVariables))); - - String md5CacheKey = currentUserIdentity + ":" + md5; + String md5CacheKey = generateCacheKey(connectContext, md5); SqlCacheContext sqlCacheContextWithVariable = sqlCaches.getIfPresent(md5CacheKey); // already exist cache in the fe, but the variable is different to this query, @@ -203,6 +207,15 @@ public class NereidsSqlCacheManager { } } + private String generateCacheKey(ConnectContext connectContext, String sqlOrMd5) { + CatalogIf<?> currentCatalog = connectContext.getCurrentCatalog(); + String currentCatalogName = currentCatalog != null ? currentCatalog.getName() : ""; + String currentDatabase = connectContext.getDatabase(); + String currentDatabaseName = currentDatabase != null ? currentDatabase : ""; + return currentCatalogName + "." + currentDatabaseName + ":" + connectContext.getCurrentUserIdentity().toString() + + ":" + sqlOrMd5; + } + private String normalizeSql(String sql) { return NereidsParser.removeCommentAndTrimBlank(sql); } @@ -402,7 +415,7 @@ public class NereidsSqlCacheManager { Variable cachedVariable = cachedUsedVariables.get(i); if (!Objects.equals(currentVariable, cachedVariable) || cachedVariable.getRealExpression().anyMatch( - expr -> !((ExpressionTrait) expr).isDeterministic())) { + expr -> !((ExpressionTrait) expr).isDeterministic())) { return true; } } diff --git a/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy b/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy index 54ab7028888..3635936e8be 100644 --- a/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy +++ b/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy @@ -827,6 +827,80 @@ suite("parse_sql_from_sql_cache") { def result = sql "select FROM_UNIXTIME(UNIX_TIMESTAMP(), 'yyyy-MM-dd HH:mm:ss')" assertNotEquals("yyyy-MM-dd HH:mm:ss", result[0][0]) } + }), + extraThread("test_same_sql_with_different_db", { + def dbName1 = "test_db1" + def dbName2 = "test_db2" + def tableName = "test_cache_table" + + sql "CREATE DATABASE IF NOT EXISTS ${dbName1}" + sql "DROP TABLE IF EXISTS ${dbName1}.${tableName}" + sql """ + CREATE TABLE IF NOT EXISTS ${dbName1}.${tableName} ( + `k1` date NOT NULL COMMENT "", + `k2` int(11) NOT NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`, `k2`) + COMMENT "OLAP" + PARTITION BY RANGE(`k1`) + (PARTITION p202411 VALUES [('2024-11-01'), ('2024-12-01'))) + DISTRIBUTED BY HASH(`k1`, `k2`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "in_memory" = "false", + "storage_format" = "V2" + ) + """ + sql "CREATE DATABASE IF NOT EXISTS ${dbName2}" + sql "DROP TABLE IF EXISTS ${dbName2}.${tableName}" + sql """ + CREATE TABLE IF NOT EXISTS ${dbName2}.${tableName} ( + `k1` date NOT NULL COMMENT "", + `k2` int(11) NOT NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`, `k2`) + COMMENT "OLAP" + PARTITION BY RANGE(`k1`) + (PARTITION p202411 VALUES [('2024-11-01'), ('2024-12-01'))) + DISTRIBUTED BY HASH(`k1`, `k2`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "in_memory" = "false", + "storage_format" = "V2" + ) + """ + + sql """ + INSERT INTO ${dbName1}.${tableName} VALUES + ("2024-11-29",0), + ("2024-11-30",0) + """ + // after partition changed 10s, the sql cache can be used + sleep(10000) + sql """ + INSERT INTO ${dbName2}.${tableName} VALUES + ("2024-11-29",0) + """ + // after partition changed 10s, the sql cache can be used + sleep(10000) + + sql "set enable_sql_cache=true" + sql "use ${dbName1}" + List<List<Object>> result1 = sql """ + SELECT COUNT(*) FROM ${tableName} + """ + assertEquals(result1[0][0],2) + + sql "use ${dbName2}" + List<List<Object>> result2 = sql """ + SELECT COUNT(*) FROM ${tableName} + """ + assertEquals(result2[0][0],1) + + sql "DROP TABLE IF EXISTS ${dbName1}.${tableName}" + sql "DROP TABLE IF EXISTS ${dbName2}.${tableName}" + sql "DROP DATABASE IF EXISTS ${dbName1}" + sql "DROP DATABASE IF EXISTS ${dbName2}" }) ).get() } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org