Skip to content

[refactor](catalog) Unify external metadata cache framework - #66633

Open
924060929 wants to merge 10 commits into
apache:masterfrom
924060929:prototype-scoped-metacache-ut
Open

[refactor](catalog) Unify external metadata cache framework#66633
924060929 wants to merge 10 commits into
apache:masterfrom
924060929:prototype-scoped-metacache-ut

Conversation

@924060929

@924060929 924060929 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #66407

Problem Summary:

FE naming caches and connector metadata caches currently use duplicate cache wrappers and independently maintained invalidation dependencies. Each connector must remember every sibling cache affected by catalog, database, table, or partition invalidation. Concurrent loads, refresh, eviction callbacks, and catalog close also need consistent publication and cleanup semantics across these implementations.

This PR makes fe-connector-cache the shared metadata-cache runtime while preserving one cache owner per catalog. It introduces declarative cache definitions and hierarchical scopes, then migrates ADBC, Hive, HMS, Hudi, Iceberg, MaxCompute, and Paimon caches to the shared framework. FE keeps a thin adapter for Doris-specific naming, object, and IdNameIndex publication semantics.

The shared runtime provides:

  • catalog/database/table/partition scoped invalidation without connector-maintained sibling-cache lists;
  • state-identity publication fencing so loads started before invalidation cannot publish stale values afterward;
  • exact-key and bulk-load invalidation fencing;
  • load deduplication, refresh, eviction cleanup, metrics, and catalog lifecycle management;
  • expected-value physical cleanup so delayed removal callbacks cannot remove newer publications;
  • per-catalog isolation without registry-wide publication locks on normal cache operations.

The change also removes duplicate CacheSpec, CacheFactory, and legacy connector-cache entry implementations. FE-specific cache publication retains the lock order names -> object -> IdNameIndex, and validates identity before mutating cache state. After synchronizing the latest master, Iceberg's snapshot-scoped equality-delete field-ID cache is also managed by the same per-catalog owner, so catalog invalidation and close cover both manifest and equality-delete metadata.

Performance measurements on the final commit show approximately 85.8 ns/op for the public CatalogMetaCache -> MetaCache hit path. Eight-thread publication reached 2.85M ops/s for one cache and 2.51M ops/s for separate caches in one registry. Invalidating and physically cleaning 120,000 entries took approximately 32 ms on the local benchmark.

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
      • fe-connector-cache: 100 tests passed
      • FE targeted metadata-cache tests: 93 tests passed
      • Iceberg cache tests: 66 tests passed
      • Latest-master conflict verification: 144 Iceberg tests passed (IcebergScanPlanProviderTest and IcebergManifestCacheTest)
      • ./build.sh --fe: all 73 Maven reactor modules passed, including Checkstyle; the outer script subsequently returned non-zero while assembling already-built filesystem plugin archives into output/
    • Manual test
      • Re-profiled the final commit with CPU, allocation, and lock async-profiler runs
      • Ran hit, cold-load, eight-thread publication, logical invalidation, and 120,000-entry cleanup benchmarks
    • 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.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No. This is an internal cache-framework refactor preserving external metadata semantics.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

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

@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?

@924060929

Copy link
Copy Markdown
Contributor Author

/review

@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@924060929
924060929 marked this pull request as ready for review August 11, 2026 01:04
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17621	3918	3904	3904
q2	2013	325	197	197
q3	10311	1344	789	789
q4	4676	469	336	336
q5	7501	807	544	544
q6	186	171	138	138
q7	752	809	596	596
q8	9768	1548	1555	1548
q9	6019	4104	4072	4072
q10	6778	1637	1351	1351
q11	493	345	314	314
q12	769	576	461	461
q13	18081	3269	2652	2652
q14	269	257	240	240
q15	q16	732	723	654	654
q17	1399	1169	949	949
q18	6476	5567	5597	5567
q19	1690	1326	1040	1040
q20	779	694	548	548
q21	5903	2546	2275	2275
q22	428	352	298	298
Total cold run time: 102644 ms
Total hot run time: 28473 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4304	4215	4205	4205
q2	270	332	208	208
q3	4521	4858	4410	4410
q4	2166	2251	1429	1429
q5	4304	4142	4158	4142
q6	230	172	130	130
q7	1688	1603	1605	1603
q8	2536	2315	2037	2037
q9	7246	7270	7238	7238
q10	4246	4232	3827	3827
q11	557	410	369	369
q12	710	742	499	499
q13	3152	3632	2828	2828
q14	295	323	307	307
q15	q16	699	745	651	651
q17	1328	1308	1278	1278
q18	12261	11039	11751	11039
q19	1280	1183	1147	1147
q20	2246	2204	1957	1957
q21	5652	4797	4700	4700
q22	535	453	401	401
Total cold run time: 60226 ms
Total hot run time: 54405 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 159564 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 527066179d0e7025c52b6385e51f38b73102c567, data reload: false

query5	4377	596	467	467
query6	485	242	221	221
query7	4847	568	362	362
query8	354	186	164	164
query9	8835	4108	4072	4072
query10	486	380	315	315
query11	5875	2203	2050	2050
query12	164	107	103	103
query13	1293	631	444	444
query14	6130	4324	4009	4009
query14_1	3833	3822	3804	3804
query15	215	199	184	184
query16	1037	520	436	436
query17	970	747	618	618
query18	2462	507	371	371
query19	227	203	165	165
query20	109	109	108	108
query21	239	162	145	145
query22	13087	12936	12815	12815
query23	15667	14982	14589	14589
query23_1	14709	14786	14669	14669
query24	7551	1705	1241	1241
query24_1	1262	1274	1246	1246
query25	603	489	432	432
query26	1324	378	231	231
query27	2617	611	402	402
query28	4595	2104	2053	2053
query29	1103	678	532	532
query30	344	269	234	234
query31	1192	1130	1056	1056
query32	118	71	75	71
query33	555	345	275	275
query34	1177	1155	642	642
query35	761	751	645	645
query36	786	772	713	713
query37	162	116	100	100
query38	1833	1788	1702	1702
query39	820	815	776	776
query39_1	783	814	786	786
query40	266	173	171	171
query41	85	83	81	81
query42	104	97	96	96
query43	322	328	281	281
query44	1456	789	777	777
query45	201	182	187	182
query46	1058	1180	701	701
query47	1598	1564	1521	1521
query48	428	426	313	313
query49	601	425	312	312
query50	1070	436	353	353
query51	10656	10320	10437	10320
query52	90	95	77	77
query53	263	286	202	202
query54	313	247	233	233
query55	78	80	72	72
query56	316	327	295	295
query57	1031	1024	969	969
query58	313	281	270	270
query59	1555	1603	1409	1409
query60	329	275	269	269
query61	181	182	187	182
query62	408	331	277	277
query63	243	202	202	202
query64	3069	1274	1067	1067
query65	3871	3776	3784	3776
query66	1876	506	399	399
query67	20145	20116	19888	19888
query68	3214	1543	972	972
query69	430	315	285	285
query70	881	801	775	775
query71	372	347	308	308
query72	3318	2930	2606	2606
query73	840	795	442	442
query74	4662	4498	4312	4312
query75	2400	2349	1985	1985
query76	2363	1141	761	761
query77	335	382	286	286
query78	11091	11169	10506	10506
query79	1440	1142	791	791
query80	1049	589	520	520
query81	553	323	287	287
query82	631	178	143	143
query83	389	342	315	315
query84	341	171	138	138
query85	1082	717	629	629
query86	376	233	223	223
query87	1987	1963	1825	1825
query88	3738	2823	2818	2818
query89	412	328	295	295
query90	1896	198	195	195
query91	224	212	187	187
query92	70	65	61	61
query93	1615	1499	913	913
query94	639	362	329	329
query95	822	536	510	510
query96	1122	767	359	359
query97	2459	2492	2348	2348
query98	196	197	185	185
query99	755	736	624	624
Total cold run time: 246876 ms
Total hot run time: 159564 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.09	0.05	0.04
query3	0.25	0.13	0.14
query4	1.61	0.14	0.14
query5	0.24	0.22	0.23
query6	1.15	0.83	0.78
query7	0.03	0.00	0.01
query8	0.06	0.04	0.04
query9	0.38	0.30	0.32
query10	0.56	0.54	0.55
query11	0.18	0.13	0.13
query12	0.17	0.14	0.14
query13	0.46	0.46	0.46
query14	1.00	0.98	0.99
query15	0.61	0.58	0.60
query16	0.33	0.34	0.29
query17	1.07	1.05	1.02
query18	0.21	0.19	0.20
query19	2.06	1.94	1.92
query20	0.02	0.01	0.01
query21	15.43	0.19	0.13
query22	4.94	0.06	0.05
query23	16.15	0.32	0.12
query24	2.96	0.41	0.32
query25	0.11	0.05	0.04
query26	0.72	0.22	0.16
query27	0.05	0.04	0.04
query28	3.54	0.81	0.34
query29	12.46	4.02	3.16
query30	0.27	0.16	0.15
query31	2.76	0.54	0.32
query32	3.22	0.58	0.49
query33	3.19	3.16	3.17
query34	15.57	3.91	3.28
query35	3.24	3.22	3.18
query36	0.55	0.42	0.40
query37	0.09	0.06	0.06
query38	0.06	0.04	0.04
query39	0.04	0.03	0.02
query40	0.17	0.14	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.18 s
Total hot run time: 23.61 s

@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 for three production-reachable concurrency regressions in the unified metadata-cache publication paths:

  • a cold FE database/table object becomes visible before its IdNameIndex action while the adapter reacquires its stripe;
  • an incremental database/table-name remap can overwrite a newer concurrent refresh snapshot; and
  • a delayed refresh can overwrite a newer value loaded after eviction.

Checkpoint conclusions:

  • Goal and proof: the catalog-local owner and hierarchical invalidation design largely accomplish the consolidation goal, and the new unit suites cover most load, invalidation, hierarchy, close, and pruning contracts. They do not cover the three accepted interleavings.
  • Scope and design: this is a broad but cohesive cache-framework refactor. Existing mechanisms were reused appropriately, and no unrelated code change was found.
  • Concurrency: remote loads stay outside gates/monitors and the gate/lock ordering showed no deadlock. The three inline findings are correctness gaps in cross-layer publication and refresh replacement.
  • Lifecycle: owner close, detached-state cleanup, removal callbacks, bulk handles, and node/tombstone pruning were traced. The queued-refresh lease concern was dismissed because it had no distinct current production impact beyond the already-retained Runnable graph.
  • Configuration and compatibility: no new configuration key, persistence format, FE-BE variable, or protocol was added. CacheSpec parsing, Maven/runtime closure, plugin classloading, and mixed old/new FE-plugin fallback showed no concrete compatibility defect.
  • Parallel paths and conditions: database/table paths, all migrated connectors, Hive collection/value scopes, replay/DDL/event invalidations, Iceberg authorization-sensitive gates, and deliberate catalog-scoped exceptions were checked. No additional distinct issue remained.
  • Tests and results: changed tests are deterministic and substantial, but latch coverage is missing for the three reported races. Per the review-runner instructions, no build or test command was run.
  • Observability and performance: existing metrics/logging remain adequate for ordinary cache operations; remote I/O remains outside locks, and no separate material performance or observability defect was substantiated.
  • Persistence, transactions, data writes, and storage/FE-BE compatibility: not applicable to this metadata-cache-only refactor.

There was no additional user-provided focus. The full 70-file authoritative diff was reviewed. After three rounds, all normal and risk-focused reviewers returned NO_NEW_VALUABLE_FINDINGS; the review is converged with no unresolved or duplicate candidate.

token = beginAction(stripe, key);
}
try {
V value = cached == null ? get(key) : cached;

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] Keep a cold object hidden until its ID mapping is published

On a miss, get(key) installs the object in the shared MetaCache before this method reaches the pre-action hook and reacquires the FE stripe. If another same-stripe mutation holds that monitor, cache-only/name paths can already observe the object while ExternalCatalog.getDbNullable(id) or ExternalDatabase.getTableNullable(id) still reads an empty IdNameIndex and returns null. The base path also put immediately before the index action, so unlocked readers had a very small interval, but it acquired the stripe (and passed the test hook) before publishing either side; this refactor turns that into an interval that can block behind stripe contention. Please keep the value unpublished until the validated auxiliary action succeeds, and cover database/table by-ID lookups with a latch-based test.

Runnable validation = Objects.requireNonNull(validationAction, "validationAction can not be null");
StripeState<K> stripe = stripeState(key);
synchronized (stripe) {
V updated = effectiveEnabled ? remapper.apply(key, data.getIfPresent(key)) : null;

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] Make name-snapshot remapping atomic with refresh

updated is derived from the current cached snapshot here, but the later invalidate/put pair is protected only by the FE stripe. Shared-runtime refresh does not take that stripe, so it can publish a newer snapshot N1 after this read; the remapper then invalidates N1 and installs U derived from the older N0, dropping any unrelated database/table names that arrived in the refresh until another full reload. Both database- and table-name caches enable auto-refresh, and their incremental add/drop paths use these remappers. Please add an exact-key atomic remap/compare-and-retry primitive so a concurrent refresh forces the function to re-evaluate the new value, with latch tests for both name caches.

V refreshed = loadAndRecord(key, loader);
if (refreshed != null) {
synchronized (lease.keyNode) {
publishCommitted(lease, key, refreshed);

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] Do not let an old refresh replace a newer miss result

This commit validates only the refresh lease's key/scope states, not that the wrapper which triggered the refresh is still current. A concrete production schedule is: refresh R starts from V1 and captures the old remote result; capacity/expiry evicts V1 without changing KeyState or loadPublicationState; a normal miss then loads and publishes V2 using those same identities; finally R reaches this line and overwrites V2 with stale V1. Bounded multi-key FE schema caches enable auto-refresh, so eviction makes this reachable. Please require the exact current wrapper/registration to remain current at refresh commit (or use expected-value conditional replacement), and add a latch test for eviction plus a newer miss.

924060929 added a commit to 924060929/incubator-doris that referenced this pull request Aug 11, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66407

Problem Summary: The unified metadata cache still exposed duplicate invalidation ownership through CachingHmsClient, retained an engine registry and route abstraction for two built-in FE cache types, and used FE-only names that were easy to confuse with the connector cache API. This change makes the connector CatalogMetaCache the sole invalidation owner, publishes partition collection and partition invalidation atomically, removes redundant Hive and Hudi client type branches, and renames FE-only cache adapters and catalog runtimes to describe their actual roles. Remote Doris schema and backend caching remain catalog-scoped, while statistics caches keep their independent asynchronous semantics.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Connector cache, HMS, Hive, and Hudi Maven unit tests
    - Targeted FE unit tests for cache runtime, naming cache, Remote Doris, external catalog/database, and refresh replay
- Behavior changed: No. Internal cache ownership and invalidation publication are refactored without changing external SQL behavior.
- Does this need documentation: No
@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@924060929

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.

Found one new blocking correctness issue, attached inline.

Review status: converged after two complete rounds. The second runtime, connector/FE, and risk-focused passes all returned NO_NEW_VALUABLE_FINDINGS after revalidating the accepted issue and the dismissed candidates.

Checkpoint conclusions:

  • Correctness and concurrency: batched cold-leaf invalidation can let a pre-refresh HMS partition result publish afterward; this is the inline P1. Miss deduplication, exact-key and ancestor fencing, expected-wrapper refresh replacement, FE auxiliary-index publication, and pruning/removal paths otherwise held up.
  • Lifecycle and cleanup: connector-owned CatalogMetaCache instances, lazy HMS construction, close races, refresh teardown, removal callbacks, scope/key pruning, and sibling connector invalidation were traced without another production-reachable defect.
  • Configuration and compatibility: legacy Hive TTL mappings, independent per-entry enable/TTL/capacity controls, disabled-cache behavior, FE/plugin Caffeine linkage, aliases, and default-versus-Remote-Doris routing were checked. No storage/protocol, rolling FE/BE, persisted-state, or FE-BE variable compatibility change applies.
  • Parallel consumers: ADBC, Hive/HMS/Hudi, Iceberg, MaxCompute, Paimon, FE schema/backends caches, local-versus-remote names, ancestor collection scopes, replay/drop/rename/refresh routes, and immutable Iceberg caches were reviewed. No second scope or routing mismatch survived verification.
  • Tests and observability: the new hierarchy, concurrency, leak, disabled-cache, connector, and FE latch tests were inspected; the accepted issue lacks the cold batch-invalidation latch described inline. Cache metrics and failure logging remain available. No builds or tests were run because the authoritative review bundle explicitly prohibits them.

The three pre-existing inline P1 threads were rechecked against the current head and appear addressed: cold FE objects publish their ID mapping inside the guarded commit, name remaps retry exact-wrapper CAS, and refresh replaces only its expected wrapper.

924060929 added a commit to 924060929/incubator-doris that referenced this pull request Aug 11, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66407

Problem Summary: The unified metadata cache still exposed duplicate invalidation ownership through CachingHmsClient, retained an engine registry and route abstraction for two built-in FE cache types, and used FE-only names that were easy to confuse with the connector cache API. This change makes the connector CatalogMetaCache the sole invalidation owner, publishes partition collection and partition invalidation atomically, removes redundant Hive and Hudi client type branches, and renames FE-only cache adapters and catalog runtimes to describe their actual roles. Remote Doris schema and backend caching remain catalog-scoped, while statistics caches keep their independent asynchronous semantics.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Connector cache, HMS, Hive, and Hudi Maven unit tests
    - Targeted FE unit tests for cache runtime, naming cache, Remote Doris, external catalog/database, and refresh replay
- Behavior changed: No. Internal cache ownership and invalidation publication are refactored without changing external SQL behavior.
- Does this need documentation: No
@924060929
924060929 force-pushed the prototype-scoped-metacache-ut branch from 2b2a1b6 to 04e684b Compare August 11, 2026 03:46
@924060929

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.

Request changes: one distinct concurrency/lifecycle correctness issue remains.

Finding

  • [P2] An identity-preserving ScopedMetaCache.compareAndSet still installs a replacement wrapper. During a FeMetaCacheEntry.computeAfterValidation retry, this synchronously reports the exact still-current ExternalDatabase as removed and resets its initialized table caches, ID index, and downstream database scope. The inline comment is attached at ScopedMetaCache.java:293.

Critical checkpoint conclusions

  • Goal and proof: the PR centralizes FE and connector metadata caches behind a catalog-scoped runtime with hierarchical invalidation, shared configuration, lifecycle, and statistics. The implementation and its added unit tests cover most load, refresh, invalidation, bulk-publication, close, and routing schedules, but no test combines an outer names-CAS retry, nested identity-preserving object publication, and the synchronous database removal listener; the accepted finding shows the goal is not fully met.
  • Focus and scope: review_focus.txt contains no additional user-provided focus. All 85 changed files and their production callers/tests were reviewed. The refactor is broad but cohesive; compatibility adapters and connector-local wrappers keep the changes focused on metadata-cache unification.
  • Concurrency and locking: event/refresh/query threads, FE stripes, key monitors, publication gates, generations, and exact wrapper registrations were traced. Late load/refresh/bulk publication and cleanup are otherwise fenced. The accepted same-instance replacement callback is the remaining race. The proposed broader callback deadlock was dismissed because the database entry, table entries, and FE schema runtime use independent CatalogMetaCache owners/registries with no reverse lock edge.
  • Lifecycle and ownership: connector owners close before their remote resources, scoped registrations are pruned, and catalog remove/recreate paths close the appropriate runtime. No static-initialization issue or additional leak/close race was found.
  • Configuration: legacy TTL overlays, non-positive TTL folding, independent enable/capacity controls, disabled-cache semantics, and ephemeral schema-cache property overlay were preserved. No new global dynamic configuration contract requires runtime propagation.
  • Compatibility: cache API/module relocation, preserved signatures, plugin classloading fallbacks, default versus remote-Doris routing, aliases, stats identity, replay, and catalog remove/recreate behavior were checked. No FE-BE protocol or storage-format change is involved.
  • Parallel paths and conditions: ADBC, Hive/HMS/Hudi, Iceberg, MaxCompute, Paimon, FE schema caches, DDL/event/replay paths, exact and collection invalidation, sibling forwarding, credentials, and time-travel variants were traced. No distinct missed path or unjustified condition remained.
  • Tests and results: the PR adds extensive latch/barrier-based FE and cache unit tests, including the previously discussed cold ID publication, names remap, expected-wrapper refresh, and cold bulk-descendant races. The exact accepted removal-listener retry is missing. No generated result file is changed. Tests/builds were not run by this reviewer under the review-only bundle instructions.
  • Error handling and data correctness: loader exception, null-as-miss, disabled-cache, conflict validation, and canonical partition-key behavior were checked. Aside from the accepted lifecycle reset, no silent error, stale publication, ID/name inconsistency, or incorrect invalidation survived review.
  • Observability: cache metrics, per-entry statistics, sorting/deduplication, and existing lifecycle logging are sufficient for the new paths; no additional critical metric or identifier gap was found.
  • Persistence, transactions, and writes: no transaction or user-data write path changes. Persisted catalog properties are not mutated by the derived overlay; EditLog/replay navigation and cold fallbacks were checked without a new persistence issue.
  • FE-BE variables: no new variable or protocol field is passed between FE and BE.
  • Memory safety and BE nullable handling: the change is FE Java metadata-cache code; BE allocator, C++ ownership, and nullable-column checkpoints are not applicable. Java cache ownership, defensive key copies, cleanup, and close were reviewed without another issue.
  • Performance: gate scope, synchronous loaders/callbacks, single-flight admission, bounded caches, node pruning, metrics, and connector-specific cache granularity were checked. No distinct production performance regression or obvious redundant operation was substantiated.
  • Other issues and duplicates: existing discussions 3754745907, 3754745909, 3754745910, and 3755059016 cover the fixed cold object/ID publication, names remap, refresh replacement, and cold bulk-descendant issues and were not duplicated.

Review status: converged after two full rounds. One inline comment is requested; every other candidate was duplicate-suppressed or dismissed with concrete code evidence.

924060929 added a commit to 924060929/incubator-doris that referenced this pull request Aug 11, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66407

Problem Summary: The unified metadata cache still exposed duplicate invalidation ownership through CachingHmsClient, retained an engine registry and route abstraction for two built-in FE cache types, and used FE-only names that were easy to confuse with the connector cache API. This change makes the connector CatalogMetaCache the sole invalidation owner, publishes partition collection and partition invalidation atomically, removes redundant Hive and Hudi client type branches, and renames FE-only cache adapters and catalog runtimes to describe their actual roles. Remote Doris schema and backend caching remain catalog-scoped, while statistics caches keep their independent asynchronous semantics.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Connector cache, HMS, Hive, and Hudi Maven unit tests
    - Targeted FE unit tests for cache runtime, naming cache, Remote Doris, external catalog/database, and refresh replay
- Behavior changed: No. Internal cache ownership and invalidation publication are refactored without changing external SQL behavior.
- Does this need documentation: No
@924060929
924060929 force-pushed the prototype-scoped-metacache-ut branch from 04e684b to 97ef95e Compare August 11, 2026 10:13
@924060929

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.

Review complete for head 97ef95eaa15a40ce82eba7f02877a35ea4602f88: no new actionable findings. This is a comment-only, no-blocker opinion.

Critical checkpoint conclusions:

  • Goal and proof: the PR unifies FE and connector metadata caches behind catalog-owned runtimes with shared configuration, hierarchical invalidation, lifecycle, and statistics. The implementation accomplishes that goal, and the added unit suites cover load/publication, exact and ancestor invalidation, refresh, bulk loading, close, pruning/leak behavior, routing, and connector migrations.
  • Scope and design: this is necessarily broad, but the changes stay focused on the cache-framework consolidation, its compatibility adapters, connector migrations, and their tests. Existing mechanisms are reused and no unrelated behavior change was found.
  • Concurrency and locking: query/event/refresh threads, FE stripes, phase gates, key monitors, scope/key generations, Caffeine removal callbacks, and refresh executors were traced. Remote loads and other heavy work remain outside publication locks; reachable production paths have consistent lock ordering; exact wrapper/state checks fence stale load, refresh, CAS, and bulk publication; and callbacks are deferred outside gates. No reachable deadlock or stale-publication defect remains.
  • Lifecycle and configuration: connector-owned runtimes close before their remote clients/catalogs, Hive closes built siblings, FE engine runtimes are removed and closed, and key/scope/tombstone state is reclaimed on eviction, invalidation, handle release, and close. Legacy enable/TTL/capacity parsing, disabled behavior, plugin overlays, and rebuild-on-property-change semantics are preserved; no new dynamic configuration contract was introduced.
  • Compatibility and parallel paths: default versus Remote Doris routing, the external_doris alias, local/remote name mappings, missing-catalog cleanup, replay/DDL/event paths, and ADBC, Hive/HMS/Hudi, Iceberg, MaxCompute, and Paimon scope projections were checked. Snapshot, branch, system-table, namespace, and partition variants converge on their owning ancestor invalidations. No storage format, public symbol, persisted-state encoding, or FE/BE protocol compatibility change is involved.
  • Tests and results: 24 changed unit-test files include deterministic latch/barrier coverage for the altered concurrency boundaries plus hierarchy, leak, configuration, routing, and connector invalidation cases. No generated regression result changes apply. Builds and tests were not run because the authoritative review instructions explicitly prohibit them, so this conclusion is based on static review of the current head and test sources.
  • Error handling, memory, observability, and performance: loader failures/null misses, disabled-cache pass-through, refresh rejection, callback failures, metrics/statistics, bounded hierarchy traversal, single-flight admission, and cleanup accounting were reviewed. Failures are surfaced or logged at the existing boundaries, remote I/O is not performed under cache locks, and no additional material correctness, leak, observability, or performance issue was substantiated.
  • Persistence, transactions, data writes, and FE/BE variables: not applicable; this refactor does not alter transaction or user-data write paths, EditLog formats, storage visibility, or variables sent between FE and BE.

The five existing live inline findings—cold object/ID publication, name-snapshot remapping, expected-wrapper refresh replacement, cold descendant batch invalidation, and identity-preserving CAS removal—are addressed in the current head and were not duplicated. There was no additional user-provided review focus.

Review status: converged after two complete full-scope rounds and independent risk-focused rechecks. All 85 authoritative changed paths were swept, every candidate was validated or dismissed with concrete production-path evidence, and no unresolved point or inline comment remains.

0AyanamiRei added a commit to 0AyanamiRei/doris that referenced this pull request Aug 20, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Routine Load cannot safely use the legacy Expr object graph as an image or journal compatibility surface. Keep the current effective load definition in origStmt, remove the duplicate execMemLimit JSON source, and cover all SQL-representable load clauses through CREATE image restore, ALTER merge, and a second image restore.

### Release note

Routine Load now persists ALTERed load clauses in the effective origin SQL used during FE recovery.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
    - Docker regression case added but not run locally
- Behavior changed: Yes, ALTERed Routine Load definitions survive journal replay and image recovery
- Does this need documentation: Yes, the existing design document and PR description must be updated
0AyanamiRei added a commit to 0AyanamiRei/doris that referenced this pull request Aug 20, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Routine Load images already persist and replay origStmt. The persistence bug is that ALTER load clauses changed runtime fields without updating that statement. Keep the existing gsonPostProcess recovery path unchanged, persist the original ALTER SQL in the journal, and rewrite origStmt to a complete effective CREATE statement after leader and follower ALTER application. Remove direct-field persistence, cache hydration, CSV validation, and other adjacent changes from this PR.

### Release note

Routine Load now preserves ALTERed load clauses across follower replay, checkpoints, and FE restart by maintaining the effective CREATE statement.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.KinesisRoutineLoadJobTest
    - KafkaRoutineLoadJobTest and AlterRoutineLoadOperationLogTest passed in the combined targeted run
    - Docker regression case added but not run locally
- Behavior changed: Yes, ALTERed load clauses update the persisted origin statement
- Does this need documentation: Yes, document mixed-version ALTER limitations
0AyanamiRei added a commit to 0AyanamiRei/doris that referenced this pull request Aug 20, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Treat the effective Routine Load fields as authoritative metadata instead of rewriting origStmt after ALTER. Persist the load-definition fields directly in images, persist RoutineLoadDesc deltas in ALTER journals, and use the original CREATE statement only when reading legacy images whose nullable effective fields are absent. Empty new definitions may also use the fallback safely because ALTER cannot unset all load clauses.

### Release note

Routine Load now preserves ALTERed load clauses across journal replay and FE restart through direct metadata persistence.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: Yes, image and ALTER journal persist effective Routine Load definitions directly
- Does this need documentation: Yes, document mixed-version ALTER limitations
0AyanamiRei added a commit to 0AyanamiRei/doris that referenced this pull request Aug 20, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: Metadata consumers now persist legacy Expr objects directly, but the existing Expr Gson test only checked subtype and JSON idempotence. Add stable serialization for SQL-relevant fields that were silently dropped, persist function ORDER BY metadata, require every Expr instance field to be serialized or explicitly classified as non-durable, and verify SQL output with and without table names for every concrete registered subtype. Add an analysis review guide for future Expr changes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest,org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: No user-facing SQL behavior; metadata Expr round trips now preserve SQL semantics
- Does this need documentation: No, contributor guidance is included in analysis/AGENTS.md
0AyanamiRei added a commit to 0AyanamiRei/doris that referenced this pull request Aug 20, 2026
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66634

Problem Summary: The first restoration of direct Routine Load persistence omitted parts of the previously reviewed design. Restore the exact persistence implementation from commit 4394fa3, including execMemLimit and memtableOnSinkNode image fields, jobProperties cache hydration, CSV ALTER cache synchronization, leader-only validation, legacy image migration, and the original Kafka/Kinesis persistence tests. Keep the separate Expr serde hardening on top.

### Release note

Routine Load persists its effective load definition and non-default task configuration directly across FE recovery.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.analysis.ExprGsonSerializationTest,org.apache.doris.load.routineload.RoutineLoadJobPersistenceTest,org.apache.doris.load.routineload.KafkaRoutineLoadJobTest,org.apache.doris.load.routineload.KinesisRoutineLoadJobTest,org.apache.doris.persist.AlterRoutineLoadOperationLogTest
- Behavior changed: Yes, restore the complete direct-state image and ALTER journal persistence contract
- Does this need documentation: Yes, document mixed-version ALTER limitations
924060929 added a commit to 924060929/incubator-doris that referenced this pull request Aug 24, 2026
Problem Summary:
PR apache#64160 added row-count cache invalidation and a test-only engine cache replacement hook after this branch diverged. Merging current master conflicted with the scoped metadata cache test setup and left the old registry-based test hook incompatible with the new cacheTypes framework.

Solution:
Preserve the row-count cache implementation and invalidation ordering from apache#64160. Resolve RefreshManagerTest against FeMetaCacheEntry and migrate replaceEngineCachesForTest to register replacement engines and aliases through the new cacheTypes model.

Tests:
- 116 focused FE unit tests passed
- 104 connector cache unit tests passed
- Maven Checkstyle reactor passed with 0 violations

Issue Number: close apache#66633
Related PR: apache#64160
924060929 added a commit to 924060929/incubator-doris that referenced this pull request Aug 24, 2026
Problem Summary:
Master advanced after the initial conflict resolution and introduced Paimon HMS identity isolation changes that overlapped the scoped Paimon cache refactor at the connector imports.

Solution:
Preserve the new HMS FileIO and catalog construction path while retaining CatalogMetaCache-based invalidation. Drop only the obsolete Identifier import, which is no longer used after table invalidation is routed through the scoped cache hierarchy.

Tests:
- 554 Paimon connector tests passed (1 skipped)
- Checkstyle validation passed in the FE reactor

Issue Number: close apache#66633
@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 82402 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 eb5efc9cd11b9a673b5ebc45b90a9c88fcb86410, data reload: false

query5	4241	402	339	339
query6	416	140	126	126
query7	4937	443	234	234
query8	305	123	120	120
query9	8727	2892	2867	2867
query10	396	225	185	185
query11	5384	1073	936	936
query12	127	72	71	71
query13	1197	435	314	314
query14	5978	2278	2095	2095
query14_1	2007	1971	1964	1964
query15	178	127	110	110
query16	936	365	371	365
query17	808	453	382	382
query18	2356	339	240	240
query19	177	142	109	109
query20	72	69	72	69
query21	211	103	85	85
query22	5517	5515	5443	5443
query23	6835	6240	6116	6116
query23_1	6093	6044	6296	6044
query24	7327	1112	753	753
query24_1	791	784	778	778
query25	447	317	268	268
query26	1227	247	127	127
query27	2772	418	264	264
query28	4695	1498	1506	1498
query29	957	450	369	369
query30	262	159	134	134
query31	843	408	333	333
query32	103	51	50	50
query33	481	228	191	191
query34	1040	837	488	488
query35	416	422	357	357
query36	577	574	532	532
query37	127	84	72	72
query38	1021	860	851	851
query39	526	498	487	487
query39_1	457	484	492	484
query40	211	93	86	86
query41	60	56	57	56
query42	76	77	75	75
query43	272	240	208	208
query44	1038	538	542	538
query45	110	105	98	98
query46	781	867	533	533
query47	781	756	713	713
query48	298	296	231	231
query49	548	244	181	181
query50	780	258	200	200
query51	8115	8086	7978	7978
query52	72	100	69	69
query53	192	204	142	142
query54	245	179	164	164
query55	84	59	56	56
query56	195	159	187	159
query57	713	701	599	599
query58	206	168	162	162
query59	1199	1217	1073	1073
query60	271	179	170	170
query61	133	110	112	110
query62	363	203	175	175
query63	169	140	137	137
query64	2822	677	587	587
query65	1667	1642	1624	1624
query66	1867	272	229	229
query67	10038	9912	9971	9912
query68	2777	1167	704	704
query69	361	227	203	203
query70	659	599	596	596
query71	254	186	170	170
query72	2360	1767	1359	1359
query73	660	628	341	341
query74	1561	1254	1171	1171
query75	1210	1130	995	995
query76	2298	752	537	537
query77	245	262	223	223
query78	4048	3912	3234	3234
query79	2343	804	590	590
query80	1584	319	279	279
query81	493	159	134	134
query82	662	125	97	97
query83	283	219	193	193
query84	301	112	88	88
query85	792	354	289	289
query86	413	178	175	175
query87	1032	987	911	911
query88	2881	2118	2101	2101
query89	298	195	177	177
query90	1990	128	128	128
query91	134	123	100	100
query92	55	48	46	46
query93	1499	1071	693	693
query94	670	275	222	222
query95	553	263	233	233
query96	801	581	266	266
query97	1086	1067	986	986
query98	144	145	135	135
query99	427	351	318	318
Total cold run time: 178577 ms
Total hot run time: 82402 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.05	0.04
query3	0.25	0.11	0.11
query4	1.60	0.10	0.10
query5	0.17	0.16	0.16
query6	1.25	0.68	0.68
query7	0.03	0.01	0.01
query8	0.04	0.03	0.03
query9	0.29	0.21	0.21
query10	0.35	0.34	0.34
query11	0.17	0.12	0.11
query12	0.15	0.12	0.12
query13	0.30	0.32	0.31
query14	0.49	0.46	0.45
query15	0.36	0.35	0.35
query16	0.21	0.22	0.21
query17	0.68	0.72	0.66
query18	0.19	0.18	0.17
query19	1.22	1.23	1.18
query20	0.02	0.01	0.01
query21	15.46	0.16	0.12
query22	5.05	0.04	0.04
query23	16.20	0.26	0.10
query24	3.38	0.30	0.28
query25	0.12	0.04	0.04
query26	0.74	0.16	0.13
query27	0.04	0.04	0.03
query28	3.67	0.58	0.29
query29	12.43	3.20	2.55
query30	0.26	0.11	0.13
query31	2.76	0.36	0.18
query32	3.51	0.31	0.23
query33	1.39	1.48	1.58
query34	15.49	2.18	1.78
query35	1.77	1.78	1.74
query36	0.47	0.31	0.29
query37	0.07	0.04	0.04
query38	0.05	0.03	0.03
query39	0.04	0.02	0.03
query40	0.11	0.08	0.07
query41	0.08	0.03	0.02
query42	0.04	0.02	0.02
query43	0.04	0.03	0.03
Total cold run time: 91.03 s
Total hot run time: 14.87 s

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Metadata cache invalidation needs catalog, database, table, partition, and exact-key isolation without stale publication races or unbounded secondary-index retention. Add an isolated catalog-local scoped cache prototype with generation-aware single-flight loading, exact-key and hierarchical publication fencing, atomic bulk commit, conditional physical cleanup, and bottom-up scope/key-node reclamation. The prototype is not wired into existing metadata cache callers yet. Add deterministic tests for the complete scope matrix, refresh/load/bulk/close races, delayed removal callbacks, generation overflow, eviction, lifecycle closure, high-cardinality churn, and a seeded reference-model state machine.

### Release note

None

### Check List (For Author)

- Test: Unit Test and FE build
    - Unit Test: fe-connector-cache Maven reactor, 86 tests passed
    - Unit Test: focused JDK 17 run-fe-ut review suite passed
    - FE build: JDK 17 ./build.sh --fe with a fresh output directory passed
- Behavior changed: No. The prototype is not connected to production callers.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: The scoped metadata cache correctness prototype allocated generic lists and snapshots on scope acquisition, recomputed single-flight address hashes, serialized bulk candidates through a redundant preliminary lock, and performed duplicate detached-entry cleanup. Share an immutable fixed-layout generation snapshot per leaf state, cache address hashes, publish bulk values only after the final fence succeeds, and make invalidation own each detached registration before physical removal. In local microbenchmarks this reduces cache-hit latency from 84-95 ns to about 61 ns, reduces same-table retained overhead from about 569 bytes to 369 bytes per entry, and raises eight-thread bulk throughput from about 1.33 million to 1.56 million operations per second while preserving the state-identity invalidation protocol.

### Release note

None

### Check List (For Author)

- Test: Unit Test and FE build
    - Unit Test: fe-connector-cache Maven reactor, 87 tests passed
    - Unit Test: focused JDK 17 run-fe-ut review suite, 54 tests passed
    - FE build: JDK 17 ./build.sh --fe with a fresh output directory passed
- Behavior changed: No. The prototype is not connected to production callers.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Cold scoped metadata loads repeatedly allocated varargs arrays and capturing lambdas and computed identity hashes for state tokens even though single-flight hashing only needs stable key and path distribution. Use allocation-free path hashing cached per shared scope snapshot, use a get/putIfAbsent scope-child fast path, cache cache-address hashes, keep full generation identity comparisons in LoadAddress.equals, and remove a redundant bulk scope check before the final publication fence. Matched local microbenchmarks reduced cold load from 652.5-768.5 ns/op to 442.6 ns/op while independent cache-hit latency remained effectively unchanged. Current-head profiling no longer shows the identityHashCode, ScopePath Object array, or child lambda hotspots.

### Release note

None

### Check List (For Author)

- Test: Unit Test and FE build
    - Unit Test: 87 fe-connector-cache tests and 54 focused scoped-cache tests
    - FE build: ./build.sh --fe
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Scoped metadata bulk publication used exclusive per-cache and registry monitors, serializing independent keys and cache owners. Replace those publication barriers with writer-preferred striped phase gates while keeping exact-key and hierarchical invalidation exclusive. Defer synchronous Caffeine removal callbacks until publication phases are released, preserve expected-value cleanup under callback reentrancy and failures, and coordinate scope-node retain, child creation, invalidation, and pruning with an exact lifecycle marker. In matched eight-thread benchmarks, the correctness-safe implementation improves same-cache publication from about 1.3-1.4 M ops/s to 2.8-3.2 M ops/s and same-registry publication from about 1.8 M ops/s to 3.0-3.3 M ops/s. CPU and lock profiles show the remaining same-cache lock bottleneck is Caffeine maintenance rather than the framework publication barriers.

### Release note

None

### Check List (For Author)

- Test: Unit Test and manual performance profiling
    - Unit Test: `./run-fe-ut.sh --run org.apache.doris.connector.cache.*Test` (99 tests; full FE reactor BUILD SUCCESS)
    - Manual test: matched eight-thread topology benchmarks and async-profiler CPU/lock profiles
- Behavior changed: Yes (independent bulk publications can overlap while invalidation and close remain exclusive)
- Does this need documentation: No
@morrySnow morrySnow changed the title [refactor](fe) Unify external metadata cache framework [refactor](catalog) Unify external metadata cache framework Aug 26, 2026
Issue Number: None

Related PR: None

Problem Summary: FE naming caches and connector metadata caches used duplicate cache wrappers and independently maintained invalidation dependencies. This refactor makes fe-connector-cache the shared runtime for scoped generation fencing, hierarchical invalidation, load deduplication, refresh, eviction cleanup, and lifecycle management. FE keeps only its naming and ID-index publication adapter, while ADBC, Hive, HMS, Hudi, Iceberg, MaxCompute, and Paimon use catalog-scoped shared cache owners. It also removes the duplicate CacheSpec and obsolete cache implementations, preserves per-catalog isolation, and closes concurrent identity-publication and refresh-close cleanup windows.

None

- Test: Unit Test
    - fe-connector-cache: 100 tests passed
    - FE targeted metadata cache tests: 93 tests passed
    - Iceberg cache tests: 66 tests passed
    - ./build.sh --fe
- Behavior changed: No. This is an internal cache framework refactor preserving existing metadata semantics.
- Does this need documentation: No
Issue Number: close apache#66633

Related PR: apache#66407

Problem Summary: The unified metadata cache still exposed duplicate invalidation ownership through CachingHmsClient, retained an engine registry and route abstraction for two built-in FE cache types, and used FE-only names that were easy to confuse with the connector cache API. This change makes the connector CatalogMetaCache the sole invalidation owner, publishes partition collection and partition invalidation atomically, removes redundant Hive and Hudi client type branches, and renames FE-only cache adapters and catalog runtimes to describe their actual roles. Remote Doris schema and backend caching remain catalog-scoped, while statistics caches keep their independent asynchronous semantics.

None

- Test: Unit Test
    - Connector cache, HMS, Hive, and Hudi Maven unit tests
    - Targeted FE unit tests for cache runtime, naming cache, Remote Doris, external catalog/database, and refresh replay
- Behavior changed: No. Internal cache ownership and invalidation publication are refactored without changing external SQL behavior.
- Does this need documentation: No
Issue Number: close apache#66633

Problem Summary: Direct, bulk, and loader publication paths could invoke synchronous removal callbacks while publication locks were still held or acquire a key monitor before the phase gates. Route all commits through the phase-gate/key ordering, defer callbacks until after unlocking, and restore the merged row-count cache test seam against the new engine cache registry.

None

- Test: Unit Test
    - Scoped metadata cache module and concurrency tests
    - ExternalRowCountCacheTest and RefreshManagerTest
    - Paimon and Iceberg connector Maven tests
    - Full FE build
- Behavior changed: No. The change preserves cache publication and invalidation semantics while removing lock inversion and callback re-entry hazards.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66914

Problem Summary: Rebasing the unified external metadata cache framework over the Iceberg resource-lifecycle fix exposed a missing ownership transition. Values loaded while caching is disabled, or values whose load or refresh loses a concurrent publication race, never become cache-owned but still reserve a cache-owner reference. Retire those unpublished values through the removal callback, preserve the explicit removal reason, and cover disabled loads, rejected refreshes, and stale concurrent loads with regression tests. Also remove stale references to the deleted MetaCacheEntry type.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - fe-connector-cache module tests (108 tests)
    - IcebergTableCacheTest (12 tests)
    - Iceberg connector module test suite (1355 tests; one unrelated existing IcebergWritePlanProviderTest failure)
    - Full FE build
- Behavior changed: No. The change preserves the resource-retirement semantics of the merged Iceberg lifecycle fix in the unified cache framework.
- Does this need documentation: No
@924060929
924060929 force-pushed the prototype-scoped-metacache-ut branch from eb5efc9 to 1182998 Compare August 26, 2026 02:40
@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@924060929

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.

Request changes: four distinct P2 ownership/lifecycle defects remain in the new shared cache runtime.

The overall design is coherent and does centralize connector cache ownership, hierarchical invalidation, metrics, and FE adaptation as intended, with substantial unit coverage. The current implementation does not yet preserve value ownership across disabled loads, invalidation-losing loads, identity-preserving refresh, and executor cancellation.

Critical checkpoint conclusions:

  • Concurrency: query misses, refresh-executor work, exact/scope invalidation, and catalog close were traced end to end. The current bulk -> registry -> key lock order and deferred synchronous callbacks close the already-reported deadlocks; the four inline lifecycle schedules remain.
  • Lifecycle/resources: disabled and rejected miss results can be reset before their caller receives them; identity refresh can retire the retained object; an accepted but discarded refresh task can permanently retain its lease/marker. Iceberg's explicit temporary loader/borrow references are otherwise balanced.
  • Configuration: the existing supported TTL-zero setting deterministically triggers one finding. No separate new-configuration or dynamic-update defect was found.
  • Parallel paths/compatibility: ADBC, Hive/HMS, Hudi, Iceberg, MaxCompute, Paimon, FE engine routing, child-first plugin loading, and pom/Caffeine boundaries were checked. Scope identities match their invalidation callers; no FE/BE protocol, storage-format, persistence, transaction, or data-write compatibility issue applies.
  • Tests/results: 27 changed test files cover the framework broadly, but omit the four ownership/cancellation schedules called out inline. Local builds/tests were not run because this review runner explicitly forbids builds. Live style, license, secrets, and dependency-review checks pass; FE UT, compile, performance, and this automated review check are still pending.
  • Observability/performance: cache metrics and logging are generally adequate. The TTL-zero defect also turns read-only database lookup into repeated downstream metadata invalidation; no additional distinct performance issue survived review.
  • User focus: the supplied focus file requested no additional focus.

The bounded three-round review converged with no new finding in the cap round; it is complete rather than capped/incomplete. All candidates were independently verified and deduplicated against the live review threads.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17692	3128	3099	3099
q2	2107	257	227	227
q3	10214	877	511	511
q4	4675	258	199	199
q5	7666	570	379	379
q6	137	112	96	96
q7	526	501	378	378
q8	9243	897	857	857
q9	3445	2431	2422	2422
q10	6552	871	715	715
q11	395	199	184	184
q12	611	260	191	191
q13	18134	1552	1175	1175
q14	161	146	135	135
q15	q16	432	391	364	364
q17	1370	937	752	752
q18	3069	2267	2239	2239
q19	1121	947	793	793
q20	382	293	190	190
q21	5288	1792	1864	1792
q22	330	267	239	239
Total cold run time: 93550 ms
Total hot run time: 16937 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3526	3453	3448	3448
q2	525	397	368	368
q3	2295	2350	2179	2179
q4	1191	1165	899	899
q5	2183	2123	2122	2122
q6	179	125	87	87
q7	1029	946	879	879
q8	1621	1452	1438	1438
q9	3160	3136	3112	3112
q10	1861	1781	1586	1586
q11	359	274	253	253
q12	448	425	348	348
q13	1476	1541	1166	1166
q14	175	169	158	158
q15	q16	396	391	356	356
q17	3645	3307	3195	3195
q18	4848	4461	4715	4461
q19	1464	884	853	853
q20	979	963	795	795
q21	3776	3142	3233	3142
q22	390	347	324	324
Total cold run time: 35526 ms
Total hot run time: 31169 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 82249 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 118299877361395b2b17bb22eb430e651b45371a, data reload: false

query5	4278	389	331	331
query6	397	141	121	121
query7	4983	428	224	224
query8	298	124	116	116
query9	8679	2906	2892	2892
query10	414	217	180	180
query11	5402	1023	922	922
query12	121	73	73	73
query13	1200	454	319	319
query14	6000	2204	2082	2082
query14_1	1985	1976	1965	1965
query15	177	122	109	109
query16	3125	385	344	344
query17	783	451	363	363
query18	2086	333	243	243
query19	169	139	110	110
query20	72	67	70	67
query21	201	102	88	88
query22	5547	5367	5427	5367
query23	6615	6241	5998	5998
query23_1	6015	6189	6062	6062
query24	7341	1117	791	791
query24_1	775	787	778	778
query25	454	312	267	267
query26	1213	216	135	135
query27	2787	431	262	262
query28	4645	1507	1468	1468
query29	954	447	367	367
query30	387	149	132	132
query31	848	400	333	333
query32	129	77	77	77
query33	496	220	183	183
query34	1022	818	485	485
query35	397	391	340	340
query36	595	597	542	542
query37	125	81	72	72
query38	1031	853	841	841
query39	518	500	470	470
query39_1	505	464	459	459
query40	250	89	78	78
query41	59	57	57	57
query42	78	70	71	70
query43	237	245	209	209
query44	1046	545	572	545
query45	107	109	107	107
query46	742	870	528	528
query47	806	770	703	703
query48	307	310	237	237
query49	553	223	179	179
query50	764	262	194	194
query51	8547	8358	8201	8201
query52	67	68	92	68
query53	191	194	141	141
query54	218	174	171	171
query55	74	61	53	53
query56	181	164	149	149
query57	684	644	669	644
query58	193	168	155	155
query59	1174	1197	1071	1071
query60	230	177	172	172
query61	121	119	118	118
query62	391	211	181	181
query63	166	131	144	131
query64	2342	706	571	571
query65	1579	1577	1546	1546
query66	1743	285	214	214
query67	10029	9738	9768	9738
query68	2864	1209	776	776
query69	522	222	200	200
query70	680	626	607	607
query71	249	171	165	165
query72	2441	1741	1516	1516
query73	711	589	312	312
query74	1853	1230	1125	1125
query75	1168	1097	966	966
query76	1868	740	532	532
query77	250	261	214	214
query78	3871	3736	3247	3247
query79	2391	794	574	574
query80	1530	328	277	277
query81	514	153	132	132
query82	745	133	93	93
query83	293	219	197	197
query84	299	115	92	92
query85	823	359	300	300
query86	442	193	168	168
query87	1030	978	894	894
query88	2808	2087	2079	2079
query89	301	198	177	177
query90	1977	127	120	120
query91	133	125	98	98
query92	82	69	72	69
query93	1518	1056	735	735
query94	660	232	221	221
query95	525	328	235	235
query96	809	556	271	271
query97	1070	1113	1025	1025
query98	160	146	137	137
query99	511	340	301	301
Total cold run time: 181165 ms
Total hot run time: 82249 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.31	0.04	0.03
query3	0.60	0.11	0.11
query4	1.71	0.10	0.09
query5	0.18	0.15	0.15
query6	1.56	0.71	0.67
query7	0.04	0.01	0.01
query8	0.05	0.03	0.03
query9	0.64	0.22	0.21
query10	0.35	0.34	0.35
query11	0.28	0.11	0.12
query12	0.21	0.12	0.12
query13	0.32	0.31	0.31
query14	0.46	0.45	0.44
query15	0.38	0.34	0.34
query16	0.23	0.22	0.22
query17	0.70	0.66	0.68
query18	0.18	0.18	0.17
query19	1.49	1.18	1.20
query20	0.02	0.01	0.01
query21	16.78	0.16	0.12
query22	4.76	0.05	0.04
query23	16.92	0.25	0.11
query24	16.75	0.33	0.26
query25	0.10	0.04	0.03
query26	0.71	0.17	0.12
query27	0.04	0.03	0.04
query28	3.63	0.53	0.26
query29	12.60	3.12	2.56
query30	0.25	0.12	0.12
query31	2.89	0.37	0.18
query32	3.56	0.31	0.22
query33	1.37	1.47	1.52
query34	15.35	2.23	1.76
query35	1.74	1.71	1.68
query36	0.47	0.30	0.29
query37	0.26	0.04	0.03
query38	0.04	0.03	0.03
query39	0.25	0.03	0.02
query40	0.20	0.08	0.07
query41	0.37	0.02	0.02
query42	0.15	0.02	0.02
query43	0.04	0.03	0.02
Total cold run time: 108.95 s
Total hot run time: 14.66 s

### What problem does this PR solve?

Issue Number: close apache#66633

Related PR: apache#66914

Problem Summary: The unified cache runtime used the removal callback for values that never became cache-owned and acquired refresh publication leases before asynchronous tasks started. A disabled or invalidation-rejected FE database load could therefore return an already-reset object, identity refresh could retire the same object, and discarded queued refresh work could retain publication state. Separate unpublished-value discard from published-value removal, keep identity refresh wrapper ownership, acquire refresh leases inside tasks, release refresh admission on close, and remove a stale external-table comment.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - fe-connector-cache module tests (110 tests)
    - FeMetaCacheEntryTest (14 tests)
    - IcebergTableCacheTest (12 tests)
    - Full FE build
- Behavior changed: No. Preserves pre-refactor ownership and cleanup semantics.
- Does this need documentation: No
@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@924060929

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.

Automated review result: request changes. I found one new actionable FE publication race and attached it inline. I read the existing review threads and raw comments first; no existing issue is duplicated. There was no additional user-provided focus.

Checkpoint conclusions:

  • Goal, accomplishment, and tests: The change establishes the shared catalog-scoped metadata-cache framework and migrates the intended FE/connector caches with substantial focused unit coverage. MAIN-01 shows that the FE name/object/ID publication goal is not yet complete for incremental database registration.
  • Scope and clarity: The diff is large but cohesive around one cache-framework migration. Framework, FE adapter, and connector-specific responsibilities are generally separated clearly.
  • Concurrency: I traced miss election, refresh, direct put/CAS, bulk publication, exact and hierarchical invalidation, pruning, synchronous callbacks, and close across the phase gates, per-key monitors, and FE stripes. The inline issue is a distinct unlocked ID-index visibility window before the object CAS. I found no additional lock inversion, stale-publication, leak, or double-retirement schedule beyond the already-live threads.
  • Lifecycle and initialization: Shared owners are closed by each migrated connector; late loads are fenced, and Iceberg cache/loader/borrower/catalog-generation references remain balanced. Static initialization and connector classloader boundaries did not expose a new issue.
  • Configuration: Enable/disable, TTL, refresh, capacity, stripe-count, and connector-specific cache knobs retain their intended construction-time behavior. No new dynamic-config handling defect was found.
  • Compatibility and rolling behavior: The moved cache API is not a connector SPI contract; plugin dependency/classloader closure and current call sites were checked. Remote Doris/default routing and exact built-in engine constants remain reachable. No wire, persisted-format, or mixed-FE/BE compatibility change was introduced.
  • Parallel paths: ADBC, Hive/HMS/Hudi, Iceberg, MaxCompute, Paimon, FE database/table caches, and missing-catalog cleanup were compared. Scope/invalidation parity is preserved; the one surviving discrepancy is the incremental FE database path described inline.
  • Special conditions and related paths: Cold/hot entries, disabled caches, rejected publication, eviction, refresh, batch invalidation, catalog/database/table/partition invalidation, close, and late completion were checked. Similar tests and callers were inspected, and comments match the current mechanisms.
  • Test coverage and modularity: The framework has focused hierarchy, concurrency, leak, lifecycle, and connector tests. The missing negative case is a latch test that lets a by-ID database lookup publish between validation.run() and the CAS. No local build or test was run because this review task explicitly prohibited it.
  • Test results: At review time, BE UT, Cloud UT, coverage, dependency review, style, license, and secret checks passed; compile, FE UT, performance, and the code-review workflow were still pending. I did not infer success for pending checks.
  • Observability: Cache hit/miss/load/eviction/error and hierarchy metrics remain available; refresh/close failures retain logging. No new observability blocker was found.
  • Transactions and persistence: This refactor does not change transaction boundaries, edit logs, durable metadata formats, or failover replay semantics.
  • Data writes and crash safety: The change affects ephemeral metadata caching rather than storage-engine writes, so atomic durable-write/crash-recovery checks are not applicable.
  • FE/BE variables and nullable semantics: The changed behavior is FE/connector-local and adds no FE-to-BE variable or protocol path. BE nullable-column handling is not applicable.
  • Performance: Remote loaders remain outside critical sections, shared scopes are bounded/pruned, and cache capacities remain explicit. I found no distinct new performance regression.
  • Other issues: No additional valuable findings survived validation and duplicate fencing.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17665	3119	3133	3119
q2	2230	266	225	225
q3	10101	864	519	519
q4	4686	247	201	201
q5	7669	576	368	368
q6	161	114	97	97
q7	536	503	381	381
q8	9275	924	904	904
q9	3474	2433	2398	2398
q10	6492	866	696	696
q11	492	193	176	176
q12	650	250	195	195
q13	18131	1503	1153	1153
q14	156	149	143	143
q15	q16	448	392	363	363
q17	1453	933	809	809
q18	3086	2238	2230	2230
q19	1273	937	819	819
q20	396	286	205	205
q21	5591	1753	1797	1753
q22	339	265	224	224
Total cold run time: 94304 ms
Total hot run time: 16978 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3552	3418	3405	3405
q2	500	394	362	362
q3	2207	2337	2185	2185
q4	1183	1167	896	896
q5	2204	2137	2080	2080
q6	170	127	87	87
q7	1021	912	850	850
q8	1612	1413	1418	1413
q9	3147	3152	3134	3134
q10	1832	1777	1619	1619
q11	359	269	249	249
q12	450	434	349	349
q13	1521	1523	1173	1173
q14	176	179	160	160
q15	q16	407	389	369	369
q17	3573	3291	3159	3159
q18	4930	4413	4693	4413
q19	991	901	880	880
q20	1020	971	795	795
q21	3776	3056	3205	3056
q22	394	349	309	309
Total cold run time: 35025 ms
Total hot run time: 30943 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81459 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 5c0c8571519df064afda155d5ff9f0c39f912096, data reload: false

query5	4299	414	348	348
query6	398	137	134	134
query7	4912	430	235	235
query8	294	128	114	114
query9	8682	2897	2872	2872
query10	394	224	180	180
query11	5369	1038	906	906
query12	123	71	74	71
query13	1213	438	325	325
query14	6184	2181	2084	2084
query14_1	1962	1944	1936	1936
query15	172	115	110	110
query16	957	364	365	364
query17	805	449	359	359
query18	2335	331	243	243
query19	170	138	109	109
query20	73	71	70	70
query21	210	114	94	94
query22	5482	5341	5316	5316
query23	7058	6226	5988	5988
query23_1	6107	5972	6115	5972
query24	7370	1081	762	762
query24_1	771	766	772	766
query25	442	315	262	262
query26	1248	220	130	130
query27	2804	420	260	260
query28	4651	1519	1507	1507
query29	950	433	362	362
query30	265	155	134	134
query31	837	398	333	333
query32	128	73	71	71
query33	472	233	181	181
query34	1004	828	466	466
query35	418	407	342	342
query36	555	543	533	533
query37	126	83	70	70
query38	993	844	809	809
query39	488	485	456	456
query39_1	472	445	434	434
query40	211	95	84	84
query41	58	55	55	55
query42	75	71	72	71
query43	250	244	214	214
query44	1054	558	552	552
query45	114	107	100	100
query46	766	859	505	505
query47	789	750	713	713
query48	306	301	208	208
query49	534	246	180	180
query50	728	264	195	195
query51	8335	8153	7995	7995
query52	69	69	59	59
query53	193	195	143	143
query54	235	155	157	155
query55	74	69	81	69
query56	229	184	151	151
query57	654	665	626	626
query58	218	169	161	161
query59	1206	1199	1087	1087
query60	228	195	188	188
query61	128	141	136	136
query62	426	202	178	178
query63	172	139	141	139
query64	2725	694	585	585
query65	1657	1576	1600	1576
query66	1933	258	213	213
query67	9737	9671	9528	9528
query68	2775	1200	733	733
query69	359	219	187	187
query70	674	572	586	572
query71	253	176	161	161
query72	2340	1729	1516	1516
query73	631	628	327	327
query74	1573	1202	1137	1137
query75	1168	1085	958	958
query76	2289	745	558	558
query77	243	262	200	200
query78	3818	3720	3215	3215
query79	2459	853	585	585
query80	1588	322	304	304
query81	528	156	133	133
query82	696	136	91	91
query83	288	214	192	192
query84	324	115	86	86
query85	816	358	283	283
query86	420	177	171	171
query87	986	974	901	901
query88	2795	2090	2085	2085
query89	295	190	183	183
query90	1975	124	126	124
query91	135	119	97	97
query92	78	70	71	70
query93	1431	1119	659	659
query94	670	257	209	209
query95	522	321	225	225
query96	800	578	262	262
query97	1062	1057	1014	1014
query98	150	134	132	132
query99	431	338	303	303
Total cold run time: 178275 ms
Total hot run time: 81459 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.04	0.04
query3	0.25	0.11	0.12
query4	1.60	0.11	0.10
query5	0.17	0.16	0.16
query6	1.23	0.70	0.74
query7	0.04	0.00	0.00
query8	0.05	0.03	0.03
query9	0.29	0.22	0.21
query10	0.35	0.35	0.36
query11	0.16	0.12	0.11
query12	0.14	0.13	0.12
query13	0.30	0.32	0.29
query14	0.45	0.44	0.44
query15	0.35	0.34	0.35
query16	0.20	0.23	0.21
query17	0.63	0.68	0.69
query18	0.18	0.17	0.17
query19	1.18	1.14	1.15
query20	0.01	0.01	0.01
query21	15.44	0.15	0.13
query22	5.08	0.04	0.04
query23	16.19	0.26	0.11
query24	2.96	0.33	0.25
query25	0.11	0.03	0.04
query26	0.74	0.17	0.13
query27	0.04	0.03	0.03
query28	3.64	0.51	0.29
query29	12.46	3.13	2.56
query30	0.27	0.12	0.12
query31	2.75	0.37	0.17
query32	3.53	0.32	0.23
query33	1.40	1.34	1.43
query34	15.38	2.17	1.74
query35	1.75	1.73	1.73
query36	0.48	0.29	0.29
query37	0.06	0.04	0.04
query38	0.04	0.03	0.03
query39	0.03	0.02	0.02
query40	0.11	0.08	0.07
query41	0.07	0.03	0.03
query42	0.03	0.02	0.02
query43	0.03	0.03	0.03
Total cold run time: 90.26 s
Total hot run time: 14.64 s

@924060929

Copy link
Copy Markdown
Contributor Author

run buildall

@924060929

Copy link
Copy Markdown
Contributor Author

/review

### What problem does this PR solve?

Issue Number: close apache#64159

Related PR: apache#64160

Problem Summary: Incremental metadata events published the ID-to-name mapping before the matching database or table object was committed to the shared cache. A concurrent lookup by ID could therefore load and publish a different object in that gap, which was then replaced and cleaned up by the event update. Publish the ID mapping and object inside one guarded cache commit, fence overlapping loads, and make the object-and-ID step run only once when the outer name-cache CAS retries so a newer object is never replaced by replaying an already completed event update.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ScopedMetaCacheConcurrencyTest
    - FeMetaCacheEntryTest
    - ExternalCatalogTest
    - ExternalDatabaseTest
    - ./build.sh --fe
- Behavior changed: No
- Does this need documentation: No
@924060929
924060929 force-pushed the prototype-scoped-metacache-ut branch from 529ed2d to f04e5f3 Compare August 27, 2026 07:55
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.

3 participants