This is an automated email from the ASF dual-hosted git repository.
Gabriel39 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 e0050c41211 [test](external) Fix removed DLF and thread warm-up
assumptions (#69156)
e0050c41211 is described below
commit e0050c41211372e813107f13366d03fe45c005d6
Author: Gabriel <[email protected]>
AuthorDate: Fri Oct 16 16:41:18 2026 +0800
[test](external) Fix removed DLF and thread warm-up assumptions (#69156)
### What problem does this PR solve?
Two external regression suites encode assumptions that no longer hold:
- `hive_on_hms_and_dlf` still expects DLF 1.0 to work as an HMS
metastore. Catalog creation now intentionally reports
`hive.metastore.type = dlf is no longer supported`. Replace these
obsolete success scenarios with an explicit rejection check using
minimal properties, without cloud credentials. Keep the complete
supported HMS storage/authentication matrix.
- `test_paimon_write_thread_lifecycle` compares the minimum of its first
two phases with the minimum of its final two. A process-thread series
such as `[100, 121, 121, 121]` therefore fails despite reaching a
plateau. Require a three-phase stable warm-up window, with at most six
warm-up phases, then freeze its low-water baseline and run six further
equal-work phases. Compare the final two low-water marks against that
fixed baseline, retaining JVM +2/process +4 tolerances. This also
rejects sustained growth of one thread per phase starting only after
warm-up while tolerating one isolated background spike.
The row-count assertion follows the actual number of disjoint INSERT
batches. The thread suite now performs 108–144 INSERT statements instead
of 60; this additional measurement budget is intentional. Process-wide
background activity can still affect its counters.
### Validation
- Executed the actual Groovy thread suite through a local replay harness
with mocked SQL/HTTP/metric boundaries: 12/12 scenarios passed,
including the observed plateau, steady and delayed slow leaks, a single
leaking backend, late stabilization, and sampling spikes.
- Compiled the complete Hive script and replayed its new negative-test
DSL; independently checked that removed-metastore validation precedes
missing-URI validation.
- Verified the supported HMS invocation matrix is unchanged; `git diff
--check` passed.
- Live external HMS/Paimon end-to-end runs remain for CI. Replay
validates test logic, not live writer behavior.
### Release note
None. Regression tests only.
### Check List (For Author)
- [x] Regression test changes
- [x] Manual test: Groovy script replay described above
- [x] No product behavior change
- [x] No documentation needed
---
.../test_paimon_write_thread_lifecycle.groovy | 84 +++++++++++++---------
.../hive_on_hms_and_dlf.groovy | 52 ++++----------
2 files changed, 64 insertions(+), 72 deletions(-)
diff --git
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_thread_lifecycle.groovy
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_thread_lifecycle.groovy
index 420f53cd18b..daa60ccefcb 100644
---
a/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_thread_lifecycle.groovy
+++
b/regression-test/suites/external_table_p0/paimon/write/test_paimon_write_thread_lifecycle.groovy
@@ -95,57 +95,73 @@ suite("test_paimon_write_thread_lifecycle",
"p0,external,paimon,nonConcurrent")
sql """use ${dbName}"""
try {
- // Warm common writer and metrics paths before measuring
phase-to-phase growth. The
- // blocking scheduler may still assign later writes to native workers
that have not entered
- // the JVM yet, so a bounded one-time increase after warm-up is not
evidence of a leak.
- for (int round = 0; round < 12; round++) {
- sql """
- INSERT INTO t_thread_lifecycle
- SELECT number + ${round * 1000}, repeat('w', 32)
- FROM numbers("number" = "1000")
- """
- }
- sleep(3000)
-
- def writePhase = { int firstRound ->
- for (int round = firstRound; round < firstRound + 12; round++) {
+ def jvmPhases = []
+ def processPhases = []
+ int nextRound = 0
+ def writeAndSamplePhase = {
+ for (int round = nextRound; round < nextRound + 12; round++) {
sql """
INSERT INTO t_thread_lifecycle
SELECT number + ${round * 1000}, repeat('x', 32)
FROM numbers("number" = "1000")
"""
}
- }
-
- def jvmPhases = []
- def processPhases = []
- for (int phase = 0; phase < 4; phase++) {
- writePhase(12 + phase * 12)
+ nextRound += 12
sleep(5000)
jvmPhases.add(minimumThreadCounts(jvmThreadCounts))
processPhases.add(minimumThreadCounts(processThreadCounts))
- logger.info("Paimon thread phase ${phase + 1}:
jvm=${jvmPhases[-1]}, "
+ logger.info("Paimon thread phase ${jvmPhases.size()}:
jvm=${jvmPhases[-1]}, "
+ "process=${processPhases[-1]}")
}
- assertEquals(60000L,
+ // Native workers can initialize after the first writes. Require a
stable window instead
+ // of treating a single increase followed by a plateau as a
continuously leaking writer.
+ def stableWindow = { phases, long tolerance ->
+ backendEndpoints.keySet().every { backendId ->
+ def counts = phases.takeRight(3).collect { sample ->
sample[backendId] as long }
+ counts.max() - counts.min() <= tolerance
+ }
+ }
+ boolean warmedUp = false
+ for (int phase = 0; phase < 6; phase++) {
+ writeAndSamplePhase()
+ if (jvmPhases.size() >= 3 && stableWindow(jvmPhases, 2L)
+ && stableWindow(processPhases, 4L)) {
+ warmedUp = true
+ break
+ }
+ }
+ assertTrue(warmedUp, "Thread counts did not stabilize during bounded
warm-up: "
+ + "jvm=${jvmPhases}, process=${processPhases}")
+
+ int warmupPhases = jvmPhases.size()
+ def baseline = { phases ->
+ backendEndpoints.keySet().collectEntries { backendId ->
+ [(backendId): phases.takeRight(3).collect { sample ->
sample[backendId] as long }.min()]
+ }
+ }
+ def jvmBaseline = baseline(jvmPhases)
+ def processBaseline = baseline(processPhases)
+ // Freeze the low-water marks before additional writes. Moving the
baseline on each phase
+ // would hide slow, persistent leaks that fit within the per-window
sampling tolerance.
+ for (int phase = 0; phase < 6; phase++) {
+ writeAndSamplePhase()
+ }
+
+ assertEquals(nextRound * 1000L,
(sql """SELECT COUNT(*) FROM t_thread_lifecycle""")[0][0] as
long)
+ // Use the final two low-water marks to tolerate one isolated
background-thread spike.
+ // Six validation phases also expose one new process thread per phase
starting after warm-up.
backendEndpoints.keySet().each { backendId ->
- // Judge persistent growth between equal measured phases.
Comparing the early and late
- // low-water marks allows a bounded worker-pool warm-up or an
isolated background-thread
- // spike, while a leaked thread cannot disappear in a later phase.
def jvmCounts = jvmPhases.collect { sample -> sample[backendId] as
long }
def processCounts = processPhases.collect { sample ->
sample[backendId] as long }
- def earlyJvmFloor = jvmCounts.take(2).min()
- def lateJvmFloor = jvmCounts.drop(2).min()
- def earlyProcessFloor = processCounts.take(2).min()
- def lateProcessFloor = processCounts.drop(2).min()
-
- assertTrue(lateJvmFloor <= earlyJvmFloor + 2,
- "JVM threads kept growing on backend ${backendId}:
phases=${jvmCounts}")
- assertTrue(lateProcessFloor <= earlyProcessFloor + 4,
- "Process threads kept growing on backend ${backendId}:
phases=${processCounts}")
+ assertTrue(jvmCounts.drop(warmupPhases).takeRight(2).min() <=
jvmBaseline[backendId] + 2,
+ "JVM threads grew after warm-up on backend ${backendId}: "
+ + "baseline=${jvmBaseline[backendId]},
phases=${jvmCounts}")
+ assertTrue(processCounts.drop(warmupPhases).takeRight(2).min() <=
processBaseline[backendId] + 4,
+ "Process threads grew after warm-up on backend
${backendId}: "
+ + "baseline=${processBaseline[backendId]},
phases=${processCounts}")
}
} finally {
sql """drop catalog if exists ${catalogName}"""
diff --git
a/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
b/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
index 9fddd9ba979..94cfa991ffe 100644
---
a/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
+++
b/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
@@ -19,6 +19,20 @@ import java.util.concurrent.ThreadLocalRandom
suite("hive_on_hms_and_dlf", "p2,external") {
+ // DLF 1.0 is no longer an HMS metastore. Check its explicit rejection
without cloud
+ // credentials, while retaining the HMS storage and authentication matrix
below.
+ sql """DROP CATALOG IF EXISTS hive_dlf_unsupported_catalog"""
+ test {
+ sql """
+ CREATE CATALOG hive_dlf_unsupported_catalog PROPERTIES (
+ 'type' = 'hms',
+ 'hive.metastore.type' = 'dlf'
+ )
+ """
+ exception "hive.metastore.type = dlf is no longer supported: " +
+ "Alibaba Cloud DLF 1.0 as an HMS thrift metastore has been
removed. Supported types: hms."
+ }
+
// Keep generated identifiers under the FE 64-character limit for long
prefixes.
def buildDbName = { String prefix ->
def suffix = String.format("_db%d%03d", System.currentTimeMillis(),
ThreadLocalRandom.current().nextInt(1000))
@@ -501,17 +515,6 @@ suite("hive_on_hms_and_dlf", "p2,external") {
"hdfs.authentication.kerberos.keytab" =
"${keytab_root_dir}/hive-presto-master.keytab"
"""
- String dlf_access_key = context.config.otherConfigs.get("dlf_access_key")
- String dlf_secret_key = context.config.otherConfigs.get("dlf_secret_key")
- /**************** DLF *******************/
-
- String dlf_oss_properties = """
- "oss.endpoint" = "${oss_endpoint}",
- "oss.access_key" = "${dlf_access_key}",
- "oss.secret_key" = "${dlf_secret_key}",
- """
-
-
String hms_kerberos_old_prop = """
"hive.metastore.uris" = "thrift://${externalEnvIp}:9583",
"hadoop.security.authentication" = "kerberos",
@@ -626,31 +629,4 @@ suite("hive_on_hms_and_dlf", "p2,external") {
testQueryAndInsert(hms_type_properties + hms_kerberos_new_prop +
hdfs_kerberos_properties, "hive_hms_hdfs_kerberos_test", db_location)
testQueryAndInsert(hms_type_properties + hms_kerberos_new_prop +
hdfs_new_kerberos_properties, "hive_hms_hdfs_new_kerberos_test", db_location)
-
- /**************** DLF *******************/
- String dlf_warehouse =
"oss://selectdb-qa-datalake-test/hive-dlf-oss-warehouse"
- String hive_dlf_catalog_base_properties = """
- 'type'='hms',
- 'hive.metastore.type'='dlf',
- "dlf.uid" = "203225413946383283",
- "dlf.catalog.id" = "p2_regression_case",
- "dlf.access_key" = "${dlf_access_key}",
- "dlf.secret_key" = "${dlf_secret_key}"
- """
- String dlf_region = "cn-beijing"
- String dlf_region_param = """
- "dlf.region" = "${dlf_region}",
- """
- String dlf_endpoint = context.config.otherConfigs.get("dlf_endpoint")
- String dlf_endpoint_properties = """
- "dlf.endpoint" = "${dlf_endpoint}",
- """
- db_location = "${dlf_warehouse}/hive/dlf-oss/" + System.currentTimeMillis()
- testQueryAndInsert(dlf_region_param + hive_dlf_catalog_base_properties,
"hive_dlf_oss_test", db_location)
- db_location = "${dlf_warehouse}/hive/dlf-oss/" + System.currentTimeMillis()
- testQueryAndInsert(dlf_region_param + dlf_oss_properties +
hive_dlf_catalog_base_properties, "hive_dlf_oss_test_with_oss", db_location)
-
- // not has region param
- db_location = "${dlf_warehouse}/hive/dlf-oss/" + System.currentTimeMillis()
- testQueryAndInsert(dlf_endpoint_properties +
hive_dlf_catalog_base_properties, "hive_dlf_oss_test", db_location)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]