Skip to content

[fix](fe) Exclude load-disabled backends from load plans - #69554

Open
HonestManXin wants to merge 1 commit into
apache:masterfrom
HonestManXin:fix_disable_load
Open

HonestManXin wants to merge 1 commit into
apache:masterfrom
HonestManXin:fix_disable_load

Conversation

@HonestManXin

Copy link
Copy Markdown
Contributor

In a three-replica deployment, marking a slow backend with disable_load did not remove it from tablet load locations, so writers still sent data to that backend and suffered long-tail latency. The disable_load feature originally checked backend load availability, but the single-replica migration fix later changed tablet load selection to check only whether a backend was alive. Restore the load-availability check while preserving the decommission watermark rule that allows an in-flight replica migration to continue writing until its post watermark is set.

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

@HonestManXin

Copy link
Copy Markdown
Contributor Author

/review

@HonestManXin

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes for two verified findings: a P1 regression in metadata callers of the shared replica enumeration, and a P2 cloud load-routing regression during graceful backend shutdown. The metadata finding combines incomplete light-schema conversion and colocate discovery/replay because they share the same changed API and remedy.

Reviewed all three changed files and their upstream/downstream load, migration, cloud, metadata and persistence paths at head 734ddac. No existing inline threads or previously reported blocking findings were present. No additional user focus was supplied.

Critical checkpoint Conclusion
Goal and proof The predicate excludes alive load-disabled backends and retains an enabled DECOMMISSION replica before its post watermark. The added unit test covers those two cases; indirect callers cause the findings below.
Scope and clarity The helper and test follow adjacent patterns and the patch is small, but the shared enumeration also serves metadata operations (P1).
Concurrency and locking ALTER/backend-heartbeat writers publish volatile load/shutdown flags and atomic alive state; backend maps and local replica membership use volatile immutable snapshots. No new lock, blocking operation, lock-order edge or demonstrated race is introduced. Existing table-lock ownership of migration state is retained.
Lifecycle and initialization No new owned resource, thread, retained state or static initializer. The existing live-but-shutting-down lifecycle exposes the P2 cloud routing defect.
Configuration No new configuration. Existing disable_load is read dynamically for fresh maps; existing transaction retry caches intentionally preserve recorded locations.
Compatibility No new wire/storage format or removed symbol. Old-master colocate journal replay can diverge on this head through the changed physical-replica enumeration (P1).
Thrift/protobuf IDs No gensrc changes; cross-branch field-ID review is inapplicable.
Parallel paths Normal sink plans, base/changelog intersection, cloud cluster/endpoint variants and create/replace-partition RPCs share the filter. Metadata callers need different eligibility (P1); cloud colocated/multi-replica selection needs rerouting (P2).
Conditional checks Backend.isLoadAvailable centralizes alive/load-disabled/shutdown rules. Backend decommission itself is not excluded. Existing post-watermark and failed-DECOMMISSION exclusions remain intact.
Test coverage The JUnit 5 test uses fresh backend/replica state and checks {1,3}. It lacks non-load metadata, cloud shutdown, post-watermark, failed/disabled DECOMMISSION, reenable and missing/dead backend cases; no end-to-end test was added.
Test results No result files changed; the new expectation matches the fixture and distinguishes the prior alive-only behavior. Tests were not executed.
Observability Existing load-quorum errors identify affected tablets/backends. No new long-lived operation requires metrics; false conversion success and skipped replay are part of P1.
Transactions and persistence Migration peer-catch-up and both watermark waits remain; publication does not use this new load gate. Metadata conversion journals incomplete IDs and colocate replay can skip metadata (P1).
Data writes and invariants Sink and commit still enforce required replicas; excluded replicas follow existing error/version handling. No direct visible-version, MoW bitmap or memory-accounting change. Persistent metadata correctness is affected by P1; availability by P2.
FE/BE variable passing No new transmitted variable. Existing tablet-location backend ID sets are filtered across fresh load-map construction paths.
Performance The existing per-replica lookup/scan is retained with constant-time flag reads; no added IO, RPC, lock or collection scan. No performance measurement was performed.
Other issues Cloud disable_load via MODIFY BACKEND is unsupported, so that hypothetical trigger was dismissed. Ordinary non-colocated cloud routing already rehashes shutdown nodes. No additional verified issue remains after the caller and special-case recheck.

Validation and coverage limits: static source review only, as required; no builds, runtime tests, source modifications or executed migration/shutdown interleavings. The two inline findings are supported by concrete control-flow triggers. No unresolved candidate or unreviewed changed file remains.

Review converged after 2 round(s).

Comment thread fe/fe-core/src/main/java/org/apache/doris/catalog/Tablet.java Outdated
Comment thread fe/fe-core/src/main/java/org/apache/doris/catalog/Tablet.java Outdated
@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17601	5130	5015	5015
q2	2110	321	256	256
q3	10230	1372	817	817
q4	4681	467	336	336
q5	7421	783	537	537
q6	184	185	153	153
q7	747	787	591	591
q8	9238	1276	1077	1077
q9	5479	4184	4165	4165
q10	6840	1316	1026	1026
q11	426	241	230	230
q12	637	401	285	285
q13	18103	3572	2994	2994
q14	277	278	256	256
q15	q16	718	721	671	671
q17	1182	749	571	571
q18	6965	6181	6085	6085
q19	1095	945	612	612
q20	382	324	223	223
q21	5067	2185	2300	2185
q22	343	301	253	253
Total cold run time: 99726 ms
Total hot run time: 28338 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5598	5594	5567	5567
q2	667	583	536	536
q3	5174	5349	4898	4898
q4	1993	2139	1557	1557
q5	5265	5139	5489	5139
q6	262	211	166	166
q7	2400	2007	1831	1831
q8	3006	2586	2640	2586
q9	8043	7985	7901	7901
q10	3725	3663	3250	3250
q11	601	431	394	394
q12	847	738	535	535
q13	3510	3863	3307	3307
q14	302	316	313	313
q15	q16	717	713	673	673
q17	8258	7406	6821	6821
q18	13056	12174	12919	12174
q19	916	777	770	770
q20	2156	2176	1906	1906
q21	5686	4669	4714	4669
q22	488	445	413	413
Total cold run time: 72670 ms
Total hot run time: 65406 ms

@hello-stephen

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

query5	4306	572	457	457
query6	431	223	190	190
query7	4815	452	220	220
query8	323	163	148	148
query9	8781	3073	3081	3073
query10	482	293	254	254
query11	6015	3889	3606	3606
query12	151	96	90	90
query13	1239	436	324	324
query14	6100	3890	3690	3690
query14_1	3430	3449	3447	3447
query15	217	200	188	188
query16	947	434	413	413
query17	854	656	575	575
query18	2419	432	303	303
query19	208	171	132	132
query20	85	85	85	85
query21	226	130	108	108
query22	12952	13000	12781	12781
query23	13502	12786	12452	12452
query23_1	12633	12624	12507	12507
query24	7124	814	464	464
query24_1	462	461	480	461
query25	514	399	339	339
query26	824	259	136	136
query27	2744	473	272	272
query28	5104	1913	1889	1889
query29	1529	608	453	453
query30	306	223	187	187
query31	1013	922	831	831
query32	149	90	89	89
query33	542	297	233	233
query34	1348	883	505	505
query35	744	787	642	642
query36	843	830	777	777
query37	122	100	86	86
query38	1827	1765	1722	1722
query39	801	799	761	761
query39_1	757	753	746	746
query40	205	120	105	105
query41	65	67	64	64
query42	91	85	83	83
query43	352	376	325	325
query44	1336	698	701	698
query45	179	189	161	161
query46	864	982	577	577
query47	3044	2948	2746	2746
query48	336	307	219	219
query49	557	406	284	284
query50	687	274	209	209
query51	10396	10294	10487	10294
query52	76	81	72	72
query53	187	203	147	147
query54	247	194	181	181
query55	69	65	63	63
query56	241	209	212	209
query57	1676	1607	1525	1525
query58	306	260	254	254
query59	2086	2103	1947	1947
query60	282	237	219	219
query61	145	141	141	141
query62	393	343	281	281
query63	188	150	151	150
query64	2061	908	732	732
query65	3329	3380	3267	3267
query66	1731	418	298	298
query67	20140	20122	20220	20122
query68	2957	1004	613	613
query69	396	340	243	243
query70	851	800	778	778
query71	299	230	207	207
query72	2706	2570	2290	2290
query73	519	523	295	295
query74	4654	4531	4347	4347
query75	2352	2279	1941	1941
query76	2327	1020	582	582
query77	314	367	263	263
query78	9802	9752	9158	9158
query79	972	843	509	509
query80	689	414	347	347
query81	535	329	276	276
query82	584	132	105	105
query83	301	204	185	185
query84	304	126	96	96
query85	852	420	353	353
query86	346	229	224	224
query87	2016	1976	1805	1805
query88	3623	2658	2636	2636
query89	344	283	234	234
query90	1791	166	166	166
query91	154	144	123	123
query92	97	80	81	80
query93	992	998	594	594
query94	485	320	285	285
query95	564	381	309	309
query96	660	488	233	233
query97	2461	2429	2303	2303
query98	162	154	148	148
query99	768	767	648	648
Total cold run time: 233792 ms
Total hot run time: 150802 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.09	0.05	0.05
query3	0.26	0.08	0.08
query4	1.61	0.10	0.11
query5	0.24	0.25	0.25
query6	1.17	0.69	0.69
query7	0.03	0.01	0.00
query8	0.05	0.04	0.03
query9	0.40	0.37	0.35
query10	0.57	0.57	0.58
query11	0.20	0.14	0.15
query12	0.18	0.14	0.15
query13	0.49	0.50	0.50
query14	1.04	1.02	0.99
query15	0.65	0.62	0.61
query16	0.34	0.34	0.35
query17	1.10	1.15	1.16
query18	0.22	0.20	0.19
query19	2.06	1.94	1.94
query20	0.02	0.01	0.02
query21	15.48	0.18	0.14
query22	4.87	0.06	0.05
query23	16.29	0.32	0.13
query24	2.86	0.57	0.41
query25	0.14	0.07	0.06
query26	1.49	0.21	0.16
query27	0.05	0.05	0.03
query28	3.35	0.81	0.36
query29	12.54	4.13	3.23
query30	0.28	0.14	0.10
query31	2.77	0.55	0.33
query32	3.22	0.59	0.51
query33	3.14	3.16	3.26
query34	15.51	4.01	3.46
query35	3.34	3.34	3.33
query36	0.54	0.45	0.42
query37	0.09	0.06	0.06
query38	0.05	0.04	0.03
query39	0.03	0.03	0.03
query40	0.18	0.15	0.15
query41	0.08	0.03	0.02
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 97.1 s
Total hot run time: 24.36 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 80.00% (4/5) 🎉
Increment coverage report
Complete coverage report

@HonestManXin

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 for one new P1: automatic partition RPCs can return an empty filtered destination list, allowing the supported legacy writer to report success while omitting an entire partition's rows. The inline finding covers the common createPartition/replacePartition failure boundary. No duplicate comments are proposed.

Existing findings were independently revalidated against 0c4461a: P1 #4361269076 is addressed because metadata/replay callers still use alive-only enumeration; P2 #4361269082 is addressed because all CloudTablet load overloads preserve the previous physical-backend selectors. No existing P0/P1 remains applicable. No additional user focus was supplied.

The traced flow is: load planning -> replica eligibility -> tablet locations -> ordinary or incremental BE writer channels -> EOS commit infos -> FE partition/quorum validation. All seven changed files and their relevant upstream/downstream and parallel paths were reviewed.

Critical checkpoint conclusions:

  1. Goal and proof: ordinary shared-nothing load plans now exclude load-disabled/shutdown backends, while metadata and cloud behavior are preserved. Dynamic empty destinations violate data correctness and error-means-failure (the P1). New unit tests cover positive routing; they do not prove the dynamic negative case.
  2. Scope and reuse: focused API split, existing Backend.isLoadAvailable predicate, and shared changelog intersection; no unrelated source change identified.
  3. Concurrency and locks: planning/RPC threads read heartbeat/DDL-updated atomic/volatile backend state and volatile immutable replica/backend snapshots. New filtering mutates a fresh map. Existing table snapshots, overwrite task locks and transaction/partition computeIfAbsent caches retain their scope; no new lock order, blocking IO or heavyweight work under locks.
  4. Lifecycle: no new thread, callback owner, persistent reference or static initializer; map ownership remains request-local.
  5. Configuration: none added. Existing backend status changes are visible to new uncached selection; cached in-flight routing intentionally remains stable.
  6. Compatibility: additive internal Java APIs; no removed symbol, stored format or wire change. Metadata replay and cloud endpoint/cluster routing are preserved.
  7. Thrift/protobuf: no definition changed; cross-branch field-ID checks are not applicable.
  8. Parallel paths: ordinary, changelog, automatic create, replacement, cloud overloads and group-commit routing were traced. Legacy and V2 writers differ on empty locations; V2 rejection does not protect the legacy path.
  9. Conditional checks: decommission post-watermark/failed-version rules remain intact; backend decommission itself is not rejected by isLoadAvailable. Same-disk changelog intersection and documented cloud bypass remain sound. Dynamic warn-only quorum handling is unsafe for empty mappings.
  10. Test coverage: added JUnit tests cover metadata/load separation, a decommission replica and cloud forwarding. Empty/sub-quorum dynamic RPCs, actual shutdown and filtered changelog pairs lack new negative coverage. The sink test fixture also leaves partition.getId() unstubbed, bypassing its intended quorum mock, although routing assertions remain meaningful.
  11. Test results: no golden outputs changed; new assertions agree with statically inspected paths. No builds, tests or runtime reproduction were performed, as required by this review contract.
  12. Observability: ordinary diagnostics now correctly name available replicas and retain tablet/count details. Dynamic warnings do not propagate failure, as described in the P1; no separate metrics change is needed for the local predicate split.
  13. Transactions and persistence: no journal schema or replay mutation introduced. FE commit checks all tablets only within partitions represented by commit infos; this allows the P1's wholly omitted partition. Existing failover/cache lifecycle is unchanged.
  14. Writes and atomicity: ordinary planning and V2 reject unusable targets; nonempty sub-quorum partitions fail FE commit. Legacy empty-target partition omission can commit partial ingestion (P1). No separate crash, leak, deadlock, visible-version or delete-bitmap regression was substantiated.
  15. FE/BE variables: none added; existing tablet/node/base-tablet fields carry the filtered mappings on all changed sending paths.
  16. Performance: O(replica-count) filtering over request-local maps; no added RPC, large allocation or heavier metadata critical section. Cloud cluster-ID hoisting is preserved.
  17. Further issues and limits: rechecked map ownership, dispatch, watermarks, placement eligibility, EOS writer enumeration, row counters, cache cohort consistency and commit partition derivation. One verified new finding; remaining test limitations are stated above. Validation is static only; no unresolved in-scope candidate remains after the final reviewer pass.

Review converged after 2 round(s).

@HonestManXin

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 on head 8d9cf2e. One new P1 is reported inline for initial load plans with reduced write quorum. The existing dynamic-partition P1 remains blocking; its overlapping RPC instance is not reposted.

Existing-thread dispositions:

  • 4361269076 is fixed: metadata callers still enumerate alive normal replicas; only the explicit load API applies load eligibility.
  • 4361269082 is fixed: all CloudTablet load overloads delegate to the previous resolved routes and preserve graceful-drain behavior.
  • 4366121929 is retained for residual whole-partition omission on createPartition/replacePartition. Its original immediate-empty RF1 trigger is fixed. With default RF3/quorum2, however, a filtered nonempty location A->{1} still passes the new guard while another partition B->{1,4,5} is usable. If BE1's tablet-writer-open RPC fails, the legacy writer counts only one failure against its unchanged allowance of one; excluded BEs2/3 never count as failures. B can commit through4/5 while A produces no commit infos and is omitted from FE's partition checks. Both RPCs still only log subquorum locations. This expands the existing thread's evidence rather than adding a duplicate comment.

Reviewed flow: initial insert/stream-load planning or dynamic create/replace RPC -> filtered TTabletLocation node lists -> legacy channels / V2 streams -> successful tablet commit infos -> FE infers involved partitions -> quorum checks within those partitions. The failure is that a wholly failed filtered partition can disappear before the final check. The new initial-planner instance uses supported min_load_replica_num=1 and requires no dynamic partition RPC. The analogous V2 tablet-level CLOSE failure also uses the configured-total failure budget, so empty-stream rejection alone does not establish safety.

Critical checkpoint conclusions:

  1. Goal and proof: load-disabled shared-nothing targets are excluded while migration watermarks are preserved, but end-to-end correctness is incomplete because filtered targets are absent from failure accounting. Added tests cover selection and immediate-empty rejection, not the verified mixed-partition failure.
  2. Scope and reuse: the explicit load API and shared empty-map helper are small and reuse existing predicates; no unrelated production change found.
  3. Concurrency and locks: heartbeat/operator updates use existing volatile/atomic backend state and immutable membership/replica snapshots. New filtering mutates local maps and adds no locks, RPCs, waits or lock-order changes. Existing table snapshots/cache synchronization remain intact. Concrete selected-target failures, rather than a speculative race, establish the finding.
  4. Lifecycle: DECOMMISSION pre/post-watermark admission and cloud route resolution are preserved. Per-transaction cached locations pin one distribution; fresh empty maps are rejected before insertion. No new static initialization, ownership cycle or release obligation.
  5. Configuration: no new config. Existing backend load flags are observed dynamically; supported table/global min_load_replica_num exposes the initial-plan defect.
  6. Compatibility: no persisted format or FE-BE wire change. Metadata replay keeps normal enumeration. Existing configured replica counts still travel beside shorter destination lists, which is the failure-accounting mismatch.
  7. Thrift/protobuf IDs: no gensrc changes; cross-branch field-ID checks do not apply.
  8. Parallel paths: initial insert/stream, dynamic create/replace, dummy locations, changelog intersection, cloud default/cluster/endpoint routes, and both writer implementations were examined. One new initial-plan instance is distinct from the retained dynamic thread.
  9. Special conditions: the empty-map guard has a concrete failure comment and catches UserException into non-OK RPC status on both paths. Nonempty destinations alone do not ensure failure propagation. Changelog same-disk intersection and companion commit validation prevent a separate partial-index corruption issue.
  10. Test coverage: inspected every added JUnit test and its fixtures/cleanup. Missing end-to-end cases combine mixed partitions, filtered destinations, actual selected-target failure, and reduced quorum. Shutdown, cloud-overload and cache behavior were traced statically.
  11. Changed test results: new assertions match the intended direct-selection/empty-map behavior; no regression .out files were added or modified. No test execution is claimed.
  12. Observability: new errors include table/partition/tablet IDs; planner errors include selected/required counts. Existing log-only quorum warnings do not turn the verified silent-success path into a failure. No separate metric requirement identified.
  13. Transactions and persistence: no new journal fields or replay protocol. DatabaseTransactionMgr derives involved partitions from successful commit infos, so it cannot validate a wholly omitted partition. No additional persistence/failover defect found in the changed mechanisms.
  14. Data writes, atomicity and crashes: a selected-target failure can commit another partition while losing all input for the omitted one; this violates data correctness and error-means-failure. No separate new leak/deadlock/cleanup issue found; crash behavior was not exercised.
  15. FE-BE variable propagation: no new field; total/required replica values retain configured counts while location filtering removes destinations. Writers must account for that difference or enforce successful participation of every touched partition.
  16. Performance: one extra small linear replica-map scan with constant-time backend lookups; cloud cluster resolution remains hoisted. No material performance defect identified.
  17. Other core invariants: visible-version, delete-bitmap and BE memory-ownership logic are unchanged. No other independent static-review finding remained after the full-scope and risk sweeps.

All eight changed files and all three initial risk focuses were covered. No additional user focus was supplied. This was a static-only review: no builds, tests, source modifications, runtime reproduction or crash/failover experiments were performed. No unresolved static-review candidate or unreviewed changed-file scope remains; execution validation is the explicit coverage limit.

Review converged after 2 round(s).

Existing P0/P1 findings confirmed for this head: #69554 (comment)

gavinchou
gavinchou previously approved these changes Oct 25, 2026

@gavinchou gavinchou 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.

LGTM.

@HonestManXin

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: two P1 correctness defects and one P2 regression-test failure remain at head 962f5b3.

The legacy writer now accounts for selected destinations, but its new initialization check rejects the synthetic one-node bootstrap tablet used by empty automatic-partition tables. Separately, VTabletWriterV2 still tolerates failure of every selected destination after filtering, allowing a touched partition to disappear from an otherwise successful mixed-partition load. The new docker regression also enables the fault before an unpruned baseline INSERT, so that setup statement fails before the intended negative case.

Existing review context was independently revalidated: 4361269076 (metadata enumeration), 4361269082 (cloud graceful routing), 4366121929 (empty dynamic locations), and 4367374261 (legacy selected-destination failure accounting) are addressed for their reported paths. None is carried as an existing blocker or reposted. The new V2 finding concerns a separate implementation, VTabletWriterV2::_create_commit_info, which the prior explicitly legacy IndexChannel finding and its fix do not cover. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal and evidence: load-specific filtering excludes shared-nothing load-disabled/shutdown backends while retaining metadata and cloud behavior. The overall goal is incomplete because of the bootstrap and V2 defects. Added tests were inspected; no runtime validation was performed.
  2. Scope and reuse: changes stay within destination selection, replica failure accounting, dynamic quorum propagation, and tests, reusing isLoadAvailable and getLoadRequiredReplicaNum. No unrelated production change found.
  3. Concurrency and locks: FE RPC/DDL snapshots retain existing table locks; the writer process thread, periodic sender bthread, send pool and BRPC callbacks retain existing _stop_check_channel, _closed_lock and _fail_lock relationships. No new lock, blocking operation under a new lock, or introduced lock-order issue was substantiated. Existing callback/map mutation patterns predate this diff.
  4. Lifecycle and initialization: count entries precede real-tablet channel initialization; partial initialization still cancels through existing ownership paths. Synthetic tablet lifetime is mishandled by the new quorum check (first P1). No new ownership cycle or cross-translation-unit static initializer was introduced.
  5. Configuration: no new configuration. Existing disable_load/shutdown flags are read when calculating new destinations; transaction caches intentionally preserve established routing. Existing minimum-load-quorum settings are used in dynamic snapshots.
  6. Compatibility: no persisted format change; dynamic counts use existing optional protocol fields and BE fallbacks. The BE helper/struct changes are internal. Old writer binaries retain their previous failure-accounting limits until upgraded.
  7. Thrift/protobuf IDs: no gensrc definition, field ID, enum value, or requiredness change; release-branch ID comparisons are not applicable.
  8. Parallel paths: initial/create/replace/cache, ordinary/changelog, cloud endpoint/cluster/default selection, and legacy/V2 consumers were traced. FE routing is consistent; V2 final failure accounting is the verified missing parallel fix. The removed single-replica mode is explicitly rejected upstream.
  9. Conditions and comments: the new real-tablet short-quorum and selected-failure checks explain concrete data-loss scenarios; cloud comments explain why resolved targets are preserved. The checks omit the synthetic bootstrap exception. Decommission replica pre/post-watermark rules remain intact.
  10. Test coverage: BE tests cover selected-count arithmetic, repeated failures, and short quorum; FE tests cover metadata, filtering, cloud routing, and both dynamic empty-location guards. Missing first-load bootstrap and V2 late-close coverage allowed the P1 defects. The docker regression has the inline P2 setup failure. The planner test helper also leaves partition.getId() unstubbed, so its positive routing tests use mocked quorum zero rather than their intended quorum; this is a coverage limitation, not an additional production finding.
  11. Test results: no golden output files changed. Aggregate expectations in the docker test are arithmetically consistent if its intended loads execute, but setup must be corrected before it proves those results.
  12. Observability: new initialization errors identify tablet, partition, load, selected and required counts; dynamic errors identify table/partition/tablet. Existing RPC/failure logs remain sufficient for these paths; no new per-row logging or additional metric requirement found.
  13. Persistence and failover: transient plan/location metadata changes do not add catalog state or require EditLog changes. Preserving the metadata selector removes the prior replay-divergence concern; commit/publish persistence paths are otherwise unchanged.
  14. Writes and atomicity: the reported legacy omitted-partition trigger is fixed, but V2 can still return successful commit infos for only the healthy partition after a late receiver tablet failure. FE infers touched partitions from those infos, so the second P1 is an atomicity/data-loss defect. No separate new recovery leak or deadlock was substantiated.
  15. FE/BE propagation: both dynamic RPCs now serialize effective total/required counts, and original response partitions are parsed for legacy and V2 incremental writers. Selected counts come from existing locations. No new wire variable or definition was added.
  16. Performance and memory: one additional linear pass over each local tablet's small replica map and one integer per legacy replica-info entry; failure arithmetic remains constant-time. No new large buffer, column/null handling, memory reservation requirement, or cloud per-tablet RPC was introduced. Existing tracking/ownership remains in use.
  17. Final recheck: all 12 changed paths, existing threads, candidate dispositions, bootstrap paths, unused planned partitions, V2 receiver close errors, cache/retry, old-FE inputs, version gaps and cloud overloads were covered. The three inline findings are the complete accepted new set.

Review scope is static only: no builds, tests, fault injection, source edits, or binary ABI audits were run. Runtime behavior and scheduling were inferred from the cited local control flow. Dedicated end-to-end tests for several traced dynamic/cloud/cache/changelog combinations are absent. No unresolved review candidate or unreviewed assigned path remains.

Review converged after 2 round(s).

Comment thread be/src/exec/sink/writer/vtablet_writer.cpp
Comment thread fe/fe-core/src/main/java/org/apache/doris/catalog/Tablet.java
@HonestManXin

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: three new verified issues remain—one legacy fatal assertion on a nonlocal automatic-partition tablet error, one V2 rejection of a quorum-successful shared load, and one older-FE/new-BE minimum-replica compatibility regression. Each is inline. Reviewed all 15 changed files and the relevant upstream/downstream paths statically at head 1298c15.

Critical checkpoint conclusions:

  1. Goal and proof: load-only eligibility, empty-location rejection and selected-destination failure budgets address the earlier omission scenarios on updated FE/BE binaries. The new findings mean the implementation is not yet complete; added tests were inspected, not executed.
  2. Scope and reuse: focused selectors, cloud wrappers and shared RPC snapshot/helper changes; no unrelated production changes identified.
  3. Concurrency: independent sink instances and final RPC callbacks can report tablets beyond local metadata (findings 1–2). Legacy failure updates use _fail_lock; no additional lock-order inversion or heavy locked operation was identified in the changes.
  4. Lifecycle/static initialization: dummy tablet 0 now uses one destination and avoids real-tablet failure accounting. Shared final-result ownership still conflicts with private metadata. No new ownership cycle, thread or static initialization dependency; the new namespace constant is constexpr.
  5. Configuration: none added. Existing load-disabled/shutdown flags affect uncached shared-nothing destinations promptly; transaction-cached routes intentionally remain stable.
  6. Compatibility: existing wire/storage formats are reused, but omitted requirements from older FE dynamic responses cause finding 3. Older BE binaries also retain the historical selected-failure behavior until upgraded; the fixes do not retrofit those binaries.
  7. Thrift/Protobuf IDs: no gensrc definitions changed; no field-ID/enum additions to audit across branches.
  8. Parallel paths: initial and incremental legacy/V2 writers, automatic create/replacement RPCs, changelog intersection and cloud wrappers were traced. Removed single-replica write mode is explicitly unsupported.
  9. Conditions and errors: new checks have concrete failure explanations and identifier-rich messages. The local-ownership assertion and omitted-field inference are invalid in the reported cases; ordinary returned Status failures otherwise propagate.
  10. Test coverage: inspected FE selector/cloud/RPC tests, BE selected-failure/dummy tests and both regression writer modes. Missing cases include multi-instance incremental late errors and older-FE omitted requirements. The FE location-test mock also leaves partition ID unstubbed, so its declared quorum stub is unused.
  11. Test results: no result files changed. No builds, tests, cluster runs or runtime validation were performed under the static-only contract.
  12. Observability: new errors include tablet/partition/load identifiers; no additional metric need was identified for these bounded metadata checks.
  13. Transactions and persistence: FE still infers touched partitions from successful commit infos, making selected-failure enforcement necessary. No new EditLog/persistence representation or failover protocol was added; request/cache cleanup follows existing paths.
  14. Data writes and core invariants: normal selected-target failure accounting closes the earlier atomicity hole on updated binaries, but the new callback/owner cases can fatally fail or reject viable writes. Read-visible versions and delete-bitmap version handling are unchanged; bitmap failures were traced as a callback trigger.
  15. FE/BE variables: existing total/required replica fields are now set by both dynamic RPC paths as well as initial plans; missing old-peer values are the compatibility defect. No new transmitted variable was introduced.
  16. Memory and performance: only small per-tablet count metadata is added under existing tracking contexts; no new long-lived allocation owner or material asymptotic regression identified. Eligibility is O(replica entries); V2 gap intersection is bounded by replica count.
  17. Other risks: unselected legacy gap IDs only affect selected-node quorum counting; V2 correctly intersects gap IDs before unioning failures. No additional verified issue from the final risk sweep.

Existing-thread disposition: metadata isolation (4361269076), cloud drain routing (4361269082), empty dynamic locations (4366121929), legacy selected-failure allowance (4367374261), bootstrap tablet (4369805659), V2 selected-failure allowance (4369805662), and regression seed ordering (4369805666) are addressed on the reviewed head. None is reposted; no existing P0/P1 is confirmed still blocking on the updated binaries.

User focus: none supplied. Coverage is complete for the requested static review; runtime behavior remains unexecuted. Review converged after two rounds: all assigned reviewers returned NO_NEW_VALUABLE_FINDINGS on this unchanged payload, all candidates were dispositioned, and all initial risk items were resolved. Convergence describes review coverage, not approval of the code.

Review converged after 2 round(s).

Comment thread be/src/exec/sink/writer/vtablet_writer.cpp
Comment thread be/src/exec/sink/writer/vtablet_writer_v2.cpp
Comment thread be/src/exec/sink/writer/vtablet_writer_v2.cpp Outdated
@HonestManXin

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.

Static review of #69554 at 6f58261. All 17 changed paths and relevant upstream/downstream flows were inspected. No builds or tests were run, and no repository source was modified.

One new P1 requires changes: excluding synthetic tablet 0 from the legacy writer's backend map can discard a real tablet's final-close error when an empty-input sender closes the bootstrap receiver last. A second partition can commit while every row in the failed partition is omitted. The inline finding describes the concrete trigger and fix direction.

The original P1 triggers in comments 4361269076, 4366121929, 4367374261, 4369805659, 4369805662 and 4370332388 are addressed on this head: metadata enumeration is separate from load selection; both dynamic RPCs reject empty locations; both writers account for selected destinations; bootstrap policy is 1/1/1; and nonlocal errors no longer reach the missing-policy assertion. No existing P0/P1 ID is carried forward. The new dummy-only error bypass is a distinct changed location and silent-loss outcome.

Known residuals remain under their existing threads and are not reposted: 4370332388 still covers quorum-valid legacy loads rejected by the guarded nonlocal path; 4370332390 is fixed for local pooled sinks but foreign-source V2 results can still lack policy; 4370332391 fixes selected=1 but an older FE's omitted minimum still causes selected=2/minimum=1 loads to reject one late failure. The cloud routing issue 4361269082 and regression seeding issue 4369805666 are addressed.

Critical checkpoint conclusions:

Checkpoint Conclusion
Goal and evidence New shared-nothing loads filter load-disabled/shutdown backends while metadata/cloud routing is preserved. Atomicity remains incomplete because of the new P1. Added tests were inspected, not executed.
Scope, clarity and reuse Changes stay focused on load selection, replica policy and failure handling; dynamic RPCs reuse one emptiness guard.
Concurrency and locks Pool metadata uses the existing mutex; failure status uses the existing failure lock. No new lock inversion or blocking I/O under the policy lock was found. Cross-sender final-EOS result ownership causes the P1.
Lifecycle and static initialization Empty-input writers open and send EOS. Receiver results can include other senders' tablets. Shared pool policy lifetime follows the existing shared owner; constexpr IDs add no static initialization dependency.
Configuration No configuration item is added. Fresh selection observes existing flags; in-flight/cached locations retain transaction stability.
Compatibility Existing optional policy fields are consumed and omitted fields have fallback handling in both writers. The known selected=2 older-FE minimum-policy residual remains as described above. No storage format is changed.
Thrift/protobuf IDs No definition or field ID is changed; release-branch ID comparison is not applicable.
Parallel paths Both initial plan builders, create/replace-partition RPCs, cloud overloads, changelog colocation, legacy and V2 writers were inspected. The new P1 is specific to legacy bootstrap-only bookkeeping.
Special conditions Insufficient-selection checks and cloud bypass have concrete explanations. The tablet-0 exclusion bypasses explicit nonlocal error handling, as documented in the inline finding.
Test coverage FE tests cover metadata/load separation, cloud preservation and dynamic empty rejection. BE tests cover policy arithmetic, bootstrap and local pooled policy; the regression covers mixed-partition selected-target failures. They omit an empty-input final sender, foreign-source policy ownership and the older-FE selected=2 case.
Test results No expected-result artifact is added or modified. No execution result or passing test is claimed.
Observability New selection/policy errors include relevant tablet, partition, backend or load identifiers. No separate logging/metrics defect was established; the P1 silently discards an error before it becomes failure status.
Transaction, persistence and failover No EditLog format or transaction state transition changes. FE still derives involved partitions from successful commit infos, which makes the discarded final error capable of omitting a whole partition. Existing replay metadata behavior is preserved.
Writes, atomicity and crashes Ordinary selected-target failure budgets are corrected in both writers, and the original callback assertion crash is removed. The new P1 can still report partial data as a successful transaction. No additional crash/leak was substantiated.
FE-BE propagation Both initial senders and both dynamic RPCs populate existing total/required fields; both consumers were traced. V2 policy is registered before stream opening. Known cross-source ownership limits are described above.
Performance and memory Added policy state is linear in tablets and replica-gap entries, with bounded replica-set copies and no new unbounded lifetime. No new hub-header include, PCH/template/unity change or libc API was introduced.
Other issues and user focus No additional user focus was supplied. Final missed-issue checks included empty-input startup, both EOS stages, sender counts, actual fault strings, cached locations, decommission watermarks and version gaps. No other new verified finding remains.

Verification limits: this was static inspection only; compilation, runtime fault reproduction and test execution remain unverified. Known issues above have explicit duplicate dispositions and are distinct from unresolved review evidence.

Review converged after 2 round(s).

if (tablet.tablet_id != V1_DUMMY_TABLET_ID) [[likely]] {
// Tablet 0 only bootstraps an empty automatic table. It receives no rows and must
// not consume the real tablets' failure allowance before partitions are created.
_tablets_by_channel[replica_node_id].insert(tablet.tablet_id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Preserve real tablet errors for bootstrap-only senders

In a parallel legacy load into an empty automatic table, W2 can open only tablet 0 on BE1 while W1 creates and writes real partitions. With replication=3 and min_load_replica_num=1, let A have only BE1 selected because its other two replicas are load-disabled, and let B have healthy destinations elsewhere. Excluding tablet 0 here leaves W2 without any _tablets_by_channel[BE1] entry. If W1 sends EOS first and W2 closes BE1 last, TabletsChannel::close() returns A's late rowset-build/delete-bitmap/commit error only to W2. Its mark_as_failed() returns at the missing-backend lookup before reaching the new nonlocal-tablet guard. Neither writer reports A's failure or an A commit info, while B's commit infos let FE skip A entirely; the load can succeed with all A rows lost. Retain backend bookkeeping while excluding the dummy tablet from failure budgets, or handle explicit tablet errors before that early return, and cover an empty-input final sender in a mixed-partition regression. Unlike thread 4370332388's sender with real-tablet bookkeeping, this new dummy-only branch silently discards the error instead of rejecting the load.

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