Skip to content

[improvement](parquet) Optimize typed dictionary range filtering - #66036

Merged
Gabriel39 merged 3 commits into
apache:masterfrom
Gabriel39:agent/parquet-typed-dictionary-filter
Jul 26, 2026
Merged

[improvement](parquet) Optimize typed dictionary range filtering#66036
Gabriel39 merged 3 commits into
apache:masterfrom
Gabriel39:agent/parquet-typed-dictionary-filter

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

File Scanner V2 could only use row-level Parquet dictionary filtering efficiently for a narrow set of predicates and projected INT columns. Range predicates and other typed dictionaries could still pay per-entry generic expression evaluation, generic SerDe insertion, or row-sized predicate-column materialization.

What is changed?

  • Enable exact typed dictionary evaluation for =, !=, <, <=, >, and >=, including symmetric literal-on-left comparisons.
  • Accept both RLE_DICTIONARY and legacy PLAIN_DICTIONARY data-page encodings for supported primitive columns.
  • Build numeric dictionary bitmaps over contiguous typed INT, BIGINT, FLOAT, and DOUBLE dictionary values, evaluating each conjunct once per dictionary generation.
  • Build string equality and range bitmaps by comparing dictionary slices directly, without per-entry Field construction or generic dictionary expression dispatch.
  • Decode selected dictionary IDs at the native page-reader layer and apply the per-entry bitmap without materializing a complete predicate value column.
  • Write all supported fixed-width survivors directly from the filter loop into the target column.
  • Gather string survivors with pre-sized character/offset buffers and one copy per selected dictionary value.
  • Add direct-path profile counters and focused INT32/BIGINT/BYTE_ARRAY dictionary microbench scenarios.

Verification

  • ASAN focused tests: 14/14 passed, covering typed numeric/string range filters, literal-on-left normalization, fixed-width fused gather, compact string gather, and benchmark scenario registration.
  • Related ASAN suite: 487 applicable tests passed across Parquet, File Scanner V2, SerDe, column mapping, JSON, WAL, and remote reader coverage. Three unrelated Flight tests could not bind their fixed localhost endpoint because it was already occupied by a pre-existing service.
  • git diff --check passed.

Microbenchmark: upstream master vs this PR

Compared upstream master 7809a73814e directly with this PR at 943c0b94ffc. Both binaries use the same Release compiler options, benchmark harness, fixtures, and fixed CPU. Each binary received three warmups; measurements used interleaved master/PR ordering and 20 samples per scenario. Values below are median CPU time. raw_rows, selected_rows, and fixture sizes were identical for every pair.

Dictionary type Selectivity Projection Master This PR Change
INT32 10% predicate only 1,332,627 ns 329,241 ns -75.3%
INT32 50% predicate only 1,344,746 ns 338,433 ns -74.8%
INT32 10% predicate projected 1,686,162 ns 1,000,973 ns -40.6%
INT32 50% predicate projected 1,713,684 ns 1,041,358 ns -39.2%
BIGINT 10% predicate only 1,053,504 ns 329,214 ns -68.8%
BIGINT 50% predicate only 1,053,577 ns 340,627 ns -67.7%
BIGINT 10% predicate projected 1,367,541 ns 996,056 ns -27.2%
BIGINT 50% predicate projected 1,438,891 ns 1,053,813 ns -26.8%
BYTE_ARRAY 10% predicate only 2,007,277 ns 386,762 ns -80.7%
BYTE_ARRAY 50% predicate only 2,017,380 ns 398,810 ns -80.2%
BYTE_ARRAY 10% predicate projected 2,437,263 ns 1,194,903 ns -51.0%
BYTE_ARRAY 50% predicate projected 2,541,460 ns 1,323,767 ns -47.9%

All twelve direct master-to-PR scenarios improved. Predicate-only scans avoid row-sized materialization and generic per-entry dispatch; projected scans additionally avoid generic survivor insertion.

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

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

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39
Gabriel39 marked this pull request as ready for review July 25, 2026 04:16
@Gabriel39
Gabriel39 requested a review from yiguolei as a code owner July 25, 2026 04:16

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes. The typed range-comparison semantics and legacy dictionary-encoding normalization look sound, but the new direct path has two blocking edge cases: it can discard a hidden predicate column before residual/delete consumers finish with it, producing wrong rows, and it aborts on a legal all-NULL page in an otherwise dictionary-encoded chunk. I also found two non-blocking issues in the performance/benchmark contract.

Review checkpoints:

  • Goal and tests: the dense INT/string happy paths demonstrate the intended dictionary-range optimization, but the added tests do not cover mixed residual/delete consumers or nullable multi-page all-NULL fragments. The author reports 179/179 ASAN unit tests and microbenchmarks; I did not run builds or tests because this review environment explicitly prohibits them.
  • Scope and parallel paths: the change is focused. The residual/delete path is the critical parallel path and is incorrect for predicate-only payload elision. Sparse selections, ordinary nullable payloads, page-index gaps, non-empty multi-page batches, and zero survivors otherwise remain aligned by static trace.
  • Concurrency and lifecycle: reader, decoder, typed-dictionary, and scratch state remain reader-local; I found no new shared-state race, lock-order issue, or cross-thread lifetime problem. The legal all-NULL fragment is the concrete cursor/lifecycle failure, including the projected-INT mode constraint described inline.
  • Configuration, compatibility, and persistence: no configuration, FE/BE protocol variable, transaction, persistence, or storage-write change is involved. Legacy PLAIN_DICTIONARY pages are normalized before the direct gate, and the admitted Field comparisons match normal Doris comparison ordering for compatible types.
  • Conditions and error handling: malformed dictionary IDs remain checked before output commit, but a legal zero-payload page is currently routed to a production DORIS_CHECK.
  • Performance and observability: the direct-path counters are initialized and published coherently, but the survivor bitmap is redundantly recounted and the mandatory benchmark guide still documents the old 152-case registration contract.
  • User focus: no additional user-provided focus was supplied.

At review time, compile, FE UT, Cloud UT, formatting, style, license, dependency, and secret checks pass; BE UT, macOS BE UT, performance, and regression checks are still pending.

const uint16_t selected_rows_before = *selected_rows;
IColumn::Filter compact_filter;
bool used_filter = false;
const bool predicate_only = request.is_predicate_only(local_id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Keep hidden values that later filters still consume

predicate_only only means the slot is not part of final output; it can still be referenced by a remaining residual or delete conjunct. This branch ignores residual_predicate_positions (unlike the fixed-width direct path) and passes nullptr, then installs defaults before later stages run. For example, with hidden dictionary column id, id > 2 plus residual id + score = 33 filters IDs first and then evaluates the residual with id=0, dropping the valid (3,30) row. Please retain/project the payload whenever any residual/delete expression references this position, and add the corresponding hidden-column test.

*projected_directly = false;
*used_filter = false;
row_filter->clear();
if (_current_encoding != tparquet::Encoding::RLE_DICTIONARY || _page_decoder == nullptr ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Handle all-NULL dictionary pages as a successful fragment

A nullable data page can legally contain only definition levels even when the Column Chunk otherwise uses RLE_DICTIONARY; load_page_data() deliberately installs EmptyValueSectionDecoder for that shape. It reports no dictionary, so this new gate returns used_filter=false after _read_dictionary_filter_values() has already consumed the definition levels, and the caller immediately hits DORIS_CHECK(used_filter). A clustered-null page in a chunk with non-NULL dictionary values can therefore terminate the BE on valid input. Please treat the zero-physical-value page as a successful all-false fragment that advances logical progress without dictionary IDs, while preserving (or making neutral) the requested projection mode across page fragments; otherwise projected INT batches can next fail the mode-consistency check. Add predicate-only and projected nullable-INT multi-page coverage with the all-NULL page on both sides of a non-NULL dictionary page.

&projected_directly, &direct_filter_used));
if (direct_filter_used) {
advance_selected_span(direct_rows_read);
const size_t survivor_count =

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] Reuse the survivor count from bitmap construction

filter_dictionary_indices() has just visited every selected row to build row_filter, but this recount scans the full bitmap again, and read_filter_columns() scans it once more with count_selected_rows(). Those extra O(selected_rows) memory passes run for every direct dictionary batch, including the predicate-only workload this PR is optimizing. Please accumulate/return the survivor count while building the bitmap and reuse it for reader statistics and scheduler selection updates.

}
}
}
for (const int selectivity : {1, 10, 50, 90}) {

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] Update the benchmark's required registration contract

These additions move the deduplicated reader matrix to 159 cases (as the changed tests assert), but be/benchmark/parquet/AGENTS.md still tells benchmark users and reviewers to expect 152 at lines 49, 129, and 302. Following that mandatory smoke-validation guide will now flag the correct binary as inconsistent. Please update all three counts and the matrix description with this change.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17867	4158	4122	4122
q2	2020	316	201	201
q3	10274	1420	819	819
q4	4694	468	347	347
q5	7584	845	567	567
q6	188	164	133	133
q7	761	818	629	629
q8	10092	1608	1473	1473
q9	5962	4356	4369	4356
q10	6791	1734	1445	1445
q11	514	349	327	327
q12	788	578	441	441
q13	18135	3300	2784	2784
q14	268	265	242	242
q15	q16	780	766	710	710
q17	1034	975	939	939
q18	6882	5652	5590	5590
q19	1550	1416	1105	1105
q20	784	729	551	551
q21	5795	2470	2413	2413
q22	432	356	294	294
Total cold run time: 103195 ms
Total hot run time: 29488 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4484	4278	4367	4278
q2	298	323	212	212
q3	4582	4934	4435	4435
q4	2090	2343	1365	1365
q5	4429	4254	4295	4254
q6	231	174	127	127
q7	2052	1919	1673	1673
q8	2535	2226	2125	2125
q9	7837	7823	7786	7786
q10	5021	4654	4193	4193
q11	588	427	439	427
q12	927	744	536	536
q13	3301	3565	3044	3044
q14	325	313	280	280
q15	q16	725	720	643	643
q17	1350	1327	1324	1324
q18	8091	7444	6979	6979
q19	1116	1129	1088	1088
q20	2232	2222	1960	1960
q21	5247	4608	4453	4453
q22	522	468	416	416
Total cold run time: 57983 ms
Total hot run time: 51598 ms

@hello-stephen

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

query5	4333	640	494	494
query6	471	233	216	216
query7	4935	572	367	367
query8	356	195	173	173
query9	8788	4112	4129	4112
query10	522	364	330	330
query11	5930	2337	2146	2146
query12	162	104	103	103
query13	1266	640	416	416
query14	6345	5262	4907	4907
query14_1	4289	4241	4225	4225
query15	222	202	184	184
query16	1046	456	456	456
query17	1139	732	592	592
query18	2624	462	358	358
query19	218	195	152	152
query20	117	107	112	107
query21	238	162	139	139
query22	13823	13520	13337	13337
query23	17232	16398	16231	16231
query23_1	16181	16292	16206	16206
query24	7623	1757	1293	1293
query24_1	1309	1359	1309	1309
query25	605	496	359	359
query26	1332	354	217	217
query27	2551	575	381	381
query28	4412	1999	1999	1999
query29	1079	607	469	469
query30	344	262	224	224
query31	1121	1086	975	975
query32	106	64	59	59
query33	519	312	280	280
query34	1175	1151	638	638
query35	765	777	680	680
query36	1224	1165	1025	1025
query37	148	104	90	90
query38	1867	1704	1656	1656
query39	896	879	831	831
query39_1	827	849	823	823
query40	246	162	142	142
query41	65	64	63	63
query42	94	94	92	92
query43	330	330	289	289
query44	1446	791	761	761
query45	193	187	175	175
query46	1025	1228	751	751
query47	2078	2134	1955	1955
query48	417	427	303	303
query49	579	427	297	297
query50	1084	425	338	338
query51	11782	11868	11849	11849
query52	88	87	79	79
query53	266	274	206	206
query54	302	247	216	216
query55	78	71	68	68
query56	299	287	286	286
query57	1315	1296	1195	1195
query58	274	262	264	262
query59	1618	1681	1444	1444
query60	309	276	262	262
query61	154	143	156	143
query62	543	505	430	430
query63	241	198	205	198
query64	2778	1049	847	847
query65	4720	4651	4624	4624
query66	1827	494	373	373
query67	29289	29299	28540	28540
query68	3281	1553	1035	1035
query69	403	297	273	273
query70	1067	924	961	924
query71	374	360	331	331
query72	3030	2750	2330	2330
query73	803	727	428	428
query74	5103	4899	4703	4703
query75	2542	2523	2151	2151
query76	2304	1193	794	794
query77	354	368	285	285
query78	11891	12026	11346	11346
query79	1378	1167	756	756
query80	768	550	469	469
query81	510	330	293	293
query82	567	157	117	117
query83	399	329	298	298
query84	298	157	134	134
query85	952	614	522	522
query86	414	288	286	286
query87	1830	1827	1767	1767
query88	3770	2834	2765	2765
query89	439	369	322	322
query90	1788	200	199	199
query91	206	188	161	161
query92	66	63	55	55
query93	1607	1504	985	985
query94	615	364	346	346
query95	782	501	574	501
query96	1036	798	371	371
query97	2631	2612	2496	2496
query98	213	213	199	199
query99	1090	1108	980	980
Total cold run time: 264428 ms
Total hot run time: 178757 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.25	0.14	0.13
query4	1.60	0.14	0.14
query5	0.24	0.23	0.22
query6	1.31	1.07	1.13
query7	0.04	0.00	0.00
query8	0.05	0.03	0.05
query9	0.39	0.31	0.30
query10	0.57	0.55	0.54
query11	0.19	0.14	0.14
query12	0.19	0.14	0.14
query13	0.48	0.47	0.47
query14	1.03	1.01	1.02
query15	0.63	0.59	0.59
query16	0.33	0.31	0.33
query17	1.07	1.16	1.16
query18	0.22	0.20	0.21
query19	2.05	2.00	1.89
query20	0.02	0.02	0.02
query21	15.43	0.20	0.14
query22	4.99	0.05	0.06
query23	16.12	0.32	0.12
query24	2.98	0.40	0.33
query25	0.12	0.05	0.04
query26	0.73	0.21	0.16
query27	0.05	0.04	0.04
query28	3.52	0.89	0.52
query29	12.52	4.18	3.30
query30	0.28	0.15	0.14
query31	2.77	0.58	0.31
query32	3.22	0.59	0.49
query33	3.26	3.16	3.19
query34	15.78	4.19	3.53
query35	3.50	3.53	3.51
query36	0.55	0.43	0.42
query37	0.08	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.04	0.03
query40	0.17	0.16	0.16
query41	0.09	0.03	0.03
query42	0.04	0.02	0.03
query43	0.04	0.03	0.04
Total cold run time: 97.1 s
Total hot run time: 25.04 s

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes. On the authoritative snapshot 943c0b9, five additional issues remain: a valid zero-value page can terminate the BE, the exact benchmark commands match no registrations, the FLOAT/DOUBLE comparison path lacks an end-to-end value oracle, retained selected-ID scratch bypasses query memory accounting, and sparse selection ranges allocate per fragment. I did not repeat the four existing threads covering the hidden residual-predicate payload, the all-NULL-page crash, the repeated survivor recount, and the stale benchmark matrix/count.

Snapshot note: the live PR head advanced to a697fb9 after this bundle and convergence were completed. This review is explicitly attached to 943c0b9; the newer commit was not part of the authoritative diff and was not reviewed here.

Critical checkpoints:

  • Goal and proof: the typed dictionary range fast path works for the covered INT32, BIGINT, and BYTE_ARRAY happy paths, but valid empty-page transitions and FLOAT/DOUBLE comparison coverage are incomplete.
  • Scope and compatibility: the patch is cohesive and changes no storage or wire format. Legacy PLAIN_DICTIONARY normalization appears safe, but the optimized path still differs incorrectly from the generic path on the already-reported hidden-payload and all-NULL cases plus the new zero-value-page case.
  • Concurrency and lifecycle: no new shared concurrency primitive or static cross-translation-unit state was introduced. Reader-local typed dictionary lifetime is sound; projection-mode transitions and retained scratch lifetime/accounting are not.
  • Configuration, variables, transactions, and persistence: no new configuration, FE/BE variable, transaction boundary, or persistent write path is involved.
  • Special conditions and parallel paths: type/encoding gates and page-index selected-span boundaries were checked. A zero-value V1/V2 page is a valid transition that reaches the new projection-mode check, while selected-range validation prevents a page-index gap from being the same defect.
  • Tests: the new scans cover useful single-page integer/string paths, but not multi-page zero/all-NULL transitions, FLOAT/DOUBLE comparison results, or staged sparse-selection allocation behavior.
  • Observability: the six new profile counters are wired from reader statistics through the scan profile.
  • Performance and memory: the existing survivor-recount thread remains valid; the two new scratch findings separately cover untracked retained IDs and repeated sparse-range allocation.
  • Documentation: the new benchmark name component invalidates the exact filters in the checked-in guide and README.
  • User focus: no additional focus was supplied.
  • Validation: static review only, as required by the review prompt; no local build or test was run. At the final live-state sweep, the newer head still had BE/compile/code-review/performance jobs pending.

return Status::OK();
}
if (*rows_read != 0) {
DORIS_CHECK_EQ(*projected_directly, loop_projected_directly);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Keep empty page transitions projection-mode neutral

A zero-value Data Page V1/V2 is a valid input that the native reader already skips. Here, after an earlier dictionary page has appended fixed-width survivors and set projected_directly=true, the zero-row page returns loop_rows=0, used_filter=true, and the default loop_projected_directly=false, so this check terminates the BE before the following page is read. This is distinct from the all-NULL-page thread because the zero-row page consumes no definition/value cursor. Please compare/update projection mode only for fragments that process logical rows, and add projected RLE_DICTIONARY/PLAIN_DICTIONARY V1/V2 coverage with a zero-value page between nonempty pages.

"/sel_" + std::to_string(scenario.selectivity_percent) + "/" +
to_string(scenario.projection) + "/width_" + std::to_string(scenario.schema_width) +
"/predicate_" + std::to_string(scenario.predicate_position);
return to_string(scenario.operation) + "/" + to_string(scenario.encoding) + "/" +

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] Update the exact benchmark filters for the new name shape

Adding /<value_type>/ changes every reader registration to .../<encoding>/<value_type>/null_..., but the exact filters in be/benchmark/parquet/AGENTS.md:93 and be/benchmark/parquet/README.md:75,87 still use .../<encoding>/null_... and now select no cases. This is distinct from the existing stale-count/matrix thread: correcting those descriptions still leaves the documented comparisons as no-ops. Please update all exact filters and validate them with --benchmark_list_tests.

return get_fixed_dictionary_raw_values<ColumnInt32>(dictionary, values, value_width);
case TYPE_BIGINT:
return get_fixed_dictionary_raw_values<ColumnInt64>(dictionary, values, value_width);
case TYPE_FLOAT:

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] Add end-to-end FLOAT/DOUBLE dictionary-filter coverage

This admits FLOAT and DOUBLE to an exact bitmap path whose covered conjunct may be removed, but the new comparison scans exercise only INT32, BIGINT, and BYTE_ARRAY. The pre-existing accept-all dictionary scan asserts only row count/broad counters, and the raw NaN unit test does not cover FLOAT/DOUBLE ID filtering, nullable placement, or fused projection. Please add differential FLOAT/DOUBLE comparison scans for projected and predicate-only modes, including NaN, signed zero, infinities, NULLs, and operand reversal, and assert output values plus direct-path counters.

// Plain or Dictionary encoding. If the dictionary grows too big, the encoding will fall back to the plain encoding
std::unordered_map<int, std::unique_ptr<Decoder>> _decoders;
NullMap _nullable_selection_nulls;
std::vector<uint32_t> _selected_dictionary_indices;

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] Track the retained selected-ID scratch

This is a persistent per-leaf buffer, but std::vector growth does not pass through Doris Allocator::consume_memory; the checked-in malloc interposer only forwards allocations to jemalloc. The retained-byte bookkeeping here drives the scratch-release policy, not the query MemTracker. With the uint16_t batch bound this can retain about 256 KiB per dictionary predicate leaf, and the 4 MiB per-buffer release threshold means that normal maximum capacity survives until reader teardown, multiplying across wide scans. Please use allocator-aware storage such as DorisVector (updating the decoder interface) or explicitly charge/release capacity to the owning query tracker.

dictionary_filter.size(), _page_decoder->dictionary_size());
}

ParquetSelection selection;

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] Reuse sparse selection-range scratch

A staged earlier predicate can leave one disjoint physical run per surviving row. This local ParquetSelection then grows ranges to that fragmentation and destroys the capacity at the end of every page fragment, so later dictionary predicates repeatedly allocate/free the same range storage. The mandatory scanner guide requires selection ranges to live in persistent reader scratch specifically to avoid this hot-path allocation thrash. Please retain and clear a reusable allocator-aware selection (including its capacity in the existing active/retained scratch policy), and cover a two-predicate fragmented-selection benchmark.

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

Automated review of current head a697fb98371101a109e3b3a32d7b7c75eee5c733: no additional inline comment remains after refreshing and deduplicating against the live PR state. The two candidates independently found in this run (per-fragment selection-range allocation and zero-match benchmark filters) are already covered by live discussions r3649660108 and r3649660099, so they were not reposted.

The PR remains not ready. Nine live inline discussions cover three correctness/test blockers and six performance, memory, coverage, or benchmark-contract issues:

  • hidden predicate-only payload is discarded before residual/delete consumers;
  • legal all-NULL and zero-value page transitions can terminate the BE;
  • the survivor bitmap is redundantly recounted;
  • retained selected-ID memory is not charged to the query tracker;
  • fragmented selection ranges allocate and free per page fragment;
  • FLOAT/DOUBLE dictionary filtering lacks an end-to-end value oracle;
  • benchmark registration counts/matrix text are stale; and
  • all checked-in exact reader benchmark filters match zero renamed cases.

Critical checkpoints:

  • Goal and proof: the patch implements typed dictionary range evaluation and fused survivor projection for covered integer/string happy paths, but the live page-transition and hidden-payload failures prevent the goal from being safely accomplished. Added tests do not prove the all-NULL/zero-page, hidden residual/delete, or FLOAT/DOUBLE cases.
  • Scope and focus: the production, profile, benchmark, test, and design changes are cohesive. No extra user focus was supplied. The checked-in benchmark commands and required matrix documentation were not updated consistently with the expanded type/name matrix.
  • Concurrency: the changed reader, decoder, dictionary-cache, and scratch state is reader-local. No new shared-state race, lock-order problem, or deadlock risk was found.
  • Lifecycle: dictionary generations, destinations, and normal cursor domains are otherwise coherent, but the live all-NULL/zero-page comments identify invalid projection/cursor lifecycle transitions. Persistent selected-ID and selection-range scratch also violates the intended memory/reuse lifecycle.
  • Configuration: no configuration item or dynamic-reload path is added.
  • Compatibility: no storage or wire format changes are introduced. Legacy PLAIN_DICTIONARY normalization and admitted comparison ordering appear compatible on the reviewed paths.
  • Parallel paths and conditions: dictionary, raw fixed-width, and generic typed comparison paths were traced, including literal reversal, nullable selection, sparse selection, page boundaries, and fallback. The live hidden-payload and empty-page conditions are the concrete divergences.
  • Tests and results: author-reported tests and benchmarks were not independently executed. This workflow requires static review only and explicitly prohibits builds; the checkout also lacks initialized third-party build dependencies.
  • Observability: the new direct-path profile counters are initialized and published through the scan profile. No additional logging/metric defect was found.
  • Transactions, persistence, writes, and FE/BE variables: not applicable; this patch adds no transaction/EditLog behavior, persistent data mutation, storage write protocol, or FE/BE variable transport.
  • Performance and memory: the intended dictionary filtering avoids full typed row materialization, but the live recount, untracked retained-ID capacity, and per-fragment range-allocation comments remain unresolved.
  • Other issues: dictionary-ID validation, destination rollback, nullable append parity, string offset preflight, comparison orientation, NaN/string ordering, and typed dictionary invalidation were rechecked without finding another nonduplicate issue.

Validation: static review of the complete authoritative 21-file diff, mandatory scanner design/review guides, tests, and live PR review state. No local build or test was run.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17616	4131	4031	4031
q2	2028	336	203	203
q3	10276	1440	833	833
q4	4698	476	340	340
q5	7587	850	579	579
q6	201	171	140	140
q7	765	822	625	625
q8	10076	1677	1580	1580
q9	6038	4400	4392	4392
q10	6810	1758	1469	1469
q11	512	349	320	320
q12	731	568	455	455
q13	18085	3254	2708	2708
q14	266	264	245	245
q15	q16	793	785	697	697
q17	1038	949	905	905
q18	7001	5760	5566	5566
q19	1335	1364	1118	1118
q20	763	688	596	596
q21	5859	2576	2403	2403
q22	424	347	291	291
Total cold run time: 102902 ms
Total hot run time: 29496 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4399	4329	4330	4329
q2	292	315	205	205
q3	4557	4967	4383	4383
q4	2091	2172	1354	1354
q5	4374	4287	4258	4258
q6	227	178	125	125
q7	1721	2329	1708	1708
q8	2451	2186	2125	2125
q9	7838	7772	7804	7772
q10	4668	4620	4200	4200
q11	577	424	380	380
q12	745	751	618	618
q13	3425	3568	3085	3085
q14	322	324	299	299
q15	q16	723	724	636	636
q17	1380	1352	1331	1331
q18	7830	7317	6862	6862
q19	1073	1090	1118	1090
q20	2185	2203	1958	1958
q21	5236	4529	4411	4411
q22	515	443	406	406
Total cold run time: 56629 ms
Total hot run time: 51535 ms

@hello-stephen

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

query5	4341	625	490	490
query6	474	228	220	220
query7	4846	599	338	338
query8	341	190	175	175
query9	8794	4057	4034	4034
query10	509	361	322	322
query11	5846	2377	2192	2192
query12	166	108	105	105
query13	1276	641	469	469
query14	6239	5239	4850	4850
query14_1	4220	4229	4214	4214
query15	225	205	176	176
query16	1043	441	434	434
query17	1248	678	556	556
query18	2431	463	346	346
query19	201	192	145	145
query20	115	107	108	107
query21	232	153	131	131
query22	13631	13529	13352	13352
query23	17350	16405	16080	16080
query23_1	16153	16107	16192	16107
query24	7456	1765	1261	1261
query24_1	1298	1316	1293	1293
query25	572	483	391	391
query26	1320	368	208	208
query27	2611	627	394	394
query28	4436	1986	1981	1981
query29	1102	626	509	509
query30	335	266	230	230
query31	1118	1098	1002	1002
query32	112	65	64	64
query33	531	322	266	266
query34	1152	1162	640	640
query35	796	785	678	678
query36	1200	1202	1011	1011
query37	156	110	96	96
query38	1878	1707	1689	1689
query39	901	869	864	864
query39_1	845	838	848	838
query40	246	169	155	155
query41	71	70	68	68
query42	96	93	91	91
query43	320	322	281	281
query44	1408	767	751	751
query45	195	189	173	173
query46	1043	1229	754	754
query47	2133	2116	1991	1991
query48	401	444	290	290
query49	594	433	311	311
query50	1083	437	331	331
query51	10431	10496	10489	10489
query52	86	89	77	77
query53	268	272	211	211
query54	297	263	239	239
query55	76	74	67	67
query56	302	333	285	285
query57	1311	1296	1215	1215
query58	295	281	259	259
query59	1608	1606	1451	1451
query60	315	284	275	275
query61	181	173	177	173
query62	548	535	424	424
query63	240	204	195	195
query64	2844	1033	841	841
query65	4750	4664	4653	4653
query66	1834	498	387	387
query67	29236	29209	29093	29093
query68	3150	1565	995	995
query69	410	314	278	278
query70	1061	1000	945	945
query71	378	338	325	325
query72	2981	2673	2348	2348
query73	847	792	436	436
query74	5074	4872	4744	4744
query75	2545	2498	2130	2130
query76	2346	1126	771	771
query77	359	368	280	280
query78	11813	11895	11210	11210
query79	1394	1171	714	714
query80	1319	585	473	473
query81	506	333	280	280
query82	606	155	123	123
query83	375	313	300	300
query84	287	161	129	129
query85	957	614	513	513
query86	419	296	267	267
query87	1823	1814	1735	1735
query88	3703	2779	2765	2765
query89	432	370	326	326
query90	1993	190	192	190
query91	201	193	166	166
query92	62	60	57	57
query93	1723	1499	939	939
query94	712	335	308	308
query95	768	614	475	475
query96	1025	783	329	329
query97	2619	2628	2508	2508
query98	213	227	209	209
query99	1083	1116	968	968
Total cold run time: 263467 ms
Total hot run time: 177176 ms

@hello-stephen

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

query1	0.00	0.00	0.01
query2	0.09	0.04	0.05
query3	0.25	0.14	0.13
query4	1.61	0.14	0.14
query5	0.24	0.23	0.22
query6	1.21	1.07	1.08
query7	0.03	0.00	0.01
query8	0.06	0.04	0.04
query9	0.39	0.32	0.32
query10	0.59	0.55	0.55
query11	0.19	0.13	0.13
query12	0.19	0.14	0.14
query13	0.47	0.46	0.46
query14	1.02	1.02	1.00
query15	0.61	0.61	0.61
query16	0.32	0.32	0.33
query17	1.11	1.13	1.13
query18	0.22	0.21	0.20
query19	2.02	1.97	1.97
query20	0.01	0.01	0.02
query21	15.47	0.23	0.13
query22	4.75	0.06	0.05
query23	16.13	0.31	0.13
query24	2.97	0.40	0.31
query25	0.11	0.05	0.05
query26	0.73	0.20	0.16
query27	0.05	0.03	0.03
query28	3.52	0.95	0.53
query29	12.49	4.10	3.35
query30	0.27	0.15	0.16
query31	2.78	0.59	0.31
query32	3.22	0.60	0.48
query33	3.25	3.19	3.20
query34	15.49	4.22	3.51
query35	3.56	3.54	3.58
query36	0.54	0.44	0.41
query37	0.08	0.06	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.17	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.05	0.03	0.03
Total cold run time: 96.48 s
Total hot run time: 25.17 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 79.03% (603/763) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 58.11% (24609/42347)
Line Coverage 42.20% (246116/583168)
Region Coverage 38.06% (195312/513205)
Branch Coverage 39.19% (88110/224840)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 84.27% (643/763) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.42% (31143/41292)
Line Coverage 60.00% (347586/579268)
Region Coverage 56.71% (292038/514958)
Branch Coverage 58.06% (130538/224846)

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

Copy link
Copy Markdown
Contributor

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

@Gabriel39
Gabriel39 merged commit 97f7f95 into apache:master Jul 26, 2026
31 checks passed
0AyanamiRei pushed a commit to 0AyanamiRei/doris that referenced this pull request Jul 27, 2026
…che#66036)

### What problem does this PR solve?

File Scanner V2 could only use row-level Parquet dictionary filtering
efficiently for a narrow set of predicates and projected INT columns.
Range predicates and other typed dictionaries could still pay per-entry
generic expression evaluation, generic SerDe insertion, or row-sized
predicate-column materialization.

### What is changed?

- Enable exact typed dictionary evaluation for `=`, `!=`, `<`, `<=`,
`>`, and `>=`, including symmetric literal-on-left comparisons.
- Accept both `RLE_DICTIONARY` and legacy `PLAIN_DICTIONARY` data-page
encodings for supported primitive columns.
- Build numeric dictionary bitmaps over contiguous typed INT, BIGINT,
FLOAT, and DOUBLE dictionary values, evaluating each conjunct once per
dictionary generation.
- Build string equality and range bitmaps by comparing dictionary slices
directly, without per-entry `Field` construction or generic dictionary
expression dispatch.
- Decode selected dictionary IDs at the native page-reader layer and
apply the per-entry bitmap without materializing a complete predicate
value column.
- Write all supported fixed-width survivors directly from the filter
loop into the target column.
- Gather string survivors with pre-sized character/offset buffers and
one copy per selected dictionary value.
- Add direct-path profile counters and focused INT32/BIGINT/BYTE_ARRAY
dictionary microbench scenarios.

### Verification

- ASAN focused tests: 14/14 passed, covering typed numeric/string range
filters, literal-on-left normalization, fixed-width fused gather,
compact string gather, and benchmark scenario registration.
- Related ASAN suite: 487 applicable tests passed across Parquet, File
Scanner V2, SerDe, column mapping, JSON, WAL, and remote reader
coverage. Three unrelated Flight tests could not bind their fixed
localhost endpoint because it was already occupied by a pre-existing
service.
- `git diff --check` passed.

### Microbenchmark: upstream master vs this PR

Compared upstream master `7809a73814e` directly with this PR at
`943c0b94ffc`. Both binaries use the same Release compiler options,
benchmark harness, fixtures, and fixed CPU. Each binary received three
warmups; measurements used interleaved master/PR ordering and 20 samples
per scenario. Values below are median CPU time. `raw_rows`,
`selected_rows`, and fixture sizes were identical for every pair.

| Dictionary type | Selectivity | Projection | Master | This PR | Change
|
|---|---:|---|---:|---:|---:|
| INT32 | 10% | predicate only | 1,332,627 ns | 329,241 ns | -75.3% |
| INT32 | 50% | predicate only | 1,344,746 ns | 338,433 ns | -74.8% |
| INT32 | 10% | predicate projected | 1,686,162 ns | 1,000,973 ns |
-40.6% |
| INT32 | 50% | predicate projected | 1,713,684 ns | 1,041,358 ns |
-39.2% |
| BIGINT | 10% | predicate only | 1,053,504 ns | 329,214 ns | -68.8% |
| BIGINT | 50% | predicate only | 1,053,577 ns | 340,627 ns | -67.7% |
| BIGINT | 10% | predicate projected | 1,367,541 ns | 996,056 ns |
-27.2% |
| BIGINT | 50% | predicate projected | 1,438,891 ns | 1,053,813 ns |
-26.8% |
| BYTE_ARRAY | 10% | predicate only | 2,007,277 ns | 386,762 ns | -80.7%
|
| BYTE_ARRAY | 50% | predicate only | 2,017,380 ns | 398,810 ns | -80.2%
|
| BYTE_ARRAY | 10% | predicate projected | 2,437,263 ns | 1,194,903 ns |
-51.0% |
| BYTE_ARRAY | 50% | predicate projected | 2,541,460 ns | 1,323,767 ns |
-47.9% |

All twelve direct master-to-PR scenarios improved. Predicate-only scans
avoid row-sized materialization and generic per-entry dispatch;
projected scans additionally avoid generic survivor insertion.
Gabriel39 added a commit to Gabriel39/incubator-doris that referenced this pull request Jul 27, 2026
…che#66036)

### What problem does this PR solve?

File Scanner V2 could only use row-level Parquet dictionary filtering
efficiently for a narrow set of predicates and projected INT columns.
Range predicates and other typed dictionaries could still pay per-entry
generic expression evaluation, generic SerDe insertion, or row-sized
predicate-column materialization.

### What is changed?

- Enable exact typed dictionary evaluation for `=`, `!=`, `<`, `<=`,
`>`, and `>=`, including symmetric literal-on-left comparisons.
- Accept both `RLE_DICTIONARY` and legacy `PLAIN_DICTIONARY` data-page
encodings for supported primitive columns.
- Build numeric dictionary bitmaps over contiguous typed INT, BIGINT,
FLOAT, and DOUBLE dictionary values, evaluating each conjunct once per
dictionary generation.
- Build string equality and range bitmaps by comparing dictionary slices
directly, without per-entry `Field` construction or generic dictionary
expression dispatch.
- Decode selected dictionary IDs at the native page-reader layer and
apply the per-entry bitmap without materializing a complete predicate
value column.
- Write all supported fixed-width survivors directly from the filter
loop into the target column.
- Gather string survivors with pre-sized character/offset buffers and
one copy per selected dictionary value.
- Add direct-path profile counters and focused INT32/BIGINT/BYTE_ARRAY
dictionary microbench scenarios.

### Verification

- ASAN focused tests: 14/14 passed, covering typed numeric/string range
filters, literal-on-left normalization, fixed-width fused gather,
compact string gather, and benchmark scenario registration.
- Related ASAN suite: 487 applicable tests passed across Parquet, File
Scanner V2, SerDe, column mapping, JSON, WAL, and remote reader
coverage. Three unrelated Flight tests could not bind their fixed
localhost endpoint because it was already occupied by a pre-existing
service.
- `git diff --check` passed.

### Microbenchmark: upstream master vs this PR

Compared upstream master `7809a73814e` directly with this PR at
`943c0b94ffc`. Both binaries use the same Release compiler options,
benchmark harness, fixtures, and fixed CPU. Each binary received three
warmups; measurements used interleaved master/PR ordering and 20 samples
per scenario. Values below are median CPU time. `raw_rows`,
`selected_rows`, and fixture sizes were identical for every pair.

| Dictionary type | Selectivity | Projection | Master | This PR | Change
|
|---|---:|---|---:|---:|---:|
| INT32 | 10% | predicate only | 1,332,627 ns | 329,241 ns | -75.3% |
| INT32 | 50% | predicate only | 1,344,746 ns | 338,433 ns | -74.8% |
| INT32 | 10% | predicate projected | 1,686,162 ns | 1,000,973 ns |
-40.6% |
| INT32 | 50% | predicate projected | 1,713,684 ns | 1,041,358 ns |
-39.2% |
| BIGINT | 10% | predicate only | 1,053,504 ns | 329,214 ns | -68.8% |
| BIGINT | 50% | predicate only | 1,053,577 ns | 340,627 ns | -67.7% |
| BIGINT | 10% | predicate projected | 1,367,541 ns | 996,056 ns |
-27.2% |
| BIGINT | 50% | predicate projected | 1,438,891 ns | 1,053,813 ns |
-26.8% |
| BYTE_ARRAY | 10% | predicate only | 2,007,277 ns | 386,762 ns | -80.7%
|
| BYTE_ARRAY | 50% | predicate only | 2,017,380 ns | 398,810 ns | -80.2%
|
| BYTE_ARRAY | 10% | predicate projected | 2,437,263 ns | 1,194,903 ns |
-51.0% |
| BYTE_ARRAY | 50% | predicate projected | 2,541,460 ns | 1,323,767 ns |
-47.9% |

All twelve direct master-to-PR scenarios improved. Predicate-only scans
avoid row-sized materialization and generic per-entry dispatch;
projected scans additionally avoid generic survivor insertion.
Gabriel39 added a commit to Gabriel39/incubator-doris that referenced this pull request Jul 28, 2026
…che#66036)

### What problem does this PR solve?

File Scanner V2 could only use row-level Parquet dictionary filtering
efficiently for a narrow set of predicates and projected INT columns.
Range predicates and other typed dictionaries could still pay per-entry
generic expression evaluation, generic SerDe insertion, or row-sized
predicate-column materialization.

### What is changed?

- Enable exact typed dictionary evaluation for `=`, `!=`, `<`, `<=`,
`>`, and `>=`, including symmetric literal-on-left comparisons.
- Accept both `RLE_DICTIONARY` and legacy `PLAIN_DICTIONARY` data-page
encodings for supported primitive columns.
- Build numeric dictionary bitmaps over contiguous typed INT, BIGINT,
FLOAT, and DOUBLE dictionary values, evaluating each conjunct once per
dictionary generation.
- Build string equality and range bitmaps by comparing dictionary slices
directly, without per-entry `Field` construction or generic dictionary
expression dispatch.
- Decode selected dictionary IDs at the native page-reader layer and
apply the per-entry bitmap without materializing a complete predicate
value column.
- Write all supported fixed-width survivors directly from the filter
loop into the target column.
- Gather string survivors with pre-sized character/offset buffers and
one copy per selected dictionary value.
- Add direct-path profile counters and focused INT32/BIGINT/BYTE_ARRAY
dictionary microbench scenarios.

### Verification

- ASAN focused tests: 14/14 passed, covering typed numeric/string range
filters, literal-on-left normalization, fixed-width fused gather,
compact string gather, and benchmark scenario registration.
- Related ASAN suite: 487 applicable tests passed across Parquet, File
Scanner V2, SerDe, column mapping, JSON, WAL, and remote reader
coverage. Three unrelated Flight tests could not bind their fixed
localhost endpoint because it was already occupied by a pre-existing
service.
- `git diff --check` passed.

### Microbenchmark: upstream master vs this PR

Compared upstream master `7809a73814e` directly with this PR at
`943c0b94ffc`. Both binaries use the same Release compiler options,
benchmark harness, fixtures, and fixed CPU. Each binary received three
warmups; measurements used interleaved master/PR ordering and 20 samples
per scenario. Values below are median CPU time. `raw_rows`,
`selected_rows`, and fixture sizes were identical for every pair.

| Dictionary type | Selectivity | Projection | Master | This PR | Change
|
|---|---:|---|---:|---:|---:|
| INT32 | 10% | predicate only | 1,332,627 ns | 329,241 ns | -75.3% |
| INT32 | 50% | predicate only | 1,344,746 ns | 338,433 ns | -74.8% |
| INT32 | 10% | predicate projected | 1,686,162 ns | 1,000,973 ns |
-40.6% |
| INT32 | 50% | predicate projected | 1,713,684 ns | 1,041,358 ns |
-39.2% |
| BIGINT | 10% | predicate only | 1,053,504 ns | 329,214 ns | -68.8% |
| BIGINT | 50% | predicate only | 1,053,577 ns | 340,627 ns | -67.7% |
| BIGINT | 10% | predicate projected | 1,367,541 ns | 996,056 ns |
-27.2% |
| BIGINT | 50% | predicate projected | 1,438,891 ns | 1,053,813 ns |
-26.8% |
| BYTE_ARRAY | 10% | predicate only | 2,007,277 ns | 386,762 ns | -80.7%
|
| BYTE_ARRAY | 50% | predicate only | 2,017,380 ns | 398,810 ns | -80.2%
|
| BYTE_ARRAY | 10% | predicate projected | 2,437,263 ns | 1,194,903 ns |
-51.0% |
| BYTE_ARRAY | 50% | predicate projected | 2,541,460 ns | 1,323,767 ns |
-47.9% |

All twelve direct master-to-PR scenarios improved. Predicate-only scans
avoid row-sized materialization and generic per-entry dispatch;
projected scans additionally avoid generic survivor insertion.
Gabriel39 added a commit that referenced this pull request Jul 28, 2026
## Proposed changes

Backport the requested changes to `branch-4.1` in master merge order,
skipping changes already present in this PR:

1. #62438
2. #65329 (merged prerequisite for the nested-schema cases)
3. #65960
4. #65965
5. #65972
6. #65998
7. #66002
8. #65992
9. #66021
10. #66036
11. #66008
12. #66073
13. #66056 (explicitly requested; current open-PR head, appended after
the merged sequence)

The branch-specific compatibility commits preserve the selected master
behavior on `branch-4.1`, including master wire IDs for file formats and
the merged Paimon test helper prerequisite. No regression expected
output, test assertion, or test input was changed to make validation
pass.

## Validation

- Full BE ASAN build passed.
- Full FE build passed.
- Targeted BE ASAN unit tests: 332 tests from 13 suites passed.
- Targeted FE Iceberg unit tests: 41 passed, 0 failed.
- Iceberg write regression: 20 suites, 0 failed, 0 fatal.
- `PaimonScanNodeTest`: all 16 test bodies completed with 0 assertion
failures; the class reports one Mockito teardown error because #66008
left four now-unused stubs on master. The still-open #65867 contains the
upstream test-only cleanup commit. This PR intentionally does not alter
those test cases.
- Final rebase against the latest `branch-4.1` completed; the branch was
already up to date.
- Working-tree, formatting, and sensitive-information audits completed.
Existing EOF blank lines in picked regression output files are
preserved.

---------

Co-authored-by: daidai <changyuwei@selectdb.com>
Co-authored-by: Mingyu Chen (Rayner) <yunyou@selectdb.com>
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. dev/4.1.4-merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants