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

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


The following commit(s) were added to refs/heads/branch-4.1 by this push:
     new a0c5a870caa branch-4.1: [test](regression) Improve BE cancel_query 
workload policy regression coverage #65145 (#65458)
a0c5a870caa is described below

commit a0c5a870caa40306779a59c947191759618c7f0e
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Jul 13 15:11:56 2026 +0800

    branch-4.1: [test](regression) Improve BE cancel_query workload policy 
regression coverage #65145 (#65458)
    
    Cherry-picked from #65145
    
    Co-authored-by: Wen Zhenghu <[email protected]>
---
 .../test_workload_policy_remote_scan_bytes.groovy  | 127 ++++++++++++----
 ..._be_workload_policy_cancel_query_metrics.groovy | 162 +++++++++++++++++++++
 2 files changed, 264 insertions(+), 25 deletions(-)

diff --git 
a/regression-test/suites/external_table_p0/hive/test_workload_policy_remote_scan_bytes.groovy
 
b/regression-test/suites/external_table_p0/hive/test_workload_policy_remote_scan_bytes.groovy
index 3b6cb46f1b3..b790e421073 100644
--- 
a/regression-test/suites/external_table_p0/hive/test_workload_policy_remote_scan_bytes.groovy
+++ 
b/regression-test/suites/external_table_p0/hive/test_workload_policy_remote_scan_bytes.groovy
@@ -42,6 +42,98 @@ suite("test_workload_policy_remote_scan_bytes", 
"p0,external") {
         forComputeGroupStr = " for ${validCluster} "
     }
 
+    // Wait for the default FE->BE publish cycle instead of mutating a shared 
FE config.
+    def waitForBePolicyPublish = {
+        Thread.sleep(40000)
+    }
+
+    // Flush and poll audit rows through a separate connection so diagnostics 
do not
+    // inherit the tested workload group or change the primary assertion 
result.
+    def fetchAuditRowsForMarker = { queryMarker ->
+        return connect(context.config.jdbcUser, context.config.jdbcPassword, 
context.config.jdbcUrl) {
+            sql """SET workload_group = ''"""
+            sql """SET enable_sql_cache = false"""
+            sql """CALL flush_audit_log()"""
+            int retry = 20
+            def auditRows = []
+            String auditSql = """
+                SELECT time, state, error_message, scan_bytes, scan_rows,
+                       scan_bytes_from_remote_storage, 
scan_bytes_from_local_storage,
+                       workload_group, stmt
+                FROM __internal_schema.audit_log
+                WHERE stmt LIKE '%${queryMarker}%'
+                  AND workload_group = '${workloadGroupName}'
+                ORDER BY time DESC
+                LIMIT 5
+            """
+            while (retry-- >= 0) {
+                auditRows = sql auditSql
+                if (!auditRows.isEmpty()) {
+                    return auditRows
+                }
+                sleep(3000)
+                sql """CALL flush_audit_log()"""
+            }
+            return auditRows
+        }
+    }
+
+    def runRemoteScanPolicyCase = { String lineitemDb, boolean 
enableFileScannerV2,
+                                    boolean requireCancellation ->
+        String scannerName = enableFileScannerV2 ? "FileScannerV2" : 
"FileScanner"
+        String queryMarker = "remote_scan_${enableFileScannerV2 ? 'v2' : 
'legacy'}_probe_"
+                + System.currentTimeMillis()
+        Throwable queryException = null
+
+        logger.info("Run remote scan bytes workload policy test item with 
${scannerName}, "
+                + "requireCancellation=${requireCancellation}")
+        sql """SET workload_group = '${workloadGroupName}'"""
+        sql """SET enable_file_cache = false"""
+        sql """SET enable_sql_cache = false"""
+        sql """SET enable_file_scanner_v2 = ${enableFileScannerV2}"""
+        try {
+            sql """
+                SELECT /* ${queryMarker} */ SUM(SLEEP(1) + l_quantity)
+                FROM (
+                    SELECT l_quantity
+                    FROM ${catalogName}.${lineitemDb}.lineitem
+                    LIMIT 10
+                ) s
+            """
+        } catch (Throwable t) {
+            queryException = t
+        }
+
+        String msg = queryException == null ? null : 
queryException.getMessage()
+        boolean cancelledByExpectedPolicy = msg != null
+                && msg.contains("cancelled by workload policy: ${policyName}")
+                && msg.contains("scan_bytes_from_remote_storage")
+
+        if (queryException != null) {
+            assertTrue(cancelledByExpectedPolicy,
+                    "unexpected ${scannerName} query failure: " + msg)
+        } else if (requireCancellation) {
+            def auditRows = fetchAuditRowsForMarker(queryMarker)
+            logger.info("Remote scan bytes workload policy audit rows for 
${queryMarker}: " + auditRows)
+            assertTrue(queryException != null,
+                    "${scannerName} query should be cancelled by remote scan 
bytes workload policy")
+        } else {
+            def auditRows = fetchAuditRowsForMarker(queryMarker)
+            assertFalse(auditRows.isEmpty(),
+                    "expected an audit row for the non-blocking ${scannerName} 
validation")
+            logger.info("${scannerName} remote scan bytes cancellation is not 
enforced yet; "
+                    + "audit rows for ${queryMarker}: " + auditRows)
+        }
+
+        if (cancelledByExpectedPolicy) {
+            logger.info("Remote scan bytes workload policy cancel message for 
${scannerName}: " + msg)
+        }
+    }
+
+    def scannerV2Variable = sql """SHOW VARIABLES LIKE 
'enable_file_scanner_v2'"""
+    assertEquals(1, scannerV2Variable.size())
+    String originalEnableFileScannerV2 = scannerV2Variable[0][1].toString()
+
     try {
         sql """DROP WORKLOAD POLICY IF EXISTS ${policyName}"""
         sql """DROP WORKLOAD POLICY IF EXISTS ${invalidPolicyName}"""
@@ -103,38 +195,23 @@ suite("test_workload_policy_remote_scan_bytes", 
"p0,external") {
         assertEquals(policyName, policy[0][0])
         
assertTrue(policy[0][1].toString().contains("be_scan_bytes_from_remote_storage 
> 1"))
 
-        // Wait for FE to publish the new BE-side policy before issuing the 
query.
-        Thread.sleep(15000)
+        waitForBePolicyPublish()
 
-        Throwable queryException = null
-        sql """SET workload_group = '${workloadGroupName}'"""
-        sql """SET enable_file_cache = false"""
-        sql """SET enable_sql_cache = false"""
-        try {
-            sql """
-                SELECT SUM(SLEEP(1) + l_quantity)
-                FROM (
-                    SELECT l_quantity
-                    FROM ${catalogName}.${lineitemDb}.lineitem
-                    LIMIT 10
-                ) s
-            """
-        } catch (Throwable t) {
-            queryException = t
-        }
-        assertTrue(queryException != null, "query should be cancelled by 
remote scan bytes workload policy")
-        String msg = queryException.getMessage()
-        logger.info("Remote scan bytes workload policy cancel message: " + msg)
-        assertTrue(msg != null && msg.contains("cancelled by workload policy: 
${policyName}"),
-                "unexpected cancel policy: " + msg)
-        assertTrue(msg.contains("scan_bytes_from_remote_storage"),
-                "remote scan bytes counter is missing from cancel message: " + 
msg)
+        // Test item 1: the legacy FileScanner already publishes remote scan 
bytes to the
+        // query-level IO context, so cancellation is required and fully 
asserted.
+        runRemoteScanPolicyCase(lineitemDb, false, true)
+
+        // Test item 2: FileScannerV2 currently does not publish file scan 
bytes to the
+        // query-level IO context. Keep this path as non-blocking coverage 
until the BE-side
+        // FileScannerV2 accounting fix is merged, then change 
requireCancellation to true.
+        runRemoteScanPolicyCase(lineitemDb, true, false)
     } finally {
         try {
             sql """SET workload_group = ''"""
         } catch (Throwable t) {
             logger.info("ignore reset workload_group failure: " + 
t.getMessage())
         }
+        sql """SET enable_file_scanner_v2 = ${originalEnableFileScannerV2}"""
         sql """DROP WORKLOAD POLICY IF EXISTS ${policyName}"""
         sql """DROP WORKLOAD POLICY IF EXISTS ${invalidPolicyName}"""
         sql """DROP WORKLOAD GROUP IF EXISTS ${workloadGroupName} 
${forComputeGroupStr}"""
diff --git 
a/regression-test/suites/workload_manager_p0/test_be_workload_policy_cancel_query_metrics.groovy
 
b/regression-test/suites/workload_manager_p0/test_be_workload_policy_cancel_query_metrics.groovy
new file mode 100644
index 00000000000..006b7a15416
--- /dev/null
+++ 
b/regression-test/suites/workload_manager_p0/test_be_workload_policy_cancel_query_metrics.groovy
@@ -0,0 +1,162 @@
+// 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.
+
+suite("test_be_workload_policy_cancel_query_metrics") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String workloadGroupName = "test_be_cancel_query_metrics_wg"
+    String forComputeGroupStr = ""
+    String currentCgName = ""
+    if (isCloudMode()) {
+        def clusters = sql "SHOW CLUSTERS"
+        assertTrue(!clusters.isEmpty())
+        String validCluster = clusters[0][0]
+        currentCgName = "${validCluster}."
+        forComputeGroupStr = " for ${validCluster} "
+    }
+
+    // Wait for the default FE->BE publish cycle instead of mutating a shared 
FE config.
+    def waitForBePolicyPublish = {
+        Thread.sleep(40000)
+    }
+
+    // Verify that the query was cancelled by the expected BE policy and that
+    // the cancellation message exposes the metric that triggered it.
+    def assertCancelledByPolicy = { querySql, policyName, metricName ->
+        Throwable queryException = null
+        try {
+            sql querySql
+        } catch (Throwable t) {
+            queryException = t
+        }
+        assertTrue(queryException != null, "query should be cancelled by 
workload policy ${policyName}")
+        String msg = queryException.getMessage()
+        logger.info("BE workload policy cancel message for ${policyName}: 
${msg}")
+        assertTrue(msg != null && msg.contains("cancelled by workload policy: 
${policyName}"),
+                "unexpected cancel policy: " + msg)
+        assertTrue(msg.contains(metricName), "missing trigger metric 
${metricName}: " + msg)
+    }
+
+    // Build isolated workload groups so all policies can be published once 
and verified independently.
+    def policyCases = [
+            [
+                    workloadGroupName: "${workloadGroupName}_time",
+                    policyName      : "test_be_cancel_query_time_policy",
+                    conditionSql    : "query_time > 1",
+                    metricName      : "query_time"
+            ],
+            [
+                    workloadGroupName: "${workloadGroupName}_scan_rows",
+                    policyName      : "test_be_cancel_query_scan_rows_policy",
+                    conditionSql    : "be_scan_rows > 1",
+                    metricName      : "scan_rows"
+            ],
+            [
+                    workloadGroupName: "${workloadGroupName}_scan_bytes",
+                    policyName      : "test_be_cancel_query_scan_bytes_policy",
+                    conditionSql    : "be_scan_bytes > 1",
+                    metricName      : "scan_bytes"
+            ],
+            [
+                    workloadGroupName: "${workloadGroupName}_memory",
+                    policyName      : "test_be_cancel_query_memory_policy",
+                    conditionSql    : "query_be_memory_bytes > 1",
+                    metricName      : "query_memory"
+            ]
+    ]
+
+    try {
+        sql """CREATE DATABASE IF NOT EXISTS ${dbName}"""
+        sql """DROP TABLE IF EXISTS 
${dbName}.test_be_workload_policy_cancel_query_metrics_tbl"""
+        sql """
+            CREATE TABLE 
${dbName}.test_be_workload_policy_cancel_query_metrics_tbl (
+                id INT,
+                payload STRING
+            )
+            DUPLICATE KEY(id)
+            DISTRIBUTED BY HASH(id) BUCKETS 1
+            PROPERTIES("replication_num" = "1")
+        """
+        sql """
+            INSERT INTO 
${dbName}.test_be_workload_policy_cancel_query_metrics_tbl
+            SELECT number, REPEAT('x', 4096)
+            FROM numbers("number" = "200")
+        """
+
+        // Use a scan-heavy query for time/rows/bytes and a sort-heavy query 
for
+        // memory so the BE runtime counters can trip the dedicated policy.
+        String scanQuerySql = """
+            SELECT SUM(SLEEP(1) + id)
+            FROM (
+                SELECT id
+                FROM ${dbName}.test_be_workload_policy_cancel_query_metrics_tbl
+                ORDER BY id
+                LIMIT 10
+            ) s
+        """
+        String memoryQuerySql = """
+            SELECT SUM(SLEEP(1) + payload_len)
+            FROM (
+                SELECT LENGTH(payload) AS payload_len
+                FROM ${dbName}.test_be_workload_policy_cancel_query_metrics_tbl
+                ORDER BY payload
+                LIMIT 10
+            ) s
+        """
+
+        policyCases.each { policyCase ->
+            sql """DROP WORKLOAD POLICY IF EXISTS ${policyCase.policyName}"""
+            sql """DROP WORKLOAD GROUP IF EXISTS 
${policyCase.workloadGroupName} ${forComputeGroupStr}"""
+            sql """
+                CREATE WORKLOAD GROUP ${policyCase.workloadGroupName} 
${forComputeGroupStr}
+                PROPERTIES ('max_cpu_percent' = '100')
+            """
+        }
+
+        // Publish all BE-side policies together and reuse the same 
propagation wait.
+        policyCases.each { policyCase ->
+            sql """
+                CREATE WORKLOAD POLICY ${policyCase.policyName}
+                CONDITIONS(${policyCase.conditionSql})
+                ACTIONS(cancel_query)
+                PROPERTIES(
+                    'priority' = '100',
+                    'workload_group' = 
'${currentCgName}${policyCase.workloadGroupName}'
+                )
+            """
+        }
+
+        waitForBePolicyPublish()
+
+        // Switch workload groups between assertions so each query can only 
match one policy.
+        policyCases.each { policyCase ->
+            sql """SET workload_group = '${policyCase.workloadGroupName}'"""
+            sql """SET enable_sql_cache = false"""
+            String querySql = policyCase.metricName == "query_memory" ? 
memoryQuerySql : scanQuerySql
+            assertCancelledByPolicy(querySql, policyCase.policyName, 
policyCase.metricName)
+        }
+    } finally {
+        try {
+            sql """SET workload_group = ''"""
+        } catch (Throwable t) {
+            logger.info("ignore reset workload_group failure: " + 
t.getMessage())
+        }
+        policyCases.each { policyCase ->
+            sql """DROP WORKLOAD POLICY IF EXISTS ${policyCase.policyName}"""
+            sql """DROP WORKLOAD GROUP IF EXISTS 
${policyCase.workloadGroupName} ${forComputeGroupStr}"""
+        }
+    }
+}


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

Reply via email to