Skip to content

[fix](cloud) Invalidate version caches on visible commit retries - #67813

Merged
luwei16 merged 7 commits into
apache:masterfrom
luwei16:fix/doris-28072-fe-version-refresh
Sep 16, 2026
Merged

luwei16 merged 7 commits into
apache:masterfrom
luwei16:fix/doris-28072-fe-version-refresh

Conversation

@luwei16

@luwei16 luwei16 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #67099

Related PR: None

Problem Summary: After a cloud commit response is lost, a retry can return a VISIBLE transaction without version results. FE can then keep using stale partition versions and the table version used to validate SQL caches.

Invalidate the affected table and partition version caches, including the MoW already-visible shortcut, and notify other FEs through the existing version synchronization RPC. Subsequent reads fetch fresh versions from MS. Commit processing performs no extra MS version query, so a version-service outage does not turn an already committed transaction into a commit error or require replaying its callbacks.

Publish batch cache updates under the tables' version write locks. Invalidation epochs prevent old in-flight MS responses and delayed commit notifications from restoring stale caches. The synchronization RPC uses table version -1 for invalidation; older FEs ignore it and retain their existing periodic synchronization. Peer notification keeps its existing asynchronous behavior and configuration.

Release note

Prevent stale reads and false commit failures after cloud commit retries.

Check List (For Author)

  • Test: Unit Test
    • 58 FE tests passed in both ordinary and JaCoCo coverage modes via run-fe-ut.sh (CloudGlobalTransactionMgrTest, CloudPartitionTest, OlapTableTest, VersionHelperTest); FE Checkstyle: 0 violations; PR diff whitespace check passed.
    • Tests cover invalidation and batch-publication locks, table/partition cache recovery, old RPC completions, successful commit callbacks during a version outage, and FE notification serialization/receiver handling.
    • No live cluster deployment or SQL regression run.
  • Behavior changed: Yes. VISIBLE retries without versions invalidate local and peer caches; subsequent reads retrieve versions without changing the successful commit result.
  • Does this need documentation: No

### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: None

Problem Summary: A cloud commit retry can return a VISIBLE transaction without
partition versions after the original response was lost. FE then returns success
while queries can still use stale partition caches. Refresh all partitions of
txn_info.table_ids using the existing MS version query before returning success,
including the MoW already-visible shortcut. Return refresh errors while keeping
the callbacks consistent with the transaction's durable commit state.

### Release note

Fix stale reads after cloud commit retries by refreshing local partition caches.

### Check List (For Author)

- Test: Unit Test
    - 29 tests pass via run-fe-ut.sh (CloudGlobalTransactionMgrTest and CloudPartitionTest).
    - FE Checkstyle: 0 violations; git diff --check passes.
    - No cluster deployment or SQL regression run.
- Behavior changed: Yes. VISIBLE retries missing version results refresh local
  partition caches synchronously; failed refreshes return an error.
- Does this need documentation: No
@luwei16
luwei16 requested a review from gavinchou as a code owner September 10, 2026 12:04
@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?

@luwei16 luwei16 changed the title [fix](fe) Refresh partition caches on visible commit retries [fix](cloud) Refresh partition caches on visible commit retries Sep 10, 2026
### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813

Problem Summary: Master and the visible-commit cache refresh fix add independent
tests at the same location in CloudGlobalTransactionMgrTest. Merge master and
retain both the exclusive transaction watermark test and all version-refresh
tests. Preserve the original cache refresh patch and upstream production changes.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - 30 tests passed via run-fe-ut.sh (CloudGlobalTransactionMgrTest and CloudPartitionTest).
    - FE Checkstyle: zero violations; diff checks against merged master passed.
    - No local product packaging, cluster deployment or SQL regression run.
- Behavior changed: No. Conflict resolution preserves both existing changes.
- Does this need documentation: No
@luwei16

luwei16 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

return;
}
List<CloudPartition> partitions = new ArrayList<>();
for (long tableId : Sets.newHashSet(tableIds)) {

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.

why try to Sets.newHashSet(tableIds)?

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17654	3086	3090	3086
q2	2057	256	223	223
q3	10256	911	524	524
q4	4687	244	209	209
q5	7740	550	386	386
q6	138	116	95	95
q7	525	583	387	387
q8	9247	885	915	885
q9	3489	2362	2391	2362
q10	6508	850	726	726
q11	409	207	178	178
q12	630	267	205	205
q13	18098	1512	1156	1156
q14	167	152	142	142
q15	q16	431	396	372	372
q17	1353	864	806	806
q18	3023	2264	2264	2264
q19	1294	886	748	748
q20	371	274	202	202
q21	5623	1679	1799	1679
q22	325	265	229	229
Total cold run time: 94025 ms
Total hot run time: 16864 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3486	3408	3367	3367
q2	510	387	387	387
q3	2257	2227	2169	2169
q4	1178	1160	882	882
q5	2193	2097	2090	2090
q6	163	122	87	87
q7	1016	942	866	866
q8	1576	1413	1396	1396
q9	3116	3073	3060	3060
q10	1866	1772	1642	1642
q11	350	265	253	253
q12	457	425	338	338
q13	1506	1529	1165	1165
q14	162	181	153	153
q15	q16	390	394	360	360
q17	3557	3343	3187	3187
q18	4757	4340	4708	4340
q19	843	794	920	794
q20	1001	951	852	852
q21	3889	3129	3242	3129
q22	387	344	328	328
Total cold run time: 34660 ms
Total hot run time: 30845 ms

@hello-stephen

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

query5	4247	412	357	357
query6	384	133	124	124
query7	4945	436	230	230
query8	293	121	118	118
query9	8667	2884	2865	2865
query10	400	219	190	190
query11	5387	1053	902	902
query12	119	72	71	71
query13	1191	441	326	326
query14	6017	2184	2087	2087
query14_1	1977	1965	1946	1946
query15	169	118	111	111
query16	919	385	312	312
query17	805	453	369	369
query18	2336	328	239	239
query19	162	141	107	107
query20	71	68	74	68
query21	196	100	85	85
query22	5359	5291	5345	5291
query23	6735	6192	6006	6006
query23_1	5869	6166	5972	5972
query24	7266	1086	784	784
query24_1	793	755	803	755
query25	425	304	250	250
query26	1235	249	128	128
query27	2769	394	249	249
query28	4691	1507	1511	1507
query29	933	435	369	369
query30	263	157	127	127
query31	823	393	331	331
query32	134	74	77	74
query33	465	224	188	188
query34	985	823	500	500
query35	390	399	342	342
query36	560	591	536	536
query37	120	83	68	68
query38	1000	842	812	812
query39	493	497	468	468
query39_1	469	462	455	455
query40	211	93	78	78
query41	59	55	55	55
query42	79	72	73	72
query43	245	241	215	215
query44	978	530	544	530
query45	115	104	105	104
query46	803	882	548	548
query47	762	763	712	712
query48	311	320	231	231
query49	550	254	228	228
query50	739	264	198	198
query51	8016	7963	7876	7876
query52	67	65	62	62
query53	187	209	147	147
query54	204	158	146	146
query55	79	63	53	53
query56	185	150	180	150
query57	697	649	634	634
query58	204	158	162	158
query59	1295	1237	1091	1091
query60	230	184	169	169
query61	123	129	117	117
query62	349	203	181	181
query63	171	138	138	138
query64	2724	741	586	586
query65	1650	1691	1630	1630
query66	1961	270	215	215
query67	10106	9615	9748	9615
query68	3004	1202	750	750
query69	348	225	199	199
query70	689	637	595	595
query71	251	169	163	163
query72	2276	1648	1512	1512
query73	638	582	330	330
query74	2011	1208	1134	1134
query75	1170	1090	978	978
query76	2369	711	513	513
query77	248	254	215	215
query78	3919	3758	3186	3186
query79	2281	806	571	571
query80	1594	307	266	266
query81	486	155	139	139
query82	620	126	94	94
query83	272	205	195	195
query84	294	108	84	84
query85	782	340	283	283
query86	386	174	169	169
query87	1020	981	891	891
query88	2742	2093	2088	2088
query89	279	198	177	177
query90	1989	130	118	118
query91	128	116	93	93
query92	78	67	71	67
query93	1380	1092	688	688
query94	634	244	220	220
query95	532	249	308	249
query96	846	559	286	286
query97	1031	1105	1019	1019
query98	162	131	132	131
query99	420	331	308	308
Total cold run time: 177476 ms
Total hot run time: 81509 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.08	0.04	0.04
query3	0.25	0.10	0.10
query4	1.60	0.10	0.09
query5	0.18	0.16	0.15
query6	1.27	0.70	0.70
query7	0.03	0.01	0.00
query8	0.04	0.02	0.02
query9	0.30	0.21	0.20
query10	0.34	0.35	0.33
query11	0.17	0.12	0.11
query12	0.15	0.12	0.12
query13	0.32	0.31	0.32
query14	0.45	0.44	0.46
query15	0.36	0.36	0.35
query16	0.21	0.23	0.22
query17	0.69	0.68	0.71
query18	0.18	0.17	0.17
query19	1.20	1.16	1.21
query20	0.01	0.00	0.01
query21	15.42	0.16	0.11
query22	5.08	0.04	0.05
query23	16.18	0.27	0.10
query24	2.97	0.32	0.24
query25	0.11	0.04	0.03
query26	0.84	0.16	0.12
query27	0.03	0.03	0.03
query28	3.69	0.51	0.26
query29	12.50	3.16	2.56
query30	0.25	0.12	0.12
query31	2.76	0.37	0.17
query32	3.54	0.33	0.23
query33	1.35	1.40	1.39
query34	15.35	2.18	1.76
query35	1.75	1.74	1.70
query36	0.46	0.29	0.28
query37	0.06	0.04	0.04
query38	0.04	0.03	0.02
query39	0.03	0.02	0.02
query40	0.11	0.08	0.08
query41	0.08	0.03	0.02
query42	0.03	0.02	0.02
query43	0.03	0.02	0.03
Total cold run time: 90.5 s
Total hot run time: 14.55 s

@morningman

Copy link
Copy Markdown
Contributor

/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: the patch targets the reported visible-retry stale-cache bug, but six P1 correctness/lifecycle gaps remain in the recovery topology.

Critical checkpoint conclusions:

  • Goal and proof: The local unit tests prove master-partition refresh, batching, dropped-table handling, a VISIBLE MoW precheck, and callback success state. They do not prove the full goal because table caches and peer FEs remain stale, failed repair lacks a retry owner, and lazy/2PC retry paths escape recovery.
  • Scope and focus: The code change is localized to the FE transaction response path and its tests, but the required behavior spans Meta Service status transitions, BE reporting, peer FE synchronization, SQL/Routine Load callers, and cache readers. No additional user focus was supplied.
  • Concurrency: The fallback installs partition versions without the table version-write locks used by the normal and peer-sync paths, so version-read-locked planners can observe a mixed multi-partition snapshot. Remote RPCs are outside catalog read locks and no distinct deadlock was found.
  • Lifecycle and error handling: A refresh exception is exposed after durable visibility and success callbacks; synchronous callers can attempt an impossible abort, Routine Load cannot safely retry, and the BE report caller drops non-OK repair results. Lazy COMMITTED completion has no reliable later FE repair owner.
  • Configuration: No configuration item is added. Reliance on the existing periodic synchronizer is not a correctness guarantee because it is configurable off and can race lazy phase one.
  • Compatibility: No wire or storage format changes were introduced. Final 2PC already-visible responses are nevertheless rejected before the new recovery, so that parallel API remains behaviorally incompatible with idempotent retry.
  • Parallel paths and conditions: Immediate, lazy-visible, subtransaction, forced-immediate Table Stream, direct FE, BE-report, MoW-precheck, and final-2PC paths were traced. The visible-only predicate and txn_info.table_ids coverage are sound for paths that reach it; final 2PC and lazy COMMITTED do not.
  • Test coverage and results: The added FE tests are correct for their local assertions but omit table/peer propagation, latch-based reader concurrency, BE report retry, synchronous caller semantics, final 2PC, and COMMITTED-to-VISIBLE lazy completion. No local build or tests were run because the review runner instructions explicitly prohibit builds. Current PR checks show compile, FE UT, BE UT, Cloud UT, P0/cloud_p0/external/nonconcurrent regression, and performance passing; check_coverage_fe is failing, without enough evidence to classify it as a separate PR defect.
  • Observability: The new failure paths log transaction context, but logging alone does not provide durable retry; no separate metrics defect was substantiated.
  • Transaction, persistence, and data correctness: Meta Service durability itself is unchanged and no EditLog schema is added, but FE post-commit state is not installed atomically or consistently across cache consumers, and failure is misreported after durable success. Failover/status boundaries were included in the lazy and already-visible analysis.
  • FE/BE variables: No new thrift/protobuf variable is added. The existing BE-to-FE report contract was checked end to end and exposes the dropped-error issue.
  • Performance: The all-partition refresh is batched but can still issue multiple synchronous RPCs; no independent performance blocker was substantiated beyond the correctness/locking findings.
  • Other: Catalog add/drop races and monotonic partition writes were checked and did not yield a separate bug; no security-sensitive behavior is changed.

Review completion: complete. The main pass plus two complete-review passes and one risk-focused pass converged in round 2; every candidate is accepted, duplicate-fenced, or dismissed with evidence.

+ "] is already aborted. abort reason: " + transactionState.getReason());
} else if (transactionState.getTransactionStatus() == TransactionStatus.COMMITTED
|| transactionState.getTransactionStatus() == TransactionStatus.VISIBLE) {
if (transactionState.getTransactionStatus() == TransactionStatus.VISIBLE) {

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 complete a lazy retry while it is only COMMITTED

A timed-out lazy commit can durably stop at COMMITTED while TxnLazyCommitTask is still responsible for publishing the partition versions. This branch now treats that state as completed, but refreshes only VISIBLE; its callers return success before executeCommitTxnRequest, afterCommitTxnResp, or success callbacks run. The lazy task later changes the transaction to VISIBLE without notifying FE, and the periodic syncer is not a safe fallback because it can be disabled or race the pending partitions after the phase-one table-version bump. Please wait/repoll through visibility and then perform the normal cache/callback completion, or install a durable repair owner before returning success.

}
}
try {
for (List<CloudPartition> batch : Lists.partition(partitions, Config.cloud_get_version_task_batch_size)) {

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] Install the refreshed snapshot under table version locks

getSnapshotVisibleVersionFromMs writes these CloudPartition caches one by one, but this new path does not take the affected tables' versionWriteLocks. Cached planners take versionReadLocks specifically while snapshotting partition versions, and both the normal commit path and peer-FE sync path use the matching write locks. A query can therefore interleave after P1 is advanced but before P2 and plan one atomically visible transaction as [new(P1), old(P2)]. Please fetch the remote values outside locks, then install all affected partition values under table version-write locks acquired in ID order.

}
try {
for (List<CloudPartition> batch : Lists.partition(partitions, Config.cloud_get_version_task_batch_size)) {
CloudPartition.getSnapshotVisibleVersionFromMs(batch, false);

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] Refresh the table cache and peer FEs too

This fallback only mutates the master FE's CloudPartition objects. Unlike the normal path above, it neither advances each OlapTable.cachedTableVersion nor calls CloudFEVersionSynchronizer.pushVersionAsync. With the default Long.MAX_VALUE table/partition cache TTLs, a warmed SQL cache can still validate against the old table version on the master, and follower/observer FEs can keep planning with their old partition versions until the periodic daemon runs. Thus an acknowledged visible retry can still serve stale results. Please recover the table versions and propagate the recovered partition/table state through the same synchronizer path as a normal commit response.

stopWatch.start();
try {
txnState = commitTxn(commitTxnRequest, transactionId, is2PC, tabletCommitInfos, tabletIds);
CommitTxnResponse response = commitTxn(commitTxnRequest, transactionId, is2PC);

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] Recover already-visible final 2PC retries

For a final 2PC retry, Meta Service returns TXN_ALREADY_VISIBLE plus only txn_info, but commitTxn(..., is2PC=true) rejects that status before it can return this response to afterCommitTxnResp. The apparent MoW precheck does not cover this: commitTransaction2PC calls getMowTableList(tableList, null), which always returns an empty list. Thus losing the first final-commit response leaves every retry failing with stale caches. Please treat the already-visible final-2PC response as the durable idempotent outcome and run the same cache recovery before completing it.

MetricRepo.COUNTER_TXN_SUCCESS.increase(1L);
MetricRepo.HISTO_TXN_EXEC_LATENCY.update(txnState.getCommitTime() - txnState.getPrepareTime());
}
afterCommitTxnResp(response, tabletCommitInfos, tabletIds);

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 return a normal commit failure after success callbacks

At this point Meta Service has returned the durable visible transaction and txnOperated is already true, so finally runs afterCommitted/afterVisible; nevertheless a refresh exception escapes from this call. TransactionEntry.commitTransaction interprets that as a failed commit, attempts to abort the already-visible transaction, and reports failure. Routine Load is worse: afterVisible renews/removes the old txn task, so retrying the returned error fails in beforeCommitted before cache repair can run. Please make repair independent/retryable (or invalidate caches) while returning an outcome that callers cannot route to abort or replay callbacks.

}
} catch (UserException e) {
LOG.warn("failed to refresh versions for reported commit, txnId: {}", request.getTxnId(), e);
return new TStatus(TStatusCode.INTERNAL_ERROR).setErrorMsgs(Collections.singletonList(e.getMessage()));

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] Give this failed refresh a retry owner

The only production caller of this report is send_stats_to_fe_async in be/src/cloud/cloud_meta_mgr.cpp; it converts this INTERNAL_ERROR to a failed status, logs it, and then deliberately returns Status::OK() without retrying. If an already-visible response reaches FE while VersionHelper exhausts its bounded retries, BE has already acknowledged the commit and this cache repair is never replayed, so the old version can remain cached after Meta Service recovers. Please retry/schedule the repair in FE or make the BE report path retry non-OK results; returning an error that its sole caller drops does not close the stale-read path.

### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813

Problem Summary: Remove the extra HashSet conversion when refreshing partition
versions for visible commit retries. Iterate the supplied transaction table IDs
directly and remove the artificial duplicate ID from the existing two-table test.
Retain all version, timestamp, TSO, response and RPC-count assertions.

### Release note

None

### Check List (For Author)

- Test: Static check
    - FE Checkstyle passed with zero violations; git diff --check passed.
    - Existing unit test fixture updated; no local unit tests rerun for this two-line change.
    - Full CI buildall will be requested after pushing this commit.
- Behavior changed: Yes. Iterate supplied table IDs without deduplication.
- Does this need documentation: No
@luwei16

luwei16 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 69.23% (27/39) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17598	3086	3072	3072
q2	2092	273	227	227
q3	10223	933	531	531
q4	4672	256	211	211
q5	7662	573	383	383
q6	141	116	94	94
q7	536	492	390	390
q8	9246	903	883	883
q9	3565	2436	2433	2433
q10	6521	871	734	734
q11	403	203	188	188
q12	607	264	194	194
q13	18140	1545	1165	1165
q14	157	153	148	148
q15	q16	452	403	374	374
q17	1345	868	760	760
q18	3157	2336	2322	2322
q19	1250	927	781	781
q20	380	289	203	203
q21	5620	1744	1892	1744
q22	337	275	238	238
Total cold run time: 94104 ms
Total hot run time: 17075 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3426	3362	3323	3323
q2	507	405	412	405
q3	2255	2461	2178	2178
q4	1210	1188	909	909
q5	2205	2158	2149	2149
q6	166	118	88	88
q7	1049	914	857	857
q8	1594	1409	1397	1397
q9	3178	3179	3127	3127
q10	1887	1833	1701	1701
q11	355	270	250	250
q12	456	438	356	356
q13	1520	1547	1167	1167
q14	176	163	169	163
q15	q16	413	393	359	359
q17	3716	3376	3315	3315
q18	4888	4514	5035	4514
q19	966	882	857	857
q20	1040	966	840	840
q21	3883	3233	3241	3233
q22	406	345	324	324
Total cold run time: 35296 ms
Total hot run time: 31512 ms

@hello-stephen

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

query5	4255	419	340	340
query6	379	137	125	125
query7	4954	402	240	240
query8	301	132	118	118
query9	8713	2923	2925	2923
query10	407	226	191	191
query11	5415	1050	919	919
query12	123	72	70	70
query13	1184	425	349	349
query14	6127	2254	2133	2133
query14_1	2010	1994	1959	1959
query15	173	120	115	115
query16	928	381	359	359
query17	803	454	363	363
query18	2332	333	246	246
query19	166	147	114	114
query20	76	76	71	71
query21	201	102	90	90
query22	5422	5557	5461	5461
query23	7085	6325	6061	6061
query23_1	6195	6270	6265	6265
query24	7273	1100	793	793
query24_1	769	814	829	814
query25	426	310	253	253
query26	1234	234	137	137
query27	2790	439	264	264
query28	4660	1495	1475	1475
query29	931	434	353	353
query30	254	157	133	133
query31	826	408	346	346
query32	140	82	81	81
query33	464	233	203	203
query34	995	823	493	493
query35	410	413	342	342
query36	567	587	524	524
query37	122	82	72	72
query38	1019	853	829	829
query39	525	486	512	486
query39_1	457	498	474	474
query40	215	94	89	89
query41	61	57	56	56
query42	80	74	76	74
query43	246	244	221	221
query44	1005	538	544	538
query45	110	110	102	102
query46	778	849	519	519
query47	774	759	742	742
query48	320	310	234	234
query49	534	243	180	180
query50	760	261	189	189
query51	8318	8181	8290	8181
query52	67	74	59	59
query53	198	254	144	144
query54	221	175	180	175
query55	67	63	57	57
query56	191	156	167	156
query57	699	672	673	672
query58	190	164	158	158
query59	1227	1249	1106	1106
query60	234	183	185	183
query61	115	110	106	106
query62	335	211	179	179
query63	181	143	140	140
query64	2849	733	626	626
query65	1659	1666	1610	1610
query66	1769	261	206	206
query67	10228	9943	9965	9943
query68	2999	1149	713	713
query69	344	221	201	201
query70	661	606	628	606
query71	249	180	172	172
query72	2280	1668	1517	1517
query73	630	582	351	351
query74	2015	1238	1145	1145
query75	1197	1128	971	971
query76	2364	722	518	518
query77	255	272	210	210
query78	4103	3796	3236	3236
query79	2329	847	602	602
query80	1601	327	276	276
query81	490	159	132	132
query82	735	130	97	97
query83	279	221	190	190
query84	295	111	90	90
query85	769	335	280	280
query86	385	173	176	173
query87	1045	1001	918	918
query88	2787	2126	2098	2098
query89	289	200	175	175
query90	1999	130	129	129
query91	132	120	94	94
query92	77	74	72	72
query93	1483	1114	685	685
query94	631	239	231	231
query95	516	329	228	228
query96	820	552	279	279
query97	1063	1095	1036	1036
query98	156	138	134	134
query99	427	350	317	317
Total cold run time: 179356 ms
Total hot run time: 83304 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.04	0.03
query3	0.26	0.11	0.10
query4	1.61	0.10	0.10
query5	0.18	0.16	0.16
query6	1.24	0.72	0.69
query7	0.03	0.00	0.01
query8	0.04	0.03	0.03
query9	0.28	0.22	0.21
query10	0.35	0.37	0.35
query11	0.17	0.12	0.12
query12	0.14	0.12	0.13
query13	0.30	0.33	0.32
query14	0.45	0.46	0.47
query15	0.37	0.35	0.35
query16	0.23	0.21	0.23
query17	0.68	0.66	0.66
query18	0.18	0.16	0.17
query19	1.22	1.13	1.20
query20	0.01	0.02	0.02
query21	15.47	0.16	0.11
query22	5.10	0.04	0.04
query23	16.18	0.27	0.10
query24	3.00	0.32	0.26
query25	0.11	0.05	0.03
query26	0.83	0.16	0.12
query27	0.04	0.05	0.03
query28	3.55	0.54	0.27
query29	12.47	3.17	2.59
query30	0.25	0.11	0.12
query31	2.76	0.39	0.17
query32	3.50	0.32	0.23
query33	1.47	1.44	1.44
query34	15.43	2.21	1.84
query35	1.78	1.77	1.72
query36	0.45	0.29	0.29
query37	0.06	0.04	0.04
query38	0.05	0.03	0.03
query39	0.03	0.02	0.03
query40	0.11	0.08	0.07
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.61 s
Total hot run time: 14.8 s

gavinchou
gavinchou previously approved these changes Sep 14, 2026
### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813

Problem Summary: A cloud commit retry may return a VISIBLE transaction without version results. Invalidate the affected table and partition caches and notify peer FEs through the existing version RPC, so subsequent reads fetch fresh versions without making a durable commit fail on a version-service outage. Protect batch cache publication with version write locks and use in-memory epochs to prevent older RPC completions from clearing invalidation.

### Release note

Prevent stale reads and false commit failures after cloud commit retries.

### Check List (For Author)

- Test: Unit Test
    - 55 FE tests passed via run-fe-ut.sh (CloudGlobalTransactionMgrTest, CloudPartitionTest, OlapTableTest); FE Checkstyle: 0 violations; git diff --check passed.
- Behavior changed: Yes. Missing-version VISIBLE responses invalidate caches; successful commit callbacks and return semantics are preserved.
- Does this need documentation: No
@luwei16 luwei16 changed the title [fix](cloud) Refresh partition caches on visible commit retries [fix](cloud) Invalidate version caches on visible commit retries Sep 14, 2026
@luwei16

luwei16 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17557	3043	3023	3023
q2	2072	262	219	219
q3	10269	867	519	519
q4	4665	263	218	218
q5	7647	548	379	379
q6	139	112	93	93
q7	523	512	394	394
q8	9244	831	864	831
q9	3477	2411	2465	2411
q10	6533	866	726	726
q11	408	202	177	177
q12	615	261	198	198
q13	18140	1530	1155	1155
q14	161	150	138	138
q15	q16	430	396	379	379
q17	1393	911	808	808
q18	3144	2312	2287	2287
q19	1246	902	783	783
q20	373	287	202	202
q21	5613	1824	1903	1824
q22	327	259	233	233
Total cold run time: 93976 ms
Total hot run time: 16997 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3394	3327	3312	3312
q2	499	396	380	380
q3	2266	2321	2172	2172
q4	1211	1201	903	903
q5	2240	2147	2132	2132
q6	175	122	88	88
q7	1065	951	873	873
q8	1582	1384	1389	1384
q9	3241	3195	3193	3193
q10	1898	1864	1686	1686
q11	360	274	254	254
q12	448	438	344	344
q13	1489	1556	1180	1180
q14	169	166	167	166
q15	q16	409	396	360	360
q17	3680	3371	3300	3300
q18	4929	4571	5004	4571
q19	960	847	854	847
q20	1021	988	862	862
q21	3858	3183	3264	3183
q22	388	345	323	323
Total cold run time: 35282 ms
Total hot run time: 31513 ms

@hello-stephen

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

query5	4257	408	341	341
query6	385	133	120	120
query7	4971	406	229	229
query8	295	139	130	130
query9	8692	2882	2850	2850
query10	393	220	184	184
query11	5372	1044	915	915
query12	115	71	70	70
query13	1183	438	335	335
query14	6026	2241	2126	2126
query14_1	2022	2028	1996	1996
query15	176	121	113	113
query16	928	394	359	359
query17	799	459	359	359
query18	2336	331	235	235
query19	162	139	116	116
query20	91	67	72	67
query21	199	101	87	87
query22	5649	5607	5501	5501
query23	6978	6359	6262	6262
query23_1	6064	6230	6182	6182
query24	7272	1141	752	752
query24_1	761	774	769	769
query25	408	277	228	228
query26	1226	222	127	127
query27	2796	432	243	243
query28	4682	1475	1487	1475
query29	918	411	345	345
query30	240	153	129	129
query31	820	413	339	339
query32	129	71	74	71
query33	474	229	165	165
query34	995	819	488	488
query35	387	387	350	350
query36	562	549	542	542
query37	120	80	68	68
query38	1023	851	833	833
query39	506	509	493	493
query39_1	458	474	449	449
query40	196	90	79	79
query41	56	51	51	51
query42	77	72	72	72
query43	243	239	210	210
query44	1003	529	536	529
query45	118	109	104	104
query46	742	847	520	520
query47	769	773	724	724
query48	297	319	233	233
query49	545	247	186	186
query50	725	266	192	192
query51	7986	7910	8033	7910
query52	65	66	58	58
query53	195	200	146	146
query54	218	166	263	166
query55	70	59	69	59
query56	187	159	154	154
query57	694	658	652	652
query58	185	162	150	150
query59	1271	1290	1127	1127
query60	234	200	191	191
query61	119	111	109	109
query62	362	206	176	176
query63	173	133	130	130
query64	2816	829	659	659
query65	1684	1699	1678	1678
query66	1787	270	256	256
query67	10162	9862	9945	9862
query68	2994	1203	747	747
query69	354	223	195	195
query70	673	625	607	607
query71	249	174	169	169
query72	2281	1645	1505	1505
query73	639	605	345	345
query74	2008	1229	1166	1166
query75	1195	1118	970	970
query76	2382	699	508	508
query77	260	277	214	214
query78	4038	3785	3297	3297
query79	2301	821	606	606
query80	1595	333	278	278
query81	492	154	134	134
query82	622	122	95	95
query83	288	209	191	191
query84	317	110	89	89
query85	784	356	284	284
query86	399	178	176	176
query87	1047	992	895	895
query88	2791	2101	2135	2101
query89	279	194	173	173
query90	2001	130	120	120
query91	129	115	94	94
query92	80	73	73	73
query93	1432	1123	702	702
query94	648	254	238	238
query95	517	271	226	226
query96	796	599	265	265
query97	1069	1088	1033	1033
query98	158	136	130	130
query99	423	356	313	313
Total cold run time: 178625 ms
Total hot run time: 82954 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.04	0.03
query3	0.26	0.10	0.11
query4	1.61	0.10	0.10
query5	0.17	0.16	0.16
query6	1.26	0.70	0.70
query7	0.03	0.01	0.00
query8	0.05	0.03	0.02
query9	0.30	0.21	0.22
query10	0.34	0.34	0.36
query11	0.17	0.12	0.12
query12	0.15	0.13	0.12
query13	0.31	0.31	0.31
query14	0.45	0.46	0.47
query15	0.37	0.35	0.37
query16	0.21	0.24	0.24
query17	0.70	0.71	0.68
query18	0.19	0.19	0.17
query19	1.19	1.11	1.19
query20	0.02	0.01	0.01
query21	15.44	0.14	0.11
query22	5.06	0.05	0.04
query23	16.21	0.25	0.10
query24	2.98	0.31	0.28
query25	0.12	0.04	0.03
query26	0.80	0.17	0.11
query27	0.04	0.03	0.04
query28	3.66	0.57	0.28
query29	12.42	3.22	2.57
query30	0.25	0.12	0.12
query31	2.78	0.38	0.17
query32	3.50	0.32	0.23
query33	1.38	1.56	1.44
query34	15.42	2.30	1.80
query35	1.80	1.75	1.74
query36	0.45	0.29	0.29
query37	0.06	0.04	0.04
query38	0.04	0.04	0.03
query39	0.03	0.02	0.02
query40	0.11	0.07	0.08
query41	0.07	0.03	0.02
query42	0.03	0.03	0.02
query43	0.03	0.03	0.02
Total cold run time: 90.55 s
Total hot run time: 14.79 s

### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813

Problem Summary: CI merges the PR into current master, where batch version
reads call getVersionFromMeta(request, maxAttempts). The cache invalidation
tests only stub the single-argument overload, causing four null-response
errors. Merge master and route both overloads through the same scoped test
stub, retaining the response injection, call counts and concurrency assertions.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - Reproduced the four CI errors after merging master.
    - All 58 focused FE tests passed in ordinary and JaCoCo coverage modes.
    - FE Checkstyle: zero violations; PR diff whitespace check passed.
- Behavior changed: No (test fixture adaptation only)
- Does this need documentation: No
@luwei16

luwei16 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 90.59% (77/85) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813

Problem Summary: The Maven build cache restores BE Java module jars without
target/lib. Cached builds skip the runtime dependency copy, so a fresh
workspace packages incomplete plugins and fails the plugin layout check.
Always rerun the paired dependency cleanup and copy executions, including
hadoop-deps's copy step, while retaining compiled-artifact cache reuse.

### Release note

Fix incomplete Java plugin packages produced by cached builds.

### Check List (For Author)

- Test: Manual test
    - Reproduced all 352 CI layout violations with actual Maven cache hits.
    - Normal and cached Java-extension builds produced matching runtime
      dependency manifests for eight plugins and hadoop-deps.
    - All nine cached modules removed obsolete dependency jar probes.
    - All eight plugins passed the existing layout checker; Checkstyle and
      git diff --check passed.
- Behavior changed: Yes (cached builds regenerate runtime dependencies)
- Does this need documentation: No
@luwei16

luwei16 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: close apache#67099

Related PR: apache#67813, apache#68000

Problem Summary: The performance pipeline fails before benchmarks because
Maven cache hits restore Java plugin jars without their runtime dependencies.
Merge upstream master and adopt its equivalent cache cleanup/copy fix,
resolving conflicts with the local repair and removing duplicate changes
from this PR. Preserve the cloud version-cache invalidation changes.

### Release note

None

### Check List (For Author)

- Test: Manual test
    - build.sh --be-java-extensions passed after the merge.
    - All eight plugins and hadoop-deps hit the cache, regenerated the same
      runtime dependency manifests as an uncached build, and removed stale jars.
    - All eight plugins passed the existing layout checker; Checkstyle for
      the nine modules and PR diff whitespace checks passed.
- Behavior changed: No (adopt the equivalent upstream build repair)
- Does this need documentation: No
@luwei16

luwei16 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 33.68% (64/190) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17593	3085	3049	3049
q2	2090	266	227	227
q3	10230	887	519	519
q4	4676	245	201	201
q5	7680	572	387	387
q6	139	115	96	96
q7	543	491	400	400
q8	9235	861	893	861
q9	3421	2393	2387	2387
q10	6539	851	728	728
q11	402	195	180	180
q12	616	258	196	196
q13	18134	1535	1157	1157
q14	161	148	139	139
q15	q16	442	391	368	368
q17	1332	803	756	756
q18	3114	2277	2253	2253
q19	1285	856	781	781
q20	375	285	205	205
q21	5655	1640	1872	1640
q22	327	273	237	237
Total cold run time: 93989 ms
Total hot run time: 16767 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3420	3399	3358	3358
q2	505	393	367	367
q3	2241	2240	2169	2169
q4	1183	1173	893	893
q5	2166	2135	2105	2105
q6	172	120	87	87
q7	1000	914	884	884
q8	1583	1406	1387	1387
q9	3135	3124	3112	3112
q10	1832	1771	1619	1619
q11	354	267	249	249
q12	453	430	338	338
q13	1503	1529	1166	1166
q14	165	169	153	153
q15	q16	390	399	381	381
q17	3590	3327	3267	3267
q18	4821	4409	4761	4409
q19	901	897	918	897
q20	975	977	849	849
q21	3837	3195	3247	3195
q22	406	341	330	330
Total cold run time: 34632 ms
Total hot run time: 31215 ms

@hello-stephen

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

query5	4239	409	346	346
query6	389	138	118	118
query7	4944	416	225	225
query8	280	122	119	119
query9	8692	2899	2891	2891
query10	400	221	176	176
query11	5379	1067	912	912
query12	120	71	68	68
query13	1198	442	313	313
query14	6081	2214	2113	2113
query14_1	2019	1976	1979	1976
query15	186	119	116	116
query16	967	368	379	368
query17	807	470	367	367
query18	2334	327	241	241
query19	165	172	101	101
query20	85	70	66	66
query21	200	101	84	84
query22	5440	5484	5376	5376
query23	6694	6180	5967	5967
query23_1	6179	6053	6160	6053
query24	7329	1090	761	761
query24_1	777	783	744	744
query25	409	268	227	227
query26	1227	235	126	126
query27	2796	418	256	256
query28	4645	1486	1494	1486
query29	928	408	335	335
query30	257	154	130	130
query31	844	397	328	328
query32	128	73	76	73
query33	466	217	167	167
query34	1002	812	485	485
query35	383	391	341	341
query36	560	544	531	531
query37	121	85	70	70
query38	1004	859	817	817
query39	494	466	464	464
query39_1	457	469	485	469
query40	209	89	76	76
query41	55	52	50	50
query42	73	72	71	71
query43	240	237	204	204
query44	1017	545	532	532
query45	115	115	96	96
query46	777	836	545	545
query47	762	803	717	717
query48	319	299	228	228
query49	541	230	189	189
query50	792	256	191	191
query51	8257	8180	8178	8178
query52	68	66	59	59
query53	196	193	147	147
query54	217	148	150	148
query55	75	60	59	59
query56	212	174	256	174
query57	707	674	623	623
query58	211	160	165	160
query59	1209	1230	1135	1135
query60	234	184	163	163
query61	124	116	127	116
query62	374	208	178	178
query63	176	144	134	134
query64	2696	683	578	578
query65	1611	1590	1568	1568
query66	1863	257	206	206
query67	9735	9627	10006	9627
query68	2977	1109	710	710
query69	346	223	202	202
query70	706	624	611	611
query71	251	195	163	163
query72	2208	1612	1472	1472
query73	630	554	338	338
query74	1997	1233	1118	1118
query75	1190	1084	948	948
query76	2362	706	525	525
query77	259	249	201	201
query78	4069	3700	3228	3228
query79	1155	871	560	560
query80	678	306	259	259
query81	446	160	135	135
query82	929	129	100	100
query83	290	200	184	184
query84	299	112	88	88
query85	881	332	277	277
query86	351	183	181	181
query87	1025	970	903	903
query88	2749	2102	2129	2102
query89	279	201	176	176
query90	1702	134	122	122
query91	128	113	97	97
query92	79	73	71	71
query93	1102	1126	701	701
query94	499	274	210	210
query95	506	308	227	227
query96	862	556	277	277
query97	1035	1052	996	996
query98	147	144	139	139
query99	426	348	307	307
Total cold run time: 175485 ms
Total hot run time: 81778 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.08	0.03	0.03
query3	0.25	0.11	0.09
query4	1.61	0.10	0.10
query5	0.17	0.17	0.16
query6	1.23	0.71	0.71
query7	0.04	0.01	0.01
query8	0.05	0.03	0.02
query9	0.29	0.21	0.21
query10	0.33	0.34	0.34
query11	0.16	0.12	0.11
query12	0.16	0.12	0.12
query13	0.31	0.30	0.30
query14	0.45	0.45	0.45
query15	0.36	0.35	0.33
query16	0.22	0.22	0.21
query17	0.71	0.68	0.69
query18	0.18	0.17	0.16
query19	1.19	1.19	1.14
query20	0.02	0.01	0.01
query21	15.46	0.14	0.11
query22	5.10	0.04	0.04
query23	16.18	0.26	0.10
query24	3.00	0.32	0.27
query25	0.10	0.04	0.03
query26	0.74	0.16	0.11
query27	0.04	0.03	0.03
query28	3.61	0.52	0.27
query29	12.50	3.21	2.59
query30	0.26	0.11	0.12
query31	2.75	0.37	0.18
query32	3.54	0.33	0.22
query33	1.39	1.55	1.41
query34	15.39	2.17	1.76
query35	1.76	1.74	1.73
query36	0.48	0.30	0.29
query37	0.06	0.04	0.03
query38	0.04	0.03	0.03
query39	0.03	0.03	0.02
query40	0.12	0.07	0.08
query41	0.08	0.02	0.03
query42	0.04	0.02	0.03
query43	0.03	0.03	0.03
Total cold run time: 90.51 s
Total hot run time: 14.65 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 75.29% (64/85) 🎉
Increment coverage report
Complete coverage report

@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 ac106fb1dd5d0a2bb6a05545918620158eb1c6d2 (static review only). The patch improves lost-visible-response recovery, but three cache-publication defects remain: a partial batch can return a mixed pre/post-commit partition snapshot; a batch can return a stale value after observing a concurrent refresher's epoch acknowledgement; and the periodic daemon cannot close the new table invalidation epoch, causing repeated Meta Service work and leaving paired partition invalidations pending on the equal-version path.

Critical checkpoint conclusions:

  • Goal and correctness: The intended lost-VISIBLE retry repair is not complete because the two batch-reader races can still plan stale or impossible snapshots after invalidation.
  • Scope and design: The five-file FE-only change is focused, but the epoch contract is not applied consistently across selective batch reads, concurrent single-item publishers, and the daemon's raw refresh path.
  • Concurrency and locking: Version-lock sets are acquired in table-ID order and no Meta Service RPC is performed while holding them; no deadlock survived review. The remaining defects are snapshot/publication-order races described inline.
  • Lifecycle, configuration, and compatibility: The new epochs are transient cache state and restart initializes uncached state safely. No configuration, persistent format, or FE/BE protocol field is added. Mixed-version, disabled-repair, and peer-FE recovery concerns are already covered by existing review threads and are not duplicated here.
  • Transactions and parallel paths: Ordinary, lazy, MoW, final-2PC, subtransaction, and BE-report paths were traced, including txn_info.table_ids completeness. Existing lazy/2PC/callback/report gaps remain covered by existing threads; no duplicate comment is added.
  • Error handling and observability: RPC failures remain visible/retryable in the cache-aware readers, and logging is adequate for the changed paths. The daemon convergence defect creates repeated RPCs but no separate logging issue.
  • Performance: The daemon's unacknowledged epoch can trigger an MS table-version RPC on every eligible pass and on cache-aware consumers until foreground repair. No other independent performance blocker survived review.
  • Testing: Current PR checks are green, but the tests omit deterministic partial-cache invalidation, value-before-epoch publication, and daemon-convergence interleavings. Per the review runner contract, no local builds or tests were run.
  • User focus: No additional focus was supplied.

Review completion: complete. The main pass plus three duplicate-safe rounds of normal and risk-focused review converged in round 3 with no new valuable findings; all candidates are accepted, duplicate-fenced, or dismissed with evidence.

}

@VisibleForTesting
protected boolean isCachedVersionExpired() {

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] Read the cached value after validating its epoch

The batch readers currently load the numeric cache before calling this epoch check. After invalidation leaves epoch 1/refreshed 0 and value v2, a concurrent single-item getVisibleVersion() can fetch v3, write it, and publish refreshed epoch 1 between those two operations. The batch then sees this check pass but returns its earlier local v2; ScanNode.setVisibleVersionForOlapScanNodes uses that stale value directly even for a one-partition query. This is distinct from the partial-subset race: the epoch never changes, so a later epoch recheck would still pass. In both partition and table batch readers, establish that the epoch is valid first and only then load the cached value (or make every epoch-acknowledging publisher take the matching version write lock), and add a deterministic interleaving test.

Long version = versions.get(i);
if (version > Partition.PARTITION_INIT_VERSION) {
// For compatibility, the existing partitions may not have mtime
long mTime = versions.size() == versionUpdateTimesMs.size() ? versionUpdateTimesMs.get(i) : 0;

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] Recheck cached siblings after a partial refresh

This write lock protects only the partitions passed in the expired subset, but the caller may already have copied other siblings from cache and released its read lock. For example, P1 is expired and P2 is cached at v2; after that snapshot, a VISIBLE retry invalidates both epochs, then this one-partition RPC returns P1=v3. The caller splices [v3, v2], and ScanNode.setVisibleVersionForOlapScanNodes sends that impossible mixed snapshot to the BEs even though the transaction made both partitions visible atomically. This is distinct from the prior unlocked-writer thread because the omitted sibling is outside this new lock. Fetch the full requested batch when any entry expires, or recheck every copied epoch and retry after intervening invalidation; apply the same rule to the partial table-version batch.

@@ -3605,13 +3609,18 @@ protected boolean isCachedTableVersionExpired() {

public boolean isCachedTableVersionExpired(long expirationMs) {
// -1 means no cache yet, need to fetch from MS

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] Let the daemon complete the invalidation epoch

Once this predicate sees an epoch mismatch, CloudSyncVersionDaemon cannot make it false: the daemon reads authoritative table versions through raw getVisibleVersionFromMeta, then calls only setCachedTableVersion, which never advances refreshedTableVersionCacheEpoch. The table is therefore selected for an MS RPC on every later daemon pass (and by every cache-aware table-version consumer until a foreground wrapper repairs it). If a delayed normal notification already supplied the same numeric table version, the daemon also skips partition refresh, leaving all partition epochs mismatched. Capture each epoch before the daemon RPC, refresh invalidated partitions even when the numeric table version is unchanged, and acknowledge only that captured epoch after the paired refresh succeeds so a concurrent invalidation remains pending.

@luwei16

luwei16 commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Local pipeline review — ✅ PASS

schema: doris-repo-review/v1
status: PASS
pr: apache/doris#67813
commit: ac106fb1dd5d0a2bb6a05545918620158eb1c6d2
base: 1a3b141824bf4c8a0d77b95338a6978360282f24
reviewed_at: 2026-09-16T12:40+08:00
reviewer: luwei16
model: gpt-6-astra
effort: xhigh
findings: {blocker: 0, major: 0, minor: 0, nit: 0}
rounds: 1
converged: true

Notes for maintainers

  • Reviewed all five changed files and their transaction/cache/peer call chains; no new findings or undeclared regressions. No builds or tests were run in this review.
  • Existing comments 3985802176 (COMMITTED shortcut) and 3985802182 (final 2PC retry) concern behavior already present at the merge base and remain unfixed; this receipt does not resolve them.
  • fe/fe-core/src/main/java/org/apache/doris/cloud/catalog/CloudPartition.java:356 — broader single-publisher/batch-reader snapshot limitations predate this change; batch publication locks do not establish universal snapshot linearizability. Peer delivery remains the declared existing asynchronous contract.

Reviewed locally with the doris-repo-review pipeline. Repository policy may accept this receipt for the matching commit; it is not a human Apache approval.

@luwei16
luwei16 merged commit 3dbe4d3 into apache:master Sep 16, 2026
46 checks passed
morningman added a commit that referenced this pull request Sep 16, 2026
…on PRs from master in merge order (#65805 #67813) (#68073)

Cherry-picked from #65805, #67813

Batch pick of every merged PR carrying the `incremental-computation`
label that `branch-incremental-computation` does not have yet (no
`incremental-computation-picked` label), in the order they landed on
master (`git log --first-parent`). One commit per PR, each created with
`git cherry-pick -x` so the message ends with `(cherry picked from
commit <master sha>)`. Follows the same convention as #67830 and #68017.

| # | Master commit | PR | Title |
|---|---|---|---|
| 1 | ec886f3 | #65805 | [fix](nereids) Disambiguate NULL/OFFSET
metadata from same-named nested fields |
| 2 | 3dbe4d3 | #67813 | [fix](cloud) Invalidate version caches on
visible commit retries |

Not included on purpose:
- The 17 labelled PRs that already carry
`incremental-computation-picked` (#62606 in the fork point, #67508 via
#67712, the nine of #67830, the six of #68017).
- #68012 carries the label but is a PR against this branch itself
(merged as `6f7c87fa892`); nothing to pick.
- #67820 is still open on master; this branch already carries its
content via #67861.

### Prerequisite check

- **#65805** lists #65591 and #66380 as related PRs: #65591 is still
open and #66380 was closed unmerged, both superseded by #65805 itself.
The nested-column-pruning series it builds on (#59263, #61888, #64535)
is before the fork point, so it is already on this branch. No master
commit between the fork point and #65805 touches
`column_reader.{cpp,h}`, `descriptors.cpp`, the nereids pruning rules or
the BE tests. The only overlap is the unrelated #66761 (TIMESTAMP_NS),
which touches `Descriptors.thrift` (a different struct) and adds an
unrelated test plus its `Config` import to
`DescriptorToThriftConverterTest.java`; that caused the one conflict,
see below.
- **#67813** declares no related PR (closes #67099). Its behavior does
not depend on any master commit missing here. The one unlabelled master
commit that touches the same main files, #66296 ("Reduce cloud version
sync config"), only adds `maxAttempts` overloads that none of #67813's
main-code hunks use. The other drift in `CloudGlobalTransactionMgr.java`
/ `CloudGlobalTransactionMgrTest.java` is this branch's own #67861 (the
branch-side version of the still-open #67820), which lives in
`commitTxn` / `releaseFinishedTso` / `afterAbortTxnResp` and does not
intersect the two hunks #67813 adds (`checkTransactionStateBeforeCommit`
and the empty-partition-list branch of the commit response handling).

Neither #66761 nor #66296 was picked; three mechanical adaptations were
needed instead, each recorded in the pick's commit message:

- **#65805** conflicted only in the import block of
`DescriptorToThriftConverterTest.java` (the master hunk sits next to the
`Config` import that #66761 added). Resolved by adding only `import
org.apache.doris.thrift.DescriptorsConstants;`. Everything else is
byte-identical to the master commit.
- **#67813** conflicted only in the import block of
`CloudGlobalTransactionMgrTest.java`: the branch already has `import
org.apache.doris.rpc.RpcException;` through #67861, so that line became
context; the other ten imports were taken as-is.
- **#67813**, test-only: the master helper `mockVersionHelper()` stubs
`VersionHelper.getVersionFromMeta(request, maxAttempts)`, an overload
that only exists on master because of #66296, so `fe-core` test
compilation failed (`method getVersionFromMeta ... cannot be applied to
given types`). On this branch every read goes through the
single-argument overload, so the helper now just returns
`Mockito.mockStatic(VersionHelper.class)`. No main-code hunk of #67813
uses the `maxAttempts` overloads.

### Drift check against master

For each pick, the diff of the touched files against the master commit's
parent before the pick and against the master commit after the pick have
identical `+`/`-` lines (only the import context lines differ as
described above), i.e. each pick added exactly its master hunks.
Leftover differences to master after the picks are:
- #65805's files: `DescriptorToThriftConverterTest.java` and
`Descriptors.thrift` differ from master by exactly #66761's hunks.
- #67813's files: `OlapTable.java`, `CloudPartition.java`,
`CloudGlobalTransactionMgr.java` and
`CloudGlobalTransactionMgrTest.java`. Applying #66296 forward and #67861
in reverse in a temporary index brings the four main files to zero diff
against master `3dbe4d3ca53`; the test file's remaining difference is
the `RpcException` import overlap plus the `mockVersionHelper()`
adaptation. `CloudFEVersionSynchronizer.java` is byte-identical to
master.

### Verification

- FE: `run-fe-ut.sh --run` on this branch (regenerates thrift/protobuf,
compiles fe-core main + test) with the test classes touched by the picks
plus the two related cloud version-cache classes:
5 classes, 139 tests, 0 failures, 0 errors, BUILD SUCCESS (2:12 min) —
`PruneNestedColumnTest` 61, `DescriptorToThriftConverterTest` 21,
`CloudGlobalTransactionMgrTest` 37 (all 13 tests #67813 adds included),
`CloudPartitionTest` 3, `OlapTableTest` 17. (`VersionHelperTest` from
#67813's checklist does not exist on this branch; #66296 added it.)
- FE checkstyle on fe-core: 0 violations.
- BE: `-fsyntax-only` with the flags of the Release build
(`compile_commands.json`, regenerated `gen_cpp` headers) passes for
`storage/segment/column_reader.cpp`, `runtime/descriptors.cpp`, and with
`-DBE_TEST -fno-access-control` for
`test/storage/segment/column_reader_test.cpp` and
`test/runtime/descriptor_test.cpp`.
- The three touched groovy suites (`lambda_null_pruning`,
`left_join_not_null_column`, `null_column_pruning`) parse cleanly
(groovy parser check).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: minghong <zhouminghong@selectdb.com>
Co-authored-by: Luwei <814383175@qq.com>
bobhan1 added a commit to bobhan1/doris that referenced this pull request Sep 17, 2026
### What problem does this PR solve?

Problem Summary: Commit retries can race concurrent lazy publication. Stale temporary-rowset candidates may be published again, and an incomplete response may leave FE version caches partially updated.

Preserve the non-snapshot batch read of all candidate tmp keys in the actual immediate write transaction. A missing key rejects the whole attempt with KV_TXN_CONFLICT; a later concurrent deletion creates a real FDB commit conflict.

FE sends distinct tablet and partition counts for the whole load, including non-base indexes and the union of sub-transactions. Unknown counts are omitted. At each MS commit path's successful response, compare the processed tablet count and returned partition count with the supplied expectations. On mismatch, clear partition versions, table stats and version timestamps while preserving the successful transaction result. The empty response uses the cache invalidation already provided by apache#67813, without another commit-time version RPC.

### Release note

Prevent duplicate rowset publication and stale FE version caches when commit retries race lazy publication.

### Check List (For Author)

- Test: Unit Test; ASAN with real FoundationDB for the six focused cases; the complete lazy-commit suite passes 33 active tests with one pre-existing disabled test. The full-suite run preceded the snapshot-pagination helper adjustment; all six affected cases pass with the final helper. FE transaction and version-cache suites pass 60 tests. Checkstyle, clang-format 16 and git diff --check pass. No live cluster or SQL regression run.
- Behavior changed: Yes; reject stale candidates and omit incomplete version results so FE invalidates its caches.
- Does this need documentation: No
morningman added a commit that referenced this pull request Sep 20, 2026
…on PRs from master in merge order (#67820 #68088) (#68236)

Cherry-picked from #67820, #68088

Batch pick of every merged PR carrying the `incremental-computation`
label that `branch-incremental-computation` does not have yet (no
`incremental-computation-picked` label), in the order they landed on
master (`git log --first-parent`). One commit per PR, each ending with
`(cherry picked from commit <master sha>)`. Follows the same convention
as #67830, #68017, #68073 and #68151.

| # | Master commit | PR | Title |
|---|---|---|---|
| 1 | 44e3ae2 | #67820 | [fix](binlog) Track committed TSO and fence
uncertain commits for bounded incremental reads |
| 2 | 3de3a75 | #68088 | [fix](binlog) Require SELECT privilege for
binlog TVF |

Not included on purpose:
- The 25 labelled PRs that already carry
`incremental-computation-picked`.
- #68012 carries the label but is a PR against this branch itself
(merged as `6f7c87fa892`); nothing to pick.

### How #67820 was picked

This branch already carried #67820 through #67861, which backported the
PR's first seven commits (up to `17272039558`) before the PR was merged.
Between that cut and the merge the PR gained six more commits and five
master merges, and the final design differs from what #67861 brought:
the Meta Service recovery RPC (`get_tso_recovery_transactions`) and the
FE startup/periodic recovery scan are gone, replaced by a durable
per-instance commit-TSO fence (`txn_tso_fence_key`, `advance_tso_fence`,
commit-time `TXN_COMMIT_TSO_EXPIRED` check,
`enable_check_commit_tso_fence`), plus the review-feedback and "release
maybe-committed TSO" fixes.

A plain `cherry-pick -x 44e3ae2` conflicts in 23 files because the
branch holds the intermediate design, so commit 1 was built by
replaying, on top of the branch, exactly what the PR gained after the
cut:
- the PR's later commits `d16e67197b2`, `e53291d196b`, `864546d5531`,
`8c55eb086e9`, `8d264ce294a`, `fc4f9969202`;
- the content that landed inside its master merges, identified by
diffing each merge against its `git merge-tree` automerge result:
`c491a293426` (`setEnvTSOService` replaced by
`Mockito.doReturn(tsoService).when(masterEnv).getTSOService()` —
`masterEnv` is the same Mockito delegating mock here since #67813) and
`29f133584b5` (the extra `TSOTransactionTrackerTest` coverage and two
comment removals in `DorisFlightSqlProducer`). The other three merges
only resolved import blocks against master-only code.

The replay then got squashed into one commit with the master PR's
message, the original author, and the `(cherry picked from commit
44e3ae2)` trailer. Adaptations, all
recorded in the commit message:
- `DorisFlightSqlProducer` / `DorisFlightSqlProducerTest` stay under
`service/arrowflight` (the branch lacks the package move of #67866).
- `8d264ce294a` is a no-op here: it removes a `catch
(FlightRuntimeException)` block that #67883 added on master and this
branch never had.
- The branch-only `get_tso_recovery_transactions` RPC, its recovery
scan, the five `TsoRecovery*` Meta Service tests and the NOLINT
suppressions #67861 had added for them are removed, as on master.
- The round-3 `mockVersionHelper()` adaptation in
`CloudGlobalTransactionMgrTest` (no
`VersionHelper.getVersionFromMeta(req, maxAttempts)` overload here,
#66296) is kept.

### Prerequisite check

- **#67820** declares #67181 and #67594 as related; #67181
(`e5a4e725fac`) is before the fork point and #67594 came with #67830.
The rest of what the commit touches on master is import-block and
neighbouring-code drift from unlabelled commits (#67866 / #67883 /
#67966 Arrow Flight and session refactors, #67761
`get_prepare_txn_by_coordinator`, #66598 pre-rowset delete bitmaps,
repair-tablet-index changes); none of it is used by the
fence/committed-TSO logic.
- **#68088** declares no related PR. The hook it implements
(`TableValuedFunctionIf.checkAuth`) and the caller chain
(`CheckPrivileges.visitLogicalTVFRelation` →
`TableValuedFunction.checkAuth` → catalog function) are byte-identical
between this branch and master, and the five-argument
`AccessControllerManager.checkTblPriv` overload exists. Applied cleanly.

### Drift check against master

- **#67820**: every one of the 54 files the master commit touches now
contains the pick's content — the master commit reverse-applies cleanly
per file onto this branch (50 files), and the four files where only the
surrounding context differs (`config.h`, `meta_service_txn.cpp`,
`StmtExecutor.java`, `StmtExecutorTest.java`) contain every added line
and none of the removed ones. 33 of the 54 files are byte-identical to
master at `44e3ae2b951`, including all of `fe/.../tso/`,
`CloudGlobalTransactionMgr.java`, `MetaServiceProxy.java`,
`keys.{h,cpp}`, `meta_service.h` and the regression suite/output. The
remaining differences are unrelated master-only or branch-only code from
unlabelled commits (#67761, #66598, #67866/#67883/#67966,
repair-tablet-index, meta-cache columns, recycler configs) plus the
documented `mockVersionHelper()` adaptation; no line in the
committed-TSO/fence domain is left over from #67861.
- **#68088**: all three files are byte-identical to master at
`3de3a756f74`.

### Verification

- FE: `run-fe-ut.sh --run` on this branch (regenerates thrift/protobuf,
compiles fe-core main + test) with every test class the picks touch: 12
classes, 175 tests, 0 failures, 0 errors, BUILD SUCCESS —
`TSOServiceTest` 38, `CloudGlobalTransactionMgrTest` 37,
`StmtExecutorTest` 27, `MetaServiceProxyTest` 22, `OlapScanNodeTest` 12,
`TimeBasedChangeVisibleWaiterTest` 12, `TSOTransactionTrackerTest` 9
(the four tests added inside the PR's last master merge included),
`DorisFlightSqlProducerTest` 7, `TsoStatusMetadataGeneratorTest` 5,
`CloudCommittedTsoTest` 3, `SchemaTableTest` 2,
`TableBinlogFunctionAuthTest` 1 (#68088). The `@Test` counts of the
touched classes equal master's.
- FE checkstyle on fe-core: 0 violations.
- Meta Service: `-fsyntax-only` with the flags of `cloud/CMakeLists.txt`
(`-Wall -Werror`, regenerated `gen_cpp/cloud.pb.h` with
`AdvanceTsoFence*` / `TxnTsoFencePB` and without
`GetTsoRecoveryTransactions*`) on `meta_service_txn.cpp`, `keys.cpp`,
`http_encode_key.cpp`, `bvars.cpp` and, with `-DUNIT_TEST -DBE_TEST
-fno-access-control`, on `meta_service_test.cpp`, `keys_test.cpp`,
`http_encode_key_test.cpp`, `meta_service_helper_test.cpp`,
`txn_lazy_commit_test.cpp`: no diagnostic in any line the pick touches
(the only errors are the pre-existing macOS-only `pthread_setname_np` /
`int64_t`-vs-`long` ones in untouched 2024/2025 code). clang-format 16
is clean on all 14 touched cloud files.
- No BE file changes in this round (the BE side of #67820 was already
byte-identical to master via #67861).
- The new `auth_p0/test_binlog_tvf_auth.groovy` and the two #67820
suites parse cleanly (groovy parser check).

---------

Co-authored-by: Luwei <814383175@qq.com>
Co-authored-by: morrySnow <zhangwenxin@selectdb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Binlog][Cloud] VISIBLE retry loses version outcome and permits stale read after Table Stream commit

5 participants