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

hello-stephen 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 61920b70576 [fix](regression) wait for adaptive scan profile (#64923)
61920b70576 is described below

commit 61920b705767456d19ab90db1fd99ec3e2bc0aa5
Author: shuke <[email protected]>
AuthorDate: Mon Jul 6 14:22:13 2026 +0800

    [fix](regression) wait for adaptive scan profile (#64923)
    
    ## Summary
    - Add shared readiness-aware profile helpers in the regression
    framework.
    - Update adaptive_pipeline_task_serial_read_on_limit and scanner_profile
    to wait for required query profile counters before asserting.
    - Update s3_load_profile_test to reuse the shared wait helper for load
    profile counters before asserting.
    - Keep the existing profile("tag") DSL one-shot and raw-format
    compatible; readiness waiting is opt-in through explicit helper calls.
    - Keep the existing immediate getProfile(profileId) API unchanged to
    avoid slowing existing custom polling loops.
    
    ## Testing
    - git diff --check
    - Groovy parsing phase check for ProfileAction.groovy,
    adaptive_pipeline_task_serial_read_on_limit.groovy,
    scanner_profile.groovy, s3_load_profile_test.groovy,
    recursive_cte/query_cache_with_rec_cte_test.groovy, and
    query_p0/cache/parse_sql_from_sql_cache.groovy
    - Not run: full regression cases, no live Doris regression environment
    was used in this fix-cases worktree.
---
 .../doris/regression/action/ProfileAction.groovy   | 107 ++++++++++++++--
 ...ptive_pipeline_task_serial_read_on_limit.groovy |  55 ++++----
 .../query_profile/s3_load_profile_test.groovy      | 140 +++++++++++----------
 .../suites/query_profile/scanner_profile.groovy    | 137 ++++++++++----------
 4 files changed, 265 insertions(+), 174 deletions(-)

diff --git 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
index d4985d0fe4f..7417d896f19 100644
--- 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
+++ 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/ProfileAction.groovy
@@ -26,6 +26,11 @@ import org.apache.doris.regression.util.JdbcUtils
 
 @Slf4j
 class ProfileAction implements SuiteAction {
+    private static final long DEFAULT_PROFILE_WAIT_TIMEOUT_MS = 30000
+    private static final long DEFAULT_PROFILE_WAIT_INTERVAL_MS = 500
+    private static final String PROFILE_LIST_COMPLETE = "COMPLETE"
+    private static final String PROFILE_COMPLETE = "Profile Completion State: 
COMPLETE"
+
     private String tag
     private Runnable runCallback
     private Closure<String> check
@@ -76,6 +81,26 @@ class ProfileAction implements SuiteAction {
         return profileData
     }
 
+    private String normalizeProfileText(String profileText) {
+        // Convert HTML entities and actual NBSPs to regular spaces,
+        // retain line breaks, and then compress multiple consecutive spaces 
into a single space.
+        profileText = profileText.replace("&nbsp;", " ")
+        profileText = profileText.replace("</br>", "\n")
+        profileText = profileText.replace('\u00A0' as char, ' ' as char)
+        return profileText.replaceAll(" {2,}", " ")
+    }
+
+    boolean isProfileReady(String profileText, List<String> requiredContents = 
[]) {
+        if (profileText == null || profileText.isEmpty()) {
+            return false
+        }
+        if (!profileText.contains(PROFILE_COMPLETE)) {
+            return false
+        }
+        return requiredContents == null || requiredContents.isEmpty()
+                || requiredContents.every { profileText.contains(it) }
+    }
+
     String getProfile(String profileId) {
         def profileCli = new HttpCliAction(context)
         def addr = context.getFeHttpAddress()
@@ -97,20 +122,84 @@ class ProfileAction implements SuiteAction {
 
             def jsonSlurper2 = new JsonSlurper()
             def profileText = jsonSlurper2.parseText(profileResp).data
-            // Convert HTML entities and actual NBSPs to regular spaces, 
-            // retain line breaks, and then compress multiple consecutive 
spaces into a single space
-            profileText = profileText.replace("&nbsp;", " ")
-            profileText = profileText.replace("</br>", "\n")
-            // Replace the actual NBSP characters with regular spaces
-            profileText = profileText.replace('\u00A0' as char, ' ' as char)
-            // Compress two or more consecutive regular spaces into a single 
space (without affecting line breaks)
-            profileText = profileText.replaceAll(" {2,}", " ")
-            result.text = profileText
+            result.text = normalizeProfileText(profileText)
         }
         profileCli.run()
         return result.text
     }
 
+    String getProfile(String profileId, List<String> requiredContents, long 
timeoutMs = DEFAULT_PROFILE_WAIT_TIMEOUT_MS,
+            long intervalMs = DEFAULT_PROFILE_WAIT_INTERVAL_MS) {
+        return waitProfile({ getProfile(profileId) }, requiredContents, 
"Profile ${profileId}", timeoutMs, intervalMs)
+    }
+
+    String waitProfile(Closure<String> profileFetcher, List<String> 
requiredContents = [],
+            String profileDescription = "Profile", long timeoutMs = 
DEFAULT_PROFILE_WAIT_TIMEOUT_MS,
+            long intervalMs = DEFAULT_PROFILE_WAIT_INTERVAL_MS) {
+        String profileText = ""
+        long deadline = System.currentTimeMillis() + timeoutMs
+        while (System.currentTimeMillis() <= deadline) {
+            String currentProfileText = profileFetcher.call()
+            if (currentProfileText != null && !currentProfileText.isEmpty()) {
+                profileText = currentProfileText
+            }
+            if (isProfileReady(currentProfileText, requiredContents)) {
+                return currentProfileText
+            }
+            log.info("{} is not ready, required contents: {}", 
profileDescription, requiredContents)
+            Thread.sleep(intervalMs)
+        }
+        throw new IllegalStateException("${profileDescription} is not ready 
after ${timeoutMs} ms, " +
+                "required contents: ${requiredContents}, last 
profile:\n${profileText}")
+    }
+
+    String getProfileBySql(String sqlPattern, List<String> requiredContents = 
[],
+            long timeoutMs = DEFAULT_PROFILE_WAIT_TIMEOUT_MS, long intervalMs 
= DEFAULT_PROFILE_WAIT_INTERVAL_MS) {
+        String profileId = ""
+        String profileText = ""
+        Throwable lastException = null
+        long deadline = System.currentTimeMillis() + timeoutMs
+        while (System.currentTimeMillis() <= deadline) {
+            for (final def profileItem in getProfileList()) {
+                if (profileItem["Sql 
Statement"].toString().contains(sqlPattern)) {
+                    profileId = profileItem["Profile ID"].toString()
+                    if (profileItem["Profile Completion State"]?.toString() != 
PROFILE_LIST_COMPLETE) {
+                        break
+                    }
+                    try {
+                        profileText = getProfile(profileId)
+                        lastException = null
+                    } catch (Throwable t) {
+                        lastException = t
+                        log.info("Profile {} with sql pattern {} is not 
available yet: {}",
+                                profileId, sqlPattern, t.getMessage())
+                        break
+                    }
+                    if (isProfileReady(profileText, requiredContents)) {
+                        return profileText
+                    }
+                    break
+                }
+            }
+            if (profileId == "") {
+                log.info("Profile with sql pattern {} is not found yet", 
sqlPattern)
+            } else {
+                log.info("Profile {} with sql pattern {} is not ready", 
profileId, sqlPattern)
+            }
+            Thread.sleep(intervalMs)
+        }
+
+        if (profileId == "") {
+            throw new IllegalStateException("Missing profile with sql pattern: 
" + sqlPattern)
+        }
+        String message = "Profile ${profileId} with sql pattern ${sqlPattern} 
is not ready after ${timeoutMs} ms, " +
+                "required contents: ${requiredContents}"
+        if (lastException != null) {
+            message += ", last error: ${lastException.getMessage()}"
+        }
+        throw new IllegalStateException("${message}, last 
profile:\n${profileText}")
+    }
+
     @Override
     void run() {
         if (runCallback.is(null)) {
diff --git 
a/regression-test/suites/query_profile/adaptive_pipeline_task_serial_read_on_limit.groovy
 
b/regression-test/suites/query_profile/adaptive_pipeline_task_serial_read_on_limit.groovy
index 0da3c8e1a94..17741302df3 100644
--- 
a/regression-test/suites/query_profile/adaptive_pipeline_task_serial_read_on_limit.groovy
+++ 
b/regression-test/suites/query_profile/adaptive_pipeline_task_serial_read_on_limit.groovy
@@ -19,26 +19,16 @@ import groovy.json.JsonOutput
 import groovy.json.JsonSlurper
 import groovy.json.StringEscapeUtils
 import org.apache.doris.regression.action.ProfileAction
-import org.awaitility.Awaitility
-import static java.util.concurrent.TimeUnit.SECONDS
 
-def verifyProfileContent = { suiteContext, profileId, stmt, serialReadOnLimit 
->
+def verifyProfileContent = { suiteContext, sqlPattern, stmt, serialReadOnLimit 
->
     def profileAction = new ProfileAction(suiteContext)
-    String profileContent = ""
-    Awaitility.await().atMost(60, SECONDS).pollInterval(1, SECONDS).until {
-        def profileItem = profileAction.getProfileList().find {
-            it["Profile ID"]?.toString() == profileId
-        }
-        if (profileItem == null) {
-            return false
-        }
-        if (profileItem["Profile Completion State"]?.toString() != "COMPLETE") 
{
-            return false
-        }
-        profileContent = profileAction.getProfile(profileId)
-        return profileContent.contains("MaxScanConcurrency")
+    String profileContent = profileAction.getProfileBySql(sqlPattern, 
["MaxScanConcurrency"], 60000, 1000)
+    if (!profileContent.contains("MaxScanConcurrency")) {
+        logger.error("Profile of ${stmt} (pattern ${sqlPattern}) does not 
contain MaxScanConcurrency, " +
+                "content:\n${profileContent}")
+        return false
     }
-    logger.info("Profile content of ${stmt} (${profileId}) 
is\n${profileContent}")
+    logger.info("Profile content of ${stmt} (pattern ${sqlPattern}) 
is\n${profileContent}")
     // Check if the profile contains the expected content
     if (serialReadOnLimit) {
         return profileContent.contains("- MaxScanConcurrency: 1") == true
@@ -103,23 +93,36 @@ suite('adaptive_pipeline_task_serial_read_on_limit') {
     sql "set parallel_pipeline_task_num=1;"
 
     // With Limit, MaxScannerThreadNum = 1
-    def verifyQueryProfile = { stmt, serialReadOnLimit ->
+    def verifyQueryProfile = { stmtBuilder, serialReadOnLimit ->
+        String token = UUID.randomUUID().toString()
+        String stmt = stmtBuilder(token)
         sql stmt
         String profileId = sql("select last_query_id()")[0][0].toString()
-        assertTrue(verifyProfileContent(context, profileId, stmt, 
serialReadOnLimit))
+        logger.info("Captured last_query_id() for statement [${stmt}]: 
${profileId}, profile token: ${token}")
+        assertTrue(verifyProfileContent(context, token, stmt, 
serialReadOnLimit))
     }
 
-    verifyQueryProfile("select * from 
adaptive_pipeline_task_serial_read_on_limit limit 10;", true)
-    verifyQueryProfile("select * from 
adaptive_pipeline_task_serial_read_on_limit limit 10000;", true)
+    // Use a statement token and profile-list lookup. Detail lookup by 
last_query_id()
+    // can be transiently unavailable after very short queries finish.
+    verifyQueryProfile({ token ->
+        """select "${token}", * from 
adaptive_pipeline_task_serial_read_on_limit limit 10;"""
+    }, true)
+    verifyQueryProfile({ token ->
+        """select "${token}", * from 
adaptive_pipeline_task_serial_read_on_limit limit 10000;"""
+    }, true)
     // With Limit, but bigger then 
adaptive_pipeline_task_serial_read_on_limit,  MaxScannerThreadNum = TabletNum
     sql "set adaptive_pipeline_task_serial_read_on_limit=9998;"
-    verifyQueryProfile("select * from 
adaptive_pipeline_task_serial_read_on_limit limit 9999;", false)
+    verifyQueryProfile({ token ->
+        """select "${token}", * from 
adaptive_pipeline_task_serial_read_on_limit limit 9999;"""
+    }, false)
     // With limit, but with predicates too. MaxScannerThreadNum = TabletNum
-    verifyQueryProfile("select * from 
adaptive_pipeline_task_serial_read_on_limit where id > 10 limit 1;", false)
+    verifyQueryProfile({ token ->
+        """select "${token}", * from 
adaptive_pipeline_task_serial_read_on_limit where id > 10 limit 1;"""
+    }, false)
     // With large engough limit, but 
enable_adaptive_pipeline_task_serial_read_on_limit is false. 
MaxScannerThreadNum = TabletNum
     sql "set enable_adaptive_pipeline_task_serial_read_on_limit=false;"
-    verifyQueryProfile("""
-        select "enable_adaptive_pipeline_task_serial_read_on_limit=false", *
+    verifyQueryProfile({ token -> """
+        select "${token}", 
"enable_adaptive_pipeline_task_serial_read_on_limit=false", *
         from adaptive_pipeline_task_serial_read_on_limit limit 1000000;
-    """, false)
+    """ }, false)
 }
diff --git a/regression-test/suites/query_profile/s3_load_profile_test.groovy 
b/regression-test/suites/query_profile/s3_load_profile_test.groovy
index 9692efde734..1056aaf31c5 100644
--- a/regression-test/suites/query_profile/s3_load_profile_test.groovy
+++ b/regression-test/suites/query_profile/s3_load_profile_test.groovy
@@ -18,7 +18,7 @@
 import groovy.json.JsonSlurper
 import org.apache.doris.regression.action.ProfileAction
 
-def getProfile = { masterHTTPAddr, id ->
+def fetchProfile = { masterHTTPAddr, id ->
     def dst = 'http://' + masterHTTPAddr
     def conn = new URL(dst + 
"/api/profile/text/?query_id=$id").openConnection()
     conn.setRequestMethod("GET")
@@ -29,13 +29,14 @@ def getProfile = { masterHTTPAddr, id ->
 }
 
 // ref 
https://github.com/apache/doris/blob/3525a03815814f66ec78aa2ad6bbd9225b0e7a6b/regression-test/suites/load_p0/broker_load/test_s3_load.groovy
-suite('s3_load_profile_test') {
-    sql "set enable_profile=true;"   
-    sql "set profile_level=2;"
-    def s3Endpoint = getS3Endpoint()
-    def s3Region = getS3Region()
-    sql "drop table if exists s3_load_profile_test_dup_tbl_basic;"
-    sql """
+suite('s3_load_profile_test', 'nonConcurrent') {
+    setFeConfigTemporary(["profile_waiting_time_for_spill_seconds": 60]) {
+        sql "set enable_profile=true;"
+        sql "set profile_level=2;"
+        def s3Endpoint = getS3Endpoint()
+        def s3Region = getS3Region()
+        sql "drop table if exists s3_load_profile_test_dup_tbl_basic;"
+        sql """
     CREATE TABLE s3_load_profile_test_dup_tbl_basic
 (
     k00 INT             NOT NULL,
@@ -102,19 +103,19 @@ PROPERTIES (
     "replication_num" = "1"
 );
 """
-    def loadAttribute =new 
LoadAttributes("s3://${getS3BucketName()}/regression/load/data/basic_data.csv",
+        def loadAttribute =new 
LoadAttributes("s3://${getS3BucketName()}/regression/load/data/basic_data.csv",
                 "s3_load_profile_test_dup_tbl_basic", "LINES TERMINATED BY 
\"\n\"", "COLUMNS TERMINATED BY \"|\"", "FORMAT AS \"CSV\"", 
"(k00,k01,k02,k03,k04,k05,k06,k07,k08,k09,k10,k11,k12,k13,k14,k15,k16,k17,k18)",
                 "", "", "", "", "")
 
-    def ak = getS3AK()
-    def sk = getS3SK()
+        def ak = getS3AK()
+        def sk = getS3SK()
 
-    def label = "test_s3_load_" + UUID.randomUUID().toString().replace("-", 
"_")
-    logger.info("s3_load_profile_test_dup_tbl_basic, label: $label")
-    loadAttribute.label = label
-    def prop = loadAttribute.getPropertiesStr()
+        def label = "test_s3_load_" + 
UUID.randomUUID().toString().replace("-", "_")
+        logger.info("s3_load_profile_test_dup_tbl_basic, label: $label")
+        loadAttribute.label = label
+        def prop = loadAttribute.getPropertiesStr()
 
-    def sql_str = """
+        def sql_str = """
         LOAD LABEL $label (
             $loadAttribute.dataDesc.mergeType
             DATA INFILE("$loadAttribute.dataDesc.path")
@@ -139,69 +140,74 @@ PROPERTIES (
         )
         ${prop}
         """
-    logger.info("submit sql: ${sql_str}");
-    sql """${sql_str}"""
-    logger.info("Submit load with lable: $label, table: 
$loadAttribute.dataDesc.tableName, path: $loadAttribute.dataDesc.path")
+        logger.info("submit sql: ${sql_str}");
+        sql """${sql_str}"""
+        logger.info("Submit load with lable: $label, table: 
$loadAttribute.dataDesc.tableName, path: $loadAttribute.dataDesc.path")
 
-    def max_try_milli_secs = 600000
-    def jobId = -1
-    while (max_try_milli_secs > 0) {
-        String[][] result = sql """ show load where 
label="$loadAttribute.label" order by createtime desc limit 1; """
-        if (result[0][2].equals("FINISHED")) {
-            if (loadAttribute.isExceptFailed) {
-                assertTrue(false, "load should be failed but was success: 
$result")
+        def max_try_milli_secs = 600000
+        def jobId = -1
+        while (max_try_milli_secs > 0) {
+            String[][] result = sql """ show load where 
label="$loadAttribute.label" order by createtime desc limit 1; """
+            if (result[0][2].equals("FINISHED")) {
+                if (loadAttribute.isExceptFailed) {
+                    assertTrue(false, "load should be failed but was success: 
$result")
+                }
+                jobId = result[0][0].toLong()
+                logger.info("Load FINISHED " + loadAttribute.label + ": 
$result" + " loadId: $jobId")
+                break
             }
-            jobId = result[0][0].toLong()
-            logger.info("Load FINISHED " + loadAttribute.label + ": $result" + 
" loadId: $jobId")
-            break
-        }
-        if (result[0][2].equals("CANCELLED")) {
-            if (loadAttribute.isExceptFailed) {
-                logger.info("Load FINISHED " + loadAttribute.label)
+            if (result[0][2].equals("CANCELLED")) {
+                if (loadAttribute.isExceptFailed) {
+                    logger.info("Load FINISHED " + loadAttribute.label)
+                    break
+                }
+                assertTrue(false, "load failed: $result")
                 break
             }
-            assertTrue(false, "load failed: $result")
-            break
-        }
-        Thread.sleep(1000)
-        max_try_milli_secs -= 1000
-        if (max_try_milli_secs <= 0) {
-            assertTrue(false, "load Timeout: $loadAttribute.label")
+            Thread.sleep(1000)
+            max_try_milli_secs -= 1000
+            if (max_try_milli_secs <= 0) {
+                assertTrue(false, "load Timeout: $loadAttribute.label")
+            }
         }
-    }
-    Thread.sleep(500)
-    qt_select """ select count(*) from $loadAttribute.dataDesc.tableName """
-    logger.info("jobId: " + jobId)
+        Thread.sleep(500)
+        qt_select """ select count(*) from $loadAttribute.dataDesc.tableName 
"""
+        logger.info("jobId: " + jobId)
 
-    def allFrontends = sql """show frontends;"""
-    logger.info("allFrontends: " + allFrontends)
+        def allFrontends = sql """show frontends;"""
+        logger.info("allFrontends: " + allFrontends)
     /*
      - allFrontends: [[fe_2457d42b_68ad_43c4_a888_b3558a365be2, 127.0.0.1, 
6917, 5937, 6937, 5927, -1, FOLLOWER, true, 1523277282, true, true, 13436, 
2025-01-22 16:39:05, 2025-01-22 21:43:49, true, , doris-0.0.0--03faad7da5, Yes]]
     */
-    def frontendCounts = allFrontends.size()
-    def masterIP = ""
-    def masterHTTPPort = ""
+        def frontendCounts = allFrontends.size()
+        def masterIP = ""
+        def masterHTTPPort = ""
 
-    for (def i = 0; i < frontendCounts; i++) {
-        def currentFrontend = allFrontends[i]
-        def isMaster = currentFrontend[8]
-        if (isMaster == "true") {
-            masterIP = allFrontends[i][1]
-            masterHTTPPort = allFrontends[i][3]
-            break
+        for (def i = 0; i < frontendCounts; i++) {
+            def currentFrontend = allFrontends[i]
+            def isMaster = currentFrontend[8]
+            if (isMaster == "true") {
+                masterIP = allFrontends[i][1]
+                masterHTTPPort = allFrontends[i][3]
+                break
+            }
         }
-    }
-    if (masterIP == "" || masterHTTPPort == "") {
-        assertTrue(false, "Cannot find master FE from show frontends result: 
$allFrontends")
-    }
-    def masterAddress = masterIP + ":" + masterHTTPPort
-    logger.info("masterIP:masterHTTPPort is:${masterAddress}")
+        if (masterIP == "" || masterHTTPPort == "") {
+            assertTrue(false, "Cannot find master FE from show frontends 
result: $allFrontends")
+        }
+        def masterAddress = masterIP + ":" + masterHTTPPort
+        logger.info("masterIP:masterHTTPPort is:${masterAddress}")
 
-    def profileString = getProfile(masterAddress, jobId.toString())
-    logger.info("profileDataString:" + profileString)
-    assertTrue(profileString.contains("NumScanners"))
-    assertTrue(profileString.contains("RowsProduced"))
-    assertTrue(profileString.contains("RowsRead"))
+        def profileAction = new ProfileAction(context)
+        def profileString = profileAction.waitProfile(
+                { fetchProfile(masterAddress, jobId.toString()) },
+                ["NumScanners", "RowsProduced", "RowsRead"],
+                "Load profile ${jobId}")
+        logger.info("profileDataString:" + profileString)
+        assertTrue(profileString.contains("NumScanners"))
+        assertTrue(profileString.contains("RowsProduced"))
+        assertTrue(profileString.contains("RowsRead"))
+    }
 }
 
 class DataDesc {
diff --git a/regression-test/suites/query_profile/scanner_profile.groovy 
b/regression-test/suites/query_profile/scanner_profile.groovy
index 9b26ce7ec3a..cb3901c400a 100644
--- a/regression-test/suites/query_profile/scanner_profile.groovy
+++ b/regression-test/suites/query_profile/scanner_profile.groovy
@@ -20,83 +20,76 @@ import groovy.json.JsonSlurper
 import groovy.json.StringEscapeUtils
 import org.apache.doris.regression.action.ProfileAction
 
-suite('scanner_profile') {
-    sql """
-        DROP TABLE IF EXISTS scanner_profile;
-    """
-    sql """
-        CREATE TABLE if not exists `scanner_profile` (
-            `id` INT,
-            `name` varchar(32)
-        ) ENGINE=OLAP
-        DISTRIBUTED BY HASH(`id`) BUCKETS 10
-        PROPERTIES (
-            "replication_allocation" = "tag.location.default: 1"
-        );
-    """
+suite('scanner_profile', 'nonConcurrent') {
+    setFeConfigTemporary(["profile_waiting_time_for_spill_seconds": 60]) {
+        sql """
+            DROP TABLE IF EXISTS scanner_profile;
+        """
+        sql """
+            CREATE TABLE if not exists `scanner_profile` (
+                `id` INT,
+                `name` varchar(32)
+            ) ENGINE=OLAP
+            DISTRIBUTED BY HASH(`id`) BUCKETS 10
+            PROPERTIES (
+                "replication_allocation" = "tag.location.default: 1"
+            );
+        """
 
-    // Insert data to table
-    sql """
-        insert into scanner_profile values 
-        (1, "A"),(2, "B"),(3, "C"),(4, 
"D"),(5,"E"),(6,"F"),(7,"G"),(8,"H"),(9,"K");
-    """
-    sql """
-        insert into scanner_profile values 
-        (10, "A"),(20, "B"),(30, "C"),(40, 
"D"),(50,"E"),(60,"F"),(70,"G"),(80,"H"),(90,"K");
-    """
-    sql """
-        insert into scanner_profile values 
-        (101, "A"),(201, "B"),(301, "C"),(401, 
"D"),(501,"E"),(601,"F"),(701,"G"),(801,"H"),(901,"K");
-    """
-    sql """
-        insert into scanner_profile values 
-        (1010, "A"),(2010, "B"),(3010, "C"),(4010, 
"D"),(5010,"E"),(6010,"F"),(7010,"G"),(8010,"H"),(9010,"K");
-    """
+        // Insert data to table
+        sql """
+            insert into scanner_profile values
+            (1, "A"),(2, "B"),(3, "C"),(4, 
"D"),(5,"E"),(6,"F"),(7,"G"),(8,"H"),(9,"K");
+        """
+        sql """
+            insert into scanner_profile values
+            (10, "A"),(20, "B"),(30, "C"),(40, 
"D"),(50,"E"),(60,"F"),(70,"G"),(80,"H"),(90,"K");
+        """
+        sql """
+            insert into scanner_profile values
+            (101, "A"),(201, "B"),(301, "C"),(401, 
"D"),(501,"E"),(601,"F"),(701,"G"),(801,"H"),(901,"K");
+        """
+        sql """
+            insert into scanner_profile values
+            (1010, "A"),(2010, "B"),(3010, "C"),(4010, 
"D"),(5010,"E"),(6010,"F"),(7010,"G"),(8010,"H"),(9010,"K");
+        """
 
-    sql "set enable_profile=true"
-    sql "set profile_level=2;"
-    
-    def token = UUID.randomUUID().toString()
+        sql "set enable_profile=true"
+        sql "set profile_level=2;"
 
-    sql """
-        select "${token}", * from scanner_profile limit 10;
-    """
-    def profileAction = new ProfileAction(context)
-    def getProfileByToken = { pattern ->
-        List profileData = profileAction.getProfileList()
-        def profileContent = ""
-        for (final def profileItem in profileData) {
-            if (profileItem["Sql Statement"].toString().contains(pattern)) {
-                profileContent = profileAction.getProfile(profileItem["Profile 
ID"].toString())
-                break
-            }
+        def token = UUID.randomUUID().toString()
+
+        sql """
+            select "${token}", * from scanner_profile limit 10;
+        """
+        def profileAction = new ProfileAction(context)
+        def getProfileByToken = { pattern, requiredContents ->
+            return profileAction.getProfileBySql(pattern, requiredContents)
         }
-        return profileContent        
-    }
 
-    List profileData = profileAction.getProfileList()
-    def profileWithLimit1 = getProfileByToken(token)
-    logger.info("${token} Profile Data: ${profileWithLimit1}")
-    assertTrue(profileWithLimit1.toString().contains("- TaskCpuTime:"))
-    assertTrue(profileWithLimit1.toString().contains("- MaxScanConcurrency: 
1"))
+        def profileWithLimit1 = getProfileByToken(token, ["TaskCpuTime", 
"MaxScanConcurrency"])
+        logger.info("${token} Profile Data: ${profileWithLimit1}")
+        assertTrue(profileWithLimit1.toString().contains("- TaskCpuTime:"))
+        assertTrue(profileWithLimit1.toString().contains("- 
MaxScanConcurrency: 1"))
 
-    token = UUID.randomUUID().toString()
-    sql """
-        select "${token}", * from scanner_profile where id < 10;
-    """
+        token = UUID.randomUUID().toString()
+        sql """
+            select "${token}", * from scanner_profile where id < 10;
+        """
 
-    String profileWithFilter = getProfileByToken(token)
-    logger.info("${token} Profile Data: ${profileWithFilter}")
-    assertTrue(profileWithFilter.toString().contains("- TaskCpuTime:"))
-    assertTrue(profileWithFilter.toString().contains("- ScannerCpuTime:"))
-    assertFalse(profileWithFilter.toString().contains("- TaskCpuTime (Cpu 
Time):"))
-    assertFalse(profileWithFilter.toString().contains("- ScannerCpuTime (Cpu 
Time):"))
-    // Verify actualRows is backfilled onto the scan node. The exact value is
-    // unstable because 9 INT keys hash-distribute into 10 buckets and a few
-    // tablets may be pruned at runtime, so only assert it is in [1, 9].
-    def matcher = (profileWithFilter.toString() =~ 
/PhysicalOlapScan[^\n]*scanner_profile[^\n]*actualRows=(\d+)/)
-    assertTrue(matcher.find(), "actualRows not found on 
PhysicalOlapScan[scanner_profile] in profile")
-    int actualRows = matcher.group(1) as int
-    assertTrue(actualRows >= 1 && actualRows <= 9,
-            "expect actualRows in [1, 9], got ${actualRows}")
+        String profileWithFilter = getProfileByToken(token, ["TaskCpuTime", 
"ScannerCpuTime"])
+        logger.info("${token} Profile Data: ${profileWithFilter}")
+        assertTrue(profileWithFilter.toString().contains("- TaskCpuTime:"))
+        assertTrue(profileWithFilter.toString().contains("- ScannerCpuTime:"))
+        assertFalse(profileWithFilter.toString().contains("- TaskCpuTime (Cpu 
Time):"))
+        assertFalse(profileWithFilter.toString().contains("- ScannerCpuTime 
(Cpu Time):"))
+        // Verify actualRows is backfilled onto the scan node. The exact value 
is
+        // unstable because 9 INT keys hash-distribute into 10 buckets and a 
few
+        // tablets may be pruned at runtime, so only assert it is in [1, 9].
+        def matcher = (profileWithFilter.toString() =~ 
/PhysicalOlapScan[^\n]*scanner_profile[^\n]*actualRows=(\d+)/)
+        assertTrue(matcher.find(), "actualRows not found on 
PhysicalOlapScan[scanner_profile] in profile")
+        int actualRows = matcher.group(1) as int
+        assertTrue(actualRows >= 1 && actualRows <= 9,
+                "expect actualRows in [1, 9], got ${actualRows}")
+    }
 }


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

Reply via email to