Skip to content

[improvement](fe) Stop fe-common depending on Hadoop and pin fe-core's hidden Hadoop passengers - #67770

Open
morningman wants to merge 19 commits into
apache:masterfrom
morningman:fe-drop-hadoop-from-core-common
Open

morningman wants to merge 19 commits into
apache:masterfrom
morningman:fe-drop-hadoop-from-core-common

Conversation

@morningman

@morningman morningman commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #66770

Problem Summary:

Groundwork for an FE kernel that ships no Hadoop classes at all — the end state
ConnectorPluginManager already names in its parent-first comment ("the intended end state is
an FE kernel with no hadoop classes at all, every plugin bringing its own"), and the one the
authorization plugin family already reached: org.apache.hadoop. is child-first there and the
Ranger plugins bundle their own Hadoop.

Nothing is removed from fe/lib here. This PR only makes the remaining coupling honest, so
that the step which does remove it cannot silently take unrelated libraries with it.

1. fe-common stops depending on Hadoop

fe-common declared hadoop-common (provided) and hadoop-aws while not naming a single Hadoop
class — the module has zero org.apache.hadoop references in source, only two configuration-key
strings in Config.

Dropping them exposed one real user: Hll uses org.apache.commons.codec.binary.StringUtils and
had been riding on hadoop-common's commons-codec. That is now declared where it is used (the
version is already managed in fe/pom.xml, and fe-core has long declared the same artifact).

hadoop-aws was compile scope, so it also stops being re-exported to fe-type, fe-catalog,
hive-udf and the BE's java-udf plugin — none of which reference org.apache.hadoop.fs.s3a
either. There is no import org.apache.hadoop.fs.s3a... anywhere in the repository; every mention
is a configuration-value string such as "org.apache.hadoop.fs.s3a.S3AFileSystem", produced by
filesystem plugins that declare hadoop-aws themselves. fe-core is unaffected: it declares
hadoop-aws directly.

The java-udf plugin is the one consumer whose closure is checked by name
(tools/be-java-plugins/check_plugin_layout.py), and it excluded hadoop-aws from fe-common
explicitly; that exclusion is now dead and goes. In its place the plugin excludes commons-codec:
the layout check records that jar as deliberately absent from java-udf — fe-common's only user of
it, Hll, is on no BE path — and it used to be absent for free, because hadoop-common's provided
scope never re-exported it. With fe-common declaring it, the plugin has to say so, or the jar
walks in. Its plugin directory is unchanged as a result.

2. fe-core's hidden Hadoop passengers are declared

fe-core likewise names no Hadoop class in src/main — its six org.apache.hadoop occurrences are
comments and the two parent-first prefix lists. But two libraries it compiles against directly
reach it only as Hadoop transitives:

Library Arrives via Used by
io.dropwizard.metrics:metrics-core (com.codahale.metrics) hadoop-auth the whole metric layer: MetricRepo, every MetricVisitor, HistogramMetric, CloudMetrics, SqlBlockRule
org.bouncycastle:bcprov-jdk18on (org.bouncycastle.util) hadoop-common TableScanParams

Both are now declared in fe-core. They are already on this classpath at these versions, so no jar
is added to fe/lib; the point is that the FE metric layer should not be a passenger of a
dependency that says nothing about it.

3. The Hadoop auth property names move to fe-foundation

fe-core read three property names from org.apache.doris.kerberos.AuthenticationConfig, a class
that imports org.apache.hadoop.conf.Configuration. The names are plain strings; the code that
turns them into a UserGroupInformation is what needs Hadoop.

They move to a new hadoop-free holder, org.apache.doris.foundation.security.HadoopAuthConfigKeys.
AuthenticationConfig re-exports every constant declared there, so both spellings name the same
property and no existing caller changes meaning.

This is not only a compile-time tidy-up. The old copies were public static String — not
compile-time constants — so reading one emitted a getstatic, and initialising
HdfsStorageVault.PropertyKey or running HdfsResource.generateHdfsParam loaded
AuthenticationConfig, and with it Hadoop's Configuration, just to obtain a string. They no
longer do. fe-core keeps its fe-kerberos dependency for ExecutionAuthenticator, which is
hadoop-free.

Release note

None

Check List (For Author)

  • Test

    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.

    Verification performed:

    • build.sh --fe — all 83 modules build, be-java-extensions included; fe-core's 4476 main
      sources compile with 0 Checkstyle violations in every module.
    • The BE's java-udf plugin directory keeps exactly its 27 jars, and
      tools/be-java-plugins/check_plugin_layout.py passes on all eight BE plugins — the one
      fe-common consumer left on the BE side loses nothing it uses.
    • mvn -pl fe-core dependency:list -DincludeScope=runtime is byte-for-byte identical before
      and after this change — 395 artifacts — so fe/lib does not change. fe-common, fe-type and
      fe-catalog lose hadoop-aws and its two transitives (wildfly-openssl,
      analyticsaccelerator-s3) and gain commons-codec.
    • No dependency is new to the build: all three declared artifacts already resolve into it today
      as transitives, at the same versions.
  • Behavior changed:

    • No.
  • Does this need documentation?

    • No.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

🤖 Generated with Claude Code

https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@morningman
morningman force-pushed the fe-drop-hadoop-from-core-common branch from 2de0320 to 5b5d21a Compare September 10, 2026 09:18
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact head 5b5d21a07fd030ecad1500ba346d10d496372cec. Six PR-local findings are inline. Existing review threads were empty; two real but pre-existing plugin-boundary defects were excluded after authoritative-base comparison.

Checkpoint conclusions:

  • Goal and proof: the dependency/authenticator decoupling is otherwise coherent, but the new architecture guard is incomplete, the shared-layer groundwork violates two of its own contracts, and the required dependency-review check fails. The shared bundle is deliberately not wired, so its 29 jars add distribution cost without delivering the class-identity benefit yet.
  • Scope and clarity: direct dependency declarations, auth-key relocation, and dead pre-auth pool removal are focused; always packaging the unused bundle is not.
  • Concurrency: ConcurrentHashMap.computeIfAbsent makes creation atomic and no new thread/lock ordering problem was found, but lexical path identity can still create two loaders for one physical root.
  • Lifecycle: the shared loader's process lifetime is intentional; caching an erroneous no-op result after suppressed attribute failures makes that lifetime harmful. Catalog authenticator reset/close behavior remains consistent.
  • Configuration: no user-facing configuration or dynamic-setting semantics were added. The shared directory is an implicit packaged path.
  • Compatibility and rolling behavior: auth-key values and connector/filesystem SPI behavior are preserved. ExternalCatalog's return descriptor changes interface owner, but all actual consumers are internal/recompiled and supported plugins do not link fe-core. No storage, wire, or rolling-upgrade format change was found.
  • Parallel paths and conditions: filesystem, connector, authorization, lineage, Kerberos/simple-auth, Maven profiles, bundle ordering, and reused-output cleanup were traced. No additional PR-local defect survived.
  • Tests and results: the new tests cover eager linkage and basic loader ordering, but omit reflective dotted dependencies, physical aliases, permission failures, and retry-form initializer diagnostics. No local build/test was run because this review task forbids builds. Live CI has CheckStyle, formatter, repository license, secrets, and large-file checks passing; dependency-review fails on bcprov; FE UT and compile remain pending at review time.
  • Observability: load summaries are adequate, but the new missing-class parser can emit a false class name and bundle recommendation.
  • Persistence, data writes, and FE/BE variables: no EditLog/storage-format/data-write/transaction or FE-BE variable path changes.
  • Performance: the unused 29-jar bundle is installed into every FE output while all existing copies remain.
  • Security: SECURITY.md and the threat model were applied because authentication code changed. Admin-installed plugin code is trusted in this model, and no in-scope security vulnerability was found.

All three convergence lanes returned NO_NEW_VALUABLE_FINDINGS in the final allowed round. Review status: complete for this head, changes requested.

Comment thread build.sh
rm -rf "${SHARED_LIB_DIR}/hadoop/lib"
rm -f "${SHARED_LIB_DIR}/hadoop"/*.jar
mkdir -p "${SHARED_LIB_DIR}/hadoop"
unzip -q -o "${HADOOP_RUNTIME_ZIP}" -d "${SHARED_LIB_DIR}/hadoop/"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Avoid shipping the shared bundle before it has a consumer

On this head, SharedLibraryLayer.resolve() has no production call site. ConnectorPluginManager and FileSystemPluginManager still pass their application classloader directly to DirectoryPluginRuntimeManager, and Env scans only plugins/connector and plugins/filesystem. This line therefore adds a 29-jar bundle to every FE output alongside the unchanged kernel/plugin copies, but no runtime path can use it. Please either wire the shared parent in this change, with a production-topology test, or defer building and unpacking the bundle until the consumer lands.

Comment thread fe/fe-core/pom.xml Outdated
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Account for this dependency in the required license check

The exact-head dependency-review job fails on this newly direct org.bouncycastle:bcprov-jdk18on dependency as LicenseRef-bad-non-standard. Doris already records Bouncy Castle under MIT in dist/licenses/LICENSE.bouncycastle.txt and dist/NOTICE-dist.txt, but .github/workflows/third_party_review.yml has no package-specific exception for this coordinate. Please add the narrow exception, or otherwise make the approved license metadata visible, so the required gate can pass.

if (root == null) {
return parent;
}
Path resolved = root.toAbsolutePath().normalize();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Canonicalize the physical root before memoizing

toAbsolutePath().normalize() removes lexical .. components but does not resolve symlinks. If one physical bundle root is reached through both a release symlink and its real path, the unequal keys each create a child-first loader over the same jars, producing duplicate Hadoop class identity and static state -- the exact condition this layer is meant to prevent. Canonicalize an existing root with toRealPath() before computeIfAbsent, preserving the documented I/O failure behavior, and add a symlink-alias identity test.

public class FeCoreHasNoHadoopClassesTest {

/** JVM internal form: how class references and descriptors are spelled in the constant pool. */
private static final List<String> FORBIDDEN = Arrays.asList(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Cover reflective dotted names in the Hadoop-free guard

This raw-byte scan rejects only JVM-internal slash names. A reflective target such as Class.forName("org.apache.hadoop.conf.Configuration") or loadClass("org.apache.doris.kerberos.AuthenticationConfig") is stored as a dotted CONSTANT_String, passes this test, and can then fail at runtime after those kernel jars disappear. fe-core already has reflective loading paths. Please reject the dotted prefixes too, narrowly allowlist the two legitimate parent-first policy owners, and add a reflective negative-control fixture.

/** The absent class named by a NoClassDefFoundError / ClassNotFoundException anywhere in the chain. */
private static String missingClassName(Throwable failure) {
for (Throwable t = failure; t != null; t = t.getCause() == t ? null : t.getCause()) {
if (t instanceof NoClassDefFoundError || t instanceof ClassNotFoundException) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not report initializer failures as a missing class named Could

After a class initializer has failed, a later JVM linkage attempt reports NoClassDefFoundError: Could not initialize class X. This branch accepts that error and line 562 returns its first whitespace token, so the new advice says that a class named Could is absent and recommends checking the shared bundle even though the class was found. Recognize the initialization-failure form before extracting a binary name, inspect the cause chain only for a genuine missing class, and add a two-attempt initializer test.

}

private static ClassLoader build(Path root, ClassLoader parent) {
if (!Files.isDirectory(root)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Preserve attribute I/O failures instead of caching an empty layer

Files.isDirectory and Files.isRegularFile return false when attributes cannot be read. A root that can be listed but whose children cannot be searched can therefore have every bundle entry silently filtered out; build() returns parent, and computeIfAbsent caches that false no-op for the process lifetime even after permissions are repaired. This contradicts the documented fail-loud behavior for an unreadable root. Use attribute reads that preserve IOException for the root, bundle, lib, and jar probes, wrap failures as documented, and add a permission-failure/non-memoization test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 44.44% (4/9) 🎉
Increment coverage report
Complete coverage report

@morningman
morningman force-pushed the fe-drop-hadoop-from-core-common branch from 5b5d21a to 058ab76 Compare September 10, 2026 13:03
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact head 058ab76a3d94d600e583adc9b1a5ba58fa393062. One new PR-local finding is inline. Existing review threads were treated as hard duplicate fences; the two additional loader gaps found during review were excluded after authoritative base/head comparison showed that they predate this PR.

Checkpoint conclusions:

  • Goal and proof: the dependency/authenticator decoupling, Hadoop-free bytecode guard, shared-layer implementation, and bundle construction are internally coherent, but the new bundle location breaks the accepted legacy dynamic-plugin name shared. The unit tests exercise classloading and linkage behavior, but no install/replay test covers this namespace interaction. The already-reported absence of a production shared-layer consumer remains fenced by discussion r3978332587.
  • Scope and clarity: most edits are focused groundwork for a Hadoop-free FE; placing shared runtime bundles directly inside the legacy dynamic-plugin namespace is the one scope boundary that is not isolated.
  • Concurrency: canonical-root ConcurrentHashMap.computeIfAbsent gives one shared loader per physical root, and directory-plugin lifecycle mutation remains under its existing lock. No new thread entry, lock-order problem, deadlock, or query-time contention was found.
  • Lifecycle and static initialization: shared loaders intentionally live for the FE process; represented plugin failures close or discard their per-plugin loaders. Authenticator initialization/reset/close remains coherent and the new direct authenticator is stateless. No cross-TU/static-order concern applies.
  • Configuration: no configuration item was added. The issue arises because the existing default Config.plugin_dir resolves to the same packaged fe/plugins parent used by this new directory.
  • Compatibility: auth-key literals and legacy re-export field descriptors are preserved, and supported connector SPI paths remain compatible. The newly occupied shared path is an incompatible change to the previously accepted dynamic-plugin name space. No wire or storage-format change was found.
  • Parallel paths: connector, filesystem, authorization, legacy dynamic-plugin install/replay/uninstall, catalog authentication, HDFS resource/vault, and Maven packaging paths were traced. The inline issue is distinct from the existing no-consumer thread; no other PR-introduced defect survived.
  • Conditional checks: archive extraction is correctly conditional on the zip, but plugins/shared is created before that condition, so the name collision occurs even when no archive exists. Other new conditions have clear failure semantics.
  • Test coverage: the new tests cover slash/dotted forbidden references, physical-root identity, jar precedence, attribute failures, and two linkage forms. They omit the legacy name=shared install/replay case and production shared-parent topology; the latter is already covered by the existing thread.
  • Test results: test assertions and changed expected behavior were inspected and are consistent; no result files changed. No local build or test was run because this review task explicitly forbids builds. Available exact-head dependency, license, and style checks were successful when inspected.
  • Observability: represented plugin load failures have staged summaries and causes; no new metric is required for this startup-only work. The namespace collision currently surfaces only as an install failure, which the requested compatibility fix/test should make explicit.
  • Transactions and persistence: no transaction or storage persistence format changes. Legacy plugin journal replay was traced and reinforces the same namespace collision.
  • Data writes: no database data-write path or atomicity behavior changes.
  • FE/BE variables: no new cross-process variable or Thrift propagation is introduced.
  • Performance: shared-layer discovery is startup-only and the cache avoids duplicate loaders. The redundant shipped bundle cost is already reported in the existing no-consumer thread; no separate performance finding remains.
  • Other issues and user focus: no additional user-provided focus was supplied. After two complete rounds, all normal and risk-focused reviewers returned NO_NEW_VALUABLE_FINDINGS; every candidate is accepted, duplicate-fenced, or dismissed with evidence. Review status: complete for this head, changes requested.

Comment thread build.sh
# a plugin, and would report this one as a plugin that failed to load.
# NOTE: plugins/shared/ is NOT added to the FE CLASSPATH - it is loaded by FE, not by the JVM
# launcher. See bin/start_fe.sh.
SHARED_LIB_DIR="${DORIS_OUTPUT}/fe/plugins/shared"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep shared bundles out of the dynamic-plugin name namespace

Config.plugin_dir defaults to this same fe/plugins directory, while PluginInfo.readFromProperties() accepts every nonempty name, including shared. DynamicPluginLoader.movePlugin() maps the descriptor name directly to pluginDir/shared and refuses an existing target. Because this hunk creates that directory unconditionally—even when the Hadoop zip is absent—a valid legacy plugin named shared can no longer be installed on the default layout. Please place shared bundles outside Config.plugin_dir/<plugin-name>, or add an explicit backward-compatible reservation/migration rule with install/replay coverage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — the unconditional mkdir is a fair catch and is fixed. The rest I'd like to push back on, with the evidence.

Fixed: the outer mkdir -p "${SHARED_LIB_DIR}" is gone. The mkdir -p "${SHARED_LIB_DIR}/hadoop" inside the if already builds the whole chain, so plugins/shared now exists only when there is a bundle to put in it; a build without the zip no longer occupies the name for nothing.

Not moving the directory out of Config.plugin_dir. Two reasons.

First, the name space this is said to break is already reserved nine times over, on master, by this same file. build.sh creates jdbc_drivers, adbc_drivers, java_udf, trino_plugins, hadoop_conf, java_extensions with an unconditional mkdir -p, and filesystem, connector, authorization from their deploy loops — all under ${DORIS_OUTPUT}/fe/plugins, which is what Config.plugin_dir resolves to. PluginInfo.readFromProperties() has never validated a name beyond non-empty, so a legacy plugin called connector or authorization is un-installable on master today, with the same error. This PR adds a tenth name to that set; it does not create the collision class. This review excluded two other findings for predating the PR, and by that standard this one is a pre-existing property of the packaged layout.

Second, the placement is deliberate and the comment on the hunk says why: DirectoryPluginRuntimeManager treats every direct subdirectory of plugins/filesystem and plugins/connector as a plugin, so a bundle under either would be reported as a plugin that failed to load. Moving it out of Config.plugin_dir means moving it out of plugins/ altogether, which costs the symmetry with the other nine reserved names.

One correction on the mechanism. movePlugin() is not reached on that path. PluginMgr.installPlugin() calls getPluginInfo() before install(), so pluginInfo is already set when install() runs its first check, and hasInstalled() (DynamicPluginLoader.java:108, :129-138) throws Plugin shared has already been installed. before movePlugin() is called. Same outcome, different line.

Where the real fix belongs. If the project wants this closed rather than documented, the fix is a reserved-name check in PluginInfo.readFromProperties() or PluginMgr.installPlugin() that rejects all ten packaged names with a message that says what actually happened, instead of the misleading "has already been installed". That repairs the nine cases already on master as well as this one, and it is a change to the legacy dynamic-plugin loader rather than to this PR's packaging — so it deserves its own PR and its own install/replay coverage, not a hunk here.

Worth recording while it is in view: for anyone who did have a legacy plugin named after one of these ten, UNINSTALL PLUGIN <name> would reach DynamicPluginLoader.uninstall() (:143-153) with installPath pointing at the packaged directory and delete it. The other two paths are safe — a failed fresh install deletes only the .install_* temp directory, and replayLoadDynamicPlugin() sets ERROR and rethrows without calling uninstall(). That hazard is identical for the nine names on master and is one more argument for fixing this in the loader.

@morningman
morningman force-pushed the fe-drop-hadoop-from-core-common branch from 058ab76 to dd9ca2c Compare September 10, 2026 15:02
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

1 similar comment
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman
morningman marked this pull request as draft September 11, 2026 05:53
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 17112 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit afc1c2e5d6d6e39471d19cdb048da4e7612e27f7, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17592	3053	3055	3053
q2	2117	266	230	230
q3	10208	922	530	530
q4	4680	257	208	208
q5	7661	560	399	399
q6	139	117	95	95
q7	556	527	403	403
q8	9229	876	953	876
q9	3500	2440	2394	2394
q10	6528	865	715	715
q11	392	204	183	183
q12	614	259	199	199
q13	18129	1545	1177	1177
q14	157	147	132	132
q15	q16	445	402	374	374
q17	1358	951	881	881
q18	3053	2278	2287	2278
q19	1116	913	774	774
q20	386	278	201	201
q21	5317	1778	1902	1778
q22	323	273	232	232
Total cold run time: 93500 ms
Total hot run time: 17112 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3405	3331	3326	3326
q2	501	385	392	385
q3	2246	2296	2200	2200
q4	1204	1178	929	929
q5	2203	2143	2160	2143
q6	170	125	89	89
q7	1057	894	854	854
q8	1611	1416	1414	1414
q9	3208	3137	3144	3137
q10	1913	1877	1696	1696
q11	361	268	253	253
q12	462	443	351	351
q13	1496	1585	1198	1198
q14	189	176	174	174
q15	q16	409	410	364	364
q17	3767	3442	3247	3247
q18	4932	4511	4996	4511
q19	964	861	850	850
q20	1006	982	837	837
q21	3884	3169	3178	3169
q22	415	349	311	311
Total cold run time: 35403 ms
Total hot run time: 31438 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 83307 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit afc1c2e5d6d6e39471d19cdb048da4e7612e27f7, data reload: false

query5	4268	416	324	324
query6	384	142	130	130
query7	4966	417	237	237
query8	293	126	128	126
query9	8695	2915	2910	2910
query10	382	211	204	204
query11	5380	1055	927	927
query12	132	74	68	68
query13	1203	427	348	348
query14	6125	2208	2126	2126
query14_1	1996	1989	1986	1986
query15	178	121	118	118
query16	915	387	355	355
query17	787	462	363	363
query18	2329	333	234	234
query19	168	137	107	107
query20	72	71	74	71
query21	200	102	89	89
query22	5472	5360	5346	5346
query23	6961	6347	6391	6347
query23_1	6349	6321	6374	6321
query24	7278	1085	785	785
query24_1	810	802	801	801
query25	425	297	255	255
query26	1226	244	129	129
query27	2769	410	251	251
query28	4714	1499	1484	1484
query29	929	431	373	373
query30	252	154	135	135
query31	825	413	343	343
query32	124	77	79	77
query33	465	223	193	193
query34	992	822	476	476
query35	391	407	351	351
query36	584	563	547	547
query37	117	79	76	76
query38	1007	862	821	821
query39	514	488	490	488
query39_1	488	480	467	467
query40	204	94	84	84
query41	59	58	57	57
query42	77	74	75	74
query43	243	247	216	216
query44	989	540	540	540
query45	115	108	113	108
query46	808	844	520	520
query47	770	763	710	710
query48	294	308	241	241
query49	546	253	230	230
query50	739	258	192	192
query51	8407	8148	8290	8148
query52	86	85	65	65
query53	200	200	153	153
query54	246	156	143	143
query55	76	61	58	58
query56	188	200	166	166
query57	700	681	670	670
query58	200	160	181	160
query59	1225	1237	1097	1097
query60	259	194	196	194
query61	118	128	137	128
query62	339	201	184	184
query63	177	142	150	142
query64	2741	687	577	577
query65	1678	1604	1615	1604
query66	1758	255	198	198
query67	9920	9814	9786	9786
query68	2992	1181	748	748
query69	362	231	204	204
query70	675	633	621	621
query71	256	187	172	172
query72	2339	1701	1509	1509
query73	659	607	354	354
query74	2015	1232	1147	1147
query75	1202	1108	993	993
query76	2390	731	521	521
query77	263	268	227	227
query78	3992	3645	3254	3254
query79	2839	801	569	569
query80	1558	314	278	278
query81	506	163	136	136
query82	625	120	95	95
query83	286	212	190	190
query84	292	110	88	88
query85	783	330	289	289
query86	474	172	160	160
query87	1023	970	907	907
query88	3076	2109	2115	2109
query89	284	203	180	180
query90	2099	130	130	130
query91	133	116	96	96
query92	98	72	72	72
query93	2250	1056	688	688
query94	649	276	184	184
query95	521	255	222	222
query96	829	573	279	279
query97	1075	1103	1021	1021
query98	177	142	134	134
query99	419	349	311	311
Total cold run time: 180933 ms
Total hot run time: 83307 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.76 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit afc1c2e5d6d6e39471d19cdb048da4e7612e27f7, data reload: false

query1	0.01	0.00	0.01
query2	0.08	0.04	0.04
query3	0.26	0.11	0.10
query4	1.60	0.10	0.10
query5	0.17	0.16	0.15
query6	1.26	0.69	0.68
query7	0.03	0.00	0.00
query8	0.04	0.03	0.03
query9	0.28	0.22	0.22
query10	0.34	0.36	0.35
query11	0.16	0.12	0.12
query12	0.15	0.12	0.12
query13	0.31	0.31	0.30
query14	0.45	0.44	0.46
query15	0.36	0.38	0.35
query16	0.24	0.22	0.22
query17	0.68	0.73	0.70
query18	0.19	0.16	0.17
query19	1.24	1.15	1.19
query20	0.01	0.00	0.00
query21	15.47	0.16	0.11
query22	5.08	0.04	0.04
query23	16.16	0.25	0.10
query24	2.99	0.32	0.23
query25	0.11	0.04	0.03
query26	0.75	0.17	0.12
query27	0.04	0.02	0.02
query28	3.62	0.60	0.28
query29	12.45	3.22	2.57
query30	0.25	0.12	0.12
query31	2.75	0.40	0.17
query32	3.49	0.32	0.22
query33	1.38	1.43	1.43
query34	15.33	2.24	1.82
query35	1.77	1.78	1.74
query36	0.46	0.31	0.30
query37	0.06	0.03	0.04
query38	0.04	0.03	0.03
query39	0.03	0.03	0.02
query40	0.12	0.08	0.08
query41	0.08	0.02	0.02
query42	0.04	0.02	0.02
query43	0.04	0.03	0.03
Total cold run time: 90.37 s
Total hot run time: 14.76 s

morningman and others added 5 commits September 15, 2026 17:56
…s hidden Hadoop passengers

Groundwork for an FE kernel that ships no Hadoop classes at all — the end state
`ConnectorPluginManager` already names in its parent-first comment. Nothing is removed
from `fe/lib` here; this PR only makes the remaining coupling honest, so that the step
that does remove it cannot silently take unrelated libraries with it.

fe-common declared `hadoop-common` (provided) and `hadoop-aws` while not naming a single
Hadoop class — the module has zero `org.apache.hadoop` references, only two configuration-key
strings in `Config`. Dropping them exposed `Hll`, which uses
`org.apache.commons.codec.binary.StringUtils` and had been riding on hadoop-common's
commons-codec; that is now declared where it is used. `hadoop-aws` was compile scope, so it
also stops being re-exported to fe-type, fe-catalog, hive-udf and the BE's java-udf plugin,
none of which reference `org.apache.hadoop.fs.s3a` either. fe-core is unaffected: it declares
hadoop-aws itself.

The BE's java-udf plugin is the one consumer whose closure is checked by name
(tools/be-java-plugins/check_plugin_layout.py), and it excluded `hadoop-aws` from fe-common
explicitly; that exclusion is now dead and goes. In its place the plugin excludes
`commons-codec`: the layout check records that jar as deliberately absent from java-udf —
fe-common's only user of it, `Hll`, is on no BE path — and it used to be absent for free,
because hadoop-common's provided scope never re-exported it. With fe-common declaring it,
the plugin has to say so, or the jar walks in. Its plugin directory is unchanged as a result.

fe-core likewise names no Hadoop class in main, but two libraries it compiles against reach it
only as Hadoop transitives:

  - metrics-core (`com.codahale.metrics`) via hadoop-auth — the entire metric layer is built on
    it: MetricRepo, every MetricVisitor, HistogramMetric, CloudMetrics, SqlBlockRule.
  - bcprov-jdk18on (`org.bouncycastle.util`) via hadoop-common — used by TableScanParams.

Both are now declared. They are already on the classpath at these versions, so no jar is added.

Finally, the three property names fe-core read from `AuthenticationConfig` — a fe-kerberos class
that imports `org.apache.hadoop.conf.Configuration` — move to a new hadoop-free holder in
fe-foundation, `HadoopAuthConfigKeys`. `AuthenticationConfig` re-exports every one of them, so
both spellings name the same property. The old copies were plain `public static String`, not
compile-time constants, so `HdfsStorageVault.PropertyKey` and `HdfsResource` loaded
`AuthenticationConfig` — and with it Hadoop's `Configuration` — to read a string; they no longer
do. fe-core keeps its fe-kerberos dependency for `ExecutionAuthenticator`, which is hadoop-free.

Verified: `build.sh --fe` builds all 83 modules, be-java-extensions included, with fe-core's
4476 main sources compiling and 0 Checkstyle violations anywhere. `dependency:list
-DincludeScope=runtime` for fe-core is byte-for-byte identical before and after — 395
artifacts — so `fe/lib` does not change. fe-common, fe-type and fe-catalog lose hadoop-aws and
its two transitives (wildfly-openssl, analyticsaccelerator-s3) and gain commons-codec. The
java-udf plugin directory keeps exactly its 27 jars, and check_plugin_layout.py passes on all
eight BE plugins.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4
Two comments in the FE kernel say why the 12.6 MB hive-exec:core jar sits in
fe/lib, and both stop one step short of the truth. The pom's says the jar exists
for CreateFunctionCommand, which validates a user JAVA_UDF jar by deriving its
symbol class and so needs org.apache.hadoop.hive.ql.exec.UDF on the FE app
classloader. ConnectorPluginManager's says that org.apache.hadoop.hive.* still
comes from the plugins because "FE carries hive-exec:core, the plugins carry
hive-metastore, and the class names do not intersect".

For three of the four plugins that reference hive-exec classes the intersection
really is empty, and the reason is the opposite of what that reads like: paimon,
hive and iceberg bundle no hive-exec class at all, so every
org.apache.hadoop.hive.ql.* reference they carry resolves to the kernel's copy.
The fourth, hudi, bundles one subset - fe-connector-hudi unpacks hive-exec's
ql/io/parquet/** (156 classes) into its own jar for the mapred/mapreduce
hierarchy its pom explains - which the parent-first prefix shadows with the
kernel's copy today, and which itself reaches a further 33 classes only the
kernel has. Measured over the built plugin zips as referenced-minus-self-carried,
cut against hive-exec:core's class list: paimon 15 classes (paimon-hive's
PaimonStorageHandler implements ql.metadata.HiveStorageHandler, HiveCatalog
.createView calls ql.metadata.Table.getEmptyTable, HiveUtils uses ql.io.sarg
.ConvertAstToSearchArg), hudi 46 (hudi-hadoop-mr reaches 25 - HoodieCombineHive
InputFormat's ql.io.HiveInputFormat, CombineHiveRecordReader and IOContextMap, the
ORC branch of HoodieInputFormatUtils, the ql.plan descriptors - and the unpacked
parquet subset 33 - ql.exec.Utilities, ql.io.HiveFileFormatUtils, ql.exec.vector.*,
llap.LlapCacheAwareFs; so carrying that subset made the plugin depend on more of
the jar, not less), hive and iceberg 3 each (the bundled Aliyun DLF metastore
client calls ql.session.SessionState.get()).

So narrowing fe/lib to be-java-extensions/hive-udf-shade, which carries 10 of
those classes, compiles green and fails at runtime on those paths - the same
shape as the hive-catalog-shade removal the pom comment already recounts. That
is a prerequisite ordering worth writing down: the plugins have to become
self-sufficient first. Note also that dropping the org.apache.hadoop. parent-first
prefix would not change any of this, since it changes the delegation order and
not the reachability - a plugin classloader that misses falls through to the app
classloader either way.

Comments only; no dependency, code or packaging change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4
…against Hadoop

fe-kerberos is a 15-class module that splits cleanly in two: an 8-class Hadoop
half (UserGroupInformation logins, AuthenticationConfig(Configuration),
HadoopAuthenticator and friends) and a Hadoop-free remainder. fe-core used
exactly one type out of it - ExecutionAuthenticator, which the module's own
javadoc calls a migration bridge over the fe-foundation interface of the same
name - and always with the passthrough implementation: no fe-core code path runs
inside a Kerberos context. The Hadoop half is used only by the hive, hudi,
iceberg and paimon connector plugins, each of which declares fe-kerberos itself.

Depending on it from fe-core put those 8 classes in fe/lib, where they can never
link, since the FE kernel does not ship the Hadoop they reference. Lazy
resolution keeps that harmless today, and it leaves a compiles-green,
fails-at-runtime path open: a future caller picking an overload whose signature
mentions no Hadoop type gets past javac on the strength of fe-kerberos.jar being
on the classpath, and only then hits NoClassDefFoundError on
org/apache/hadoop/security/UserGroupInformation.

So fe-core now takes ExecutionAuthenticator straight from fe-foundation
(org.apache.doris.foundation.security) and drops the dependency. The two
anonymous empty implementations become ExecutionAuthenticator.DIRECT, the
constant fe-foundation provides for exactly this - the foundation interface
leaves execute(Callable) abstract rather than defaulting it to a passthrough.
The change is source-compatible for callers (both interfaces have the same
execute(Callable)/execute(Runnable) shape, and the two call sites just run a
lambda) and carries no metadata risk: ExternalCatalog.executionAuthenticator has
no @SerializedName, so HiddenAnnotationExclusionStrategy keeps it out of
persistence entirely.

Also removes what the dependency was masking: ThreadPoolManager's three
*WithPreAuth members and ExternalCatalog.threadPoolWithPreAuth, its shutdown and
its getter. The field never had an assignment anywhere in the repo and the
methods had no callers - dead since the connectors were pluginised.

FeCoreHasNoHadoopClassesTest is the new guard, and the reason this is worth a
commit rather than a cleanup. It scans fe-core's own compiled output and fails on
a constant-pool reference to org/apache/hadoop/ or org/apache/doris/kerberos/,
which is the form a dependency actually takes - it catches the reference no
import reveals, such as an inherited supertype or a type that appears only in a
descriptor. It matches the JVM internal spelling only, since
ConnectorPluginManager and FileSystemPluginManager legitimately hold
"org.apache.hadoop." as a parent-first classloader-policy string. Two assertions
keep it from passing vacuously: it must scan more than a thousand classes, and it
must find a positive control. Verified in both directions - green today (0
offenders in 6176 classes), red with the exact class named when a probe holding a
new org.apache.hadoop.conf.Configuration() is compiled into fe-core.

fe/lib loses fe-kerberos.jar; the four connector plugin zips still carry it, as
they declare it directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4
…ing dependency from killing FE startup

Some libraries cannot be bundled per plugin. A library whose classes inherit from
one another across jars has to be loaded once or the JVM refuses the link; one
that holds process-wide static state - a client cache, a login context, a
first-caller-wins registry - has to be loaded once or two plugins silently stop
sharing it; one with a JNI native image can only bind to a single classloader per
process. Hadoop is all three at once, which is why the FE kernel currently ships
it and both plugin managers list org.apache.hadoop. as parent-first: giving each
plugin its own copy is not the same thing duplicated, it is a behavior change.

SharedLibraryLayer is where such a library goes instead of the kernel. It turns a
root of bundle directories into one classloader that becomes the PARENT of every
plugin classloader, so plugins reach it by the ordinary child-first fallback and a
plugin carrying its own copy keeps using that one. The layout is the plugin
directory convention - <root>/<bundle>/*.jar then <root>/<bundle>/lib/*.jar,
bundles by name - which is also how a bundle ships a patched class that also
exists in one of its dependency jars: patch in the bundle root, stock jar under
lib/. The layer is memoized on the resolved root, which is the point of the class
rather than an optimization: two layers over the same jars would mean two copies
of every class in them, the exact situation it exists to prevent. A root that does
not exist or holds no jar returns the parent unchanged, so a deployment that
installs no bundle keeps the classloader graph it has today. A root that exists
but cannot be read is raised instead, because degrading that to "nothing
installed" turns a permissions mistake into a missing-class failure much later and
somewhere else.

Nothing calls resolve() yet - this commit adds the mechanism and its tests only,
and no existing behavior changes.

The second half is the gap that mechanism opens. Once a plugin can expect a
dependency from a layer rather than from its own jars, "plugin installed, bundle
not" becomes a reachable state, and the JVM reports it as NoClassDefFoundError -
an Error, not a ReflectiveOperationException. DirectoryPluginRuntimeManager caught
only the latter at the two points where it touches plugin bytecode, so the Error
walked out of loadAll, out of initXxxPluginManager, and took FE startup with it.
One uninstalled bundle must cost the plugins that need it, not the FE. Both catch
sites now include LinkageError, matching what factory.name() and
factory.description() already do a few lines below, and the failure message names
the class that was missing and says where a dependency is expected to come from -
a bundle that was never installed otherwise looks exactly like a broken plugin jar.

The two failures land one step apart and both are covered: an absent supertype
fails while the class is being resolved, an absent class reached from a static
initializer fails at first initialization. The tests reproduce the real
reachability rather than simulating it - the fabricated jar omits the dependency
and the parent classloader refuses it - and both go red, with the
NoClassDefFoundError escaping loadAll, if either catch is narrowed back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4
…plugins

Nine FE plugins need Hadoop and today each carries its own copy: 175MB across
the plugin zips, nine independent FileSystem.CACHEs, nine UserGroupInformation
logins, and a jindo native image that can only bind to one classloader per
process. SharedLibraryLayer already knows how to load one such bundle for all of
them; this is the bundle.

fe-hadoop-runtime has no sources. It exists so the bundle has one dependency
resolution and one artifact list, which is what turns "every plugin gets the same
Hadoop" from a coincidence of nine poms agreeing into something checkable. It
resolves what fe-filesystem-hdfs-base resolves - hadoop-client and hadoop-auth
with the same exclusions, plus hadoop-common directly, since hadoop-client is the
slim client POM and prunes com.jcraft:jsch, which the connector plugins ship
today - and its versions come from the parent's dependencyManagement, so bundle
and plugins cannot drift.

Membership is an allowlist, not the resolved closure, and the two boundaries are
in the assembly descriptor at length. What must be shared: classes that inherit
across jars, plus the process-wide state that is what "two plugins talk to one
cluster" actually means; hadoop-hdfs-client is in because hdfs:// resolves
through META-INF/services rather than a fs.hdfs.impl entry, and the patched
FileSystem scans those with its own loader. What must not be: anything reachable
through fs.<scheme>.impl stays with the plugin that configures it, hadoop-aws
above all, because the filesystem plugins take software.amazon.awssdk parent-first
from fe/lib on purpose. General libraries - jackson, guava, netty, commons-* -
stay out because fe/lib already has them at the version fe-core arbitrated and
the layer falls back there; a second copy is how a shared layer starts answering
with different versions than the kernel.

The bundle produced here is exactly the set the nine plugins carry today: 28 jars
in lib/, same filenames, therefore same versions, plus hadoop-deps.jar at the
root, where the layer's root-before-lib ordering makes the Doris-patched
FileSystem win over hadoop-common's. An allowlist fails silently when it is too
narrow, so the module asserts the shape it produced: the patched jar is at the
root, Hadoop made it into lib/, and nothing Doris-owned did.

Nothing reads the bundle yet. build.sh unpacks it to fe/plugins/shared/hadoop/
and stops there - plugins/shared/ is not on the FE CLASSPATH and no plugin
manager scans it, so this release ships the bundle alongside the kernel's Hadoop
rather than instead of it. Verified by starting an FE on the built output: 14
filesystem plugins, 9 connector plugins and 2 authorization plugins load with
zero failures, and not one log line mentions the new directory.

fe-hadoop-runtime has to be named in build.sh's module list explicitly: nothing
depends on it, so -am does not reach it, and a module that is never built leaves
the deploy step silently unpacking whatever zip an older build left behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYs8EpL1D6bjufhYSt3mC4
@morningman
morningman force-pushed the fe-drop-hadoop-from-core-common branch from afc1c2e to b9fc9a8 Compare September 15, 2026 10:12
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman
morningman marked this pull request as ready for review September 15, 2026 10:44
@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 50.00% (5/10) 🎉
Increment coverage report
Complete coverage report

morningman and others added 3 commits September 15, 2026 21:49
…names, and carry the cause into the failure message

Review of the loader change in this branch found four defects in what a plugin
that fails to link leaves behind.

The cause-chain walk in missingClassName had no bound: the `t.getCause() == t`
guard is dead against java.lang.Throwable (getCause() already returns null for a
self-cause), and a two-node cycle is legal Java - a.initCause(b) after b was built
with cause a. A plugin constructor throwing such a chain spun FE startup forever
under the loader's lifecycle lock, before any port was open. The walk is now
identity-bounded, in both the advice and the new cause summary.

The walk read the first whitespace token of any NoClassDefFoundError or
ClassNotFoundException message as the class name. Plugin code wraps lookups in
sentences ("Cannot load driver class com.x.Y" advertised a missing class named
"Cannot"), and the JVM's own "a/B (wrong name: c/D)" form means the class WAS
found under the wrong jar path - a broken jar, for which the shared bundle is
exactly the wrong place to send the reader. Only a message that is one class name
in the binary or internal spelling is read as a miss; a sentence-shaped node is
skipped in favour of the JDK's own node below it; the wrong-name form gets its
own sentence.

For every LinkageError that is not a missing class - a static initializer
throwing IllegalStateException, a VerifyError - the failure message carried
nothing: ExceptionInInitializerError's message is null, so a consumer recording
the message alone (the authorization manager's rejection list, any log line that
consumed the throwable through a placeholder) recorded a bare class name. The
innermost cause is now appended to the LoadFailure message.

Both catch sites caught ReflectiveOperationException | LinkageError while their
comment appealed to factory.name()'s RuntimeException | LinkageError precedent.
asSubclass() throws ClassCastException for a service file naming a class that is
not a factory, and defineClass throws SecurityException for a signed package the
plugin also ships unsigned classes into; neither was caught, so the classloader
leaked and the exception reached FE startup. Both sites now catch RuntimeException
too, and the ClassCastException case names the factory type that was expected.

The comments that described <clinit> failures as always arriving as
ExceptionInInitializerError, and the "Could not initialize class" wording as
unreachable from loadAll, said what JDK 17 does not do: an Error thrown by an
initializer propagates unwrapped (JLS 12.4.2), and the second-attempt wording is
reachable through a parent-first class whose initializer failed under an earlier
plugin. Both are reworded; the catch shape they justify is unchanged.

Tests: a cyclic chain is walked once (under a timeout, so a regression hangs the
test rather than the suite); an initializer that throws a plain exception yields a
failure whose message carries the reason; a service file naming a non-factory
class is a load failure, not a throw; the sentence-shaped, trailing-dot and
wrong-name messages are negative controls, with the JDK node below a sentence
still found.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nagers' first calls into plugin code

Once a plugin that fails to link is skipped instead of taking FE startup down,
the record of why it was skipped is all the operator has. The three managers
that consume the loader's report logged each failure as
"message={}, cause={}" - four placeholders for four arguments, which log4j
renders with the throwable's toString() and no stack trace; for an
ExceptionInInitializerError that is the bare class name. The summary line
stayed at INFO. Each failure is now logged with three placeholders and the
throwable trailing, so the trace is printed (the shape the loader's README
prescribes and FileSystemPluginManager already used for its post-load call),
and the two shipped families - connector and filesystem - log the summary at
ERROR when any plugin failed, because an FE serving without a shipped plugin
is an FE serving degraded.

The loader's widened catch stops at the loader. The connector manager's first
calls into a loaded plugin - getType() and acceptedCreateTableEngineNames() -
ran with no guard, and the lineage manager ran factory.create() and
plugin.initialize() inside catch (Exception): a NoClassDefFoundError there,
one step after loadAll returned, still escaped to Env.initialize and exited
the FE. Both now catch RuntimeException | LinkageError, refuse that plugin and
release its classloader, mirroring the guard FileSystemPluginManager has on
sensitivePropertyKeys(). Built-in connector providers keep failing loudly: a
classpath provider that cannot link is a broken build, not a broken plugin
directory.

Tests: a directory connector provider whose getType() throws
NoClassDefFoundError is refused rather than thrown, and rethrown for a
built-in; a lineage plugin jar whose create() throws NoClassDefFoundError is
skipped by start() with no active plugin and no throw.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hout the plugin having loaded

The aliases a filesystem plugin declares sensitive were masked only because each
loaded plugin's sensitivePropertyKeys() was registered into
DatasourcePrintableMap.SENSITIVE_KEY at startup. With a shipped plugin skipped
at load - the state this branch makes survivable - the registration never ran,
while every catalog, repository and vault created with that plugin's aliases
stayed in metadata. SHOW CREATE CATALOG, SHOW CATALOG, the catalogs() TVF and the
audit-log encryption of CREATE/LOAD/TVF/OUTFILE statements all mask through the
same exact-key set, so cos.session_token, AZURE_CLIENT_SECRET, ozone.secret_key
and sixteen more aliases were printed in clear.

The static set now carries the 19 aliases the shipped plugins declare beyond the
legacy union it already inlined, and exposes the static contents as an immutable
BUILTIN_SENSITIVE_KEYS so a test can pin the providers' aliases to it without the
registration that runs in the same JVM masking a gap: the test loads every
FileSystemProvider on the test classpath and fails on any sensitive alias the
static set does not contain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ba673af made the two-argument BrokerDesc constructor rethrow the binding
error when no broker name was given, so that OUTFILE on an absent provider
reports the loaded providers instead of "Unknown broker name(null)". That
message is part of the contract a regression test pins:
export_p0/test_export_table_with_label_retry exports to a file:// path that
routes nowhere and asserts exactly that text in the cancelled job's ErrorMsg,
and cloud_p0 went red on it. The wording of that refusal is not this PR's
concern; the fallback is restored as it was at the base, and the
deserialisation-time tolerance in StorageDesc - the part of that commit the
review asked for - stays.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static review status: complete for 28577df9f6df3446f7fd1d0c90032fb7d85c7733...7881f7e5b2f7225d18de71711eae29a05c99d426.

No new distinct inline finding survived the duplicate fence. The current head still contains issues already covered by existing threads: the shared Hadoop layer is not wired into the production plugin parent topology and occupies the shared plugin namespace; lineage plugin admission does not fully roll back factory/registry/instance state; and repository/broker recovery has the already-reported ALTER-repair, legacy-type, live ADD BROKER, and resumed-task failure gaps. I did not repost those issues. Earlier comments about physical-root identity, attribute-I/O propagation, class-initialization diagnostics, dotted reflective-name guarding, and the Bouncy Castle dependency are addressed on this head.

Critical-checkpoint conclusions:

  • Goal and scenarios: the implementation decouples FE kernel dependencies, hardens per-plugin loading, stages a shared Hadoop bundle, and makes persisted storage/repository state tolerate missing providers. I traced normal startup, plugin failure, image/replay, restart, live ALTER/ADD BROKER, backup, restore, CloudRestore, load/export, and Azure-present/absent paths. The PR body is stale relative to this much broader 56-file change and does not describe these scenarios or their behavior changes.
  • Minimal and focused change: the dependency cleanup, plugin runtime, storage routing, repository migration, lineage lifecycle, build packaging, and tests form a very large coupled patch. The cross-layer coupling is traceable, but this is not a narrowly isolated change.
  • Concurrency and locks: shared-layer memoization, provider publication, repository-manager mutation, backup-job mutation, and the cached per-catalog filesystem lifecycle were checked. No new lock-order, publication-race, or heavyweight-under-lock issue was found beyond the existing lineage rollback thread.
  • Lifecycle and initialization: class definition, static initialization, metadata probing, duplicate admission, discard, loader close, connector config, filesystem close, and lineage instance initialization/close were traced. Connector/filesystem rejection paths clean up; the distinct lineage partial-publication path is already threaded.
  • Configuration and dynamic behavior: Hadoop config-directory injection, optional OBS/COS build profiles, Azure host-suffix configuration, plugin config fallback, and static/dynamic sensitive-key registration were checked. Loaded and absent Azure routing use the same probe view; no new drift or credential-masking gap was found.
  • Compatibility and rolling upgrade: repository JSON keeps the legacy field while adding the descriptor migration path, transient adapters are rebound after load, and broker metadata is restored before backup repositories. The remaining restart/live-repair incompatibilities are exactly the existing repository threads; no additional format or FE protocol break was found.
  • Parallel paths: built-in versus directory plugins, connector versus filesystem families, live versus replayed metadata, and backup/restore/CloudRestore/load/export consumers were compared. No distinct unfenced path remained.
  • Special conditions and comments: null/empty properties, absent or throwing providers, symlinks, unreadable attributes, repeated builds, duplicate names, locale-sensitive folding, no-backend connectivity checks, and initialization-failure cause chains were reviewed. Current comments generally explain the non-obvious invariants; no new comment/code mismatch rose to a finding.
  • Tests: the patch adds focused unit coverage for loader/linkage failures, shared-layer identity and ordering, repository persistence/recovery, Azure parity, masking, connector context, and backend-property propagation. The negative cases missing from those tests map to existing review threads. Per workflow contract I ran no local build or tests. At the submission gate, GitHub reported COMPILE, BE UT, Cloud UT, coverage, dependency/license, and CheckStyle successful; FE UT and regression/performance suites were still pending.
  • Observability and errors: plugin failures retain stage/cause and stack traces, repository unavailability is surfaced, and job-loop boundaries were traced. No new swallowed error or misleading metric/log path was found beyond the existing broker task-construction issue.
  • Persistence and failover: image module order, Gson post-processing, journal replay, checkpoint serialization, resumed jobs, and corrective ALTER were inspected. Every substantiated defect here is already fenced by the four existing repository/broker threads.
  • Data writes and atomicity: no table/storage-engine write path changes. Repository create/alter validation, manager publication, journaling, and remote-operation status propagation were checked; no new partial metadata commit was found.
  • FE/BE propagation: storage type, normalized locations, backend properties, broker addresses, and vended/static credentials were followed from FE binding through backup/restore/load/export task construction. The only surviving exception boundary is already reported on FileSystemDescriptor.
  • Performance: cached normalized locations and per-catalog filesystems avoid repeated binding; shared-layer scanning is process-lifetime memoized. No new unbounded hot-path work or memory-retention issue was found apart from the already-threaded lineage loader retention.
  • Optimizer plan trees: not applicable; the Nereids changes are repository display/resource-analysis commands rather than optimizer rewrites or plan-node generation.
  • Other: dependency assembly, archive cleanup/precedence, public bridge types, removed pre-auth APIs, and all 56 changed paths were included in the final sweep. Current/base searches found no in-tree consumer of the removed APIs and no distinct runtime linkage regression.

User focus: no additional focus was supplied, so the review covered the full PR without a narrower override.

This is a summary-only review, not an approval of the existing unresolved threads. Review evidence is static except for the live PR SHA and CI-status checks noted above.

…air an unbound repository, and roll back a refused lineage plugin

Follow-ups to the review-bot findings on the previous head.

A typed legacy record whose provider is loaded but threw or rejected the
properties during migration, with a broker of the same name registered, still
took the broker fallback: the rule only recognised an absent provider as the
explanation, so a provider failure plus a same-name broker persisted the
record as BROKER - the original defect through one more door. A name that is
a storage type's (a shipped provider other than BROKER, which is a family a
broker may well be named after) is now never read as a broker's: the record
is kept with the reason, absent or failed. Only a name that is no storage
type's and is a registered broker's is a broker record.

ALTER REPOSITORY refused every unavailable repository, including one whose
descriptor merely did not bind at load because a formerly accepted property
is now rejected - the case ALTER exists to repair. It now refuses only a
record with no descriptor to merge into, binds the merged properties itself
and reports the binding's reason as the DDL error when they still do not.

A broker repository binds per call and nothing checks its provider at load,
so a resumed backup or restore passed getBrokerAddress() and threw from
StorageAdapter.ofBroker() while constructing its task. getBrokerAddress()
binds the broker descriptor and answers with a Status instead.

A lineage plugin refused at create()/initialize() left its factory in the map
(retaining the discarded classloader) and an instance whose initialize() had
failed unclosed. Both go with the plugin now; the inventory row stays, since
the registry has no removal and a row for a plugin that was found but refused
is what an operator reading information_schema.extensions after the WARN
needs. A legacy record whose broker is not registered says to restart after
ADD BROKER: the migration is retried at load only.

Tests: a same-name broker with a throwing provider keeps the typed record; a
repository unbound at load is repaired by ALTER and a still-unbindable
correction is refused with the reason; a lineage plugin whose initialize()
throws is closed and its factory dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact range 28577df9f6df3446f7fd1d0c90032fb7d85c7733...c1fc199b3a4ef7760ce1dd9fb71ee2888ca6d5e4. Two distinct PR-local P2 findings are inline. Existing rendered threads, raw review comments, and prior summaries were treated as hard duplicate fences.

Critical-checkpoint conclusions:

  • Goal and proof: the dependency isolation, plugin-failure containment, and repository migration work is broadly coherent, but late filesystem linkage is not contained at repository I/O and the Azure-absent routing branch does not honor an explicitly empty live suffix list. Focused tests cover many degraded-provider cases but omit these two triggers.
  • Scope and clarity: all 56 authoritative changed paths match the authoritative diff. The build, loader, authentication, storage, repository, and persistence edits are related, but this is a large cross-layer change rather than a small local refactor.
  • Concurrency and locks: plugin admission follows the existing loader lifecycle synchronization; repository maps retain their concurrent-map/manager-lock protection; repository ping and backup daemons can overlap live DDL. No new race, lock-order inversion, deadlock, or heavy I/O under a newly introduced lock was found.
  • Error handling: M-001 violates the new nonthrowing repository boundary: NoClassDefFoundError escapes the local Status/errMsg paths and is only logged by the outer daemon. Other candidate exception paths were either already threaded or converted to their normal status boundary.
  • Memory safety: no BE/native allocation path changes. Loader/factory ownership and close/discard paths were traced; the one substantiated lineage retention/rollback issue is already covered by existing discussion r4018143606.
  • Lifecycle and initialization: plugin discovery, definition, static initialization, admission, image load, replay, checkpoint, provider loss/recovery, and first filesystem use were traced. First-use JVM linkage is the uncovered lifecycle transition in M-001; other repository recovery gaps are already fenced by existing threads.
  • Configuration: no new config item is added. The existing azure_blob_host_suffixes array is mutable and read dynamically, but its valid empty state is lost in M-002; nonempty overrides and explicit provider=azure retain their intended behavior.
  • Compatibility and rolling behavior: the foundation/Kerberos bridge preserves in-tree type/property compatibility, and legacy repository metadata is retained when migration cannot be decided. No additional wire, storage-format, edit-log, or rolling-upgrade defect survived review beyond the existing repository threads.
  • Parallel paths: connector/filesystem/lineage loaders; direct and BROKER repositories; backup/restore/cloud restore/load/export; live/replayed ALTER; and loaded/absent Azure routes were compared. Parallel late direct-filesystem failures collapse into M-001, while broker task construction remains fenced by r4018143626.
  • Conditional checks: provider presence, storage-type versus broker classification, unavailable-repository guards, Azure guess fallback, and null/empty properties were checked. M-002 is the one new condition that conflates “no probe context” with “configured empty override.”
  • Test coverage: added unit tests cover absent/throwing providers, repository migration/replay, shared-loader identity, masking, Azure routing, and plugin admission. Missing negative cases are a filesystem that links only on first exists/list and a cleared Azure suffix config with the provider loaded and absent.
  • Test results: no local build or test was run because this review contract forbids it; conclusions are static-only. Live exact-head CI currently reports COMPILE, BE UT, Cloud UT, CheckStyle, license, and dependency review successful; FE UT and regression jobs remain pending, and check_coverage_fe currently reports failure. These are CI results, not independent execution.
  • Observability: plugin-stage logging and stored repository reasons generally improve diagnosis. M-001 leaves repository status null/stale and exposes the cause only in the outer daemon log; no additional metric/logging defect survived.
  • Persistence and transactions: repository image migration, checkpoint precedence, manager replacement, edit-log replay, corrective ALTER, and resumed jobs were traced. No user transaction-visibility path changes; the remaining metadata/recovery defects outside these two findings are already covered by existing discussions.
  • Data writes and crash behavior: no table-data write, MoW, or delete-bitmap path changes. Repository metadata and remote-operation boundaries were checked; no additional partial commit or crash inconsistency was substantiated.
  • FE/BE propagation: no new Thrift/session variable is introduced. Storage type, normalized location, backend properties, broker address, and credentials were followed through backup/restore/load/export task construction; no new distinct propagation issue survived.
  • BE null/nullable handling: not applicable; this PR changes FE Java/build code and no BE column path.
  • Performance: plugin scans, map copies, binding, and shared-layer memoization are startup/control-plane work; no material hot-path CPU, memory, or I/O regression was found. The unused bundle cost is already covered by existing comment 3978332587.
  • Other issues and focus: no additional user focus was supplied. Two bounded rounds converged; both normal reviewers and the separate risk reviewer returned NO_NEW_VALUABLE_FINDINGS in the final round. Review status: complete for this exact head, static-only, changes requested.

+ ": Invalid path. " + path + ", error: " + e.getMessage();
return false;
} catch (IOException e) {
} catch (IOException | RuntimeException e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Contain late filesystem linkage failures inside the repository boundary

A provider can bind and construct its filesystem successfully, then resolve a missing class only when exists() or list() first executes. This catch now contains RuntimeException but still lets NoClassDefFoundError escape. RepositoryMgr's new outer catch only logs it, so ping() leaves errMsg null or stale; listSnapshots() likewise bypasses its Status path and live BACKUP submission throws instead of reporting repository unavailability. Please contain LinkageError at the repository I/O boundary (including list paths), record or return the normal error status, and test a filesystem whose first I/O call fails to link.

// Azure-shaped map must be refused here rather than fall through to type=s3: the resource
// type is persisted and ALTER RESOURCE cannot change it, so an S3Resource created while
// the plugin was absent would stay one after the plugin is repaired.
if (AzureBlobEndpointSignals.guessIsAzure(FileSystemPluginManager.withProbeContext(properties))) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Preserve an explicitly empty Azure suffix whitelist

When Config.azure_blob_host_suffixes is cleared at runtime, withProbeContext() omits the marker, while AzureBlobEndpointSignals treats an absent marker as “use built-in defaults.” This new Azure-plugin-absent fallback therefore reclassifies *.blob.core.windows.net as Azure and rejects type=s3 even though the live whitelist is empty. Please carry an explicit empty override through the probe context, distinguish it from no context, and cover both loaded- and absent-Azure-provider paths.

…ll inside the repository

A provider can bind and construct its filesystem and only link a missing
class when exists() or list() first runs - the plugin-absent case one step
later than the binding. The repository's I/O paths contained IOException (and
ping() a RuntimeException) there but let the LinkageError through: ping()
left errMsg stale so SHOW REPOSITORIES showed the repository healthy, and
listSnapshots(), upload() and download() threw past their Status instead of
reporting it, into the job loop. Each of those boundaries now returns or
records the error like an IOException.

Test: a filesystem whose exists() and list() throw NoClassDefFoundError makes
ping() false with the reason in errMsg and listSnapshots() an error Status,
without a throw.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: three distinct plugin-boundary correctness gaps remain on exact head 05b472131ef889d8cefbaa0846e3c683f8ea99d7.

  1. A malformed nested ServiceLoader lookup can still escape the new directory-plugin guards as ServiceConfigurationError, abort the family load, and bypass classloader cleanup.
  2. Connector engine names remain a plugin-owned Set traversed twice outside the failure guard, so traversal failure can abort later plugins and leave partial claims.
  3. Post-admission filesystem probing/binding can raise the same service-configuration error during StorageDesc replay and abort image load or follower journal replay instead of taking the documented retry-at-use path.

Critical checkpoints: correctness, lifecycle, persistence/replay, cleanup ownership, and negative-path coverage are blocked by the inline findings. Startup serialization, repository/job locking, copy-on-write provider publication, compatibility of the foundation/kerberos split, dependency reachability, Azure routing outside the already-reported explicit-empty case, legacy/new repository formats, FE/BE property propagation, observability for contained failures, and performance were traced with no additional unfenced issue. The change is broad but otherwise internally coherent and readable. Existing review threads were treated as hard duplicate fences.

Tests: static review only as required by the review task; I did not run builds or tests. The live CI snapshot at submission has check_coverage_fe failed and nine checks pending.

Focus: no additional user-provided review focus was supplied.

factory = factoryClass.getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException e) {
} catch (ReflectiveOperationException | RuntimeException | LinkageError e) {
// newInstance() is where the factory class is first initialized. A static initializer

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Contain ServiceLoader configuration failures per plugin

ServiceConfigurationError is an Error, but not a LinkageError, so a factory initializer or name()/description() callback that performs a malformed nested ServiceLoader lookup still escapes this new catch. loadAll() catches only PluginLoadException, which means one bad directory plugin aborts the rest of the family load and this runtime classloader is never closed. The built-in connector/lineage paths already treat this standard provider failure as rejectable. Please include ServiceConfigurationError in every new external-plugin guard (generic factory/metadata plus family admission/init/cleanup), convert it to the normal per-plugin failure/cleanup path, and cover a malformed nested service lookup.

try {
type = provider.getType();
engineNames = provider.acceptedCreateTableEngineNames();
} catch (RuntimeException | LinkageError e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Snapshot plugin-owned engine names inside the failure guard

This guard only calls acceptedCreateTableEngineNames(); the returned plugin-owned Set is first traversed later in createTableEngineNameProblem() and then traversed again after claimedTypes is mutated. A lazy/custom set whose iterator links a missing optional class (or otherwise throws) therefore escapes registerDiscovered(), aborts the remaining connector plugins, and leaves this handle undiscarded; a second-pass failure also leaves the type name claimed. Please materialize the set into a host-owned snapshot inside this same guard, validate/publish that snapshot, and test an iterator-time failure.

try {
initStorageAdapter();
} catch (RuntimeException | LinkageError e) {
LOG.warn("Storage descriptor (name={}, type={}) could not bind its filesystem provider at"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Contain service-configuration failures during replay binding

ServiceConfigurationError is an Error, not a LinkageError, so an admitted filesystem provider that performs a property-dependent nested ServiceLoader lookup from supportsExplicit(), supportsGuess(), or bind() still escapes this new guard. Because gsonPostProcess() runs while persisted load/export jobs are restored, that aborts image load or follower journal replay instead of leaving the descriptor unbound for the documented retry-at-use path. This is post-admission, so fixing the directory-loader boundary does not cover it. Please catch ServiceConfigurationError explicitly at these provider-backed persistence boundaries and add a StorageDesc round-trip case whose provider throws it while probing or binding.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16855 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 05b472131ef889d8cefbaa0846e3c683f8ea99d7, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17569	3072	3022	3022
q2	2116	244	216	216
q3	10216	896	511	511
q4	4670	252	201	201
q5	7746	571	383	383
q6	139	117	95	95
q7	525	510	397	397
q8	9245	867	921	867
q9	3472	2407	2426	2407
q10	6510	852	739	739
q11	389	199	180	180
q12	606	262	201	201
q13	18130	1558	1151	1151
q14	155	157	148	148
q15	q16	434	399	372	372
q17	1371	893	834	834
q18	3156	2298	2335	2298
q19	1115	903	718	718
q20	364	273	200	200
q21	5277	1682	1893	1682
q22	329	279	233	233
Total cold run time: 93534 ms
Total hot run time: 16855 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3385	3319	3315	3315
q2	513	410	384	384
q3	2255	2368	2210	2210
q4	1225	1189	916	916
q5	2241	2217	2154	2154
q6	174	125	90	90
q7	1042	969	893	893
q8	1600	1407	1401	1401
q9	3223	3221	3195	3195
q10	1922	1836	1658	1658
q11	362	280	257	257
q12	462	438	346	346
q13	1498	1537	1171	1171
q14	172	178	155	155
q15	q16	403	397	365	365
q17	3650	3496	3280	3280
q18	4990	4567	4965	4567
q19	929	864	843	843
q20	1024	998	888	888
q21	3887	3252	3248	3248
q22	389	348	337	337
Total cold run time: 35346 ms
Total hot run time: 31673 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 83563 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 05b472131ef889d8cefbaa0846e3c683f8ea99d7, data reload: false

query5	4236	428	337	337
query6	387	152	124	124
query7	4924	437	238	238
query8	284	127	114	114
query9	8675	2944	2923	2923
query10	391	222	179	179
query11	5390	1060	922	922
query12	121	72	73	72
query13	1191	445	319	319
query14	6126	2287	2247	2247
query14_1	2039	2022	2031	2022
query15	184	134	112	112
query16	925	398	364	364
query17	792	456	363	363
query18	2328	341	242	242
query19	163	135	109	109
query20	73	77	74	74
query21	201	105	86	86
query22	5576	5735	5559	5559
query23	7026	6394	6316	6316
query23_1	6265	6204	6330	6204
query24	7328	1106	766	766
query24_1	776	791	766	766
query25	426	303	254	254
query26	1237	230	132	132
query27	2772	429	260	260
query28	4719	1507	1497	1497
query29	926	431	367	367
query30	253	155	132	132
query31	814	410	333	333
query32	132	78	84	78
query33	463	228	201	201
query34	994	837	475	475
query35	422	415	341	341
query36	570	588	567	567
query37	119	78	70	70
query38	1014	869	864	864
query39	489	482	476	476
query39_1	470	471	482	471
query40	198	88	80	80
query41	54	56	51	51
query42	69	70	76	70
query43	240	242	211	211
query44	1006	531	531	531
query45	112	107	115	107
query46	799	846	528	528
query47	775	784	731	731
query48	305	306	222	222
query49	558	239	202	202
query50	718	260	193	193
query51	7989	8076	7970	7970
query52	74	71	99	71
query53	235	193	144	144
query54	218	165	149	149
query55	70	57	53	53
query56	177	173	150	150
query57	739	649	669	649
query58	197	160	162	160
query59	1260	1285	1147	1147
query60	227	190	167	167
query61	110	103	103	103
query62	412	203	172	172
query63	169	137	151	137
query64	2827	693	558	558
query65	1741	1664	1661	1661
query66	1765	261	195	195
query67	9886	9976	9876	9876
query68	2767	1185	752	752
query69	323	225	197	197
query70	688	651	616	616
query71	244	174	165	165
query72	2218	1687	1539	1539
query73	647	593	353	353
query74	1560	1252	1176	1176
query75	1189	1114	990	990
query76	2281	718	498	498
query77	253	245	209	209
query78	4141	3884	3349	3349
query79	1213	818	570	570
query80	1209	327	294	294
query81	498	157	136	136
query82	650	125	98	98
query83	319	215	196	196
query84	297	112	94	94
query85	980	393	342	342
query86	388	183	173	173
query87	1063	996	914	914
query88	2786	2115	2104	2104
query89	285	199	178	178
query90	1896	128	121	121
query91	127	116	94	94
query92	78	71	69	69
query93	1317	1107	688	688
query94	627	273	177	177
query95	500	247	216	216
query96	812	599	275	275
query97	1092	1068	1043	1043
query98	145	136	136	136
query99	421	347	312	312
Total cold run time: 176623 ms
Total hot run time: 83563 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.82 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 05b472131ef889d8cefbaa0846e3c683f8ea99d7, data reload: false

query1	0.01	0.00	0.01
query2	0.08	0.04	0.04
query3	0.24	0.11	0.10
query4	1.60	0.10	0.10
query5	0.17	0.16	0.15
query6	1.25	0.68	0.71
query7	0.03	0.01	0.00
query8	0.04	0.04	0.03
query9	0.29	0.22	0.23
query10	0.35	0.35	0.36
query11	0.17	0.12	0.12
query12	0.15	0.12	0.12
query13	0.31	0.30	0.30
query14	0.46	0.46	0.47
query15	0.36	0.35	0.36
query16	0.21	0.24	0.22
query17	0.71	0.73	0.67
query18	0.18	0.18	0.17
query19	1.18	1.15	1.14
query20	0.01	0.01	0.01
query21	15.43	0.15	0.11
query22	5.06	0.04	0.05
query23	16.16	0.27	0.10
query24	2.95	0.32	0.26
query25	0.11	0.04	0.03
query26	0.79	0.16	0.12
query27	0.04	0.02	0.03
query28	3.69	0.54	0.27
query29	12.45	3.25	2.57
query30	0.25	0.12	0.13
query31	2.76	0.38	0.17
query32	3.50	0.34	0.24
query33	1.43	1.43	1.47
query34	15.42	2.23	1.84
query35	1.78	1.81	1.76
query36	0.47	0.30	0.30
query37	0.06	0.04	0.03
query38	0.05	0.03	0.03
query39	0.03	0.02	0.02
query40	0.12	0.07	0.08
query41	0.08	0.03	0.02
query42	0.03	0.02	0.02
query43	0.04	0.03	0.02
Total cold run time: 90.5 s
Total hot run time: 14.82 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 68.75% (121/176) 🎉
Increment coverage report
Complete coverage report

… and walk a plugin's engine-name set inside the guard

ServiceConfigurationError is an Error but not a LinkageError: a plugin whose
static initializer, name(), probe or bind runs a nested ServiceLoader lookup
over one of its own malformed service files - its driver discovery - threw it
through every guard this branch added, which caught RuntimeException and
LinkageError only. In the loader that aborted the rest of the family load and
leaked the classloader; in StorageDesc.gsonPostProcess it took image load or a
follower's journal replay down; in the family managers, the repository binds
and I/O boundaries and the job and ping loops it escaped the same way. Every
such guard now names ServiceConfigurationError too.

The connector manager's first-call guard covered calling
acceptedCreateTableEngineNames() but not walking its answer: the plugin-owned
set was first traversed in the problem checks and again while claiming, both
outside the guard, so a lazy set whose iterator links a missing class threw out
of registerDiscovered() - after the type name had been claimed on the second
pass. The set is copied into a host-owned snapshot inside the guard, and the
checks and claims walk the copy.

Tests: a plugin whose initializer runs a nested lookup over a service file
naming a class that does not exist is one LoadFailure whose cause is the
ServiceConfigurationError; a provider whose probe throws it leaves a persisted
load job's descriptor unbound at replay instead of failing the replay; a
connector provider whose engine-name set throws when walked is refused with no
type claimed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes: two new correctness issues remain on exact head b273abf0be9bc1088ba4336b4234384846665a57: legacy broker migration can persist the wrong storage identity, and filesystem plugin admission can publish state before validating plugin-owned sensitive-key metadata.

Critical checkpoints:

  • Goal and proof: The dependency/classloader decoupling and failure-containment direction is implemented and has substantial unit coverage, but the two inline cases show the end-to-end goal is not yet met. The missing checkpoint/reload broker-shape tests and lazy-set/content tests are required.
  • Scope/focus: The 58-file change is broader than the PR description (dependency cleanup plus plugin/repository lifecycle fixes), so it is not narrowly scoped; every authoritative path was reviewed. No additional user focus was supplied.
  • Concurrency: Plugin loading is startup-oriented and provider lists use copy-on-write; repository maps use their existing manager lock. No new deadlock/race was substantiated, but the filesystem issue is non-transactional publication even without a race.
  • Lifecycle: Loader handle discard/close, registry/provider publication, lineage initialization/close, and resumed backup/restore paths were traced. The filesystem issue leaves retained/partially published state.
  • Configuration: Dynamic Azure suffix routing and loaded/absent-provider parity were checked; the known explicit-empty issue is already covered by an existing thread. No other new configuration issue was found.
  • Compatibility: Dependency/authenticator/API and old/new plugin classloader combinations were checked. No additional supported API/rolling issue was found, but the broker migration issue breaks persisted legacy repository compatibility.
  • Parallel paths and conditions: Built-in and directory filesystem admission were both checked and share the sensitive-key issue. The storage-type-name/broker/provider decision table is covered by the migration issue.
  • Tests and results: Existing tests cover many negative loader/provider paths but omit the two exact cases above. Per the task contract this was static-only: no build, unit test, or regression test was run, and no generated result was modified.
  • Observability: New logs improve plugin/repository diagnosis; no separate metrics gap was substantiated. Logging does not repair partial publication or a wrong persisted identity.
  • Persistence/failover: Edit-log replay, image load/checkpoint, ALTER replay, heterogeneous FE/provider availability, and master failover were traced. The migration issue is blocking because checkpoint/reload preserves the wrong or unrecoverable identity.
  • Writes/atomicity: No BE data-write protocol changes were introduced. Plugin admission is not atomic in the filesystem issue, and metadata identity persistence is incorrect in the migration issue.
  • FE/BE propagation: No new thrift/config variable requires additional propagation; backend repository property/task construction paths were traced.
  • Performance: Changes are predominantly startup/load-time; no new hot-path regression or material optimization gap was found.
  • Other issues: Existing review threads remain the duplicate fence for shared-runtime wiring, loader/linkage containment, Azure empty override, lineage rollback, and related repository recovery cases.

Review status: complete after three bounded rounds; all final-round reviewers returned NO_NEW_VALUABLE_FINDINGS beyond the two accepted comments.

// edit-log replay: LinkageError included, so a half-installed plugin costs this
// repository, not the FE - the same catch CatalogFactory uses for catalogs.
try {
StorageAdapter storageAdapter = StorageAdapter.of(props);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve broker identity before routing legacy properties

This routes prop before consulting the registered broker name. A real legacy WITH BROKER broker_0 HDFS repository commonly stores fs.defaultFS/hadoop.username; the HDFS provider therefore binds here, and the next checkpoint permanently records HDFS instead of BROKER, so later backup I/O bypasses broker_0. The catch-side name heuristic has the inverse edge too: a legal broker actually named HDFS is left descriptor-less and cannot be repaired by ALTER. These are distinct from the existing typed-provider-failure thread because the provider succeeds and the old record genuinely is BROKER. Please recognize ordinary registered brokers before typed routing and retain/add an explicit discriminator or repair path for ambiguous names, with checkpoint/reload tests for broker HDFS/S3 passthrough properties.

try {
sensitiveKeys = provider.sensitivePropertyKeys();
} catch (RuntimeException | LinkageError e) {
} catch (RuntimeException | LinkageError | ServiceConfigurationError e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Materialize the sensitive-key set inside this guard

The guarded call can return a plugin-owned lazy/custom Set; its iterator is first consumed later by registerSensitiveKeys() via the case-insensitive addAll. At that point providers.add(provider) has already made the directory provider routable, so an iterator-time failure (or a null/invalid element) aborts the family load with the provider active, its aliases partially/not masked, no inventory row, and later successful handles skipped. loadBuiltins() has the same root cause in the opposite publication order: it writes the inventory row before traversing the set and does not roll it back on failure. This is distinct from the connector engine-name thread because this path controls filesystem admission and secret masking. Please materialize and validate a host-owned set inside the guard before any publication in both paths, discard on failure, and test iterator/content failures.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 68.54% (122/178) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16808 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit b273abf0be9bc1088ba4336b4234384846665a57, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17563	3053	3057	3053
q2	2100	252	223	223
q3	10233	962	518	518
q4	4673	250	205	205
q5	7674	577	373	373
q6	136	112	95	95
q7	529	499	388	388
q8	9243	837	884	837
q9	3451	2417	2386	2386
q10	6486	846	752	752
q11	391	199	182	182
q12	609	268	205	205
q13	18120	1536	1175	1175
q14	162	146	139	139
q15	q16	439	406	368	368
q17	1281	883	742	742
q18	3143	2273	2223	2223
q19	1257	929	812	812
q20	395	278	206	206
q21	5636	1699	1864	1699
q22	324	267	227	227
Total cold run time: 93845 ms
Total hot run time: 16808 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3417	3361	3399	3361
q2	496	388	368	368
q3	2312	2254	2163	2163
q4	1187	1167	893	893
q5	2179	2103	2122	2103
q6	169	123	88	88
q7	1028	908	953	908
q8	1590	1391	1403	1391
q9	3120	3114	3109	3109
q10	1856	1781	1615	1615
q11	354	267	252	252
q12	465	431	344	344
q13	1487	1522	1153	1153
q14	167	179	162	162
q15	q16	395	395	354	354
q17	3617	3297	3253	3253
q18	4821	4368	4713	4368
q19	870	915	883	883
q20	993	975	828	828
q21	3837	3227	3218	3218
q22	392	355	328	328
Total cold run time: 34752 ms
Total hot run time: 31142 ms

…and walk a provider's sensitive keys before publishing it

The legacy migration routed the record's properties first and consulted its
name only when no provider claimed them. A WITH BROKER repository commonly
stores fs.defaultFS and hadoop.username, which the HDFS provider claims, so
such a record was migrated as HDFS, the next checkpoint made that permanent,
and every later backup bypassed the broker it was created on. The record's
name is the one identity it carries - a storage type for a typed record, the
broker for a broker record - and now decides: a storage type's name binds
that type (or is kept with the reason, which for a broker that happens to be
named after a storage type says to DROP and re-CREATE); a registered broker's
name is a broker record, whatever its properties route to; only a name that
is neither - one from before the type names, or a broker since dropped - is
routed as before.

FileSystemPluginManager guarded the call to sensitivePropertyKeys() but not
the walk over its answer, which happened in the masking set's addAll after
the provider was already routable (and, for a built-in, after its inventory
row): a plugin-owned lazy set failing when iterated, or a null alias failing
the case-insensitive comparator, aborted the family load with the provider
active and unmasked. The set is copied and checked inside the guard, before
anything is published, on all three admission paths.

Tests: a legacy broker record with HDFS-shaped properties stays a broker
repository through a checkpoint round trip; a provider whose sensitive-key
set fails when walked, or carries a null alias, is refused before it is
published.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@morningman

Copy link
Copy Markdown
Contributor Author

/review

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Request changes on exact head 7467c22861a7bd6a9330bd33c9597acfe05fb3d9.

I found three distinct exact-head defects, reported inline:

  1. Typed legacy repository migration recognizes the saved provider name, then ignores it and priority-routes the properties, so a valid AZURE record can be checkpointed permanently as S3.
  2. Backend task-property conversion is brought inside the job Status boundary only for BROKER; the parallel non-BROKER path can still throw from upload/restore task construction and retry unchanged until timeout.
  3. The new continue-after-plugin-rejection path can replay metadata without an out-of-tree provider's process-local sensitive aliases, exposing those stored credentials through catalog SHOW surfaces.

Critical-checkpoint conclusions:

  • Goal and proof: the exact head is a broad FE filesystem-SPI, plugin-failure, Hadoop-runtime, and repository-migration change. It makes substantial progress, but the three transitions above mean the migration/degraded-operation goal is not yet correct. The changed unit tests do not cover those transitions.
  • Scope and focus: 59 files are changed across build/deployment, FE core, extension loading, filesystem SPI/providers, persistence, and tests. That is materially broader than the current PR description/checklist, which should be refreshed before merge.
  • Concurrency: the new process-wide provider/registry state uses the existing startup ordering and copy-on-write provider collections; I found no new distinct lock, race, or deadlock issue after fencing the existing plugin-publication threads.
  • Lifecycle: startup admission, image replay, checkpoint, ALTER, resumed jobs, and plugin rejection were traced end to end. The restart and resumed-job gaps are covered by the inline findings; other substantiated lifecycle defects are already covered by existing review threads.
  • Configuration: the loaded/absent Azure routing paths share the new probe context for nonempty suffix settings. The explicit-empty setting defect is already covered by an existing thread; no additional distinct configuration issue survived review.
  • Compatibility: legacy repository metadata and FE-to-BE task properties are compatibility-sensitive. The typed-record rewrite and non-BROKER projection gaps are reported inline. I found no additional distinct public API/runtime-closure issue beyond existing threads.
  • Parallel paths and conditions: BROKER versus non-BROKER, built-in versus out-of-tree providers, admitted versus rejected plugins, loaded versus absent Azure, and constructor versus replay paths were compared. The asymmetric non-BROKER guard and rejected-plugin masking path are reported inline.
  • Tests and results: 28 changed/new test-source files exercise many local cases, but miss the three concrete cross-restart/task-construction transitions above. This review was static only; I did not run builds or tests. At submission, BE UT, Cloud UT, coverage, CheckStyle, dependency review, license, secret, large-file, and formatter checks are green; FE UT, compile, performance, and the automated review contexts are still pending.
  • Observability: plugin load summaries and repository unavailability messages are generally improved and include useful causes/identifiers. I found no separate observability blocker.
  • Persistence, transactions, and writes: repository descriptor creation, checkpoint preference, image/edit-log replay, ALTER replacement, and active-job refresh were traced. The permanent wrong-type checkpoint is the blocking persistence defect; no BE data-write transaction path is changed here.
  • FE/BE propagation: storage type and backend properties reach backup, restore, and cloud-restore task construction. The missing non-BROKER validation boundary is reported inline; no other new transmitted field was introduced.
  • Performance: I found no substantiated new hot-path complexity, allocation, or I/O regression distinct from the existing review context.
  • Other issues: existing inline threads were treated as hard duplicate fences and are not repeated here. There was no additional user-provided review focus.

This is a complete static review of the supplied exact-head diff after convergence; it is not build or test validation.

// reason; a registered broker's name is a broker record; anything else - a name from before
// the type names, or a broker since dropped - is routed as it always was. A kept record is
// retried at the next start, and every use reports the reason until then. Every bind runs
// plugin code at image load and edit-log replay, so a LinkageError or a plugin's own

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Bind typed legacy records through their saved provider

This branch treats fsName as the authoritative storage type but then ignores it by calling generic priority routing. For example, a valid legacy AZURE record that also carries a stale fs.s3.support=true flag is claimed by S3 first; the next line builds an S3 descriptor, and the next checkpoint permanently makes backup/restore use S3 normalization and BE properties. This is distinct from the broker-identity thread because the typed branch is already selected and every bind succeeds. Please use StorageAdapter.ofProvider(fsName, props) here and cover checkpoint/reload with properties that another provider also claims.

if (unavailableReason != null) {
// The first repository call every backup and restore job makes before it reads the
// descriptor's properties: a job on an unusable repository fails here with a Status and is
// cancelled, instead of throwing out of run() on every tick.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Validate task properties for non-broker repositories too

This guard is reached only after the non-BROKER early return, but backend-property projection is a separate provider callback that bind/create/ping never exercises. A non-BROKER provider can therefore serve FE I/O and still return no toBackendProperties() value or link-fail there; upload, restore, and cloud-restore then throw while constructing their BE tasks, and the daemon only logs/retries the unchanged job until timeout. ALTER can likewise journal the new repository before active-task refresh throws. Please validate/cache this projection for every repository type inside the Status boundary (and before committing ALTER), then pass that validated map to task construction.

// The aliases the shipped filesystem plugins declare sensitive beyond the legacy union above.
// Masking must not depend on a plugin having loaded: a shipped plugin that fails to load is
// skipped and the FE serves on, while every catalog, repository and vault created with its
// aliases stays in metadata and is printed by SHOW CREATE CATALOG, SHOW CATALOG, the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve custom sensitive aliases when a plugin is rejected

The new degraded-startup path can now reject an out-of-tree provider and continue into image replay, but that provider's sensitivePropertyKeys() snapshot lived only in the previous JVM. This fallback restores shipped aliases only, so a catalog created with a custom alias such as acme.auth_blob is replayed after the plugin link failure and SHOW/SHOW CREATE prints the credential verbatim to users with catalog SHOW privilege. This is distinct from the lazy-set thread: admission succeeded in the old process and the provider is wholly absent in the new one. Please persist a host-owned alias snapshot independently of executable provider admission and restore it before printable metadata becomes available, with a successful-create then rejected-on-restart test.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 19.70% (39/198) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16968 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 7467c22861a7bd6a9330bd33c9597acfe05fb3d9, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17632	3058	3057	3057
q2	2115	253	220	220
q3	10221	989	534	534
q4	4671	247	207	207
q5	7678	542	386	386
q6	135	118	95	95
q7	523	494	383	383
q8	9244	875	925	875
q9	3510	2442	2408	2408
q10	6521	877	711	711
q11	391	194	181	181
q12	621	259	200	200
q13	18137	1534	1164	1164
q14	164	156	142	142
q15	q16	443	396	372	372
q17	1296	956	781	781
q18	3085	2289	2244	2244
q19	1290	862	783	783
q20	368	295	204	204
q21	5625	1795	1822	1795
q22	328	270	226	226
Total cold run time: 93998 ms
Total hot run time: 16968 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3443	3349	3370	3349
q2	497	386	371	371
q3	2252	2765	2168	2168
q4	1197	1179	904	904
q5	2184	2121	2104	2104
q6	170	121	87	87
q7	1026	891	876	876
q8	1606	1406	1414	1406
q9	3143	3139	3122	3122
q10	1860	1799	1620	1620
q11	351	272	249	249
q12	458	441	338	338
q13	1468	1527	1163	1163
q14	176	167	157	157
q15	q16	399	407	365	365
q17	3587	3340	3286	3286
q18	4793	4416	4764	4416
q19	969	867	871	867
q20	994	987	832	832
q21	3835	3223	3206	3206
q22	397	345	335	335
Total cold run time: 34805 ms
Total hot run time: 31221 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81720 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 7467c22861a7bd6a9330bd33c9597acfe05fb3d9, data reload: false

query5	4258	412	349	349
query6	381	139	140	139
query7	4923	421	233	233
query8	293	128	120	120
query9	8710	2905	2899	2899
query10	394	233	189	189
query11	5378	1056	921	921
query12	125	75	71	71
query13	1199	465	309	309
query14	6069	2204	2091	2091
query14_1	1980	1973	1966	1966
query15	174	117	116	116
query16	923	360	346	346
query17	780	450	354	354
query18	2324	327	246	246
query19	168	136	112	112
query20	71	70	70	70
query21	199	102	89	89
query22	5389	5378	5290	5290
query23	6647	6387	6044	6044
query23_1	6086	5912	6138	5912
query24	7282	1089	752	752
query24_1	765	770	783	770
query25	426	295	249	249
query26	1232	246	136	136
query27	2769	421	258	258
query28	4723	1515	1525	1515
query29	933	438	353	353
query30	254	158	131	131
query31	840	399	334	334
query32	124	79	72	72
query33	458	219	179	179
query34	985	811	483	483
query35	394	413	354	354
query36	560	581	520	520
query37	128	87	71	71
query38	1005	855	808	808
query39	495	487	476	476
query39_1	446	442	446	442
query40	205	92	79	79
query41	58	56	57	56
query42	75	72	77	72
query43	244	245	222	222
query44	983	545	553	545
query45	113	104	105	104
query46	759	847	557	557
query47	755	763	721	721
query48	312	310	239	239
query49	539	272	191	191
query50	815	258	194	194
query51	8253	8030	8385	8030
query52	66	72	65	65
query53	197	205	152	152
query54	242	170	151	151
query55	69	63	59	59
query56	191	261	173	173
query57	672	680	665	665
query58	196	156	157	156
query59	1236	1244	1074	1074
query60	227	182	167	167
query61	113	106	104	104
query62	356	208	186	186
query63	174	138	141	138
query64	2745	727	618	618
query65	1651	1583	1614	1583
query66	1817	256	200	200
query67	9780	9448	9647	9448
query68	3051	1197	744	744
query69	358	273	194	194
query70	649	577	629	577
query71	246	194	167	167
query72	2264	1645	1469	1469
query73	663	582	322	322
query74	2003	1233	1142	1142
query75	1191	1097	956	956
query76	2389	723	542	542
query77	247	267	211	211
query78	3886	3767	3250	3250
query79	2681	857	586	586
query80	1587	335	285	285
query81	512	156	138	138
query82	666	121	99	99
query83	274	207	194	194
query84	292	111	86	86
query85	804	347	265	265
query86	463	177	177	177
query87	1020	966	919	919
query88	3010	2142	2115	2115
query89	289	200	175	175
query90	2068	132	132	132
query91	132	119	96	96
query92	90	67	69	67
query93	2117	1063	738	738
query94	637	260	208	208
query95	541	259	299	259
query96	780	591	257	257
query97	1053	1062	1012	1012
query98	176	135	132	132
query99	422	352	315	315
Total cold run time: 179129 ms
Total hot run time: 81720 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.69 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 7467c22861a7bd6a9330bd33c9597acfe05fb3d9, data reload: false

query1	0.00	0.00	0.01
query2	0.08	0.04	0.03
query3	0.24	0.11	0.11
query4	1.61	0.10	0.10
query5	0.18	0.16	0.16
query6	1.23	0.70	0.69
query7	0.04	0.01	0.00
query8	0.05	0.03	0.02
query9	0.28	0.21	0.22
query10	0.33	0.34	0.36
query11	0.16	0.12	0.12
query12	0.14	0.12	0.12
query13	0.31	0.32	0.31
query14	0.45	0.47	0.45
query15	0.36	0.36	0.38
query16	0.21	0.21	0.22
query17	0.70	0.70	0.72
query18	0.18	0.14	0.15
query19	1.21	1.14	1.22
query20	0.01	0.01	0.01
query21	15.44	0.15	0.11
query22	5.09	0.04	0.04
query23	16.17	0.25	0.10
query24	2.99	0.31	0.25
query25	0.10	0.04	0.03
query26	0.76	0.17	0.14
query27	0.04	0.03	0.04
query28	3.58	0.56	0.28
query29	12.43	3.22	2.58
query30	0.26	0.12	0.13
query31	2.76	0.37	0.17
query32	3.51	0.32	0.23
query33	1.39	1.36	1.56
query34	15.36	2.16	1.79
query35	1.72	1.75	1.74
query36	0.47	0.29	0.28
query37	0.06	0.04	0.03
query38	0.04	0.03	0.02
query39	0.03	0.02	0.03
query40	0.12	0.08	0.08
query41	0.08	0.02	0.02
query42	0.03	0.03	0.02
query43	0.03	0.03	0.03
Total cold run time: 90.23 s
Total hot run time: 14.69 s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants