Skip to content

[improvement](be) Reuse memory-tracked scratch when validating Variant payloads - #69019

Merged
morningman merged 2 commits into
apache:masterfrom
morningman:b2m-t20a-variant-validate-scratch
Oct 15, 2026
Merged

morningman merged 2 commits into
apache:masterfrom
morningman:b2m-t20a-variant-validate-scratch

Conversation

@morningman

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #68959

Problem Summary:

In short. Validating a Variant value no longer allocates a fresh, untracked std::vector for every object it checks. A new VariantPayloadValidator keeps that scratch in one DorisVector that every later row reuses, and the callers that validate whole batches (encoded-row inserts, the encoded-row appender that #68959 uses to import unshredded Parquet Variant values, the native Arrow Variant reader and sanity_check) now hold one validator per batch, or for the appender's whole life. This was raised in the review of #68959.

Background. Encoded Variant bytes that come from outside (Parquet files, JNI readers, Arrow batches) are validated before a ColumnVariantV2 takes them. For an object, validate_variant_payload() checks that the field values exactly tile the object's value section: it collects the byte span of every field value, sorts the spans by offset and rejects overlaps, gaps and trailing bytes. require_valid_object() collected those spans into a local std::vector with reserve(field_count), so every object it checked, nested objects included, allocated once and freed the vector when its check returned. VariantBatchBuilder, which the Parquet importer used before #68959, checked the same intervals in a DorisVector it reuses across rows.

The problem, and what it cost.

Validating a batch of 4096 object rows master with this PR
Scratch allocations at least one per object, so at least 4096 per batch, plus one per nested object one buffer per batch (one per appender for the Parquet importer); it grows to the widest path of objects and is then reused
Allocator of the scratch (16 bytes per field) plain malloc through std::allocator, which the Doris memory trackers do not see the Doris Allocator, counted by the thread's memory tracker

insert_encoded_rows() (JNI readers, inserted encoded values, Variant element extraction), the encoded-row appender and the native Arrow Variant reader validate every row, so this is per-row work on the read path.

How this PR fixes it.

  • VariantPayloadValidator (new header core/value/variant/variant_payload_validator.h) keeps the spans in one DorisVector used as a stack. An object pushes the span of each field after checking that field, so a nested object pushes its spans above those of its ancestors, sorts and checks only its own range and pops back before returning. The checks, their order and their error messages are unchanged. A call that throws leaves the entries of its unfinished objects behind, so validate() starts by clearing the stack.
  • The class is defined in variant_field.cpp next to the checks it shares with validate_variant_payload(), which remains the one-shot form for a single value (VariantField::from_ref / from_bytes, parse_canonical_serialized). It is declared in its own header so that core/field.h, which includes variant_field.h, does not pull in core/custom_allocator.h (its include-closure budget has no slack).
  • ColumnVariantV2::insert_encoded_rows(), ColumnVariantV2::sanity_check() and the native Arrow reader in DataTypeVariantV2SerDe create one validator per call; EncodedRowsAppender keeps one in its Impl, so all the chunks a Parquet reader imports share it.

Results.

  • The reusable validator accepts and rejects the same 13 payloads as the one-shot call: nested and wide objects, objects inside arrays, and the corrupt objects of the existing tests (duplicate offset, overlapping spans, gap, trailing bytes, unordered keys). A corrupt object nested in field b throws after three entries are on the stack, and the next valid payload still validates (ReusableValidatorMatchesOneShotValidation).
  • Validating a 1000-field object and a nested object 4096 times each leaves the scratch capacity where the first row put it (ReusableValidatorReusesScratchAcrossRows); the appender keeps the same capacity across two 4096-row chunks (EncodedRowsAppenderReusesValidationScratchAcrossChunks).
  • The scratch of a 4096-field object shows up in the thread's memory tracker (at least 64 KiB while the validator lives) and is released with it (ReusableValidatorScratchIsMemTrackerVisible).
  • Each new test catches the regression it is written for: with the appender back on the one-shot call, only EncodedRowsAppenderReusesValidationScratchAcrossChunks fails; with the scratch back on std::vector, only ReusableValidatorScratchIsMemTrackerVisible fails; without the clear() at the start of validate(), ReusableValidatorMatchesOneShotValidation stops at the DCHECK that the stack is empty after a valid payload.
  • The 233 tests of the Variant suites listed below pass locally, except ColumnVariantV2Test.TypedComparisonBoundariesMatchEncodedWithoutMaterializing, which also fails on master on the macOS machine used here and passes in CI.

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
      • VariantFieldTest.ReusableValidatorMatchesOneShotValidation, ReusableValidatorReusesScratchAcrossRows, ReusableValidatorScratchIsMemTrackerVisible, ColumnVariantV2Test.EncodedRowsAppenderReusesValidationScratchAcrossChunks; the existing VariantFieldTest, ColumnVariantV2Test, DataTypeVariantV2*, ArrowFlightVariantTest, VariantColumnReaderTest, VariantBatchBuilderTest, VariantElementV2EncodedTest and JniDataBridgeTest suites pass.
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases

…t payloads

### What problem does this PR solve?

Issue Number: None

Related PR: apache#68959

Problem Summary: validate_variant_payload() checks that the field values of
every Variant object exactly tile the object's value section. To do that,
require_valid_object() collected the byte spans of the field values into a
fresh std::vector for every object it checked, nested ones included, and freed
it when the check returned. ColumnVariantV2::insert_encoded_rows() (JNI
readers, inserted encoded values, Variant element extraction), the
EncodedRowsAppender that apache#68959 uses to import unshredded Parquet Variant
values, and the native Arrow Variant reader validate every row this way. A
4096-row batch of object rows therefore paid at least 4096 allocations, and
the scratch (16 bytes per field) came from plain malloc, which Doris memory
tracking does not see. VariantBatchBuilder, which that importer replaced,
checked the same intervals in a reused, tracked DorisVector.

Add VariantPayloadValidator, which keeps the spans in one DorisVector used as
a stack: an object pushes the span of each field after checking the field, so
a nested object pushes above its ancestors and pops back before it returns.
The checks, their order and their errors are unchanged. The batch callers
hold one validator for the batch, and the encoded-row appender holds one for
its whole life; validate_variant_payload() stays as the one-shot form for a
single value. The class is declared in its own header so that core/field.h,
which includes variant_field.h, does not pull in core/custom_allocator.h.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - VariantFieldTest: the reusable validator accepts and rejects the same
      payloads as the one-shot call, including a corrupt nested object
      followed by a valid one; its scratch capacity stays the same over 4096
      rows; the scratch is visible to the memory tracker
    - ColumnVariantV2Test.EncodedRowsAppenderReusesValidationScratchAcrossChunks
- Behavior changed: No
- Does this need documentation: No

Co-Authored-By: Claude Opus 5.5 (1M context) <[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?

@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed all seven changed files at head 714d816. One new P2 finding: removing the known-count span reservation adds repeated allocation and relocation work in existing row-wise deserialization, where both validators are fresh for each row. The inline comment describes the concrete caller chain and fix direction. No existing inline findings or blocking comment IDs apply.

The review converged after 2 rounds: both general reviewers and the separate recursive-stack/memory reviewer returned NO_NEW_VALUABLE_FINDINGS in the latest round; main independently verified the final finding, full changed-file coverage, and all risk dispositions. No unresolved candidate or uncovered changed-file scope remains. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal and evidence: batch/appender scratch is reused and Doris-accounted. Four new unit tests inspect correctness/recovery, reuse across rows/chunks, and tracked allocation/release; the fresh-caller performance regression remains the P2 finding.
  2. Scope: the seven-file change is focused on reusable validation and its tests.
  3. Concurrency/locks: scratch is local to synchronous calls or locally owned appenders; existing Parquet materialization locking is unchanged. No new shared state, thread, or lock order.
  4. Lifecycle/static initialization: RAII releases capacity; appender moves transfer its unique Impl; actual appenders end within their invoking context. Spans contain only offsets/sizes. No new global initializer or ownership cycle.
  5. Configuration: no additions or dynamic-update behavior.
  6. Compatibility: payload/metadata/column formats, validation errors and the one-shot public signature are preserved; no execution-version gate is needed for ephemeral scratch.
  7. Thrift/protobuf: no definitions or IDs changed.
  8. Parallel paths: explicit/compact metadata, sanity checks, JNI, native Arrow and both Parquet appender users were traced. Remaining one-shot and single-row callers expose the reported growth regression.
  9. Conditional checks: rejection conditions remain unchanged. The stack example and failed-call reset comment match the implementation; nested failures safely reset before reuse.
  10. Test coverage: inspected wide/nested/array/empty-object, malformed span/key, recovery, chunk reuse and tracker tests, plus existing framing/depth/primitive/UTF-8/COW/Arrow cases. Current reuse assertions miss repeatedly fresh validator allocation work.
  11. Test results: no golden files changed; new unit expectations match their encoded inputs and owner lifetimes by inspection.
  12. Observability: existing errors, Arrow error conversion and Parquet import timing/counters remain sufficient for this internal change.
  13. Transactions/persistence/failover: no transaction, visibility-version, delete-bitmap, EditLog or persistence protocol changes.
  14. Writes/atomicity: new scratch allocations and input validation remain before destination mutation; Arrow publishes a validated temporary batch. Existing COW ownership and null handling are preserved.
  15. FE-BE variables: none added or changed.
  16. Performance: retained validators avoid per-row scratch allocation after warmup; fresh wide-object validators repeatedly grow from zero, as reported inline. No throughput magnitude was measured.
  17. Other/module checks: recursive growth keeps only numeric base indices, constructs spans after children return, and restores ancestor state. No additional correctness issue found. The pure-text build-hygiene gate passed header layering/budgets/PCH, extern-template pairing and unity-skip checks.

Core invariants: malformed input still fails by exception/status and significant scratch is tracked by Doris allocation; committed-data visibility, partition versions and MoW state are untouched. This was a static review: no builds, unit/regression tests, ASAN/fault injection, final ELF ABI audit, or benchmarks were executed.

Review converged after 2 round(s).

std::vector<ObjectValueSpan> spans;
spans.reserve(count);
// Entries below base belong to the ancestors of this object; see _object_spans.
const size_t base = _object_spans.size();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Preserve the known-count reservation for fresh validators

For wide flat objects, replacing spans.reserve(count) with unreserved pushes adds repeated allocation and span-copy work in callers that never reuse a validator. In particular, ColumnVariantV2::deserialize() loops through insert_data(), which creates a fresh validator in parse_canonical_serialized() and another in its single-row insert_encoded_rows() call; both scratch buffers are destroyed on every row. These paths now repeatedly grow from zero instead of making the previous single span allocation per validation, and the batch-reuse tests miss this regression. Reserve capacity for this object's base + count spans before the loop while keeping it reusable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 54c9572. require_valid_object() reserves the object's base + count spans before it checks the fields, taking at least twice the current capacity. A fresh validator therefore allocates once for a flat object (1000 fields: one allocation of 1000 instead of growing 1, 2, 4, ..., 1024). Taking at least twice the capacity matters for siblings: with an exact base + count, a root of 26 objects of 30 fields would reallocate for every sibling once k + 30 passes the capacity; this grows 26 -> 52 -> 104.

VariantFieldTest.FreshValidatorReservesAnObjectOnce pins both: capacity 1000 after the flat object and 104 after the nested one. Without the reservation it reads 1024 and 64, and with an exact reservation the nested case reads 55.

… fields

The reusable validator dropped the reservation the one-shot validator made
for each object. Callers that still validate every value with a fresh
validator, such as ColumnVariantV2::deserialize() through insert_data(),
then grew the span buffer from zero for each wide object: about ten
allocations for an object of 1000 fields instead of one.

require_valid_object() now reserves base + count spans before checking the
fields. It takes at least twice the current capacity, so sibling objects
that each need a little more space do not reallocate one entry at a time: in
a root of 26 objects of 30 fields, field k needs k + 30 entries, and the
buffer grows 26 -> 52 -> 104 instead of once per sibling.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@morningman

Copy link
Copy Markdown
Contributor Author

run buildall

@morningman

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17591	5712	5602	5602
q2	2121	320	264	264
q3	10224	1423	837	837
q4	4684	483	353	353
q5	7439	807	553	553
q6	195	192	166	166
q7	800	819	617	617
q8	9273	1358	1122	1122
q9	5758	4538	4479	4479
q10	6831	1299	1039	1039
q11	454	255	234	234
q12	628	407	300	300
q13	18035	3098	2403	2403
q14	277	269	254	254
q15	q16	731	735	655	655
q17	1198	736	589	589
q18	7117	6248	6188	6188
q19	1250	966	610	610
q20	408	335	232	232
q21	5859	2629	2659	2629
q22	416	367	309	309
Total cold run time: 101289 ms
Total hot run time: 29435 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6684	6609	6842	6609
q2	742	639	570	570
q3	5639	5757	5275	5275
q4	2076	2213	1607	1607
q5	5687	5773	5819	5773
q6	258	203	157	157
q7	2251	2016	1802	1802
q8	3239	2707	2764	2707
q9	8261	8188	8109	8109
q10	3673	3624	3323	3323
q11	605	415	386	386
q12	701	712	513	513
q13	2796	3126	2418	2418
q14	291	297	258	258
q15	q16	674	680	626	626
q17	7815	7051	6970	6970
q18	13076	12267	13100	12267
q19	936	819	804	804
q20	2178	2183	1937	1937
q21	5917	4754	4881	4754
q22	513	462	410	410
Total cold run time: 74012 ms
Total hot run time: 67275 ms

@hello-stephen

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

query5	4316	599	448	448
query6	425	219	195	195
query7	4802	479	228	228
query8	318	180	172	172
query9	8794	4066	4053	4053
query10	478	319	268	268
query11	6019	3468	3264	3264
query12	164	91	86	86
query13	1273	462	329	329
query14	6578	4843	4596	4596
query14_1	4215	4227	4304	4227
query15	213	211	184	184
query16	923	439	436	436
query17	859	663	576	576
query18	2428	432	327	327
query19	207	169	138	138
query20	83	82	77	77
query21	211	137	115	115
query22	13076	13072	12757	12757
query23	13225	12590	12161	12161
query23_1	12131	12179	12295	12179
query24	7097	849	459	459
query24_1	473	479	473	473
query25	562	436	407	407
query26	1278	278	139	139
query27	2737	457	288	288
query28	4591	1965	1954	1954
query29	1602	610	468	468
query30	304	233	191	191
query31	908	777	666	666
query32	154	91	93	91
query33	512	300	243	243
query34	915	857	505	505
query35	773	794	675	675
query36	843	808	730	730
query37	138	108	93	93
query38	1854	1790	1715	1715
query39	733	751	715	715
query39_1	693	680	679	679
query40	238	127	99	99
query41	74	70	70	70
query42	90	89	89	89
query43	365	384	339	339
query44	1331	711	715	711
query45	186	184	165	165
query46	864	1013	584	584
query47	2890	2975	2940	2940
query48	298	303	214	214
query49	565	399	308	308
query50	688	272	213	213
query51	10661	10697	10547	10547
query52	81	88	68	68
query53	185	205	158	158
query54	230	208	194	194
query55	76	68	68	68
query56	230	212	200	200
query57	1623	1585	1582	1582
query58	281	251	285	251
query59	2356	2393	2152	2152
query60	300	240	227	227
query61	148	147	146	146
query62	399	342	288	288
query63	196	165	170	165
query64	2764	979	794	794
query65	3600	3499	3480	3480
query66	1780	412	302	302
query67	20272	20578	20227	20227
query68	2983	1011	622	622
query69	381	289	248	248
query70	911	845	832	832
query71	297	219	206	206
query72	2826	2626	2374	2374
query73	514	526	296	296
query74	4626	4515	4340	4340
query75	2417	2335	1971	1971
query76	2293	1017	608	608
query77	366	406	301	301
query78	9367	9224	8642	8642
query79	1018	880	531	531
query80	1193	461	360	360
query81	585	334	275	275
query82	725	139	110	110
query83	308	199	177	177
query84	322	124	105	105
query85	862	471	368	368
query86	378	239	229	229
query87	2027	1982	1863	1863
query88	3620	2713	2695	2695
query89	350	297	255	255
query90	1845	180	178	178
query91	156	149	125	125
query92	97	90	86	86
query93	1031	1008	578	578
query94	608	316	282	282
query95	599	348	328	328
query96	669	518	243	243
query97	2498	2435	2348	2348
query98	161	148	149	148
query99	788	781	673	673
Total cold run time: 236204 ms
Total hot run time: 153701 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.10	0.05	0.05
query3	0.28	0.12	0.12
query4	1.60	0.12	0.13
query5	0.26	0.25	0.25
query6	1.18	0.71	0.69
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.42	0.36	0.35
query10	0.62	0.61	0.57
query11	0.20	0.14	0.15
query12	0.18	0.15	0.16
query13	0.49	0.50	0.50
query14	0.99	0.97	0.97
query15	0.65	0.62	0.63
query16	0.31	0.36	0.36
query17	1.17	1.16	1.10
query18	0.23	0.21	0.21
query19	2.14	2.05	2.00
query20	0.02	0.02	0.01
query21	15.50	0.25	0.14
query22	4.49	0.05	0.06
query23	16.19	0.31	0.12
query24	2.84	1.19	0.41
query25	0.11	0.06	0.06
query26	1.66	0.26	0.16
query27	0.04	0.03	0.04
query28	2.20	0.60	0.38
query29	12.49	4.11	3.27
query30	0.28	0.13	0.14
query31	2.77	0.59	0.34
query32	3.21	0.62	0.53
query33	3.24	3.20	3.25
query34	15.65	4.09	3.43
query35	3.34	3.34	3.36
query36	0.54	0.46	0.43
query37	0.10	0.06	0.06
query38	0.05	0.04	0.04
query39	0.03	0.03	0.03
query40	0.18	0.14	0.13
query41	0.09	0.03	0.02
query42	0.04	0.03	0.02
query43	0.04	0.03	0.04
Total cold run time: 96.03 s
Total hot run time: 24.6 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 all seven changed files at head 54c9572e943213f7c5e9189c0e9dca01d3100ef4, their upstream/downstream callers, parallel validation paths and tests. No new verified finding. Review converged in 1 round: both complete reviewers and the separate risk reviewer returned NO_NEW_VALUABLE_FINDINGS; all candidates and risk questions were independently reconciled and dismissed with evidence.

The existing P2 reservation discussion is addressed at this head: fresh objects reserve their known field count before traversal, and nested siblings grow capacity geometrically (26 -> 52 -> 104). No existing P0/P1 finding applies. No additional user focus was supplied.

Critical checkpoint conclusions:

  1. Goal/tests: source implements reused, tracked scratch at all changed batch callers. New unit tests assert acceptance/rejection, failed-call reset, capacities, chunks and tracking. No builds or unit/regression tests were run in this review environment.
  2. Scope: seven files; a separate validator header avoids adding allocator closure to variant_field.h/core/field.h; no unrelated runtime behavior changes identified.
  3. Concurrency/locks: no new threads, locks, static shared validator, or cross-column state. Per-call validators are local; appender state follows existing exclusive scoped adapter contract.
  4. Lifecycle/static initialization: local validators own the vector; appender owns it through unique Impl. Production appender callers create/use/destroy lexically within Parquet conversion calls. No new global initializer or ownership cycle.
  5. Configuration: no additions or dynamic-setting changes.
  6. Compatibility: Variant Encoding V1 and canonical bytes untouched, metadata/order/size/error checks preserved, one-shot public symbol retained; no exec-version gate needed for scratch-only refactor. No new libc API/toolchain change identified; release ELF audit not performed.
  7. Thrift/protobuf: none changed.
  8. Parallel paths: encoded rows compact/explicit metadata, appender, Arrow and sanity all use batch-local scratch. VariantField/canonical single-value wrappers deliberately keep the same one-shot entry point. Existing typed/shredded paths and builder remain separate, appropriate to their ownership.
  9. Conditions/comments: changed reserve has concrete flat/sibling examples; validate clear documents exception leftovers; stack header documents ancestor/child example. Existing correctness checks and failures remain in place.
  10. Test coverage: added tests plus existing noncanonical offset, corruption, maximum-depth, invalid encoded insert/appender and Arrow guards were statically reviewed. Direct runtime allocation-fault and exhaustive end-to-end execution are not evidenced here.
  11. Results: no regression golden/output files changed; new expected capacity and boolean outcomes match source logic by inspection. Author-reported local test results are not this review's test evidence.
  12. Observability: existing corruption and allocation failure exceptions retained; refactor adds no new distributed operation requiring logs/metrics.
  13. Transactions/persistence: no visibility, rowset/delete-bitmap, EditLog, transaction or failover logic touched.
  14. Data writes/atomicity: scratch mutation only; encoded destination validation still precedes typed/shredded conversion or bytes append, Arrow still validates a temporary batch first. Allocation/error exceptions unwind local scratch; production Parquet scope releases appender on return/throw.
  15. FE-BE variables: no new variables or send paths.
  16. Performance/memory: DorisVector uses CustomStdAllocator/Allocator consume/release; geometric reservation retains capacity across rows/chunks while maintaining known-count reservation for fresh objects. Object span sort complexity is unchanged; no references into scratch survive child reallocation.
  17. Other/BE hygiene: new members' definitions stay in existing variant_field.cpp Core target; no source-including tests or new instantiation/pch/gate-table edits. Pure-text hygiene passed and full integrations result reconciled; compiled linking/runtime behavior remain unverified by contract.

Validation limits: static source review and pure-text build hygiene only. No builds, unit/regression tests, runtime allocation-fault checks or release-artifact audits were run. No unresolved static candidate or uncovered changed-file scope remains.

Review converged after 1 round(s).

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17604	5626	5569	5569
q2	2098	304	259	259
q3	10266	1377	838	838
q4	4671	470	350	350
q5	7418	801	540	540
q6	186	184	153	153
q7	757	791	604	604
q8	9241	1310	1052	1052
q9	5769	4405	4442	4405
q10	6833	1291	1023	1023
q11	446	251	237	237
q12	624	400	285	285
q13	18080	3046	2361	2361
q14	267	275	256	256
q15	q16	731	719	669	669
q17	1175	736	570	570
q18	7064	6198	6146	6146
q19	1101	961	609	609
q20	382	344	228	228
q21	4699	2217	2359	2217
q22	355	314	265	265
Total cold run time: 99767 ms
Total hot run time: 28636 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6351	6091	6105	6091
q2	657	545	557	545
q3	5184	5396	4959	4959
q4	1970	2107	1532	1532
q5	5237	5132	5885	5132
q6	245	193	149	149
q7	2280	2073	1837	1837
q8	3136	2822	2841	2822
q9	8189	8175	8171	8171
q10	3906	3763	3334	3334
q11	643	460	421	421
q12	718	698	518	518
q13	2900	3247	2544	2544
q14	295	325	304	304
q15	q16	702	719	705	705
q17	8380	7575	7480	7480
q18	13193	12235	13057	12235
q19	900	786	782	782
q20	2186	2154	1956	1956
q21	5784	4603	4720	4603
q22	514	456	413	413
Total cold run time: 73370 ms
Total hot run time: 66533 ms

@hello-stephen

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

query5	4297	578	418	418
query6	420	210	191	191
query7	4805	433	227	227
query8	316	182	167	167
query9	8750	3947	3907	3907
query10	468	298	255	255
query11	5937	3420	3207	3207
query12	147	87	81	81
query13	1254	448	320	320
query14	6514	4725	4488	4488
query14_1	4247	4183	4235	4183
query15	213	201	180	180
query16	942	460	420	420
query17	861	647	532	532
query18	2421	420	311	311
query19	203	167	136	136
query20	83	79	81	79
query21	210	134	113	113
query22	13159	12935	12853	12853
query23	13150	12529	12082	12082
query23_1	12243	12165	12206	12165
query24	7117	826	470	470
query24_1	479	487	470	470
query25	540	417	358	358
query26	1268	261	140	140
query27	2768	432	272	272
query28	4593	1957	1969	1957
query29	1537	595	455	455
query30	305	222	186	186
query31	881	759	637	637
query32	144	91	94	91
query33	501	301	250	250
query34	899	866	515	515
query35	754	776	644	644
query36	791	806	725	725
query37	127	103	93	93
query38	1783	1770	1677	1677
query39	713	720	691	691
query39_1	664	677	668	668
query40	218	124	100	100
query41	71	70	67	67
query42	90	84	83	83
query43	360	375	326	326
query44	1290	701	716	701
query45	188	186	167	167
query46	865	954	568	568
query47	2947	3008	2937	2937
query48	300	311	225	225
query49	612	390	287	287
query50	666	284	216	216
query51	10706	10323	10652	10323
query52	79	82	69	69
query53	197	200	152	152
query54	240	199	187	187
query55	73	70	61	61
query56	216	224	202	202
query57	1601	1586	1570	1570
query58	283	266	247	247
query59	2352	2357	2121	2121
query60	267	233	220	220
query61	143	143	143	143
query62	391	335	286	286
query63	198	167	160	160
query64	2750	944	834	834
query65	3456	3381	3377	3377
query66	1773	414	289	289
query67	20286	20266	20097	20097
query68	3102	994	622	622
query69	377	285	279	279
query70	909	833	798	798
query71	311	237	207	207
query72	2684	2570	2257	2257
query73	502	523	292	292
query74	4556	4475	4287	4287
query75	2328	2280	1909	1909
query76	2290	1003	599	599
query77	359	393	295	295
query78	9047	9006	8544	8544
query79	976	860	532	532
query80	525	409	342	342
query81	523	334	282	282
query82	581	137	108	108
query83	305	189	176	176
query84	322	116	105	105
query85	806	416	357	357
query86	315	237	233	233
query87	2043	1962	1815	1815
query88	3585	2697	2640	2640
query89	340	298	253	253
query90	1889	175	176	175
query91	153	146	118	118
query92	90	86	78	78
query93	978	987	575	575
query94	453	309	287	287
query95	576	399	323	323
query96	677	515	234	234
query97	2436	2424	2316	2316
query98	152	147	146	146
query99	778	788	659	659
Total cold run time: 233706 ms
Total hot run time: 151754 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.10	0.05	0.05
query3	0.27	0.12	0.12
query4	1.61	0.13	0.11
query5	0.24	0.24	0.26
query6	1.16	0.67	0.71
query7	0.04	0.00	0.01
query8	0.06	0.04	0.04
query9	0.42	0.36	0.35
query10	0.57	0.57	0.57
query11	0.21	0.14	0.15
query12	0.19	0.14	0.14
query13	0.50	0.49	0.48
query14	0.96	0.96	0.95
query15	0.62	0.61	0.62
query16	0.31	0.34	0.32
query17	1.12	1.13	1.14
query18	0.23	0.20	0.21
query19	2.04	2.01	2.01
query20	0.02	0.01	0.02
query21	15.51	0.29	0.15
query22	4.38	0.06	0.06
query23	16.29	0.32	0.12
query24	3.00	0.64	0.40
query25	0.10	0.05	0.07
query26	1.44	0.23	0.16
query27	0.06	0.03	0.03
query28	2.10	0.58	0.38
query29	12.56	4.07	3.31
query30	0.29	0.14	0.13
query31	2.77	0.58	0.34
query32	3.22	0.60	0.52
query33	3.20	3.16	3.25
query34	15.61	3.98	3.41
query35	3.33	3.37	3.37
query36	0.55	0.46	0.42
query37	0.10	0.07	0.06
query38	0.05	0.03	0.04
query39	0.03	0.03	0.03
query40	0.17	0.15	0.14
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 95.6 s
Total hot run time: 24.51 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (17/17) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.94% (35506/46147)
Line Coverage 62.20% (401902/646122)
Region Coverage 58.50% (338691/578932)
Branch Coverage 59.51% (156231/262536)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (17/17) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.94% (35506/46147)
Line Coverage 62.21% (401921/646122)
Region Coverage 58.51% (338754/578932)
Branch Coverage 59.51% (156244/262536)

@morningman
morningman merged commit bdcd7ea into apache:master Oct 15, 2026
37 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Oct 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

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

Labels

approved Indicates a PR has been approved by one committer. backport/4.2-master reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants