This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 0133b003bb1 branch-4.0:[fix](regression) Adjust large TTL cache 
regression case(pick#64789) (#66127)
0133b003bb1 is described below

commit 0133b003bb1a32004426854f0ad0123a214b92a6
Author: zhengyu <[email protected]>
AuthorDate: Tue Jul 28 23:08:17 2026 +0800

    branch-4.0:[fix](regression) Adjust large TTL cache regression 
case(pick#64789) (#66127)
    
    ### What problem does this PR solve?
    
    Issue Number: N/A
    
    Related PR: #64789
---
 .../cloud/alter/CloudSchemaChangeHandler.java      |  9 ++++-
 .../apache/doris/common/util/PropertyAnalyzer.java | 32 +++++++++++------
 .../commands/info/ModifyTablePropertiesOp.java     |  2 ++
 .../apache/doris/common/PropertyAnalyzerTest.java  | 38 ++++++++++++++++++++
 .../cloud_p0/cache/ttl/alter_ttl_max_int64.groovy  | 41 ++++++++++++++++++++--
 5 files changed, 108 insertions(+), 14 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/alter/CloudSchemaChangeHandler.java
 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/alter/CloudSchemaChangeHandler.java
index 1b4c1899845..30bceb03db4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/cloud/alter/CloudSchemaChangeHandler.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/cloud/alter/CloudSchemaChangeHandler.java
@@ -30,6 +30,7 @@ import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.Tablet;
 import org.apache.doris.cloud.proto.Cloud;
 import org.apache.doris.cloud.rpc.MetaServiceProxy;
+import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.MetaNotFoundException;
@@ -65,7 +66,13 @@ public class CloudSchemaChangeHandler extends 
SchemaChangeHandler {
 
         UpdatePartitionMetaParam param = new UpdatePartitionMetaParam();
         if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS)) {
-            long ttlSeconds = 
Long.parseLong(properties.get(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS));
+            long ttlSeconds;
+            try {
+                ttlSeconds = PropertyAnalyzer.analyzeFileCacheTtlSeconds(
+                        
properties.get(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS));
+            } catch (AnalysisException e) {
+                throw new DdlException(e.getMessage());
+            }
             olapTable.readLock();
             try {
                 if (ttlSeconds == olapTable.getTTLSeconds()) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java
index 962dd6751c3..d4db907582d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java
@@ -126,6 +126,7 @@ public class PropertyAnalyzer {
     public static final String PROPERTIES_INMEMORY = "in_memory";
 
     public static final String PROPERTIES_FILE_CACHE_TTL_SECONDS = 
"file_cache_ttl_seconds";
+    public static final long MAX_FILE_CACHE_TTL_SECONDS = Long.MAX_VALUE / 2L;
 
     // _auto_bucket can only set in create table stmt rewrite bucket and can 
not be changed
     public static final String PROPERTIES_AUTO_BUCKET = "_auto_bucket";
@@ -606,20 +607,31 @@ public class PropertyAnalyzer {
     public static long analyzeTTL(Map<String, String> properties) throws 
AnalysisException {
         long ttlSeconds = 0;
         if (properties != null && 
properties.containsKey(PROPERTIES_FILE_CACHE_TTL_SECONDS)) {
-            String ttlSecondsStr = 
properties.get(PROPERTIES_FILE_CACHE_TTL_SECONDS);
-            try {
-                ttlSeconds = Long.parseLong(ttlSecondsStr);
-                if (ttlSeconds < 0) {
-                    throw new NumberFormatException();
-                }
-            } catch (NumberFormatException e) {
-                throw new AnalysisException("The value " + ttlSecondsStr + " 
formats error or  is out of range "
-                           + "(0 < integer < Long.MAX_VALUE)");
-            }
+            ttlSeconds = 
analyzeFileCacheTtlSeconds(properties.get(PROPERTIES_FILE_CACHE_TTL_SECONDS));
         }
         return ttlSeconds;
     }
 
+    public static long analyzeFileCacheTtlSeconds(String ttlSecondsStr) throws 
AnalysisException {
+        long ttlSeconds;
+        try {
+            ttlSeconds = Long.parseLong(ttlSecondsStr);
+        } catch (NumberFormatException e) {
+            throw invalidFileCacheTtlSecondsException(ttlSecondsStr);
+        }
+        if (ttlSeconds < 0 || ttlSeconds > MAX_FILE_CACHE_TTL_SECONDS) {
+            throw invalidFileCacheTtlSecondsException(ttlSecondsStr);
+        }
+        return ttlSeconds;
+    }
+
+    private static AnalysisException 
invalidFileCacheTtlSecondsException(String ttlSecondsStr) {
+        return new AnalysisException("The value " + ttlSecondsStr + " formats 
error or is out of range "
+                + "(0 <= integer <= " + MAX_FILE_CACHE_TTL_SECONDS + "). 
Larger values may overflow in BE "
+                + "and change TTL cache to normal cache; please use " + 
MAX_FILE_CACHE_TTL_SECONDS
+                + " or a smaller value.");
+    }
+
     public static int analyzePartitionRetentionCount(Map<String, String> 
properties) throws AnalysisException {
         int retentionCount = -1;
         if (properties != null && 
properties.containsKey(PROPERTIES_PARTITION_RETENTION_COUNT)) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ModifyTablePropertiesOp.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ModifyTablePropertiesOp.java
index 6376d24a46a..eea71384582 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ModifyTablePropertiesOp.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ModifyTablePropertiesOp.java
@@ -343,6 +343,8 @@ public class ModifyTablePropertiesOp extends AlterTableOp {
             this.opType = AlterOpType.MODIFY_TABLE_PROPERTY_SYNC;
         } else if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS)) {
             this.needTableStable = false;
+            PropertyAnalyzer.analyzeFileCacheTtlSeconds(
+                    
properties.get(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS));
             this.opType = AlterOpType.MODIFY_TABLE_PROPERTY_SYNC;
         } else if 
(properties.containsKey(PropertyAnalyzer.PROPERTIES_PARTITION_RETENTION_COUNT)) 
{
             // do a check here for valid value
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java
index 926d803f931..586139dca78 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/common/PropertyAnalyzerTest.java
@@ -143,6 +143,44 @@ public class PropertyAnalyzerTest {
         Assert.assertEquals(0.05, 
PropertyAnalyzer.analyzeBloomFilterFpp(properties), 0.0001);
     }
 
+    @Test
+    public void testAnalyzeFileCacheTtlSeconds() throws AnalysisException {
+        Map<String, String> properties = Maps.newHashMap();
+        properties.put(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS, 
"0");
+        Assert.assertEquals(0L, PropertyAnalyzer.analyzeTTL(properties));
+
+        properties.put(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS,
+                String.valueOf(PropertyAnalyzer.MAX_FILE_CACHE_TTL_SECONDS));
+        Assert.assertEquals(PropertyAnalyzer.MAX_FILE_CACHE_TTL_SECONDS, 
PropertyAnalyzer.analyzeTTL(properties));
+
+        properties.put(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS,
+                String.valueOf(PropertyAnalyzer.MAX_FILE_CACHE_TTL_SECONDS + 
1L));
+        try {
+            PropertyAnalyzer.analyzeTTL(properties);
+            Assert.fail("Expected an AnalysisException to be thrown");
+        } catch (AnalysisException e) {
+            Assert.assertTrue(e.getMessage().contains("please use "
+                    + PropertyAnalyzer.MAX_FILE_CACHE_TTL_SECONDS));
+        }
+
+        properties.put(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS, 
String.valueOf(Long.MAX_VALUE));
+        try {
+            PropertyAnalyzer.analyzeTTL(properties);
+            Assert.fail("Expected an AnalysisException to be thrown");
+        } catch (AnalysisException e) {
+            Assert.assertTrue(e.getMessage().contains("Larger values may 
overflow in BE"));
+            Assert.assertTrue(e.getMessage().contains("please use"));
+        }
+
+        properties.put(PropertyAnalyzer.PROPERTIES_FILE_CACHE_TTL_SECONDS, 
"invalid");
+        try {
+            PropertyAnalyzer.analyzeTTL(properties);
+            Assert.fail("Expected an AnalysisException to be thrown");
+        } catch (AnalysisException e) {
+            Assert.assertTrue(e.getMessage().contains("formats error or is out 
of range"));
+        }
+    }
+
     @Test
     public void testStorageMedium() throws AnalysisException {
         long tomorrowTs = System.currentTimeMillis() / 1000 + 86400;
diff --git 
a/regression-test/suites/cloud_p0/cache/ttl/alter_ttl_max_int64.groovy 
b/regression-test/suites/cloud_p0/cache/ttl/alter_ttl_max_int64.groovy
index 9ffde534860..afb67b123f5 100644
--- a/regression-test/suites/cloud_p0/cache/ttl/alter_ttl_max_int64.groovy
+++ b/regression-test/suites/cloud_p0/cache/ttl/alter_ttl_max_int64.groovy
@@ -19,7 +19,8 @@ import org.codehaus.groovy.runtime.IOGroovyMethods
 
 suite("test_ttl_max_int64") {
     sql """ use @regression_cluster_name1 """
-    def ttlProperties = """ 
PROPERTIES("file_cache_ttl_seconds"="9223372036854775807") """
+    long safeLargeTtlSeconds = Long.MAX_VALUE / 2L
+    def ttlProperties = """ 
PROPERTIES("file_cache_ttl_seconds"="${safeLargeTtlSeconds}") """
     String[][] backends = sql """ show backends """
     String backendId;
     def backendIdToBackendIP = [:]
@@ -47,7 +48,6 @@ suite("test_ttl_max_int64") {
         }
     }
 
-    def tables = [customer_ttl: 15000000]
     def s3BucketName = getS3BucketName()
     def s3WithProperties = """WITH S3 (
         |"AWS_ACCESS_KEY" = "${getS3AK()}",
@@ -93,12 +93,47 @@ suite("test_ttl_max_int64") {
         }
     }
 
+    def getTabletIds = { String table ->
+        def tablets = sql "show tablets from ${table}"
+        assertTrue(tablets.size() > 0, "No tablets found for table ${table}")
+        tablets.collect { it[0] as Long }
+    }
+
+    def waitForFileCacheType = { List<Long> tabletIds, String expectedType, 
long timeoutMs = 60000L, long intervalMs = 2000L ->
+        long start = System.currentTimeMillis()
+        while (System.currentTimeMillis() - start < timeoutMs) {
+            boolean allMatch = true
+            for (Long tabletId in tabletIds) {
+                def rows = sql "select type from 
information_schema.file_cache_info where tablet_id = ${tabletId}"
+                if (rows.isEmpty()) {
+                    logger.warn("file_cache_info is empty for tablet 
${tabletId} while waiting for ${expectedType}")
+                    allMatch = false
+                    break
+                }
+                def mismatch = rows.find { row -> 
!row[0]?.toString()?.equalsIgnoreCase(expectedType) }
+                if (mismatch) {
+                    logger.info("tablet ${tabletId} has cache types 
${rows.collect { it[0] }} while waiting for ${expectedType}")
+                    allMatch = false
+                    break
+                }
+            }
+            if (allMatch) {
+                logger.info("All file cache entries for tablets ${tabletIds} 
are ${expectedType}")
+                return
+            }
+            sleep(intervalMs)
+        }
+        assertTrue(false, "Timeout waiting for file_cache_info type 
${expectedType} for tablets ${tabletIds}")
+    }
+
     clearFileCache.call() {
         respCode, body -> {}
     }
     sleep(30000)
 
     load_customer_once("customer_ttl")
+    def tabletIds = getTabletIds.call("customer_ttl")
+    waitForFileCacheType.call(tabletIds, "ttl")
     sleep(30000) // 30s
     getMetricsMethod.call() {
         respCode, body ->
@@ -113,7 +148,7 @@ suite("test_ttl_max_int64") {
                         continue
                     }
                     def i = line.indexOf(' ')
-                    assertTrue(line.substring(i).toLong() > 838860800)
+                    assertTrue(line.substring(i).trim().toLong() > 838860800)
                     flag1 = true
                 }
             }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to