Skip to content

[refactor](udf) Isolate Python process pools by function id - #69255

Open
linrrzqqq wants to merge 5 commits into
apache:masterfrom
linrrzqqq:pyudf-process-pool
Open

linrrzqqq wants to merge 5 commits into
apache:masterfrom
linrrzqqq:pyudf-process-pool

Conversation

@linrrzqqq

@linrrzqqq linrrzqqq commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: None

Problem Summary:

Refactor Python UDF process scheduling to maintain an independent process pool for each function id, simplifying process allocation, package isolation and lifecycle management for Python UDF, UDAF and UDTF.

As part of the refactoring, add two function properties:

  • pool_size: maximum number of Python processes per function on each BE, defaulting to 3.
  • auto_suspend: idle timeout in seconds, defaulting to -1 to keep pools resident. Nonnegative values allow idle pools to be terminated during the 30-second monitor scan and recreated on the next invocation.

Both properties are persisted in function metadata and currently supported only for Python functions.

Adapt cleanup to the new pool ownership:

  • DROP FUNCTION releases the corresponding pool while existing clients retain the processes and package files they still use.
  • Processes retained by active clients remain included in memory accounting.
  • Permanently removed databases trigger cleanup of their Python function pools.
  • Deleted function ids cannot recreate package-cache entries that could delete files still used by active queries.

Release note

Python functions use independent process pools. The pool_size and auto_suspend properties control pool capacity and idle reclamation.

Check List (For Author)

  • Test: Full BE/FE build; 83 BE unit tests; 46 FE unit tests; clang-tidy and header hygiene; cluster startup and basic query verification. Python regression suites were exercised during implementation.
  • Behavior changed: Yes, Python process allocation and lifecycle management are scoped by function id, with configurable pool size and idle reclamation.
  • Does this need documentation: Yes, English and Chinese documentation changes are prepared separately in doris-website.

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

@linrrzqqq

Copy link
Copy Markdown
Collaborator 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.

Reviewed all 58 changed paths at b94dd43a8bdd9c7b85306bb23e88a4c807241af0. Three P2 defects are reported inline: dropped generations can be recreated by late queries (F1), native import can resolve a supplied UDF entry point to a preloaded server module (F2), and temporary backend outages permanently lose database cleanup notifications (F3). No P0/P1 finding was identified. There were no existing inline threads to duplicate or carry as blockers, and no additional user-provided focus points.

Required critical checkpoint conclusions:

  1. Goal and proof: Per-function capacity and idle suspension are wired through FE metadata and all three BE function types. Retirement and import compatibility still have the defects above. Added unit/regression sources cover the intended behavior; their execution was not verified in this review.
  2. Scope and reuse: Changes are focused on Python process/package ownership, settings, and cleanup. Shared metadata copies, Thrift conversion, pool management, and client leases provide the common mechanisms.
  3. Concurrency and locks: Foreground opens, detached initialization/coordinator/repair workers, the monitor, and cleanup tasks were traced. Map -> pool -> process-registry locking has no new reverse acquisition found. Fork, process termination, and cleanup submission run outside metadata/pool locks where required. F1 concerns acquisition after retirement rather than an ordinary lock inversion.
  4. Lifecycle and static initialization: Leases protect initialization and active clients; process/package ownership and weak RSS registry avoid cycles. No new cross-translation-unit static initialization dependency was found. F1 and F3 leave dropped generations alive; F1 can also invalidate a later package owner.
  5. Configuration: pool_size defaults to 3 and must be positive; any negative auto_suspend disables suspension, with default -1. These are persisted CREATE properties, not mutable BE settings. Nonnegative timeouts are checked by the 30-second monitor. Removal of max_python_process_num is reflected in all changed pipeline configurations.
  6. Compatibility: Missing Thrift fields use explicit BE defaults 3/-1, and legacy JSON uses initialized metadata defaults. Return types, nullable behavior, and aggregate intermediate representations are unchanged. F2 is a demonstrated module-name compatibility regression. No release binary ABI audit was performed.
  7. Thrift/protobuf: Complete TFunction definitions were checked on HEAD and origin/branch-3.1, branch-4.0, branch-4.1, and branch-4.2. IDs 20/21 are unused on those branches; both additions are optional. No protobuf change.
  8. Parallel paths: Scalar UDF, aggregate UDAF, table UDTF, outer UDTF, global/database functions, expression copies, and catalog reconstruction retain the settings. Normal and outer UDTFs receive distinct IDs. All three BE open paths pin module packages and acquire clients.
  9. Conditional/error handling: Parsing, nonpositive capacity, shutdown, stopped-pool, and empty-cleanup branches have concrete failure/lifecycle reasons. Existing client errors release leases after cleanup. No additional ignored Status or exception-boundary regression was found. Module binding publishes its root and identity under one lock.
  10. Test coverage: New source covers defaults/explicit properties, integer errors/overflow, Java rejection, copies/JSON/Thrift, database recovery/erase modes, independent pools, active RSS, shutdown, and idle lease behavior. The late-retirement, preloaded-module-name, and unavailable-backend cases behind the findings are missing.
  11. Expected results: Scalar 11/12/13, UDAF sum 6, outer-UDTF NULL, and native-cache value 1107/12 rows match their definitions statically. Both new zip members match checked-in helper sources and old archive entries are preserved. Automatic generation of .out files was not independently established.
  12. Observability: Creation logs identify function/runtime/capacity; cleanup logs identify backend/function; RSS remains visible after DROP. The memory threshold only warns, so it cannot reclaim pools leaked by F1/F3. No additional demonstrated logging/metric defect was found.
  13. Persistence and failover: Fields have Gson annotations and survive shared copy/image/add-function replay paths. Recoverable database drops retain function generations. Cleanup runs after metadata removal; its notification has no retained retry/reconciliation, as discussed in F3.
  14. Writes and atomicity: No table-data, transaction-visibility, visible-version, rowset, or delete-bitmap path changes. Existing metadata logging and table-lock ordering remain. The reported failures concern query/module execution and resource retirement.
  15. FE-to-BE variables: The central scalar/aggregate converters, all Nereids Python reconstruction paths, and all three BE extraction sites propagate the new settings. Non-Python Thrift functions leave them unset; no separate sending path was found to omit them.
  16. Performance and memory: Pool capacity now scales with used function generations; the weak registry accounts for dropped-but-active processes. No additional verified hot-path regression was found. F1/F3 make this resource growth permanent for dropped generations.
  17. Additional issues: A final upstream/downstream and special-case sweep found no other substantiated defect beyond the three inline comments.

Validation and limits: no builds, Doris unit/regression tests, cluster startup, or source modifications were performed. An isolated review script extracted the actual base/head Python loader definitions: a supplied types.py entry point succeeds on the base and fails on this head. Distributed race schedules and backend outages were established from control flow, not exercised. Regression idle sleeps are shorter than the 30-second monitor interval, and the concurrent-import suite warms the module before concurrent calls; those suites do not independently prove restart or concurrent first import. These execution limits do not leave an undisposed review candidate or an uncovered changed path.

Review converged after 3 round(s).

Comment thread be/src/udf/python/python_server.cpp
Comment thread be/src/udf/python/python_server.py
Comment thread fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionUtil.java
@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

/review

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Static review of all 68 changed paths at 77973138307951d290ed94cb8cc86b4a30424d46. Two new P2 findings concern cleanup delivery for ordinary/global DROP FUNCTION and permanent database erasure across FE master failover. No new P0/P1 finding was verified.

Checkpoint conclusions:

  • Goal and proof: fixed per-function pools, persistent imports, package pins and idle policy are implemented across scalar UDF, UDAF and UDTF. Added unit/regression tests support the main flows; cleanup remains incomplete in the two new findings and the existing retirement/import threads.
  • Scope and reuse: changes are focused on this lifecycle refactor. The ordinary DROP path still needs the queued cleanup mechanism used by database erasure.
  • Concurrency: query, agent, monitor and detached fork/repair entrants were traced. Map-to-pool-to-registry locking is consistent; process shutdown and monitor join occur outside map/pool locks. FE cleanup submission occurs after metadata locks are released. No additional lock cycle was established.
  • Lifecycle and initialization: leases protect client initialization through stream/state cleanup; package handles pin lazy imports; weak registry entries retain visibility for RSS without owning processes. No new ownership cycle or cross-translation-unit initialization dependency found. Dropped-generation retirement remains incomplete in the existing thread.
  • Configuration: pool_size defaults to 3 and rejects nonpositive values; auto_suspend defaults to -1, with negative values disabling suspension and nonnegative values observed by the monitor. These are persisted CREATE properties rather than mutable BE settings. Removal of max_python_process_num is reflected in the changed pipeline configurations.
  • Compatibility: old JSON defaults, Function copies, expression copies and optional-field BE defaults were inspected. No new persisted storage-format incompatibility found; older BEs ignore the new optional tuning fields.
  • Thrift/protobuf: complete TFunction definitions were compared with branch-4.2, branch-4.1, branch-4.0 and branch-3.1 snapshots. IDs 20/21 are unused there and optional here; existing IDs retain their meanings. No protobuf change.
  • Parallel paths: scalar/aggregate/table normal and outer functions, local/global registration and DROP, inline/module loading, and common cloud/shared-nothing execution paths were traced. The ordinary/global cleanup omission is one new finding.
  • Conditions and errors: startup/STOPPED/idle checks and cleanup error acknowledgements have concrete scenarios; failed task acknowledgements remain queued and success removes only the acknowledged generation. No additional silent-error regression verified.
  • Test coverage: inspected BE lifecycle/cache/ack tests, FE validation/copy/serialization/recycle/retry tests, and Python regression suites. Ordinary/global DROP outage and pending-cleanup master failover are missing failure cases. Existing late-retirement and preloaded-module collisions also lack coverage.
  • Expected results: all seven new output files match the inspected query/package semantics and ordering. The changed ZIP adds only the two native-cache helpers, byte-identical to their loose sources; prior entries are unchanged. Output-generation provenance was not verified.
  • Observability: pool initialization, process errors/exits and cleanup logs include useful runtime/function/backend context; existing task proc output exposes queued and failed cleanups, and the process registry retains RSS accounting for active dropped clients. No separate observability defect verified.
  • Persistence and failover: new properties flow through existing Function image/journal/replay mechanisms. Pending cleanup after permanent database erasure is only process-local, producing the second new finding.
  • Data writes and crashes: no database data-write, visible-version, delete-bitmap or transaction protocol changes. Process failure/reaping and asynchronous cache deletion paths were inspected; retained pool resources are the identified crash/failover consequence.
  • FE-BE propagation: both thrift converters, all three Python expression families and their copy paths, and scalar/UDAF/UDTF BE consumers carry both settings with matching defaults; shared expression serialization covers constant/point uses.
  • Performance and memory: fixed pools and native imports remove shared-runtime interference and repeated import eviction. Notification work scales with backends times functions; RSS accounting includes active retained processes. The verified cleanup gaps can accumulate persistent pools. No additional concrete hot-path regression found.
  • Other checks: touched code preserves function type/nullability and aggregate intermediate semantics; changed headers introduce no PCH, unity-skip or explicit-instantiation-family change requiring a separate finding.

Existing context: late-query retirement still applies before the first pool and after STOPPED reclamation; preloaded module collision also remains. Both are existing P2 findings and were not reposted. The original database cleanup during a backend outage is fixed for same-master recovery by queueing, resend and acknowledgement; the new failover finding concerns a separate persistence boundary. No existing P0/P1 comment applies, so the blocking-ID list is empty.

No additional user focus was supplied. Static analysis only: no builds, tests, cluster execution or source changes. Runtime behavior, compile/link artifacts and generated-output provenance were not verified. No unresolved static candidate or changed-path coverage gap remains after the final sweep. Review converged in two rounds.

Review converged after 2 round(s).

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17393	5190	5066	5066
q2	2080	311	261	261
q3	10158	1386	839	839
q4	4674	459	334	334
q5	7437	805	535	535
q6	183	188	157	157
q7	764	791	598	598
q8	9278	1361	1184	1184
q9	5504	4217	4193	4193
q10	6831	1334	1027	1027
q11	471	247	232	232
q12	637	404	277	277
q13	18124	3556	3027	3027
q14	286	279	246	246
q15	q16	734	720	647	647
q17	1223	777	601	601
q18	7635	6181	6122	6122
q19	1116	969	642	642
q20	409	340	228	228
q21	5502	2465	2475	2465
q22	402	329	265	265
Total cold run time: 100841 ms
Total hot run time: 28946 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6022	5886	6163	5886
q2	735	611	612	611
q3	5563	5714	5313	5313
q4	2039	2146	1541	1541
q5	5789	5869	5695	5695
q6	238	184	142	142
q7	2237	2029	1822	1822
q8	3180	2631	2621	2621
q9	8009	7922	7491	7491
q10	3635	3612	3143	3143
q11	569	404	379	379
q12	672	663	539	539
q13	3248	3585	3065	3065
q14	290	299	256	256
q15	q16	668	694	604	604
q17	7694	7148	6891	6891
q18	12963	12211	12810	12211
q19	935	814	805	805
q20	2149	2139	1912	1912
q21	5542	4547	4706	4547
q22	499	445	443	443
Total cold run time: 72676 ms
Total hot run time: 65917 ms

@hello-stephen

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

query5	4335	576	438	438
query6	427	206	189	189
query7	4818	452	222	222
query8	321	169	151	151
query9	8782	3041	3070	3041
query10	475	298	259	259
query11	5988	4039	3557	3557
query12	148	95	87	87
query13	1244	435	328	328
query14	6100	3880	3610	3610
query14_1	3406	3343	3409	3343
query15	211	196	179	179
query16	946	436	405	405
query17	854	678	541	541
query18	2413	433	313	313
query19	197	164	134	134
query20	88	84	83	83
query21	213	125	106	106
query22	12830	12965	12818	12818
query23	13525	12752	12506	12506
query23_1	12574	12529	12584	12529
query24	7417	825	471	471
query24_1	477	487	478	478
query25	529	411	369	369
query26	1262	259	137	137
query27	2767	436	268	268
query28	4679	1940	1927	1927
query29	1541	600	452	452
query30	307	217	182	182
query31	1018	951	809	809
query32	135	95	92	92
query33	526	308	245	245
query34	996	844	500	500
query35	734	749	642	642
query36	810	795	783	783
query37	123	104	87	87
query38	1799	1706	1631	1631
query39	784	792	741	741
query39_1	726	730	730	730
query40	222	118	99	99
query41	71	69	68	68
query42	93	84	85	84
query43	341	399	314	314
query44	1310	689	685	685
query45	183	174	176	174
query46	834	962	567	567
query47	2913	2925	2915	2915
query48	313	319	222	222
query49	617	396	301	301
query50	688	274	202	202
query51	10664	10241	10104	10104
query52	83	77	70	70
query53	185	206	151	151
query54	239	191	182	182
query55	76	65	63	63
query56	237	210	210	210
query57	1651	1604	1585	1585
query58	284	261	254	254
query59	2177	2186	1983	1983
query60	271	245	219	219
query61	141	145	145	145
query62	385	329	278	278
query63	185	159	153	153
query64	2778	944	742	742
query65	3295	3243	3264	3243
query66	1767	429	296	296
query67	20327	20350	20213	20213
query68	3275	999	603	603
query69	396	275	257	257
query70	831	769	770	769
query71	295	236	255	236
query72	2861	2645	2385	2385
query73	525	516	284	284
query74	4617	4469	4318	4318
query75	2349	2259	1910	1910
query76	2400	1015	579	579
query77	355	394	284	284
query78	10089	9769	9180	9180
query79	965	840	509	509
query80	1218	437	356	356
query81	592	321	270	270
query82	610	135	103	103
query83	300	211	175	175
query84	317	127	106	106
query85	886	434	388	388
query86	402	254	224	224
query87	1979	1941	1780	1780
query88	3711	2667	2642	2642
query89	333	277	245	245
query90	1917	166	163	163
query91	161	153	125	125
query92	100	89	80	80
query93	1063	1008	571	571
query94	655	302	268	268
query95	553	336	359	336
query96	668	494	233	233
query97	2448	2450	2347	2347
query98	166	151	149	149
query99	772	767	654	654
Total cold run time: 236393 ms
Total hot run time: 150803 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.09	0.05	0.05
query3	0.26	0.09	0.09
query4	1.61	0.10	0.10
query5	0.22	0.24	0.23
query6	1.16	0.67	0.68
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.41	0.35	0.35
query10	0.57	0.57	0.57
query11	0.21	0.15	0.15
query12	0.19	0.16	0.15
query13	0.48	0.49	0.48
query14	1.02	1.00	1.01
query15	0.64	0.61	0.61
query16	0.35	0.35	0.31
query17	1.08	1.14	1.15
query18	0.20	0.18	0.20
query19	2.02	1.93	1.99
query20	0.02	0.01	0.01
query21	15.48	0.20	0.13
query22	4.87	0.05	0.06
query23	16.30	0.31	0.12
query24	2.83	0.62	0.42
query25	0.10	0.05	0.08
query26	1.45	0.20	0.15
query27	0.04	0.04	0.03
query28	3.49	0.77	0.38
query29	12.49	4.15	3.27
query30	0.29	0.13	0.08
query31	2.77	0.57	0.32
query32	3.22	0.60	0.50
query33	3.17	3.21	3.29
query34	15.41	4.01	3.42
query35	3.34	3.31	3.35
query36	0.55	0.45	0.40
query37	0.09	0.07	0.06
query38	0.06	0.03	0.03
query39	0.03	0.03	0.03
query40	0.17	0.14	0.14
query41	0.08	0.04	0.03
query42	0.03	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.94 s
Total hot run time: 24.25 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 85.87% (79/92) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.57% (35494/46357)
Line Coverage 61.71% (399197/646885)
Region Coverage 58.26% (337382/579069)
Branch Coverage 59.12% (155719/263396)

@linrrzqqq

Copy link
Copy Markdown
Collaborator 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 PR #69255 at 241b1f1a712091824e5c05a7a8fdfd3ecbc3fc2c: no new distinct verified inline findings. This does not resolve the existing concerns below.

Existing-thread dispositions:

Critical checkpoint conclusions:

  1. Goal and evidence: per-function pools, capacity and idle timeout are wired through FE metadata, BE acquisition and the Python server. New unit/regression cases exercise these behaviors; the three existing limitations above prevent claiming complete lifecycle correctness.
  2. Scope and reuse: production changes remain focused on Python scheduling, ownership, metadata and cleanup. The shared cleanup helper also consistently serves local/global DROP; most regression edits opt into idle reclamation.
  3. Concurrency and locks: foreground clients, detached initialization/repair, the monitor and cleanup workers were traced. Map-to-pool locking and lease acquisition before initialization protect idle reclamation; process termination runs outside map/pool locks. No additional deadlock or active-client reclamation defect was verified.
  4. Lifecycle and static initialization: leases outlive stream cleanup, package handles pin files, detached workers retain pool/registry owners, and STOPPED blocks late publication. No new cross-translation-unit static initialization dependency was found. Retirement and failover gaps remain in the existing threads.
  5. Configuration: the global process-count setting is removed; pool_size and auto_suspend are persisted per-function properties. New generations acquire the configured values, and the 30-second monitor applies nonnegative idle timeouts. Negative timeouts retain pools; runtime ALTER support is not introduced.
  6. Compatibility: absent property defaults, function copies and serialization paths were checked. New BE readers default missing fields; old readers can ignore the optional additions. An old BE does not implement the new cleanup acknowledgement, so queued tasks can remain until it is upgraded; id-scoped cleanup is still executed.
  7. Shared definitions: TFunction was compared with live branch-3.1, branch-4.0, branch-4.1 and branch-4.2. IDs 20/21 are unused there, remain optional, and do not change existing field meanings.
  8. Parallel paths: scalar/UDAF/UDTF, generated outer functions, expression copies, both thrift converters, local/global DROP, force DROP DB and all three recycler erasure paths were checked. No additional propagation omission was verified.
  9. Conditional checks: positive pool-size validation, absent-field fallbacks, idle eligibility, stopped publication guards and acknowledgement conditions have concrete triggering cases. No additional incorrect branch was verified.
  10. Coverage: added BE/FE unit tests cover pool isolation, leases, reclamation, invalid properties, metadata copies, package lifetime and retry/acknowledgement. Regression cases cover SQL results, native/lazy imports and backend outage recovery. They do not prove master-failover durability or permanent retirement, and 2.5-second SQL sleeps alone do not guarantee a 30-second monitor pass; dedicated BE tests exercise termination.
  11. Results and artifacts: expected values were checked against suite inputs; the updated zip adds exactly the two new native-cache scripts, matching their source bytes while preserving original entries. Execution and result-file generation were not independently reproduced.
  12. Observability: function-id initialization/cleanup logs, process errors and aggregate RSS tracking remain available, including accepted initialization/repair processes after DROP. No separate observability defect was verified.
  13. Persistence and failover: Gson fields/defaults and journal/replay paths were inspected. Cleanup intent durability is still the existing failover finding; same-master retries now work through the agent queue.
  14. Data mutation and crashes: table-write, visibility/version and delete-bitmap protocols are unchanged. Metadata deletion and process cleanup are asynchronous; crash-related resource retention is covered by the existing durability concern.
  15. FE-to-BE variables: both properties pass through scalar, aggregate, table/outer, catalog-copy, Nereids-copy and thrift paths; all three BE consumers supply compatible defaults.
  16. Performance: pool size bounds each function's processes, selection favors the least-shared live process, and import caching avoids repeated module loading. Per-function resource growth and monitor scans follow the intended ownership model; no additional concrete hot-path regression was verified.
  17. Other concerns and focus: all 144 changed paths were covered. No additional user focus was supplied. No new unique verified issue remains outside the existing threads.

Validation was static only: no builds, tests, cluster execution or source modifications. Convergence concerns the completed review and deduplicated finding set; it does not mean the existing P2 issues are fixed.

Review converged after 1 round(s).

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17584	5201	5050	5050
q2	2126	314	260	260
q3	10158	1381	824	824
q4	4673	460	335	335
q5	7433	813	534	534
q6	181	184	152	152
q7	750	791	602	602
q8	9255	1342	986	986
q9	5547	4212	4173	4173
q10	6884	1297	1029	1029
q11	431	245	233	233
q12	651	403	272	272
q13	18135	3564	3009	3009
q14	274	269	241	241
q15	q16	730	719	664	664
q17	1210	762	574	574
q18	6968	6201	6144	6144
q19	1100	957	584	584
q20	381	338	231	231
q21	4908	2381	2522	2381
q22	360	340	288	288
Total cold run time: 99739 ms
Total hot run time: 28566 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5933	5850	5910	5850
q2	715	580	559	559
q3	5562	5718	5289	5289
q4	2028	2150	1561	1561
q5	6014	5750	5778	5750
q6	245	189	143	143
q7	2272	2034	1825	1825
q8	2973	2612	2444	2444
q9	7582	7513	7533	7513
q10	3636	3565	3123	3123
q11	587	413	384	384
q12	666	662	499	499
q13	3291	3476	3047	3047
q14	293	291	285	285
q15	q16	660	682	613	613
q17	7640	7025	6884	6884
q18	13046	12289	12816	12289
q19	895	773	778	773
q20	2144	2175	1912	1912
q21	5531	4563	4681	4563
q22	509	451	427	427
Total cold run time: 72222 ms
Total hot run time: 65733 ms

@hello-stephen

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

query5	4314	577	452	452
query6	428	218	194	194
query7	4813	448	230	230
query8	320	170	152	152
query9	8763	3088	3067	3067
query10	471	304	257	257
query11	5886	3829	3577	3577
query12	152	93	87	87
query13	1244	428	320	320
query14	6065	3903	3637	3637
query14_1	3434	3416	3395	3395
query15	212	202	182	182
query16	940	447	401	401
query17	859	653	566	566
query18	2411	409	296	296
query19	189	156	130	130
query20	83	86	79	79
query21	207	122	104	104
query22	12922	12984	12765	12765
query23	13575	12901	12385	12385
query23_1	12603	12489	12466	12466
query24	7338	802	450	450
query24_1	466	466	456	456
query25	510	398	342	342
query26	1268	252	131	131
query27	2794	433	267	267
query28	4612	1923	1913	1913
query29	1532	586	436	436
query30	292	219	186	186
query31	1021	926	798	798
query32	132	86	90	86
query33	514	303	236	236
query34	891	842	490	490
query35	724	753	637	637
query36	835	812	731	731
query37	144	107	91	91
query38	1785	1720	1679	1679
query39	790	803	743	743
query39_1	742	724	741	724
query40	220	118	98	98
query41	67	64	64	64
query42	86	84	81	81
query43	343	364	311	311
query44	1290	672	697	672
query45	184	180	160	160
query46	832	963	555	555
query47	3015	2903	2754	2754
query48	308	313	225	225
query49	571	410	298	298
query50	668	286	210	210
query51	10506	10714	10607	10607
query52	82	79	73	73
query53	181	217	151	151
query54	243	226	199	199
query55	75	69	66	66
query56	255	244	231	231
query57	1662	1634	1558	1558
query58	294	277	264	264
query59	2127	2180	1946	1946
query60	329	243	224	224
query61	165	171	139	139
query62	383	342	291	291
query63	187	153	165	153
query64	2744	952	766	766
query65	3298	3246	3273	3246
query66	1776	417	316	316
query67	20129	20262	19947	19947
query68	2907	994	601	601
query69	378	286	254	254
query70	881	776	774	774
query71	305	240	217	217
query72	2762	2633	2315	2315
query73	533	529	288	288
query74	4636	4493	4339	4339
query75	2336	2274	1915	1915
query76	2319	1010	568	568
query77	341	375	269	269
query78	9717	9742	9144	9144
query79	865	821	512	512
query80	514	417	339	339
query81	520	318	270	270
query82	200	131	105	105
query83	197	199	186	186
query84	286	127	104	104
query85	755	421	374	374
query86	252	240	228	228
query87	1980	1978	1806	1806
query88	3581	2670	2619	2619
query89	311	282	254	254
query90	2123	172	162	162
query91	155	155	127	127
query92	100	87	88	87
query93	977	984	577	577
query94	456	315	278	278
query95	575	414	320	320
query96	660	489	233	233
query97	2440	2420	2317	2317
query98	155	155	150	150
query99	755	758	664	664
Total cold run time: 232872 ms
Total hot run time: 150511 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.13	0.09	0.08
query3	0.35	0.14	0.13
query4	1.60	0.13	0.13
query5	0.30	0.27	0.27
query6	1.15	0.69	0.67
query7	0.04	0.00	0.01
query8	0.10	0.08	0.08
query9	0.47	0.38	0.38
query10	0.61	0.64	0.62
query11	0.32	0.18	0.18
query12	0.31	0.19	0.18
query13	0.51	0.53	0.53
query14	0.94	0.94	0.92
query15	0.66	0.58	0.58
query16	0.37	0.38	0.39
query17	1.07	1.04	1.00
query18	0.32	0.29	0.28
query19	2.04	1.88	1.89
query20	0.02	0.01	0.01
query21	15.39	0.34	0.30
query22	4.90	0.13	0.13
query23	15.86	0.49	0.30
query24	2.23	0.52	0.39
query25	0.15	0.10	0.10
query26	0.76	0.26	0.21
query27	0.10	0.09	0.10
query28	3.39	0.86	0.41
query29	12.62	4.47	3.48
query30	0.36	0.17	0.14
query31	2.76	0.61	0.37
query32	3.24	0.62	0.51
query33	3.07	3.04	3.11
query34	15.96	4.08	3.48
query35	3.42	3.39	3.39
query36	0.58	0.50	0.47
query37	0.12	0.10	0.09
query38	0.08	0.06	0.07
query39	0.06	0.06	0.06
query40	0.19	0.17	0.17
query41	0.11	0.05	0.04
query42	0.05	0.06	0.06
query43	0.07	0.06	0.06
Total cold run time: 96.79 s
Total hot run time: 25.65 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 5.16% (71/1375) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.01% (35794/46477)
Line Coverage 62.28% (403803/648366)
Region Coverage 58.71% (340585/580098)
Branch Coverage 59.67% (157617/264151)

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 98.96% (95/96) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.04	0.05
query3	0.26	0.08	0.09
query4	1.61	0.10	0.10
query5	0.23	0.25	0.24
query6	1.17	0.68	0.69
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.39	0.36	0.33
query10	0.57	0.59	0.58
query11	0.21	0.14	0.15
query12	0.19	0.16	0.15
query13	0.50	0.51	0.49
query14	1.04	1.02	1.02
query15	0.66	0.64	0.59
query16	0.34	0.35	0.36
query17	1.11	1.12	1.12
query18	0.20	0.19	0.18
query19	2.02	2.01	2.03
query20	0.02	0.02	0.01
query21	15.49	0.21	0.14
query22	4.89	0.06	0.05
query23	16.24	0.32	0.13
query24	2.96	0.82	0.41
query25	0.11	0.06	0.06
query26	1.27	0.22	0.16
query27	0.05	0.03	0.06
query28	3.17	0.80	0.38
query29	12.51	4.12	3.23
query30	0.29	0.12	0.09
query31	2.77	0.57	0.32
query32	3.22	0.59	0.50
query33	3.26	3.18	3.22
query34	15.46	4.01	3.42
query35	3.37	3.36	3.37
query36	0.56	0.44	0.42
query37	0.11	0.07	0.07
query38	0.04	0.04	0.03
query39	0.04	0.03	0.02
query40	0.17	0.15	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.85 s
Total hot run time: 24.4 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.20% (35866/46457)
Line Coverage 62.44% (404708/648135)
Region Coverage 58.89% (341608/580079)
Branch Coverage 59.88% (158141/264110)

@linrrzqqq

Copy link
Copy Markdown
Collaborator 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.

Reviewed all 150 changed paths at e83bfc03ce541b8c30e7842a91a8a81b2e3bf2a1 using static analysis, including the scalar/UDAF/UDTF execution paths, FE metadata and cleanup, release-branch protocol definitions, tests, expected results, configuration changes, and packaged Python helpers. No additional distinct finding was substantiated. Three existing P2 concerns still apply and should be addressed; they are not reposted inline.

Existing review context:

Critical checkpoint conclusions:

Checkpoint Conclusion
Goal and evidence Independent function-ID pools and the two properties are implemented throughout the three function types. Unit/regression coverage supports the intended behavior at source level; the existing retirement, import, and failover concerns qualify completion of that behavior.
Scope and clarity Source changes form a cohesive lifecycle refactor; most regression edits only set pool capacity and idle suspension. Shared lease, registry, and cleanup helpers have distinct responsibilities.
Concurrency and lock cost Traced query, cleanup, monitor, detached initialization/repair, and Flight threads. Manager map precedes pool locking; registry snapshots do not invert that order. Fork, RPC/client construction, RSS reads, and retired-process shutdown occur outside pool/map locks. No additional lock inversion was found.
Ownership and static initialization Leases cover client initialization through stream cleanup, including error exits; pool/process handles pin package files. Detached workers retain pool/registry ownership and reject STOPPED publication. Weak registry entries account for dropped active processes without an ownership cycle. No new cross-translation-unit static dependency was found. The remaining retirement hole is the existing thread above.
Configuration Removed max_python_process_num consistently. Function properties persist defaults of 3/-1; positive pool-size validation and negative/zero/positive suspension behavior are consistent across paths. No new mutable BE configuration was added.
Compatibility New BE paths supply defaults for absent fields; FE constructors, copies, Gson metadata, expression copies, SQL display, and conversion routes preserve both properties. Older BEs perform cleanup but lack the new acknowledgement: task bookkeeping remains pending until BE upgrade/restart permits report-driven retry to the new callback. No distinct execution regression was substantiated from that rollout limit.
Thrift/protobuf Read complete TFunction definitions on HEAD and current remote-matching branches 3.1, 4.0, 4.1, and 4.2. IDs 20/21 are unused there, optional here, and do not reuse another meaning. No protobuf change.
Parallel paths Checked scalar/UDAF/UDTF and outer variants, local/global function drops, force/expired/same-name/instant database erasure, recoverable database retention, and cloud/shared-nothing backend enumeration.
Conditions and error handling New lifecycle branches explain their concrete triggering cases. Cleanup status/acknowledgement and lease-release paths were traced; existing best-effort Java cleanup behavior is retained. No additional unhandled failure path was substantiated.
Test breadth and negative cases Inspected invalid property values, metadata copies/serialization, retry/acknowledgement failures, pool isolation, initialization/repair, leases, idle duration, RSS, DROP, and package tests. The retirement tests do not attempt acquisition after reclamation; the native-cache concurrency test warms its module first. These qualify test evidence for the already-known concerns.
Changed expected results All seven new result files were checked against their query inputs and inline/packaged implementations. ZIP changes add the matching two helpers without changing existing entries. Test execution and generated-file provenance were not verified.
Observability Pool creation/cleanup includes generation identifiers; existing runtime/PID failure logs, task status/reporting, and RSS warnings cover the changed lifecycle. No separate new metrics requirement was established.
Persistence and failover Both properties use serialized metadata fields. Recoverable databases retain their function generations. Permanent erasure cleanup still has the existing journal/replay durability gap described above. No data transaction protocol is changed.
Data writes and crash behavior No rowset/version/delete-bitmap or transaction atomicity change. Process/package cleanup crash and failover behavior was reviewed; remaining issues are covered by the existing threads.
FE-to-BE transmission Both converter overloads and all three expression/catalog/BE entry paths preserve pool size and suspension, including copied expressions and UDTF outer functions.
Performance Fixed per-function capacity, least-shared live-process selection, retained native imports, and weak child accounting match the intended design. No additional demonstrated performance defect was found.
Other module requirements No new hub/PCH include, gate-table edit, explicit-instantiation family, source-including test, or suspect libc/TLS/link dependency was introduced. Final GLIBC 2.17 ELF compatibility was not validated.

There was no additional user-provided focus. Review convergence means the review investigation is complete; it does not mean the existing P2 bugs are fixed. No applicable existing P0/P1 finding was identified. Builds, tests, a live cluster, final binary ABI checks, and regression-output generation were not run under this static-only contract.

Review converged after 1 round(s).

@HappenLee

Copy link
Copy Markdown
Contributor

I think these two parameters need tighter resource bounds and a different default:

  1. pool_size: require a positive value and cap the effective pool size at the CPU core count of the executing BE. The current FE and BE checks already reject zero and negative values; please retain those checks. The missing part is the upper bound: pool_size = 10000 is currently accepted, and _start_pool_initialization() sizes the process vector and launches an initialization thread per slot, each attempting to start a Python process. A single function should not be able to attempt 10,000 Python processes on a BE. Enforce the CPU-based bound before allocation or process startup on each BE, including heterogeneous clusters, and make sure the default of 3 also respects that bound on smaller BEs. Please cover zero, negative values, the CPU-count boundary, and an excessive value such as 10000 in tests.

  2. auto_suspend: please use 4 hours (14400 seconds) as the default instead of -1. With pools now isolated per function, the current default keeps every initialized function's processes resident indefinitely after it becomes idle. Resource consumption therefore accumulates as more functions are used. Reclaiming a pool after 4 hours without active clients is a more reasonable default; the next invocation can recreate it. If disabling suspension is supported, it should require explicitly setting -1. Please keep this default consistent across function creation, catalog metadata, Thrift, and BE fallback paths, and cover the omitted-property behavior and idle reclamation/recreation in tests.

linrrzqqq added a commit to linrrzqqq/doris that referenced this pull request Oct 22, 2026
### What problem does this PR solve?

Related PR: apache#69255

Problem Summary: Per-function Python pools could allocate and start as many
processes as requested, and their default idle policy retained processes
indefinitely. Cap each pool at the executing backend's CPU core count before
allocating slots or starting processes, while retaining positive pool_size
validation. Set auto_suspend to 14400 seconds consistently across function
creation, catalog metadata, Thrift, and backend defaults. Require explicit -1
to disable idle reclamation and reject smaller values.

### Release note

Python function pools are capped by each backend's CPU core count and are
reclaimed after four hours without active clients by default. The next call
recreates the pool. Explicit auto_suspend=-1 disables idle reclamation.

### Check List (For Author)

- Test: Full build; 38 FE unit tests; 29 BE unit tests on both host and one-core
  configurations; four targeted regression suites; all 19 Python UDTF suites;
  verified pool_size=10000 starts exactly one Python server on a one-core BE;
  clang-format 16 and clang-tidy checks.
- Behavior changed: Yes, cap effective pool_size per backend and default
  auto_suspend to four hours; reject auto_suspend values below -1.
- Does this need documentation: Yes, English and Chinese development-version
  descriptions are updated in the separate doris-website working directory.
@linrrzqqq

Copy link
Copy Markdown
Collaborator 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 head 1118af03752ccfb9b7d5cc4d2746786cbd1b66b0, using the supplied aggregate diff and all 151 changed paths. Main review plus three independent reviewers completed one round; all three returned NO_NEW_VALUABLE_FINDINGS. Review converged. No additional verified inline finding beyond existing threads; no applicable existing P0/P1 finding.

Existing review dispositions:

Current defaults are pool_size=3, CPU-capped on BE, and auto_suspend=14400 seconds. The PR description and historical thread wording that call -1 the default are stale; explicit -1 still disables suspension. This also limits the indefinite-process-retention examples in existing threads to explicit -1; missing cleanup can still retain package-cache entries.

Critical checkpoint conclusions:

  1. Goal and proof: per-function isolation, size/idle properties, package ownership and cleanup retries are implemented across scalar UDF, UDAF and UDTF. Added unit/regression cases support these paths by inspection. Known lifecycle gaps remain as linked above.
  2. Scope and reuse: production changes stay focused on Python scheduling/lifecycle; the shared cleanup helper and existing metadata converters avoid separate implementations. Regression property updates consistently use small reclaimable pools.
  3. Concurrency: query/group creation, detached initialization/repair, monitor and cleanup worker interactions were traced. Map-before-pool lock order and shared repair guards are consistent; lease acquisition protects client initialization against reclamation. Fork and process shutdown are outside the map lock. FE submits cleanup after metadata locks release.
  4. Lifecycle/static initialization: cache handles reach all three function forms, pools and accepted processes; streams/state/process references are cleaned before lease release. Detached workers retain pool/registry ownership and reject STOPPED publication; the weak process registry avoids ownership cycles and retains accounting visibility. No new cross-translation-unit initialization dependency found. Retired-ID protection remains the existing concern.
  5. Configuration: the global max_python_process_num setting is removed, including pipeline configurations. New function properties are immutable DDL metadata, validated for positive i32 capacity and i64 timeout >= -1; no dynamic ALTER behavior is introduced.
  6. Compatibility: old JSON and absent wire fields receive consistent defaults; copies and serialization preserve explicit values. Older peers ignore optional fields. Runtime mixed-version execution was not performed.
  7. Thrift/protobuf IDs: complete TFunction definitions on HEAD and origin/branch-3.1, branch-4.0, branch-4.1, branch-4.2 and master were compared. New IDs 20/21 are unused on those release branches, optional, and existing IDs retain their meanings. No protobuf change.
  8. Parallel paths: scalar/aggregate/table, inline/module, normal/outer UDTF, volatile/distinct expression copies, local/global DROP, force/expiry/same-name/instant database erase, recoverable database retention, constant folding and point serialization were traced. Cloud backend enumeration retains all compute-group coverage.
  9. Conditional/error handling: range checks, empty cleanup maps, STOPPED states and active-client/idle gates correspond to concrete invalid-input or lifecycle cases. Initialization/client failures release leases; failed cleanup acknowledgement retains retry intent. No additional distinct error-path defect established.
  10. Test coverage: inspected unit tests cover resource validation/defaults/copies, pool isolation, active leases, initialization failures, reclamation, memory accounting, lost acknowledgement and backend recovery. Regression additions cover idle settings/PID replacement, normal/outer forms, lazy/concurrent imports and cleanup retry. Failover/retired-ID gaps remain the existing findings.
  11. Expected results: all seven new output files were matched to their queries; deterministic arithmetic, null and aggregate results agree by inspection. The changed ZIP adds only the two matching native-cache helpers; its 22 existing members are byte-identical. Generated-result provenance was not independently established.
  12. Observability: function/backend IDs, existing task status/resend accounting, fork/repair failures and process RSS tracking cover the changed paths. No additional required metric omission established.
  13. Persistence/failover: new properties use existing Function image/EditLog serialization and replay. Pending cleanup intent remains in memory only, as the existing failover finding explains.
  14. Writes/atomicity/crashes: transaction visibility, rowsets and delete bitmaps are unchanged. Metadata locking/journaling and process failure transitions were inspected; no additional data-write or crash-consistency defect found.
  15. FE-BE variables: both new fields propagate through catalog constructors/copies, Nereids roundtrips and scalar/aggregate converters into all three BE consumers, with identical missing-field defaults.
  16. Performance: capacities are CPU-capped before allocation, imports reuse Python's module cache, and cleanup queues deduplicate generation IDs. Serial monitor repair can lengthen scans as function count grows; the repair mechanism preexists and no distinct new correctness failure or violated reclamation deadline was established.
  17. Other checks: unchanged null/Arrow semantics, header/include changes, template instantiations and new unit-test includes were inspected; no new static hygiene or glibc API dependency issue identified. Final missed-case sweep found no additional substantiated defect.

User focus: none was supplied. Coverage is complete for the supplied changed-path list; no unresolved new candidates or unreviewed paths remain. Validation is static only: no builds, tests, sanitizer runs, cluster execution or release-binary ABI inspection were performed. Convergence describes completion of this review, not resolution of the previously reported P2 issues.

Review converged after 1 round(s).

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17415	5238	5095	5095
q2	2149	298	256	256
q3	10215	1414	835	835
q4	4684	465	338	338
q5	7422	817	554	554
q6	181	186	158	158
q7	755	813	607	607
q8	9253	1340	1090	1090
q9	5573	4235	4244	4235
q10	6844	1294	1048	1048
q11	433	258	233	233
q12	645	410	287	287
q13	18129	3592	3046	3046
q14	268	277	239	239
q15	q16	732	713	688	688
q17	1210	767	576	576
q18	6960	6168	6114	6114
q19	1126	970	612	612
q20	397	351	229	229
q21	4887	2240	2420	2240
q22	353	297	254	254
Total cold run time: 99631 ms
Total hot run time: 28734 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5631	5602	5648	5602
q2	689	567	535	535
q3	5227	5400	4932	4932
q4	2012	2189	1595	1595
q5	5250	5179	5617	5179
q6	256	200	154	154
q7	2261	2084	1862	1862
q8	3051	2710	2705	2705
q9	8042	7952	7991	7952
q10	3755	3676	3468	3468
q11	626	459	449	449
q12	748	705	556	556
q13	3652	3787	3207	3207
q14	336	332	310	310
q15	q16	706	713	680	680
q17	8375	7280	6808	6808
q18	12988	12155	12919	12155
q19	946	832	843	832
q20	2179	2135	1942	1942
q21	5717	4679	4821	4679
q22	495	428	430	428
Total cold run time: 72942 ms
Total hot run time: 66030 ms

@hello-stephen

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

query5	4333	607	429	429
query6	431	205	190	190
query7	4800	446	225	225
query8	322	162	153	153
query9	8782	3080	3068	3068
query10	478	309	256	256
query11	5925	3873	3576	3576
query12	163	91	86	86
query13	1250	469	323	323
query14	6103	3924	3669	3669
query14_1	3423	3448	3437	3437
query15	215	195	191	191
query16	959	475	435	435
query17	855	655	540	540
query18	2424	426	314	314
query19	206	168	137	137
query20	86	84	84	84
query21	207	129	106	106
query22	12987	12968	12649	12649
query23	13412	12942	12473	12473
query23_1	12579	12612	12589	12589
query24	7272	855	473	473
query24_1	485	480	477	477
query25	538	420	368	368
query26	1275	260	141	141
query27	2763	438	273	273
query28	4584	1929	1915	1915
query29	1579	610	462	462
query30	301	221	180	180
query31	1012	928	824	824
query32	152	97	90	90
query33	533	305	245	245
query34	923	850	500	500
query35	731	750	647	647
query36	825	823	698	698
query37	121	98	85	85
query38	1762	1713	1650	1650
query39	803	787	747	747
query39_1	745	730	752	730
query40	221	122	98	98
query41	72	70	68	68
query42	88	81	83	81
query43	347	368	316	316
query44	1382	683	683	683
query45	177	179	167	167
query46	843	956	572	572
query47	3049	3068	2960	2960
query48	290	309	217	217
query49	568	396	291	291
query50	689	284	222	222
query51	10575	10390	10432	10390
query52	76	83	70	70
query53	191	213	152	152
query54	240	204	194	194
query55	71	69	68	68
query56	230	212	216	212
query57	1666	1613	1567	1567
query58	280	258	253	253
query59	2038	2134	1982	1982
query60	292	252	227	227
query61	155	146	146	146
query62	389	337	285	285
query63	185	163	158	158
query64	2738	987	748	748
query65	3339	3270	3244	3244
query66	1770	430	324	324
query67	20078	20235	19992	19992
query68	2945	1023	614	614
query69	381	302	250	250
query70	874	786	800	786
query71	301	223	202	202
query72	2764	2696	2257	2257
query73	531	549	296	296
query74	4636	4524	4346	4346
query75	2346	2294	1914	1914
query76	2272	1029	636	636
query77	362	388	284	284
query78	9775	9731	9121	9121
query79	1009	917	521	521
query80	700	418	347	347
query81	563	320	267	267
query82	559	132	103	103
query83	271	196	191	191
query84	317	115	107	107
query85	866	423	370	370
query86	355	236	230	230
query87	2028	1938	1803	1803
query88	3690	2660	2654	2654
query89	329	277	242	242
query90	1806	179	171	171
query91	165	148	129	129
query92	97	79	89	79
query93	1063	1029	577	577
query94	474	317	278	278
query95	598	389	298	298
query96	678	498	234	234
query97	2429	2430	2303	2303
query98	166	148	144	144
query99	782	760	650	650
Total cold run time: 234141 ms
Total hot run time: 150865 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.13	0.08	0.07
query3	0.34	0.13	0.14
query4	1.61	0.13	0.12
query5	0.26	0.25	0.24
query6	1.15	0.66	0.66
query7	0.04	0.01	0.01
query8	0.09	0.06	0.06
query9	0.45	0.36	0.37
query10	0.58	0.58	0.59
query11	0.32	0.19	0.19
query12	0.31	0.23	0.18
query13	0.52	0.53	0.52
query14	0.93	0.92	0.93
query15	0.66	0.57	0.58
query16	0.35	0.35	0.34
query17	1.04	1.02	1.05
query18	0.29	0.29	0.29
query19	1.98	1.90	1.81
query20	0.02	0.02	0.01
query21	15.39	0.35	0.30
query22	4.91	0.12	0.13
query23	15.87	0.48	0.29
query24	1.97	0.51	0.43
query25	0.15	0.11	0.10
query26	0.75	0.28	0.21
query27	0.11	0.10	0.10
query28	3.58	0.89	0.40
query29	12.61	4.45	3.40
query30	0.35	0.17	0.14
query31	2.76	0.61	0.34
query32	3.22	0.62	0.48
query33	2.99	3.00	2.96
query34	15.90	4.13	3.44
query35	3.38	3.38	3.37
query36	0.59	0.50	0.49
query37	0.11	0.10	0.09
query38	0.07	0.06	0.07
query39	0.06	0.06	0.06
query40	0.19	0.17	0.16
query41	0.10	0.06	0.05
query42	0.06	0.05	0.05
query43	0.06	0.06	0.06
Total cold run time: 96.26 s
Total hot run time: 25.18 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 98.98% (97/98) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: None

Problem Summary: Refactor Python UDF process scheduling to maintain an independent process pool for each function id. Each function owns a fixed-size pool, simplifying allocation, package isolation and lifecycle management for Python UDF, UDAF and UDTF.

As part of the refactoring, add two function properties: pool_size controls the maximum process count per function on each BE and defaults to 3; auto_suspend specifies the idle timeout in seconds and defaults to -1 to keep pools resident. The existing 30-second monitor terminates eligible idle pools and subsequent invocations recreate them. Active clients, including clients being initialized, prevent reclamation. The new properties are persisted in function metadata and rejected for Java functions.

Adapt DROP FUNCTION and permanent database removal to release the corresponding Python pools. Existing clients retain their processes and package files until release, and those processes remain included in memory accounting. Prevent deleted function ids from recreating package-cache entries that share files with active clients. Keep the existing one-shot cleanup notification behavior.

### Release note

Python functions use independent process pools. The pool_size and auto_suspend properties control pool capacity and idle reclamation.

### Check List (For Author)

- Test: Full BE/FE build; 83 BE unit tests; 46 FE unit tests; clang-tidy and header hygiene; cluster startup and basic query verification. Python regression suites were exercised during implementation.
- Behavior changed: Yes, Python process allocation and lifecycle management are scoped by function id, with configurable pool size and idle reclamation.
- Does this need documentation: Yes, English and Chinese documentation changes are prepared separately in doris-website.
### What problem does this PR solve?

Issue Number: N/A

Problem Summary: Keep dropped function pools STOPPED in the manager while existing
clients are alive, so a running UDAF cannot recreate the pool when it encounters
another GROUP BY key. Reclaim stopped pools in the 30-second health check after
the last client closes, regardless of auto_suspend. Document the distinction
between DROP cleanup and idle suspension, and cover UDF/UDAF/UDTF client rejection
and same-name function recreation.

### Release note

None

### Check List (For Author)

- Test: BE/FE build, 83 BE unit tests, 20 regression suites (including all 18
  pythonudtf_p0 suites), clang-tidy, formatting and header hygiene passed for the
  lifecycle changes. The final equivalent guard consolidation was checked for
  boolean equivalence and formatting/header hygiene without rerunning the full
  suite. BE UT compilation used temporary adaptations to three unrelated baseline
  Variant test files; those adaptations were restored.
- Behavior changed: Yes, DROP retains a STOPPED pool until the monitor observes
  no active clients and reclaims it.
- Does this need documentation: No
Queue local and global DROP FUNCTION cleanup for retry after backend recovery. Set auto_suspend=0 in ordinary Python regression cases to release idle processes.

Validation: full build, 17 FE unit tests, and 86 Python regression suites passed.
### What problem does this PR solve?

Related PR: apache#69255

Problem Summary: Per-function Python pools could allocate and start as many
processes as requested, and their default idle policy retained processes
indefinitely. Cap each pool at the executing backend's CPU core count before
allocating slots or starting processes, while retaining positive pool_size
validation. Set auto_suspend to 14400 seconds consistently across function
creation, catalog metadata, Thrift, and backend defaults. Require explicit -1
to disable idle reclamation and reject smaller values.

### Release note

Python function pools are capped by each backend's CPU core count and are
reclaimed after four hours without active clients by default. The next call
recreates the pool. Explicit auto_suspend=-1 disables idle reclamation.

### Check List (For Author)

- Test: Full build; 38 FE unit tests; 29 BE unit tests on both host and one-core
  configurations; four targeted regression suites; all 19 Python UDTF suites;
  verified pool_size=10000 starts exactly one Python server on a one-core BE;
  clang-format 16 and clang-tidy checks.
- Behavior changed: Yes, cap effective pool_size per backend and default
  auto_suspend to four hours; reject auto_suspend values below -1.
- Does this need documentation: Yes, English and Chinese development-version
  descriptions are updated in the separate doris-website working directory.
@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

/review

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Static review of eee46a1: one new P2 finding, a deterministic failure of multi-worker BE tests on a host/container with one effective CPU. No additional production defect was established beyond existing review threads. All 151 changed paths and their relevant callers, teardown, replay, and test paths were covered. No additional user-provided focus was specified.

Existing-thread disposition: module entrypoint collisions, late-query generation recreation/package deletion, and cleanup intent lost on FE failover still apply and are not reposted. Head now defaults auto_suspend to 14400 seconds; explicit -1 still permits indefinite retention in the relevant cleanup scenarios. The prior database retry and ordinary/global DROP retry gaps are addressed by queued generation-scoped tasks and acknowledgements. No existing P0/P1 finding was confirmed.

Critical checkpoint conclusions:

  1. Goal and evidence: function-id pools, native package caching, resource properties, and same-master cleanup retries are implemented with unit/regression coverage; remaining lifecycle/import concerns are the existing threads above.
  2. Scope and reuse: changes are coherent across FE metadata, BE ownership, and tests; FunctionUtil centralizes cleanup dispatch.
  3. Concurrency and locks: acquisition leases protect initialization/use/close; map-before-pool ordering is consistent, registry snapshots release their lock before further work, and fork/shutdown work occurs outside map locks. No additional deadlock or active-client reclamation issue was verified.
  4. Lifecycle and static initialization: shared handles pin packages/processes, weak registry entries avoid cycles, and STOPPED rejects new clients while retained. Permanent retirement remains incomplete as already reported; no new cross-TU initialization dependency was found.
  5. Configuration: pool_size and auto_suspend are per-function metadata, preserved through copies and persistence. The removed global process-count setting has no remaining source/config references. FE/BE defaults agree at 3/14400; PR prose describing -1 as the default is stale.
  6. Compatibility: optional-field fallbacks agree. Old BEs execute tracked cleanup but retain bookkeeping until their upgrade restart allows resend/acknowledgement; no distinct query correctness defect was established from this limitation.
  7. Thrift/protobuf: complete TFunction definitions were compared on HEAD and current branch-3.1/4.0/4.1/4.2 refs, verified against the remote. IDs 20/21 are unused across those branches and both additions are optional; no protobuf changes.
  8. Parallel paths: scalar/UDAF/UDTF and outer-function metadata, local/global DROP, force/expired/same-name/instant database erasure, and cloud/non-cloud backend enumeration were checked.
  9. Conditions and errors: invalid pool/timeout values are rejected; invalid cleanup IDs report failure; empty cleanup sets avoid signature fallback. Lease cleanup also runs after writer errors. No additional changed-path error-propagation defect was verified.
  10. Test coverage: property validation, copies, Gson/Thrift, idle/PID reclamation, package isolation, dropped-active memory, retries, lost acknowledgements, and ordinary/global DROP are represented. The new CPU cap is not reflected in every multi-worker unit-test expectation, as reported inline. Existing late-open/failover gaps remain tied to the existing findings.
  11. Test results: new golden outputs match their SQL and unchanged null/outer semantics on inspection. The ZIP adds exactly the two matching module-cache sources; existing members are unchanged. Execution and artifact-generation provenance were not verified.
  12. Observability: existing RSS tracking now includes retained processes; initialization/cleanup/retry logs include relevant identifiers and use existing task metrics. No additional required metric/log defect was established.
  13. Persistence and failover: function fields are serialized, copied, and replayed through existing metadata paths. Cleanup intent remains volatile across failover, as already reported.
  14. Data writes and crashes: transaction visibility, rowset versions, and delete bitmaps are unchanged. Crash-related cleanup retention is covered by the existing failover concern.
  15. FE-BE variables: both converters, all Python planner reconstruction/copy routes, and all three BE entry points carry/default the new properties consistently. Return/null/aggregate intermediate representations are unchanged.
  16. Performance: per-function process scaling is intentional and capped by effective CPUs; cleanup scales with removed generations and backends. No additional avoidable hot-path regression was substantiated.
  17. Final recheck and limits: candidate deduplication, package ownership, detached workers, locks, tests, and special paths received an additional pass. This review is static-only: no builds, tests, cluster runs, or source modifications were performed. Runtime behavior and final binary ABI remain unvalidated.

Review converged after 2 round(s).

auto first_pool = mgr.process_pool_snapshot_for_test(101);
auto second_pool = mgr.process_pool_snapshot_for_test(102);
ASSERT_EQ(first_pool.size(), 1);
ASSERT_EQ(second_pool.size(), 2);

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] Make multi-worker tests respect the CPU pool cap

On a one-CPU host or cgroup-limited runner, the new min(meta.pool_size, CpuInfo::num_cores()) creates only one process for second, so this unconditional size-2 assertion fails even though the pool behaves correctly. The adapted EnsurePoolInitializedSucceedsWithOneStuckWorkerAndOneUsableWorker also now launches only its deliberately stuck worker and fails initialization; the previous explicit global limit of 2 allowed both workers. Derive sizes/indexing from the effective pool size, and skip or control the CPU count for scenarios that require at least two workers.

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 78.02% (2080/2666)
Line Coverage 66.33% (38382/57868)
Region Coverage 53.71% (36015/67054)
Branch Coverage 57.25% (11608/20276)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 66.63% (32018/48054)
Line Coverage 51.43% (337814/656874)
Region Coverage 46.78% (273270/584139)
Branch Coverage 48.52% (128812/265491)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.22% (35953/46558)
Line Coverage 62.51% (406180/649832)
Region Coverage 58.93% (342976/582019)
Branch Coverage 59.92% (158696/264832)

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17591	5186	5079	5079
q2	2122	327	266	266
q3	10161	1424	848	848
q4	4676	463	338	338
q5	7442	807	532	532
q6	181	189	153	153
q7	749	803	624	624
q8	9271	1381	1130	1130
q9	5532	4245	4228	4228
q10	6879	1302	1036	1036
q11	442	251	230	230
q12	645	403	284	284
q13	18133	3625	3056	3056
q14	285	260	237	237
q15	q16	757	735	660	660
q17	1228	754	590	590
q18	7049	6181	6151	6151
q19	1161	977	628	628
q20	405	347	229	229
q21	5548	2216	2341	2216
q22	363	314	254	254
Total cold run time: 100620 ms
Total hot run time: 28769 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5655	5599	5632	5599
q2	675	566	526	526
q3	5240	5393	4940	4940
q4	2021	2169	1549	1549
q5	5279	5118	5832	5118
q6	255	189	155	155
q7	2318	2124	1835	1835
q8	3144	2878	2776	2776
q9	8085	8039	8217	8039
q10	3747	3664	3222	3222
q11	619	459	428	428
q12	714	688	527	527
q13	3599	3957	3203	3203
q14	309	320	288	288
q15	q16	728	715	659	659
q17	8418	7515	7455	7455
q18	13064	12212	12933	12212
q19	927	830	825	825
q20	2155	2143	1898	1898
q21	5878	4803	4901	4803
q22	512	461	405	405
Total cold run time: 73342 ms
Total hot run time: 66462 ms

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 80.61% (79/98) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

query5	4312	594	429	429
query6	430	210	198	198
query7	4808	447	229	229
query8	317	168	151	151
query9	8792	3132	3124	3124
query10	480	313	265	265
query11	5960	3860	3562	3562
query12	155	96	86	86
query13	1241	454	326	326
query14	6180	3923	3660	3660
query14_1	3419	3397	3450	3397
query15	206	206	181	181
query16	950	430	412	412
query17	882	668	545	545
query18	2417	427	310	310
query19	195	173	146	146
query20	87	88	84	84
query21	209	133	108	108
query22	12925	12948	12710	12710
query23	13642	12939	12668	12668
query23_1	12734	12628	12585	12585
query24	7369	827	485	485
query24_1	488	477	482	477
query25	548	429	378	378
query26	1269	273	151	151
query27	2756	438	274	274
query28	4636	1944	1982	1944
query29	1543	590	433	433
query30	301	218	181	181
query31	1005	921	802	802
query32	146	88	89	88
query33	528	290	232	232
query34	902	868	508	508
query35	751	742	638	638
query36	796	798	744	744
query37	120	99	83	83
query38	1780	1759	1660	1660
query39	798	790	752	752
query39_1	735	724	760	724
query40	217	115	94	94
query41	66	65	61	61
query42	82	84	79	79
query43	348	362	322	322
query44	1325	686	689	686
query45	172	175	162	162
query46	823	975	563	563
query47	2885	3052	2750	2750
query48	296	306	218	218
query49	569	400	291	291
query50	693	291	214	214
query51	10523	10237	10189	10189
query52	80	80	70	70
query53	184	210	162	162
query54	261	196	188	188
query55	71	69	64	64
query56	251	202	202	202
query57	1646	1608	1593	1593
query58	290	267	251	251
query59	2082	2156	1912	1912
query60	283	259	229	229
query61	150	146	149	146
query62	387	336	288	288
query63	187	161	157	157
query64	2719	935	782	782
query65	3331	3270	3280	3270
query66	1792	418	307	307
query67	20205	20095	19930	19930
query68	3288	1012	608	608
query69	402	291	257	257
query70	841	758	774	758
query71	307	233	207	207
query72	2780	2567	2350	2350
query73	545	544	301	301
query74	4624	4525	4324	4324
query75	2334	2296	1918	1918
query76	2415	1037	612	612
query77	356	381	280	280
query78	9860	9737	9211	9211
query79	1012	845	535	535
query80	586	461	368	368
query81	535	321	286	286
query82	579	140	109	109
query83	313	205	193	193
query84	364	120	98	98
query85	807	433	357	357
query86	329	236	228	228
query87	2017	1954	1796	1796
query88	3650	2682	2677	2677
query89	329	280	238	238
query90	1918	175	166	166
query91	166	150	122	122
query92	98	91	87	87
query93	1024	1024	577	577
query94	447	292	252	252
query95	579	399	307	307
query96	663	496	232	232
query97	2444	2450	2318	2318
query98	162	158	144	144
query99	773	764	635	635
Total cold run time: 235021 ms
Total hot run time: 150827 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.26	0.09	0.09
query4	1.60	0.10	0.09
query5	0.24	0.25	0.24
query6	1.17	0.68	0.68
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.40	0.34	0.34
query10	0.56	0.56	0.57
query11	0.20	0.14	0.14
query12	0.18	0.15	0.15
query13	0.49	0.50	0.49
query14	1.04	1.01	1.02
query15	0.65	0.61	0.60
query16	0.35	0.34	0.35
query17	1.10	1.12	1.14
query18	0.20	0.18	0.18
query19	2.08	2.02	1.99
query20	0.02	0.02	0.01
query21	15.48	0.20	0.13
query22	4.89	0.06	0.05
query23	16.27	0.32	0.12
query24	3.03	0.67	0.64
query25	0.12	0.07	0.04
query26	1.64	0.22	0.15
query27	0.04	0.05	0.03
query28	3.49	0.76	0.35
query29	12.46	4.07	3.23
query30	0.27	0.13	0.09
query31	2.77	0.54	0.32
query32	3.21	0.59	0.52
query33	3.13	3.22	3.19
query34	15.29	4.02	3.35
query35	3.34	3.32	3.36
query36	0.56	0.44	0.42
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 97.27 s
Total hot run time: 24.45 s

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants