Skip to content

[improvement](be) Remove per-term contention from SNII index build memory accounting - #70007

Merged
airborne12 merged 3 commits into
apache:masterfrom
airborne12:snii-build-contention
Nov 6, 2026
Merged

airborne12 merged 3 commits into
apache:masterfrom
airborne12:snii-build-contention

Conversation

@airborne12

@airborne12 airborne12 commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Related PR: #66052, #67657

Problem Summary: Stream load into a SNII table stops scaling once flush threads compete. On a log table with ten inverted indexes and mostly unique terms, SNII loaded at 314 MB/s against 854 MB/s for V2, with 3.0 times the CPU and 9.8 times the kernel CPU. The adaptive flush pool is on by default and allows up to 4 threads per core, so this is the normal case on a busy BE. With the pool fixed at 6 threads SNII was 23% slower than V2, and at 30 threads 60% slower.

Two process-wide hot spots cause it, and both are reached per term:

  1. SpimiTermBuffer::report_arena_delta() calls GlobalMemoryLimiter::report() whenever the resident total changes, which is once per new term. report() takes a process-wide mutex, looks the writer up and reads the memory signals. The limiter keeps only the arena size, which grows one 32 KiB block at a time, so nearly every call repeats the same number. At 30 threads the flush threads blocked about 476k times per second against 21k for V2, and every futex wait sampled was on one address. That was 13.6 cores of kernel CPU against 3.5.
  2. The Reservations that [improvement](index) Bound SNII posting workspace across spill and encoding #67657 added to the term encoders change several times per term, and each change updates two process-wide atomics through snii_build_consume_release(). That lambda took 54% of the user CPU of the flush threads.

Both scale with new terms and with threads, which is why duplicate data and a small pool look mild.

  • The limiter is now told only when the arena size changes, or when the resident total has moved by 1 MiB since its last decision. Nothing it stores is lost. The step catches capacity doublings that move the resident total by MiBs inside one arena block, and it is the step in which the decision's input moves anyway. On 2M tokens with 600k new terms a buffer now makes 321 decisions; before, every new term was one.
  • A reporter now holds its changes back from the two process-wide counters until they add up to 1 MiB, and publishes the remainder whenever its live bytes are back at zero, and when it is destroyed. One term swings tens of KiB plus a ZSTD context, so per-term reservations no longer reach the shared cache lines. The zero rule matters because a finished text writer's reporter is not destroyed with the writer: its IndexFileWriter keeps it until the rowset writer closes.

What this costs. The reporter itself stays exact, so per-writer budgets and spill thresholds do not change. The process-wide counters can lag each writer that is still building by less than 1 MiB:

  • SniiIndexBuild and snii_index_build_mem_consumption no longer show a writer that stays below 1 MiB while it builds. They are exact again as soon as a writer is empty, so a finished segment leaves nothing behind.
  • The forced-spill decision reads the sum, so it can start late by the lag of the writers still building: at most 1 GiB with 100 flush threads on a 10-index table, against a share of at least 4 * inverted_index_ram_buffer_size (2 GiB by default). A writer below 1 MiB could not be a victim anyway, since forced spills only pick arenas above snii_forced_spill_min_arena_bytes (64 MiB by default), and the process-level backstops read real memory.

The index bytes do not change.

Throughput, MB/s, default adaptive flush pool V2 SNII SNII vs V2 SNII CPU / V2 CPU
Log data, before 854 314 -62.9% 3.01
Log data, after 852 770 -7.7% 1.11
Short logs, before 997 389 -61.0% 2.84
Short logs, after 1003 865 -13.7% 1.20

Both binaries were built from master and alternated in one window, 4 rounds each with the order flipped, and the table shows medians. One BE pinned to 32 cores, local disk, stream load of JSON lines with 16 concurrent 100 MB batches. Log data is expanded from a real sample of service logs, where 1% of the rows carry base64 blobs and make up 68% of the bytes. Short logs leave those rows out. V2 is unchanged, as it should be, and kernel CPU falls from 516 s to 43 s on the log data.

An earlier prototype with the same two changes also held up with other shapes and pools: fixed 30 threads -59.6% to -8.7%, fixed 6 threads -23.1% to -14.8%, 1 GB batches -43.8% to -13.7%, and data with few unique terms -20.2% to -11.7%.

Forced spills were checked on a real load: with snii_index_build_max_memory_limit_percent = 1, snii_forced_spill_min_arena_bytes = 1 MiB, and 16 concurrent 1 GB batches, the spill directory held up to 224 files at once and the limiter logged its shortfall warning. It stayed empty with the default share. Eight MATCH, phrase and equality queries returned the same counts as V2 on the 11M rows, and the tracker went back to 0.

Release note

Improve load throughput of the SNII inverted index format on columns with many unique terms.

Check List (For Author)

  • Test: Unit Test (NewTermsThatKeepTheArenaStayOffTheLimiter: new terms inside one arena block never reach the limiter while the resident total moves; ResidentStepInsideOneArenaBlockReachesTheLimiter: a 1 MiB resident step inside one block is decided at that term; PressureIsDecidedWhenTheArenaNextGrows: pressure that arrives inside a block still ends in a forced spill; PerTermSwingsStayOffTheSharedCounters (both populations), AnEmptyReporterHoldsNothingBack: a retained reporter that is back at zero leaves nothing in the shared counters, HeldBackBytesArePublishedTogetherAtTheStep, DestroyingAReporterPublishesTheLastPartialStep, ConcurrentChangesOnOneReporterLoseNothing: the coalescing, its remainder and concurrent use; existing tracker tests that asserted exact visibility of a few KB now use changes of at least one step; eight mutants of the change each fail tests; 2248 SNII, BKD and inverted index tests pass under ASAN).
    Manual test: the A/B and the forced-spill load above.
  • Behavior changed: Yes. The SniiIndexBuild tracker and snii_index_build_mem_consumption lag each writer by less than 1 MiB, and the forced-spill decision can start late by that lag added up.
  • Does this need documentation: No

🤖 Generated with Claude Code

…mory accounting

### What problem does this PR solve?

Issue Number: None

Related PR: apache#66052, apache#67657

Problem Summary: Stream load into a SNII table stops scaling once flush threads compete.
On a log table with ten inverted indexes and mostly unique terms, SNII loaded at 314 MB/s
against 854 MB/s for V2, with 3.0 times the CPU and 9.8 times the kernel CPU.

Two process-wide hot spots cause it, and both are reached per term.

1. SpimiTermBuffer::report_arena_delta() calls GlobalMemoryLimiter::report() whenever the
   resident total changes, which is once per new term, and report() takes a process-wide
   mutex. The limiter keeps only the arena size, which grows one 32 KiB block at a time,
   so nearly every call repeats the same number. At 30 flush threads that was 476k
   voluntary context switches per second against 21k for V2, with every futex wait
   sampled on one address.
2. The Reservations that apache#67657 added to the term encoders change several times per
   term, and each change updates two process-wide atomics through
   snii_build_consume_release(). That lambda took 54% of the flush threads' user CPU.

The limiter is now told only when the arena size changes. Nothing it stores is lost, and
pressure is still re-decided whenever the arena grows. A reporter now holds its changes
back from the two process-wide counters until they add up to 1 MiB, and publishes the
remainder when it is destroyed.

The reporter stays exact, so per-writer budgets and spill thresholds do not change. The
process-wide counters can lag each live reporter by less than 1 MiB, so a writer that
stays below 1 MiB no longer shows on the SniiIndexBuild tracker, and the forced-spill
decision can start late by that lag added up. The index bytes do not change.

Results in the same window, 4 rounds each, medians, MB/s for V2 and SNII:

- Log data before: 854 and 314, 62.9% slower.
- Log data after: 852 and 770, 7.7% slower.
- Short logs before: 997 and 389, 61.0% slower.
- Short logs after: 1003 and 865, 13.7% slower.

### Release note

Improve load throughput of the SNII inverted index format on columns with many unique
terms.

### Check List (For Author)

- Test: Unit Test, Manual test
    - 2246 SNII, BKD and inverted index tests pass under ASAN. New tests cover both
      fixes, and five mutants of the change are each caught by them.
    - Fix and base binaries were compared in stream loads on one BE.
    - Forced spills on a real load under a low share, confirmed in the spill directory:
      eight queries return the same counts as V2 on 11M rows, and the tracker returns
      to 0.
- Behavior changed: Yes. The SniiIndexBuild tracker and its metric lag each writer by
  less than 1 MiB, and the forced-spill decision can start late by that lag added up.
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@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?

@airborne12

Copy link
Copy Markdown
Member Author

run buildall

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41566861508

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17588	5106	5014	5014
q2	2158	344	251	251
q3	10196	1387	819	819
q4	4684	471	335	335
q5	7435	794	530	530
q6	177	182	151	151
q7	749	834	611	611
q8	9260	1316	1104	1104
q9	5470	4167	4154	4154
q10	6818	1297	1054	1054
q11	437	245	229	229
q12	637	402	290	290
q13	18092	3683	3039	3039
q14	274	276	251	251
q15	q16	730	719	687	687
q17	1206	760	587	587
q18	6962	6192	6137	6137
q19	1117	993	589	589
q20	387	345	226	226
q21	5077	2514	2481	2481
q22	371	323	271	271
Total cold run time: 99825 ms
Total hot run time: 28810 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5967	5865	6038	5865
q2	729	636	568	568
q3	5718	5800	5326	5326
q4	2008	2131	1570	1570
q5	5738	5860	5692	5692
q6	236	190	143	143
q7	2248	2091	1813	1813
q8	2962	2614	2641	2614
q9	8098	7634	7598	7598
q10	3626	3584	3125	3125
q11	568	401	387	387
q12	667	653	500	500
q13	3329	3571	3098	3098
q14	285	288	255	255
q15	q16	661	673	616	616
q17	7720	7094	6917	6917
q18	12969	12255	12856	12255
q19	1032	783	780	780
q20	2126	2140	1911	1911
q21	5547	4580	4633	4580
q22	483	438	408	408
Total cold run time: 72717 ms
Total hot run time: 66021 ms

@hello-stephen

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

query5	4321	598	431	431
query6	432	208	187	187
query7	4798	446	226	226
query8	325	166	154	154
query9	8768	3175	3157	3157
query10	471	313	252	252
query11	5957	3882	3591	3591
query12	146	93	87	87
query13	1249	433	321	321
query14	6157	3929	3631	3631
query14_1	3473	3497	3477	3477
query15	203	202	182	182
query16	942	428	422	422
query17	871	678	514	514
query18	2406	406	291	291
query19	191	164	127	127
query20	84	83	79	79
query21	207	123	108	108
query22	13038	12921	12815	12815
query23	13549	12803	12448	12448
query23_1	12608	12587	12433	12433
query24	7349	821	477	477
query24_1	486	474	481	474
query25	508	399	340	340
query26	1260	255	140	140
query27	2780	439	270	270
query28	4619	2052	2044	2044
query29	1550	586	435	435
query30	309	230	183	183
query31	1028	942	813	813
query32	141	87	90	87
query33	520	294	236	236
query34	949	844	502	502
query35	742	759	648	648
query36	822	825	730	730
query37	121	97	78	78
query38	1772	1726	1661	1661
query39	794	793	745	745
query39_1	720	733	744	733
query40	212	116	94	94
query41	72	63	64	63
query42	86	86	84	84
query43	344	370	313	313
query44	1339	725	722	722
query45	185	191	168	168
query46	838	976	585	585
query47	2825	2809	2719	2719
query48	306	312	229	229
query49	587	408	297	297
query50	675	287	222	222
query51	10827	10475	10419	10419
query52	88	86	75	75
query53	188	205	155	155
query54	243	203	184	184
query55	73	68	64	64
query56	252	224	236	224
query57	1669	1642	1578	1578
query58	303	278	264	264
query59	2172	2195	2001	2001
query60	286	255	241	241
query61	186	147	145	145
query62	394	346	284	284
query63	184	155	159	155
query64	2745	933	760	760
query65	3352	3291	3270	3270
query66	1778	407	296	296
query67	20263	20477	20069	20069
query68	3025	999	622	622
query69	374	298	247	247
query70	869	765	777	765
query71	296	221	203	203
query72	2752	2633	2307	2307
query73	517	541	292	292
query74	4644	4482	4316	4316
query75	2333	2289	1910	1910
query76	2327	1024	589	589
query77	354	376	265	265
query78	9718	9795	9225	9225
query79	889	855	533	533
query80	494	421	350	350
query81	532	325	281	281
query82	200	127	107	107
query83	280	200	185	185
query84	302	121	103	103
query85	811	421	370	370
query86	264	240	231	231
query87	1973	1931	1788	1788
query88	3791	2774	2759	2759
query89	321	282	241	241
query90	2101	168	163	163
query91	166	151	133	133
query92	104	87	89	87
query93	1010	977	588	588
query94	453	318	273	273
query95	573	335	297	297
query96	689	496	243	243
query97	2476	2467	2353	2353
query98	157	150	148	148
query99	758	763	654	654
Total cold run time: 234489 ms
Total hot run time: 151219 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 27adda9f7133b97ed3c397163ae9fab155239d1b, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.04
query3	0.27	0.09	0.09
query4	1.61	0.10	0.11
query5	0.27	0.23	0.24
query6	1.17	0.69	0.68
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.41	0.36	0.35
query10	0.57	0.58	0.58
query11	0.20	0.14	0.13
query12	0.18	0.14	0.15
query13	0.51	0.50	0.49
query14	1.04	1.02	1.01
query15	0.64	0.61	0.64
query16	0.36	0.35	0.35
query17	1.14	1.14	1.11
query18	0.20	0.18	0.20
query19	2.07	1.95	1.97
query20	0.02	0.02	0.01
query21	15.52	0.21	0.13
query22	4.79	0.06	0.06
query23	16.26	0.32	0.13
query24	3.13	0.58	0.28
query25	0.11	0.06	0.06
query26	0.97	0.21	0.16
query27	0.06	0.04	0.05
query28	2.74	0.80	0.39
query29	12.52	4.28	3.30
query30	0.28	0.12	0.12
query31	2.78	0.57	0.33
query32	3.22	0.59	0.50
query33	3.16	3.13	3.18
query34	15.22	4.00	3.39
query35	3.34	3.35	3.36
query36	0.56	0.44	0.42
query37	0.09	0.06	0.06
query38	0.04	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.08	0.03	0.02
query42	0.04	0.03	0.03
query43	0.04	0.03	0.03
Total cold run time: 96.03 s
Total hot run time: 24.25 s

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed apache/doris PR #70007 at head 27adda9f7133b97ed3c397163ae9fab155239d1b against the supplied merge-base diff. The PR reduces per-term contention in SNII build accounting, and the tracker callback's atomic publication, registered/unregistered classification, destructor drain, writer ownership, registry locking, and changed test coverage were checked.

One blocking memory-control issue is reported inline: the new arena-only limiter report can leave a floor-sized eligible arena unflagged when process or other-writer pressure begins while resident vocabulary data grows without allocating another arena block. The local writer cap does not cover a writer below its own cap, so this can miss the process-wide backstop until an unrelated future arena growth.

Critical checkpoint conclusions: data/version/delete-bitmap and FE/BE protocol paths are not involved; no transaction or persistence changes are present; concurrent callback and limiter registry lifetimes were traced and are safe; error propagation and test registration were inspected; the changed tests cover partial-step draining, concurrent callbacks, limiter selection, and spill ownership. I inspected tests and did not execute builds or tests under the static-only review contract. No additional user-provided review focus was supplied.

The review converged after 2 rounds: every assigned reviewer returned NO_NEW_VALUABLE_FINDINGS in round 2, the accepted candidate was independently reverified, and all other risk points were dismissed with evidence.

Review converged after 2 round(s).

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 67.22% (32068/47703)
Line Coverage 52.04% (337049/647676)
Region Coverage 47.58% (274010/575915)
Branch Coverage 49.40% (129119/261355)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.64% (35869/46201)
Line Coverage 62.96% (403238/640420)
Region Coverage 59.50% (340966/573034)
Branch Coverage 60.67% (157959/260342)

…side one arena block

### What problem does this PR solve?

Issue Number: None

Related PR: apache#67657

Problem Summary: The first commit of this PR reports to the process-wide limiter only
when a buffer's arena grows. A capacity doubling moves the resident total by MiBs in one
token without touching the arena: the term slots doubling from 2^17 to 2^18 entries add
3.5 MiB. Before that commit such a token re-decided pressure at once; with the arena gate
alone it waited for the next 32 KiB block.

The limiter is now also told when the resident total has moved by kBuildBytesPublishStep
(1 MiB) since its last decision. That is the step in which the decision's input, the
registered build bytes, moves anyway. On 2M tokens of a buffer with 600k new terms this
adds 11 decisions to 310, and on 2M new terms 13 to 550; before the first commit every
new term was a decision.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ResidentStepInsideOneArenaBlockReachesTheLimiter finds a term whose resident step
      lands inside one arena block and checks that it is decided at that term; it fails
      without the new clause. 2247 SNII, BKD and inverted index tests pass under ASAN.
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@airborne12

Copy link
Copy Markdown
Member Author

run buildall

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41620749115

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17587	5244	5271	5244
q2	2127	355	272	272
q3	10186	1541	820	820
q4	4683	465	338	338
q5	7443	802	525	525
q6	180	182	157	157
q7	741	833	584	584
q8	9252	1368	1027	1027
q9	5461	4214	4179	4179
q10	6832	1311	1040	1040
q11	419	249	228	228
q12	638	402	278	278
q13	18075	3736	3080	3080
q14	268	273	241	241
q15	q16	729	728	670	670
q17	1201	759	592	592
q18	7054	6163	6159	6159
q19	1258	972	616	616
q20	389	337	222	222
q21	5743	2400	2527	2400
q22	395	343	270	270
Total cold run time: 100661 ms
Total hot run time: 28942 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5946	5906	6081	5906
q2	716	632	593	593
q3	5710	5776	5387	5387
q4	2080	2148	1586	1586
q5	5943	5606	5585	5585
q6	234	182	141	141
q7	2260	2012	1766	1766
q8	2953	2685	2628	2628
q9	7796	7488	7497	7488
q10	3639	3611	3118	3118
q11	570	401	397	397
q12	714	662	507	507
q13	3297	3619	3028	3028
q14	297	289	260	260
q15	q16	673	679	627	627
q17	7683	7012	6839	6839
q18	12938	12141	12870	12141
q19	887	797	786	786
q20	2135	2140	1917	1917
q21	5573	4568	4661	4568
q22	509	445	420	420
Total cold run time: 72553 ms
Total hot run time: 65688 ms

@hello-stephen

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

query5	4306	609	435	435
query6	422	215	201	201
query7	4806	443	233	233
query8	318	166	149	149
query9	8793	3173	3204	3173
query10	475	316	266	266
query11	6016	3899	3633	3633
query12	146	91	88	88
query13	1236	460	332	332
query14	6163	3924	3697	3697
query14_1	3413	3503	3445	3445
query15	207	202	183	183
query16	940	458	414	414
query17	876	684	546	546
query18	2426	435	321	321
query19	205	174	140	140
query20	85	84	84	84
query21	212	128	107	107
query22	13033	13119	12862	12862
query23	13605	12898	12550	12550
query23_1	12672	12702	12566	12566
query24	7378	828	472	472
query24_1	477	480	480	480
query25	516	396	347	347
query26	1260	257	138	138
query27	2778	444	272	272
query28	4639	2026	2026	2026
query29	1532	582	436	436
query30	302	226	189	189
query31	1015	940	821	821
query32	155	94	87	87
query33	521	287	232	232
query34	967	857	517	517
query35	735	754	651	651
query36	828	837	720	720
query37	117	96	84	84
query38	1786	1749	1656	1656
query39	811	799	744	744
query39_1	736	736	729	729
query40	218	119	95	95
query41	65	64	66	64
query42	84	84	82	82
query43	344	364	312	312
query44	1348	700	699	699
query45	177	176	173	173
query46	825	969	557	557
query47	2908	2962	2622	2622
query48	298	304	223	223
query49	581	395	291	291
query50	684	272	210	210
query51	10549	10496	10443	10443
query52	91	80	71	71
query53	190	207	151	151
query54	234	205	186	186
query55	74	67	64	64
query56	238	212	222	212
query57	1679	1632	1558	1558
query58	289	270	263	263
query59	2105	2190	1975	1975
query60	280	241	226	226
query61	148	139	145	139
query62	408	335	281	281
query63	190	157	158	157
query64	2751	951	772	772
query65	3350	3333	3269	3269
query66	1773	412	297	297
query67	20182	20249	20076	20076
query68	3163	1013	617	617
query69	401	283	252	252
query70	854	781	745	745
query71	305	233	224	224
query72	2854	2554	2325	2325
query73	511	557	295	295
query74	4677	4541	4352	4352
query75	2366	2293	1937	1937
query76	2331	1033	621	621
query77	353	376	278	278
query78	9843	9739	9182	9182
query79	893	870	533	533
query80	486	423	335	335
query81	517	319	273	273
query82	197	133	104	104
query83	197	204	195	195
query84	281	121	102	102
query85	767	411	373	373
query86	258	249	235	235
query87	1995	1980	1822	1822
query88	3708	2772	2767	2767
query89	315	287	253	253
query90	2086	171	173	171
query91	165	155	133	133
query92	101	90	89	89
query93	995	989	576	576
query94	453	322	263	263
query95	572	379	310	310
query96	694	492	238	238
query97	2431	2439	2322	2322
query98	158	155	151	151
query99	763	767	645	645
Total cold run time: 234407 ms
Total hot run time: 151653 ms

@hello-stephen

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

query1	0.01	0.00	0.00
query2	0.09	0.05	0.05
query3	0.27	0.09	0.08
query4	1.61	0.10	0.10
query5	0.24	0.24	0.24
query6	1.19	0.69	0.67
query7	0.04	0.01	0.00
query8	0.05	0.04	0.04
query9	0.40	0.34	0.35
query10	0.57	0.61	0.58
query11	0.20	0.14	0.14
query12	0.18	0.15	0.15
query13	0.50	0.49	0.50
query14	1.03	1.02	0.99
query15	0.64	0.60	0.60
query16	0.34	0.35	0.34
query17	1.13	1.14	1.08
query18	0.20	0.19	0.19
query19	2.13	2.02	1.94
query20	0.01	0.01	0.02
query21	15.50	0.20	0.13
query22	4.83	0.06	0.05
query23	16.29	0.31	0.12
query24	2.83	0.69	0.50
query25	0.12	0.05	0.05
query26	1.28	0.23	0.16
query27	0.05	0.03	0.06
query28	2.63	0.80	0.36
query29	12.54	4.19	3.23
query30	0.28	0.14	0.10
query31	2.77	0.56	0.34
query32	3.23	0.60	0.50
query33	3.17	3.20	3.29
query34	15.36	4.00	3.41
query35	3.33	3.33	3.34
query36	0.55	0.48	0.42
query37	0.10	0.06	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.16	0.14	0.14
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.1 s
Total hot run time: 24.31 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.70% (35916/46225)
Line Coverage 63.05% (404070/640865)
Region Coverage 59.67% (342178/573489)
Branch Coverage 60.79% (158456/260658)

@airborne12
airborne12 marked this pull request as ready for review November 4, 2026 01:10
@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41761883468

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41817369156

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41823060421

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41831224020

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41955215478

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41984326022

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

eldenmoon
eldenmoon previously approved these changes Nov 5, 2026

@eldenmoon eldenmoon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@airborne12

Copy link
Copy Markdown
Member 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 #70007 at head 57843ed against base 8ebf20d completed in round 1. No new actionable P0-P3 findings were verified. I reviewed all seven changed files and traced HeldBackBuildBytes through MemoryReporter reservation/report/destructor paths, registered versus unregistered counters, and the GlobalMemoryLimiter/SpimiTermBuffer report, registry, and forced-spill lifecycle. Existing inline P1 comment 4450932617 was independently rechecked: the resident-step trigger catches capacity growth inside an unchanged arena, and fixed 32 KiB arena allocation bounds the delay for new posting growth; idle/no-growth behavior predates this PR, so the existing issue does not still apply. No additional user focus was provided. Static-only validation inspected the authoritative diff, related code, threads, ledger, and exact refs; no builds or tests were executed under the review contract. Changed-file review checkpoints found no new hub include, gate-table, PCH, source-including-test, or comment-condition defect. All assigned subagents returned NO_NEW_VALUABLE_FINDINGS, so convergence was achieved.

Review converged after 1 round(s).

…is empty

### What problem does this PR solve?

Issue Number: None

Related PR: apache#67657

Problem Summary: The first commit of this PR holds a reporter's changes back from the
process-wide counters until they add up to 1 MiB, and publishes the remainder when the
reporter is destroyed. A text writer's reporter is not destroyed with the writer:
IndexFileWriter keeps it in _snii_memory_reporters, and BetaRowsetWriter keeps the
IndexFileWriter of every segment until the rowset writer closes. Each finished segment
therefore left up to 1 MiB per text index in g_registered_build_bytes, the input of the
forced-spill decision, and in the SniiIndexBuild tracker, for the rest of the load. With
many segments the sum can push the decision over its share and force-spill healthy
writers, which the merge base never did. A local doris-repo-review run found it.

A reporter now also publishes when its live bytes are back at zero. A writer holds its
arena for the whole build, so per-term swings never reach zero: this is one publish per
finished writer, and a scratch reservation taken and given back leaves nothing to publish.

The same commit covers the other points of that review: the per-term swing test now runs
for kUnregistered reporters too, the report_arena_delta() declaration describes the
limiter half, the resident-step test no longer assumes one decision per token, and the
BKD test asserts without slack.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - AnEmptyReporterHoldsNothingBack keeps a reporter alive, takes it back to zero
      through report() and through a reservation, and checks that nothing is left; it
      fails without the zero rule. PerTermSwingsStayOffTheSharedCounters now covers both
      populations and fails when unregistered reporters publish every change.
      2248 SNII, BKD and inverted index tests pass under ASAN.
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@airborne12

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17574	5172	5062	5062
q2	2131	354	249	249
q3	10219	1370	816	816
q4	4669	462	334	334
q5	7463	796	540	540
q6	184	188	154	154
q7	773	790	600	600
q8	9256	1403	1083	1083
q9	5498	4185	4205	4185
q10	6826	1297	1033	1033
q11	432	239	233	233
q12	647	399	281	281
q13	18083	3630	3032	3032
q14	281	278	249	249
q15	q16	727	718	654	654
q17	1168	742	573	573
q18	6926	6137	6106	6106
q19	1131	955	585	585
q20	362	338	225	225
q21	5201	2510	2445	2445
q22	413	345	291	291
Total cold run time: 99964 ms
Total hot run time: 28730 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6025	5847	5928	5847
q2	717	600	580	580
q3	5522	5790	5327	5327
q4	2092	2156	1557	1557
q5	5807	5699	5744	5699
q6	243	185	147	147
q7	2277	2044	1807	1807
q8	2890	2444	2426	2426
q9	7526	7482	7549	7482
q10	3608	3583	3121	3121
q11	576	403	375	375
q12	665	673	510	510
q13	3321	3576	3056	3056
q14	294	301	268	268
q15	q16	677	679	605	605
q17	7731	7027	6846	6846
q18	12963	12216	12916	12216
q19	886	807	809	807
q20	2186	2163	1945	1945
q21	5743	4743	4834	4743
q22	514	455	424	424
Total cold run time: 72263 ms
Total hot run time: 65788 ms

@hello-stephen

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

query5	4312	607	443	443
query6	428	213	193	193
query7	4807	442	224	224
query8	323	165	150	150
query9	8794	3154	3198	3154
query10	480	306	242	242
query11	6019	3911	3597	3597
query12	143	89	88	88
query13	1244	450	321	321
query14	6117	3935	3663	3663
query14_1	3424	3456	3420	3420
query15	205	206	181	181
query16	945	434	417	417
query17	862	670	551	551
query18	2433	417	311	311
query19	204	181	138	138
query20	86	84	83	83
query21	214	126	108	108
query22	12991	13090	12841	12841
query23	13521	12871	12414	12414
query23_1	12403	12564	12569	12564
query24	7374	862	484	484
query24_1	490	480	489	480
query25	582	406	337	337
query26	1271	257	136	136
query27	2760	446	274	274
query28	4593	2026	2011	2011
query29	1512	593	438	438
query30	300	221	183	183
query31	1012	932	807	807
query32	130	93	91	91
query33	514	306	229	229
query34	885	852	489	489
query35	733	749	658	658
query36	797	811	713	713
query37	123	98	84	84
query38	1778	1748	1672	1672
query39	790	788	736	736
query39_1	732	718	736	718
query40	222	116	95	95
query41	67	64	63	63
query42	93	87	84	84
query43	347	361	310	310
query44	1362	704	731	704
query45	178	171	171	171
query46	824	961	564	564
query47	2927	2859	2910	2859
query48	304	313	217	217
query49	576	400	297	297
query50	704	275	224	224
query51	10393	10446	10562	10446
query52	79	80	69	69
query53	200	214	157	157
query54	246	193	184	184
query55	71	66	63	63
query56	221	214	209	209
query57	1679	1618	1579	1579
query58	280	266	260	260
query59	2127	2154	1994	1994
query60	273	248	228	228
query61	152	149	151	149
query62	387	330	286	286
query63	191	154	162	154
query64	2757	917	783	783
query65	3341	3276	3271	3271
query66	1772	433	299	299
query67	22657	22740	22466	22466
query68	3044	1028	612	612
query69	399	286	252	252
query70	865	779	774	774
query71	293	239	215	215
query72	2781	2566	2297	2297
query73	516	531	298	298
query74	4604	4550	4367	4367
query75	2336	2296	1918	1918
query76	2313	1039	600	600
query77	361	375	268	268
query78	9744	9786	9197	9197
query79	889	866	521	521
query80	525	449	357	357
query81	524	322	267	267
query82	213	134	118	118
query83	195	196	183	183
query84	293	127	101	101
query85	763	435	382	382
query86	252	239	232	232
query87	1996	1941	1830	1830
query88	3729	2773	2753	2753
query89	317	285	245	245
query90	2098	179	171	171
query91	170	154	128	128
query92	103	89	90	89
query93	988	1007	581	581
query94	452	329	277	277
query95	575	377	310	310
query96	685	512	247	247
query97	2456	2412	2299	2299
query98	164	157	145	145
query99	768	763	672	672
Total cold run time: 235888 ms
Total hot run time: 153906 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.05
query3	0.26	0.09	0.09
query4	1.60	0.10	0.10
query5	0.23	0.25	0.26
query6	1.17	0.69	0.67
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.41	0.37	0.33
query10	0.62	0.62	0.62
query11	0.20	0.16	0.14
query12	0.18	0.14	0.14
query13	0.50	0.49	0.51
query14	1.04	1.02	1.00
query15	0.65	0.62	0.63
query16	0.32	0.35	0.36
query17	1.13	1.11	1.10
query18	0.21	0.19	0.20
query19	2.14	1.99	1.92
query20	0.02	0.01	0.01
query21	15.48	0.20	0.14
query22	4.82	0.05	0.06
query23	16.26	0.33	0.12
query24	2.80	0.51	0.56
query25	0.10	0.06	0.06
query26	1.44	0.20	0.15
query27	0.06	0.05	0.04
query28	4.08	0.84	0.37
query29	12.54	4.12	3.33
query30	0.27	0.13	0.10
query31	2.78	0.59	0.33
query32	3.22	0.61	0.50
query33	3.25	3.28	3.15
query34	15.35	4.08	3.41
query35	3.35	3.38	3.36
query36	0.57	0.45	0.46
query37	0.10	0.06	0.06
query38	0.06	0.04	0.05
query39	0.04	0.03	0.04
query40	0.17	0.16	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 97.81 s
Total hot run time: 24.56 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 67.43% (32185/47733)
Line Coverage 52.28% (338907/648213)
Region Coverage 47.79% (275493/576425)
Branch Coverage 49.62% (129878/261756)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.83% (35991/46245)
Line Coverage 63.19% (405160/641145)
Region Coverage 59.85% (343365/573737)
Branch Coverage 60.92% (158895/260816)

@airborne12

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review converged in round 1 with no new verified findings.

The change meets its stated goal: per-reporter SNII build bytes are batched into process-wide observation counters, flushed when a reporter reaches zero, and used by the global limiter without charging the local reporter twice. I traced the text, BKD, compaction, MemoryReporter, SpimiTermBuffer, GlobalMemoryLimiter, and IndexFileWriter lifecycles. The pending/live atomics preserve the publication invariant at quiescence; reporter destruction and member ordering drain reservations safely; the limiter registry remains mutex-protected and owner-thread spill requests are consumed on the next token. No configuration, wire/protocol, persistence, transaction, or storage-format compatibility change is present, and parallel registered/unregistered populations are handled consistently.

The added unit tests cover threshold batching, zero-drain through report and reservations, destructor cleanup, concurrent callbacks, resident-step limiter refresh, pressure during an unchanged arena, and BKD accounting. Static review inspected the authoritative diff and related call paths; no builds or tests were run under the review contract. No additional user focus was supplied.

Existing P1 inline thread 4450932617 was independently rechecked against this head. The resident-step condition now re-evaluates pressure for active resident-only growth inside an unchanged arena, so that finding is treated as fixed and is not reposted.

Review converged after 1 round(s).

@eldenmoon eldenmoon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@airborne12
airborne12 merged commit f7396d7 into apache:master Nov 6, 2026
44 checks passed
@airborne12
airborne12 deleted the snii-build-contention branch November 6, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants