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(" ", " ")
+ 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(" ", " ")
- 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]