Skip to content

[refactor](const column) unify const column read method - #65684

Merged
yiguolei merged 12 commits into
apache:masterfrom
yiguolei:debug_65558
Oct 13, 2026
Merged

yiguolei merged 12 commits into
apache:masterfrom
yiguolei:debug_65558

Conversation

@yiguolei

@yiguolei yiguolei commented Jul 16, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

unify const column read method including: new column and hidden column. To support zonemap and predicates

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • 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
  • Confirm document
  • Add branch pick label

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

@yiguolei
yiguolei force-pushed the debug_65558 branch 2 times, most recently from 3480093 to fbe2cf4 Compare July 18, 2026 15:41
@yiguolei
yiguolei force-pushed the debug_65558 branch 2 times, most recently from 0760b1a to e8dfc53 Compare September 15, 2026 09:49
@yiguolei
yiguolei requested a review from deardeng as a code owner September 16, 2026 03:57
@yiguolei yiguolei changed the title Debug 65558 [refactor](const column) unify const column read method Sep 20, 2026
@yiguolei

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.

Requesting changes for seven substantiated issues.

  • Goal, data correctness, and parallel paths: the constant-reader refactor does not yet preserve rowset-scoped hidden values in the full-row TopN lazy-fetch and short-circuit/row-cache branches.
  • Schema evolution and compatibility: nested-group compaction, NESTED SEARCH, and ordinary generated VARIANT-path scans cross current logical descriptors with historical rowset/segment schemas, causing throws, query errors, or stale-root binding after ADD or same-name DROP/ADD. The storage-only UINT and protobuf-field changes themselves remain compatible in the traced old/new consumers.
  • Tests and results: coverage is broad, but the new TopN suite has no output file and the time-travel suite is missing ten output blocks, so normal regression execution rejects both as committed. The fixtures also miss the actual historical-schema provenance behind the VARIANT failures.
  • Scope and conditions: the 88-file refactor is coherent around one reader abstraction, but its comments/conditions assume intended NOT_FOUND and rowset synthesis paths that the reported branches bypass.
  • Concurrency, lifecycle, and performance: no additional race, lock-order, static-lifetime, statistics-owner, cache-lifetime, or material hot-path issue was found; request-scoped constants stay out of the shared reader cache.
  • Configuration, observability, persistence, and FE/BE contracts: no new config, EditLog/transactional-write, metric/logging, or cross-process variable contract requires action. Segment/protobuf compatibility and direct column-store context propagation were checked.
  • Validation: static review only, as required by the review environment; no build or test was run, so author/CI test claims were not independently validated.
  • User focus: no additional focus was supplied; the complete patch was reviewed.

iterator_item.storage_read_options.io_ctx.reader_type = ReaderType::READER_QUERY;
iterator_item.storage_read_options.io_ctx.file_cache_miss_policy =
file_cache_miss_policy;
// A rowid fetch bypasses TabletReader, so copy the rowset context it would have

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] Synthesize hidden columns in row-store lazy fetch

The rowset context only reaches the column-store branch. When fetch_row_store=true, the branch above decodes full-row JSONB directly, even though that JSONB persists hidden VERSION/COMMIT_TSO placeholders. RowStoreFetchChecker does not exclude those hidden slots, so TopN lazy materialization on a store_row_column=true table can still return 0. Please either keep runtime hidden columns off row-store lazy fetch or overwrite them from this rowset context, and cover that full-row-store case in the TopN regression.

// An empty row_columns_uids() means the row-store column contains the full row. Keep
// missing_cids empty so full-row point queries can be served entirely from the row store,
// including row-cache hits. Read-time-synthesized hidden columns are intentionally not
// supported on this fast path: for example, JSONB stores 0 for __DORIS_VERSION_COL__, while

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] Do not return hidden placeholders from point queries

This knowingly turns a valid hidden-column projection into the persisted placeholder: full-row short-circuit eligibility does not reject __DORIS_VERSION_COL__/__DORIS_COMMIT_TSO_COL__, and clearing their UIDs makes both live JSONB decoding and row-cache hits skip the rowset-aware branch below. A prepared point query can therefore return 0 instead of the visible rowset value. Please preserve these runtime columns as missing (and bypass the row cache for them), or disqualify such projections from the short-circuit path, with a regression covering both hidden fields.

OlapReaderStatistics stats;
Status st = segment->get_column_reader(variant_uid, &column_reader, &stats);
StorageReadOptions read_options(stats);
const auto& variant_column = rowset->tablet_schema()->column_by_uid(variant_uid);

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 current VARIANT identity in compaction

This lookup happens in the historical rowset schema, so a rowset that predates ADD VARIANT (or predates a same-name DROP/ADD with a new UID) has no variant_uid; column_by_uid() uses .at() and throws before the NOT_FOUND branch can run. The caller already has the current variant_column; please pass that descriptor through and let get_variant_root_reader() decide whether each segment has physical metadata, then cover both schema-evolution cases in compaction.

DORIS_CHECK(index_exec_ctx->column_iter_opts().stats != nullptr);
StorageReadOptions read_options(*index_exec_ctx->column_iter_opts().stats);
read_options.io_ctx = index_exec_ctx->column_iter_opts().io_ctx;
Status st = segment->get_variant_root_reader(segment->tablet_schema()->column(column_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] Resolve NESTED roots from the current schema

The descriptor passed here was resolved by name from the segment's historical schema. For a segment predating ADD VARIANT, the earlier field_index returns -1 and errors instead of reaching this NOT_FOUND handling; after same-name DROP/ADD, it can bind the old UID and search dropped data. Please resolve the current logical root/UID from the scan schema (the current field map is presently ignored) and pass that descriptor here, with ADD and DROP/ADD NESTED SEARCH coverage.

Comment thread be/src/storage/segment/segment.cpp Outdated

// Validate the root rather than an extracted path's leaf type. For example, `v.user.id` may be
// BIGINT while its root uid=7 still identifies a physical VARIANT reader.
const TabletColumn* root_column = &col;

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 a historically absent VARIANT root before leaf validation

On a production pre-ADD rowset, Segment is opened with the historical rowset schema, so it does not contain the current root_uid. For a generated child such as v.a, root_column then remains this scalar leaf and the VARIANT check below returns InvalidArgument; get_data_type_of() never receives the NOT_FOUND it expects for its declared-type fallback, and ordinary SegmentIterator initialization fails. The new unit test masks this by opening old physical data with the current full schema. Please preserve/resolve the current root descriptor (or detect physical absence before leaf validation) and test with an actually historical segment schema, including same-name DROP/ADD.

assertTrue(lazyHiddenOnlyRead.every { row -> (row[0] as Long) > 0 },
"TopN rowid fetch returned an invalid hidden version: ${lazyHiddenOnlyRead}")

order_qt_topn_mixes_constant_and_physical_rows """

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] Commit the TopN expected output

This order_qt requires a checked-in expected-output file, but regression-test/data/query_p0/topn_lazy/test_constant_column_topn_lazy_rowid.out is absent. Normal regression mode throws Missing outputFile rather than generating it, so this new suite cannot pass as committed. Please generate and commit the .out with the regression runner.


// Case 3: these predicates are evaluated against the constant zonemaps of the historical rowset.
// c_default in the same predicates is also a constant because it was added after the write.
order_qt_hidden_initial_version_equal """

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] Generate every expected time-travel block

The committed .out contains only hidden_after_alter_add_default; this label and the other nine labels that follow have no output blocks. Suite.quickRunTest throws Missing output block for tag in normal mode, so the suite stops here. Please regenerate and commit all expected blocks using the regression runner rather than hand-writing them.

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

过了一遍这个 PR(对着 head c82cb08)。const 列统一的核心是干净的、方向也对:ConstantColumnIterator 跟旧 DefaultValueColumnIterator 语义对等,ConstantColumnReader 构造期那两处类型校验正常路径不可达,三个 hidden 列在 segment 的 zonemap / page / 谓词 / pushed-agg / 物化各路径都走统一 resolver _get_column_reader_for_read,多版本也正确地不替换。

两点建议合并前看一下,都标在具体行上了:一个 HIGH(两个新回归套 normal 模式跑不起来、CI 会红),一个 MEDIUM(hidden 列在整行行存快路径返回占位符 0)。上一轮 review 的 VARIANT 那三条(nested_group 写计划 / variant_inverted_index_search / segment get_variant_root_reader)我核过,已经修好了。

assertTrue(lazyHiddenOnlyRead.every { row -> (row[0] as Long) > 0 },
"TopN rowid fetch returned an invalid hidden version: ${lazyHiddenOnlyRead}")

order_qt_topn_mixes_constant_and_physical_rows """

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.

[HIGH] 两个新加的回归测试套件在 normal 模式跑不起来:topn_lazy/test_constant_column_topn_lazy_rowid 的 .out 整个没提交,跑到 order_qt_topn_mixes_constant_and_physical_rows 直接报 Missing outputFile;time_travel 的 test_constant_hidden_column_statistics.out 只有 hidden_after_alter_add_default 一个 block,groovy 有 11 个 tag,跑到第 2 个 order_qt_hidden_initial_version_equal 就报 Missing output block for tag。

这两条套子恰是这次 const 列重构在 TopN 回捞 / 时间旅行统计上的回归测试保护(走的是已修好的列存 / segment 路径),跑不起来就等于这块没了回归测试兜底。

用 regression runner 重新生成并提交完整 .out(-forceGenOut),别手写补 block。

// supported on this fast path: for example, JSONB stores 0 for __DORIS_VERSION_COL__, while
// its published value must be obtained from the rowset. Resolving it would require bypassing
// the row cache and reading the column store with rowset context, defeating this optimization.
if (schema.row_columns_uids().empty()) {

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.

[MEDIUM] 整行行存表(store_row_column=true)上,短路点查和 TopN lazy 回捞直接解 JSONB,__DORIS_VERSION_COL__/__DORIS_COMMIT_TSO_COL__ 读回的是盘上占位符 0 而不是 rowset 真实值。rowset context(version/commit_tso)只传到列存分支,这两条快路径没接上。

这处(point_query_executor.cpp)你已用注释标成主动接受的限制,但 row cache 没绕过、命中也返回 0;be/src/exec/rowid_fetcher.cpp:1023 那处没任何说明,一声不响返回错值。

要么把带 hidden 投影的查询从这两条快路径踢出去、回退到正确的 segment 读,要么从 rowset context 覆盖这两列。两处一起改,至少给 rowid_fetcher 补上说明或报错。

注:这条定 MEDIUM——是内部 hidden 列、要 show_hidden_columns 才投影得到,且本 PR 没有 store_row_column=true 的用例覆盖这两条路径。

@yiguolei

yiguolei commented Oct 8, 2026

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.

COMPLETE static review of PR #65684 at 627b590. I inspected all 100 changed paths, the relevant FE/BE callers and compaction lifecycle, existing threads, and the supplied diff. Two normal review rounds and focused risk passes converged. Request changes for one new P1 and four still-applicable P1s already reported inline. No builds or tests were run, as the review prompt prohibits them.

New finding: the range reader assumes hidden COMMIT_TSO/VERSION pages have been materialized. Ordinary ordered compaction can instead link singleton segment files with physical zero placeholders into a range rowset. On a primary DUP_KEYS table with ROW binlog, this can make FOR TIME AS OF include rows committed after the snapshot; hidden-column pruning and MIN/MAX also see zeros. A UNIQUE non-MoW table has the same linked VERSION gap. This linked-range symptom existed before the refactor, but the changed reader retains and documents the invalid assumption; the new synthetic-range unit case does not exercise linked singleton provenance.

Existing inline P1s independently confirmed at this head: 4061765393 (row-store lazy fetch decodes placeholder JSONB), 4061765399 (point-query full-row and row-cache paths return placeholders), 4061765423 (TopN suite has no expected-output file), and 4061765433 (hidden-statistics suite has only one of eleven expected blocks). I did not repost them. Earlier VARIANT P1s 4061765403, 4061765408, and 4061765417 are fixed by current-root UID checks and are not carried. The later HIGH/MEDIUM replies repeat the four retained concerns.

Critical checkpoints:

  1. Goal and proof: Request-scoped constant readers, historical defaults, and current VARIANT identity are implemented across ordinary column reads. The linked-range and two existing row-store/point paths keep hidden-column correctness incomplete. BE cases and regressions were inspected, not executed; the linked-compaction case lacks a discriminating test.
  2. Scope: Changes span 43 BE production files, 40 BE test files, nine regression suites, seven outputs, and one instructions file. The changes largely follow the reader contract, though its parallel paths need completion.
  3. Concurrency: The new constants are request-scoped rather than stored in the shared column-reader cache. I found no new thread entry, lock-order change, or separate race; the concurrent point-query regression was inspected only.
  4. Lifecycle: Rowset version/TSO context is copied through normal and delayed iterator construction. Linked compaction preserves segment pages while replacing rowset metadata, which breaks the range read assumption. No new cross-translation-unit static initializer or ownership cycle was found.
  5. Configuration: No new runtime configuration was added. Existing enabled ordered compaction makes the linked case reachable; no dynamic-configuration issue was found.
  6. Compatibility: Historical missing columns get typed defaults and current VARIANT UID checks prevent same-name root confusion. Storage-only unsigned reader types have no identified logical serialization caller. No new wire or storage format was found; rolling-upgrade behavior was not executed.
  7. Parallel paths: Column-store point/rowid reads carry rowset context, while the two previously commented row-store JSONB paths still bypass it. Linked ordered compaction is the distinct new inline finding.
  8. Conditions: Singleton synthesis and pre-publish placeholder handling are guarded, but the statement that all range rowsets contain materialized TSOs is false for linked singleton files. Missing-column/index fallbacks otherwise remain conservative by static trace.
  9. Coverage: Added BE tests cover constant values, nulls, types, pruning, VARIANT UID history, and transaction TSO. Changed regressions cover schema evolution, partial update, point query, and time travel, but no test forces ordered link compaction of two published singleton rowsets with distinct TSOs.
  10. Expected results: The TopN output file is absent and the hidden-statistics output has one of eleven tags; the other seven changed suites' literal query tags have matching blocks. None of these results were generated or run here.
  11. Observability: Existing statuses and logging identify publish TSO failures. I found no separate observability requirement that would fix the silent linked-placeholder read; the value itself must be corrected.
  12. Transaction and persistence: FE allocates, persists/replays, and sends positive ROW-binlog TSOs, and local BE validates publish before visibility. Ordinary materializing compaction preserves them; ordered linking writes a TSO range into metadata without materializing the constituent pages. No separate EditLog gap was found.
  13. Writes and crashes: Fixed/flexible partial-update and compaction write flows were traced; the linked-page mismatch is the substantiated data-correctness issue. I found no distinct atomicity, leak, or crash-recovery regression.
  14. FE/BE propagation: Rowset version/TSO reaches ordinary BE readers and direct column-store fetches. The already-commented JSONB shortcuts omit that context at output, and linked ranges lose per-source values. No new protocol field is required by this PR.
  15. Performance and other issues: Reader creation is request-scoped and I found no separate substantiated CPU, memory, or allocation regression. Ordered linking is efficient but cannot be used for these hidden columns without preserving their logical values. No other distinct candidate survived the final sweep.

User focus file contains no additional focus point. Review completion: COMPLETE after two bounded rounds and a final 100-path sweep; one new inline P1 plus four retained existing blocking IDs.

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

}
if (read_options.version.first == read_options.version.second) {
// A singleton needs its publish TSO to replace the on-disk NULL/0 placeholder.
// Range rowsets already contain materialized TSOs: compacting the initial empty

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Preserve hidden metadata when ordered compaction links singleton segments. This range branch assumes COMMIT_TSO pages were materialized, but ordinary ordered compaction can link two tidy singleton rowsets without rewriting their physical zero placeholders. A primary DUP_KEYS table with ROW binlog then reads TSO=0, so FOR TIME AS OF can include rows committed after the snapshot; hidden-column pruning and MIN/MAX also use those zeros. The same link path leaves __DORIS_VERSION_COL__=0 on eligible UNIQUE non-MoW tables. Materialize these values, retain per-input rowset metadata for linked segments, or disable linking for affected schemas; test snapshots before and between the two commits.

@yiguolei

yiguolei commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

/review

@yiguolei

yiguolei commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Complete static review of PR #65684 at head c2db726. I reviewed all 105 changed paths, the related read/write and compaction call chains, tests and expected-output files, and existing inline discussions. No build or test was run because this review's instructions prohibit them.

New finding: one [P2] inline comment. Deleting StorageReadOptions's default constructor leaves the optional BE benchmark target with a zero-argument construction in benchmark_variant_segment.hpp, so BUILD_BENCHMARK=ON cannot compile that target.

Existing P1 findings that still apply and are carried by ID rather than reposted: #4214939756 (ordered compaction links singleton segments with hidden-column placeholders into a range rowset); #4061765399 (full-row point-query JSONB can return hidden placeholders); and #4061765393 (TopN row-store lazy fetch can return hidden placeholders). The former VARIANT root/NESTED/streaming-plan concerns in #4061765417, #4061765408, and #4061765403 appear repaired by current-schema root UID binding and historical-schema checks. The former missing-output concerns in #4061765423 and #4061765433 now have matching checked-in output blocks by static inspection. There was no additional user-provided focus.

Critical checkpoints:

  1. Goal and proof: the change moves defaults and hidden metadata into request-scoped constant readers and separates logical from physical reader lookup. The changed unit and regression cases cover scalar defaults, VARIANT, pruning, point/TopN reads, partial updates, and time travel. They do not prove ordered linking or full-row-store hidden projections; no tests were executed here.
  2. Scope and clarity: the cross-layer refactor is internally related, but the constructor API migration misses the benchmark caller identified inline.
  3. Concurrency and locks: traced publish, segment/rowset reads, lazy iterators, and request-scoped readers. No new shared mutable reader state or lock-order change was substantiated; the three carried hidden-value issues are correctness paths, not races.
  4. Lifecycle and static initialization: copied StorageReadOptions borrow statistics owned for the reader lifetime in the checked query, vertical, rowid, point-query, and segcompaction paths. No new cross-translation-unit static initialization dependency was found.
  5. Configuration: no new configuration item or dynamic-update requirement was identified.
  6. Compatibility: existing physical offset types receive IDataType handling, while historical segment columns are resolved against current schema identity or supplied logical constants. No new FE/BE wire field or on-disk encoding change was found; the optional benchmark source compatibility regression is reported inline.
  7. Parallel paths: compared column-store reads with full-row JSONB point and lazy-fetch paths, and rewriting compaction with ordered/binlog segment linking. The three still-applicable P1 threads cover the missed paths.
  8. Conditional checks: reviewed singleton-versus-range metadata selection, current-root UID checks, and constant-reader pruning capabilities. The singleton condition does not account for ordered-linked placeholders, as covered by #4214939756; no other unsupported branch was substantiated.
  9. Test coverage: changed BE unit and regression suites exercise defaults, search, pruning, partial update, point/TopN, and time travel. Ordered linking, full-row-store hidden projections, and the optional benchmark compile remain unproved by those cases.
  10. Test results: all nine changed regression suites have corresponding output files whose query tags match by static inspection. Their values and test pass status were not independently validated; no builds or tests were run.
  11. Observability: existing Status and logging paths provide failure context in the inspected reader/compaction changes. No separate logging or metrics defect was substantiated.
  12. Persistence and failover: checked BE rowset commit-TSO publication, physical placeholders, historical schemas, and compaction metadata. No FE EditLog or new replay protocol was changed; ordered linking remains the persisted-metadata interpretation issue already reported.
  13. Writes and atomicity: reviewed partial-update hidden-value reset, segment writing, publish, and compaction. No separate commit/crash atomicity defect was established beyond the carried ordered-link issue.
  14. FE/BE variables: no new variable or protocol field requiring propagation across FE and BE paths was added. NESTED binding now uses the current ReadSchema identity in inspected paths.
  15. Performance and remaining issues: constant readers avoid reading absent physical pages; checked pruning/index fallbacks and stats lifetimes found no substantiated new hot-path regression. The sole new accepted issue is the benchmark constructor break; all other investigated candidates were either fixed, preexisting, or duplicates of the carried P1 threads.

Review status: COMPLETE after two full-review rounds, focused risk passes, and a final changed-file and candidate sweep. Static inspection only.

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

// Every storage read needs a statistics sink. Deleting the default constructor keeps copied
// options valid from creation; for example, SegmentIterator stores a copy and later
// dereferences stats while reading pages.
StorageReadOptions() = delete;

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 caller for the required statistics argument. benchmark_variant_segment.hpp:1282 still declares StorageReadOptions options;, but this deleted constructor is used when benchmark_main.cpp includes that header for BUILD_BENCHMARK=ON. The optional benchmark_test target cannot compile. Construct it with the existing stats object and remove the later options.stats assignment.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17584	5682	5554	5554
q2	2106	327	258	258
q3	10230	1431	875	875
q4	4677	482	346	346
q5	7459	807	555	555
q6	189	187	162	162
q7	806	817	630	630
q8	9266	1392	1071	1071
q9	5710	4462	4515	4462
q10	6832	1300	1038	1038
q11	445	259	241	241
q12	628	414	289	289
q13	18092	3087	2388	2388
q14	268	266	252	252
q15	q16	744	728	663	663
q17	1215	748	570	570
q18	7091	6241	6188	6188
q19	1260	965	597	597
q20	386	348	231	231
q21	6389	2625	2632	2625
q22	400	355	322	322
Total cold run time: 101777 ms
Total hot run time: 29317 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6655	6595	6751	6595
q2	734	606	545	545
q3	5636	5857	5311	5311
q4	2034	2166	1582	1582
q5	5755	5764	5858	5764
q6	246	188	146	146
q7	2291	2019	1801	1801
q8	3151	2786	2760	2760
q9	8199	8232	8060	8060
q10	3653	3612	3276	3276
q11	587	398	387	387
q12	664	696	495	495
q13	2756	3124	2389	2389
q14	278	291	261	261
q15	q16	655	675	607	607
q17	7759	7012	6878	6878
q18	13087	12263	13110	12263
q19	919	800	819	800
q20	2200	2171	1944	1944
q21	5745	4756	4859	4756
q22	488	446	397	397
Total cold run time: 73492 ms
Total hot run time: 67017 ms

@hello-stephen

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

query5	4321	593	435	435
query6	427	219	194	194
query7	4816	447	226	226
query8	311	180	177	177
query9	8767	4000	4003	4000
query10	465	313	256	256
query11	5933	3425	3186	3186
query12	139	84	84	84
query13	1260	441	316	316
query14	6552	4777	4526	4526
query14_1	4282	4269	4241	4241
query15	210	202	181	181
query16	981	448	415	415
query17	869	659	557	557
query18	2429	424	311	311
query19	194	157	139	139
query20	82	83	89	83
query21	210	137	117	117
query22	13098	13024	12950	12950
query23	13201	12647	12206	12206
query23_1	12314	12213	12348	12213
query24	7107	874	486	486
query24_1	473	469	477	469
query25	546	418	378	378
query26	1246	255	144	144
query27	2768	442	276	276
query28	4607	1939	1941	1939
query29	1580	593	459	459
query30	302	218	181	181
query31	889	776	661	661
query32	171	98	95	95
query33	515	304	274	274
query34	910	863	501	501
query35	765	770	664	664
query36	869	814	724	724
query37	139	104	91	91
query38	1795	1784	1727	1727
query39	717	726	670	670
query39_1	680	684	704	684
query40	219	119	102	102
query41	73	70	70	70
query42	94	83	85	83
query43	370	382	324	324
query44	1294	695	700	695
query45	179	176	161	161
query46	844	969	572	572
query47	2931	3005	2955	2955
query48	295	297	222	222
query49	565	387	293	293
query50	671	277	208	208
query51	10467	10476	10655	10476
query52	78	81	65	65
query53	189	210	154	154
query54	229	187	192	187
query55	71	66	66	66
query56	223	219	217	217
query57	1624	1591	1553	1553
query58	284	262	254	254
query59	2379	2382	2138	2138
query60	283	230	222	222
query61	157	147	137	137
query62	390	342	291	291
query63	197	161	155	155
query64	2726	964	757	757
query65	3425	3377	3377	3377
query66	1782	455	305	305
query67	20055	20146	20036	20036
query68	3070	992	600	600
query69	376	298	250	250
query70	916	823	818	818
query71	300	225	213	213
query72	2749	2331	2230	2230
query73	516	522	294	294
query74	4572	4480	4327	4327
query75	2369	2283	1955	1955
query76	2300	1004	604	604
query77	362	396	280	280
query78	9292	9057	8532	8532
query79	967	907	522	522
query80	761	412	336	336
query81	578	324	270	270
query82	688	139	113	113
query83	289	192	178	178
query84	308	114	102	102
query85	944	437	357	357
query86	349	237	236	236
query87	1999	1950	1824	1824
query88	3642	2714	2683	2683
query89	337	296	257	257
query90	1716	186	181	181
query91	164	158	125	125
query92	99	87	91	87
query93	1001	996	553	553
query94	494	320	296	296
query95	593	347	401	347
query96	668	538	243	243
query97	2438	2402	2314	2314
query98	158	145	141	141
query99	774	766	645	645
Total cold run time: 234610 ms
Total hot run time: 152546 ms

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17627	5723	5567	5567
q2	2106	307	236	236
q3	10267	1377	826	826
q4	4681	479	344	344
q5	7439	788	528	528
q6	188	187	155	155
q7	749	796	605	605
q8	9253	1322	1082	1082
q9	5654	4493	4447	4447
q10	6810	1295	1045	1045
q11	441	274	234	234
q12	633	400	279	279
q13	18064	3039	2378	2378
q14	272	272	244	244
q15	q16	733	722	675	675
q17	1175	743	574	574
q18	7075	6243	6158	6158
q19	1102	956	587	587
q20	392	341	225	225
q21	5511	2510	2506	2506
q22	394	333	284	284
Total cold run time: 100566 ms
Total hot run time: 28979 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6557	6501	6461	6461
q2	729	571	532	532
q3	5552	5755	5474	5474
q4	2084	2151	1621	1621
q5	5842	5726	5567	5567
q6	248	193	151	151
q7	2383	2004	1821	1821
q8	3148	2886	2818	2818
q9	8202	7813	7711	7711
q10	3659	3666	3227	3227
q11	600	440	392	392
q12	671	699	500	500
q13	2748	3071	2368	2368
q14	297	292	257	257
q15	q16	664	678	636	636
q17	7842	7053	6890	6890
q18	13118	12233	13049	12233
q19	897	778	780	778
q20	2185	2192	1946	1946
q21	5914	4801	4874	4801
q22	490	446	416	416
Total cold run time: 73830 ms
Total hot run time: 66600 ms

@hello-stephen

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

query5	4326	601	457	457
query6	445	215	203	203
query7	4806	443	230	230
query8	323	180	169	169
query9	8767	3942	3957	3942
query10	464	312	263	263
query11	6011	3446	3188	3188
query12	143	90	85	85
query13	1247	457	356	356
query14	6541	4811	4519	4519
query14_1	4215	4219	4179	4179
query15	198	197	181	181
query16	933	439	415	415
query17	834	649	529	529
query18	2404	421	301	301
query19	194	153	128	128
query20	79	77	78	77
query21	210	128	111	111
query22	12936	13015	12946	12946
query23	13219	12563	12087	12087
query23_1	12076	12140	12242	12140
query24	7109	816	450	450
query24_1	473	465	469	465
query25	505	396	344	344
query26	1268	249	136	136
query27	2786	428	271	271
query28	4608	1922	1915	1915
query29	1534	576	438	438
query30	298	216	183	183
query31	858	759	653	653
query32	138	88	92	88
query33	502	291	232	232
query34	908	846	498	498
query35	742	768	643	643
query36	814	829	772	772
query37	131	99	91	91
query38	1801	1759	1686	1686
query39	695	718	676	676
query39_1	648	669	674	669
query40	224	111	89	89
query41	66	62	65	62
query42	84	82	86	82
query43	366	379	327	327
query44	1284	701	686	686
query45	186	177	160	160
query46	825	966	562	562
query47	3005	3019	2831	2831
query48	286	308	211	211
query49	567	400	290	290
query50	680	275	206	206
query51	10713	10661	10473	10473
query52	85	88	84	84
query53	183	205	150	150
query54	232	185	175	175
query55	74	73	61	61
query56	240	223	201	201
query57	1621	1594	1590	1590
query58	274	258	250	250
query59	2360	2369	2123	2123
query60	276	234	248	234
query61	149	146	150	146
query62	397	339	285	285
query63	196	163	167	163
query64	2735	926	755	755
query65	3435	3355	3360	3355
query66	1787	424	311	311
query67	20115	20089	19903	19903
query68	2970	1017	614	614
query69	393	294	257	257
query70	941	847	854	847
query71	307	224	211	211
query72	2857	2755	2301	2301
query73	514	525	300	300
query74	4608	4499	4312	4312
query75	2313	2273	1943	1943
query76	2295	1036	628	628
query77	364	402	318	318
query78	9116	8971	8477	8477
query79	969	835	516	516
query80	556	449	372	372
query81	524	326	285	285
query82	577	137	111	111
query83	304	220	185	185
query84	366	118	101	101
query85	792	422	361	361
query86	324	281	222	222
query87	1988	1946	1835	1835
query88	3560	2698	2671	2671
query89	334	293	256	256
query90	1892	171	177	171
query91	161	147	126	126
query92	101	104	88	88
query93	983	1000	567	567
query94	428	307	276	276
query95	594	392	321	321
query96	670	513	234	234
query97	2472	2440	2321	2321
query98	166	148	146	146
query99	791	772	659	659
Total cold run time: 233577 ms
Total hot run time: 151842 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.04
query3	0.27	0.12	0.11
query4	1.61	0.12	0.12
query5	0.24	0.25	0.25
query6	1.18	0.68	0.69
query7	0.04	0.01	0.01
query8	0.05	0.03	0.04
query9	0.42	0.35	0.35
query10	0.57	0.57	0.56
query11	0.20	0.14	0.14
query12	0.19	0.16	0.14
query13	0.49	0.50	0.50
query14	0.98	0.98	0.98
query15	0.63	0.61	0.61
query16	0.33	0.33	0.35
query17	1.11	1.16	1.16
query18	0.23	0.22	0.21
query19	2.08	2.06	2.02
query20	0.02	0.01	0.01
query21	15.51	0.29	0.14
query22	4.44	0.05	0.05
query23	16.25	0.32	0.12
query24	3.14	0.56	0.41
query25	0.11	0.08	0.05
query26	1.25	0.25	0.14
query27	0.06	0.04	0.03
query28	2.25	0.60	0.38
query29	12.51	4.13	3.28
query30	0.28	0.14	0.14
query31	2.78	0.58	0.34
query32	3.23	0.62	0.52
query33	3.18	3.18	3.16
query34	15.51	3.94	3.39
query35	3.33	3.36	3.36
query36	0.54	0.49	0.46
query37	0.09	0.06	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.14	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: 95.64 s
Total hot run time: 24.57 s

### What problem does this PR solve?

Problem Summary: The index builder metadata-preservation tests expected a zero
commit TSO when reading published singleton rowsets with absent or invalid TSO
metadata. Segment readers now reject those reads, so four parameterized cases
failed before exercising index build/drop. Assert the expected internal error
for those inputs while retaining metadata checks before and after build/drop
and value/predicate checks for valid TSOs.

### Release note

None

### Check List (For Author)

- Test: Manual source review; build-support/check-format.sh and git diff --check passed. Attempted ./run-be-ut.sh --run --filter='CommitTso/IndexBuilderCommitTsoTest.*' -j 4; stopped during Java environment validation before compilation.
- Behavior changed: No (test expectations only)
- Does this need documentation: No
@yiguolei

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17594	5645	5550	5550
q2	2105	325	260	260
q3	10252	1377	824	824
q4	4679	475	365	365
q5	7450	803	539	539
q6	186	188	156	156
q7	762	798	613	613
q8	9254	1333	1135	1135
q9	5701	4466	4462	4462
q10	6812	1308	1042	1042
q11	438	251	233	233
q12	637	401	283	283
q13	18073	3094	2405	2405
q14	279	263	248	248
q15	q16	727	732	685	685
q17	1197	741	579	579
q18	7084	6215	6193	6193
q19	1116	953	586	586
q20	381	329	223	223
q21	5842	2481	2588	2481
q22	395	360	299	299
Total cold run time: 100964 ms
Total hot run time: 29161 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6526	6455	6488	6455
q2	730	616	607	607
q3	5502	5723	5273	5273
q4	2151	2162	1565	1565
q5	5835	5592	5680	5592
q6	238	185	146	146
q7	2402	2033	1816	1816
q8	3099	2875	2781	2781
q9	8269	7995	7726	7726
q10	3659	3592	3219	3219
q11	602	405	393	393
q12	658	693	501	501
q13	2760	3099	2364	2364
q14	281	283	262	262
q15	q16	672	686	626	626
q17	7817	6986	6878	6878
q18	13162	12267	13170	12267
q19	917	778	788	778
q20	2185	2217	1988	1988
q21	6024	4889	4935	4889
q22	504	458	442	442
Total cold run time: 73993 ms
Total hot run time: 66568 ms

@hello-stephen

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

query5	4305	585	478	478
query6	416	199	195	195
query7	4804	446	243	243
query8	319	193	170	170
query9	8760	4056	4049	4049
query10	476	338	265	265
query11	6075	3422	3192	3192
query12	153	89	86	86
query13	1264	449	320	320
query14	6543	4846	4528	4528
query14_1	4294	4261	4293	4261
query15	209	202	184	184
query16	950	437	421	421
query17	845	655	538	538
query18	2431	434	316	316
query19	201	168	132	132
query20	81	78	79	78
query21	216	136	113	113
query22	13053	12966	12749	12749
query23	13165	12574	12088	12088
query23_1	12281	12349	12254	12254
query24	7127	850	468	468
query24_1	466	481	487	481
query25	541	431	363	363
query26	1246	265	141	141
query27	2762	441	268	268
query28	4633	1947	1938	1938
query29	1537	590	471	471
query30	297	220	184	184
query31	904	772	655	655
query32	144	92	96	92
query33	508	311	263	263
query34	988	839	492	492
query35	750	759	657	657
query36	795	794	713	713
query37	131	104	92	92
query38	1787	1762	1722	1722
query39	705	707	672	672
query39_1	674	675	674	674
query40	211	114	90	90
query41	65	64	61	61
query42	82	81	83	81
query43	363	374	340	340
query44	1296	691	701	691
query45	175	175	160	160
query46	844	950	562	562
query47	2803	2997	2936	2936
query48	297	303	208	208
query49	552	394	291	291
query50	670	274	206	206
query51	10791	10703	10741	10703
query52	79	80	77	77
query53	186	205	156	156
query54	225	205	177	177
query55	79	67	61	61
query56	217	226	223	223
query57	1616	1589	1556	1556
query58	284	254	239	239
query59	2356	2405	2145	2145
query60	283	236	206	206
query61	143	152	145	145
query62	401	344	285	285
query63	196	163	160	160
query64	2733	933	779	779
query65	3400	3359	3393	3359
query66	1779	405	307	307
query67	20274	20098	19750	19750
query68	3034	997	618	618
query69	376	276	253	253
query70	925	828	815	815
query71	305	225	199	199
query72	2707	2573	2217	2217
query73	518	531	294	294
query74	4596	4457	4316	4316
query75	2315	2288	1972	1972
query76	2307	1005	594	594
query77	352	404	296	296
query78	8914	9119	8470	8470
query79	876	879	526	526
query80	517	412	340	340
query81	528	328	272	272
query82	252	135	114	114
query83	310	201	179	179
query84	316	113	96	96
query85	850	427	365	365
query86	313	241	232	232
query87	2016	1960	1852	1852
query88	3644	2718	2694	2694
query89	330	295	255	255
query90	1795	180	184	180
query91	159	151	124	124
query92	95	88	88	88
query93	1001	1005	569	569
query94	453	294	291	291
query95	599	359	330	330
query96	676	527	236	236
query97	2445	2424	2314	2314
query98	154	152	143	143
query99	777	764	654	654
Total cold run time: 233414 ms
Total hot run time: 152223 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.26	0.12	0.11
query4	1.60	0.11	0.12
query5	0.26	0.22	0.25
query6	1.17	0.70	0.67
query7	0.03	0.00	0.00
query8	0.05	0.04	0.03
query9	0.41	0.36	0.36
query10	0.56	0.54	0.56
query11	0.20	0.14	0.14
query12	0.18	0.14	0.14
query13	0.48	0.50	0.48
query14	0.97	0.96	0.96
query15	0.62	0.60	0.60
query16	0.35	0.31	0.31
query17	1.10	1.17	1.11
query18	0.22	0.20	0.20
query19	2.06	1.99	1.97
query20	0.02	0.01	0.01
query21	15.51	0.27	0.15
query22	4.46	0.05	0.06
query23	16.27	0.32	0.12
query24	2.97	0.61	0.40
query25	0.12	0.06	0.04
query26	1.40	0.25	0.15
query27	0.05	0.04	0.03
query28	2.29	0.62	0.40
query29	12.55	4.15	3.31
query30	0.28	0.14	0.13
query31	2.77	0.58	0.33
query32	3.22	0.60	0.52
query33	3.18	3.29	3.24
query34	15.44	4.02	3.38
query35	3.34	3.35	3.39
query36	0.54	0.48	0.43
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.15	0.15
query41	0.09	0.02	0.02
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 95.55 s
Total hot run time: 24.4 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 83.33% (40/48) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.93% (35469/46103)
Line Coverage 62.21% (401402/645246)
Region Coverage 58.64% (338880/577946)
Branch Coverage 59.52% (155985/262080)

@yiguolei

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.

Complete static review of head 8474e0659562ba9360ecbe54ef398a52af636c2f: all 106 changed paths reviewed. Two complementary full-review scans and one separate risk scan returned NO_NEW_VALUABLE_FINDINGS in round 1. Main-agent validation and the final changed-file/unresolved-candidate sweep are complete. No new inline findings; existing concerns are not reposted.

Recommendation: request changes. Three existing P1 findings independently remain applicable:

  • Ordered compaction: linking tidy singleton inputs preserves physical hidden placeholders while the output becomes a range rowset. COMMIT_TSO can become 0 for snapshot filtering/pruning/statistics; eligible UNIQUE non-MoW VERSION values are affected too.
  • Full-row point queries: full-row JSONB decoding and row-cache hits still return hidden placeholders; the new rowset context reaches only the column-store branch.
  • Row-store lazy fetch: the JSONB branch still bypasses hidden synthesis, and FE eligibility permits these hidden slots.

The existing P2 benchmark constructor finding also remains: benchmark_variant_segment.hpp:1282 uses the deleted default constructor. It is acknowledged without a duplicate inline comment.

Earlier VARIANT compaction/current-root/NESTED-binding findings (4061765403, 4061765408, 4061765417) are addressed: historical UID absence is checked before schema access/type validation, and NESTED receives the current ReadSchema descriptor. Missing-output findings (4061765423, 4061765433, also human thread 4120227936) are addressed; all eight committed goldens contain all 71 referenced qt tags.

The reviewed invocation chain is:

ReadSchema + rowset version/TSO -> logical constant or cached physical reader
                              -> values, predicates, zonemaps and statistics
Direct column-store point/rowid reads -> supplied rowset context
Full-row JSONB and ordered file linking -> existing P1 gaps above

Critical checkpoint conclusions:

Checkpoint Conclusion
Goal and data correctness Constant/default resolution is centralized for projection, pruning and statistics; the three existing hidden-value P1 exceptions prevent approval. Tests exercise the corrected paths but were not executed.
Scope, clarity and reuse Reader capability separation and caller migrations are focused on this refactor. Physical reader/writer test deletion reduces independent legacy coverage.
Concurrency and locks Request constants stay outside the shared physical cache. Existing cache/tablet/transaction locks remain; no additional evidenced race, lock inversion or heavy lock operation found. Cloud bitmap tasks serialize pending metadata mutation.
Lifecycle and static initialization Statistics sinks are retained by their read owners; delayed iterator options are initialized before use. IndexExecContext owns ReadSchema while borrowing its columns. No new ownership cycle or cross-TU initialization dependency found.
Configuration No configuration item added; existing cache, type-check, pruning and aggregate controls remain.
Compatibility and internal APIs No persisted layout change introduced. Internal constructor migration is incomplete in the known optional benchmark. Pre-publish physical reads remain supported; published unknown singleton TSO fails explicitly.
Thrift/protobuf IDs No changed definitions; cross-release field-ID audit is not applicable.
Parallel paths Checked local/cloud publish, fixed/flexible updates, column/row-store reads, horizontal/vertical/segment/link compaction, and typed/sparse/doc/default VARIANT paths. Known row-store/link gaps remain.
Conditions and errors Missing-root, singleton/pending and typed-default checks have concrete failure semantics. Warm physical-cache predicate removal is safe because logical singleton matching rejects nonmatching segments first. No distinct silent failure found.
Test coverage Broad scalar/decimal/temporal/object/complex/lazy/UID/default and negative unit cases, plus eight regression suites. Row-store hidden projection and linked snapshot cases remain uncovered. The prepared-point suite is sequential despite its name.
Expected results All 71 golden tags exist and row values are statically consistent with their queries. Runtime results and golden-generation provenance are unverified.
Observability Existing statistics/binding diagnostics remain; new column debug output includes UID/type/path/default-presence without default contents. No additional required metric identified.
Transactions, persistence and failover Local validation precedes visibility. Cloud eager/lazy/subtransaction commit paths overwrite temporary TSO before persistence; TSO tablets bypass BE fast-publication caches. No EditLog change.
Writes, atomicity and crash behavior Fixed updates reset output hidden metadata to defaults; normal flexible input does not skip-mark those fields. Existing publication/delete-bitmap protocols remain. The known linked-value defect persists.
FE/BE variable propagation No new transmitted variable; current schema is passed inside BE. Column-store bypasses supply existing rowset context; JSONB exceptions are the known findings.
Performance and memory No distinct unbounded allocation, ownership leak or hot-loop regression substantiated. Defaults parse per reader and use existing bulk insertion/dictionary handling; physical readers retain cache reuse.
Other concerns and user focus No additional user focus supplied. All main risk items and subagent points have duplicate, fixed or evidence-backed dismissal dispositions; no unresolved candidate remains.

Validation was static only, as required: no builds, tests, source edits or submodule initialization. This completed review does not claim runtime test passes or verify mixed-version execution empirically. Known P1 IDs are carried in the blocking set instead of duplicated.

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

@eldenmoon

Copy link
Copy Markdown
Member

当前仍存在的三条问题,PR 评论中均已指出:

  1. P1:ordered compaction 后 hidden 列可能返回错误值。 链接 singleton rowset 的 segment 不重写物理占位值;输出变成 range rowset 后直接读盘,TSO/VERSION 可能仍为 0,影响时间旅行、剪枝和 MIN/MAX。读取分支 (line 1078)
  2. P2:整行 row-store 点查和 TopN 回捞返回 hidden 占位值。 JSONB 解码路径没有接入 rowset 的真实 VERSION/TSO;点查注释承认了限制,但仍直接返回错误值。点查路径 (line 104)
  3. P2:VARIANT benchmark 无法编译。 StorageReadOptions() 已删除,benchmark 仍使用默认构造。应改成 StorageReadOptions options(stats)。调用位置 (line 1282)
    VARIANT 重点检查结果:
  • 功能与语义:缺失 root 的值读取与物理元数据查询已分开;ADD、同名 DROP/ADD 的 UID 修正方向正确。NESTED SEARCH 使用当前 ReadSchema,避免绑定已删除的旧列。
  • 兼容性:没有发现新增存储格式或 FE/BE 协议变化;旧数据缺失 sparse stream 时补空 MAP,doc compaction 缺失 bucket 时补 nullable VARIANT,调用链一致。
  • 性能与可维护性:常量 reader 不进入共享缓存,避免请求间 VERSION/TSO 串值;接口职责更清楚。未做性能测量。
  • 测试:有针对性的 BE 单测;新增 8 个回归 suite 的 81 个 qt 标签均有输出块。仍缺少 VARIANT schema evolution 后完整 compaction 的端到端覆盖。

@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

@yiguolei

Copy link
Copy Markdown
Contributor Author

order compaction 在开了tso 之后会禁用的。 那个行存的隐藏列之前是错误的,目前还不知道怎么搞行存的时候的隐藏列。

@yiguolei
yiguolei merged commit 37c805f into apache:master Oct 13, 2026
38 of 39 checks passed
@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Oct 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

airborne12 added a commit to airborne12/apache-doris that referenced this pull request Oct 13, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#68758

Problem Summary: Bring the branch up to date with master 3c060af, which the
PR could no longer merge with. apache#65684 (unify const column read method) edits
function_search.cpp and variant_inverted_index_search.cpp at the paths this PR
moved to exprs/function/search/; the other upstream changes merge cleanly.

The change is ported to the moved files: SEARCH and its NESTED evaluator take
the bound nested TabletColumn instead of the column-id map, and the evaluator
reads the VARIANT root through that column. The SEARCH tests and the SNII search
benchmark this PR added pass nullptr for the column, as master's tests do, and
the variant reader test master changed includes the moved SEARCH headers.

### Release note

None

### Check List (For Author)

- Test: Unit Test. 1,772 ASAN tests in 119 suites ran, including SEARCH,
  NESTED search, VSearchExpr and the suites of test files changed on both sides:
  1,769 pass and 3 skip by their own conditions. The merged SEARCH sources
  compile with GCC, and the merged-tree format preflight passes.
- Behavior changed: No additional query engine behavior changes.
- Does this need documentation: No
mrhhsg added a commit to mrhhsg/doris that referenced this pull request Oct 13, 2026
…n test

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Rebasing onto master picked up apache#65684, which deleted
`DefaultValueColumnIterator` and moved default-value parsing into
`Segment::get_default_value_field`, together with a new
`constant_column_iterator_test.cpp`. That file's
`NonEmptyComplexTextDefaultsAreRejected` asserted the pre-PR restriction that
a non-empty ARRAY/MAP/STRUCT literal default is rejected
(`NOT_IMPLEMENTED_ERROR`), which no longer holds once this branch's earlier
commits teach the complex SerDes to parse such literals. Replace it with
`NonEmptyComplexTextDefaultsAreParsed`, asserting that `[1]`, `{"k":7}`, and a
positional struct literal are parsed into the matching typed `Field` through
`Segment::get_default_value_field`.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - `./run-be-ut.sh --run --filter="ConstantColumnIteratorTest.*" -j 32` (34 tests, all pass)
- Behavior changed: No (test-only; the behavior change itself is in the earlier commits)
- Does this need documentation: No
mrhhsg added a commit to mrhhsg/doris that referenced this pull request Oct 13, 2026
… unified constant column reader

### What problem does this PR solve?

Issue Number: None

Related PR: apache#68125

Problem Summary: master now resolves a single-version segment's `__DORIS_VERSION_COL__`, `__DORIS_COMMIT_TSO_COL__` and `__DORIS_BINLOG_TSO__` inside `Segment` with a request-scoped `ConstantColumnReader` (apache#65684): predicate and expression zone maps, MIN/MAX statistics, Bloom filter, page zone map and inverted index pruning all see the logical value, the reader never enters the UID-keyed cache, and `SegmentIterator` no longer rewrites those columns after the read. That replaces the segment-side part of this change, so the rebase keeps only the paths `Segment` does not cover: point-query and row-ID direct reads of the row store, the online index build's read options and replacement metadata, ordered link compaction and the JSONB decode row count.

This commit adapts what is left to the unified reader. `get_read_time_hidden_column_value` loses the `read_row_binlog` parameter that only `SegmentIterator` used to need: direct reads answer VERSION/COMMIT_TSO of a single-version rowset without opening the segment and leave every other column, BINLOG_TSO included, to `Segment`, which synthesizes it from the same rowset version and commit TSO the row-ID fetcher and the point query now put into their `StorageReadOptions`. The point-query comment that declared read-time hidden columns unsupported on the full-row-store fast path is replaced by what `Reusable::init` does: it takes them out of the JSONB decode and the row cache.

The segment-level unit tests of this change are rebuilt on the master fixture. They still write the physical placeholder (0 or NULL) under a Bloom filter, page zone maps and an inverted index, and assert that a single-version read returns the rowset value for predicates, expression zone maps and MIN/MAX pushdown, that no physical index filters rows, and that the constant reader neither reuses nor pollutes the cached physical reader. Two expectations follow the unified reader: a forced or regular MIN/MAX over VERSION or BINLOG_TSO now runs on the statistics iterator with the read-time constant instead of falling back to `SegmentIterator`, and a BINLOG_TSO read with an unassigned commit TSO is rejected by `Segment` rather than answered with 0, which master already covers.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - `SegmentIteratorExprZonemapTest.*`, `PointQueryHiddenColumnTest.*`, `BlockSerializeTest.*`, `OrderedDataCompactionTest.*` and `IndexBuilderTest.ReplacementRowsetKeepsPublishTimeMetadata` with the adapted helper.
- Behavior changed: No
- Does this need documentation: No
LuciferYang added a commit to LuciferYang/doris that referenced this pull request Oct 15, 2026
…substitutes their zone maps

apache#65684 reads the hidden version/TSO columns of a single-version segment through a
ConstantColumnReader whose zone map is the substituted value, so expr zone-map
pruning no longer sees the on-disk placeholder. Remove is_read_time_substituted_col
and keep the regression, plus a miss case that pruning on the real value handles.

Co-Authored-By: Claude Code <[email protected]>
mrhhsg added a commit to mrhhsg/doris that referenced this pull request Oct 17, 2026
… unified constant column reader

### What problem does this PR solve?

Issue Number: None

Related PR: apache#68125

Problem Summary: master now resolves a single-version segment's `__DORIS_VERSION_COL__`, `__DORIS_COMMIT_TSO_COL__` and `__DORIS_BINLOG_TSO__` inside `Segment` with a request-scoped `ConstantColumnReader` (apache#65684): predicate and expression zone maps, MIN/MAX statistics, Bloom filter, page zone map and inverted index pruning all see the logical value, the reader never enters the UID-keyed cache, and `SegmentIterator` no longer rewrites those columns after the read. That replaces the segment-side part of this change, so the rebase keeps only the paths `Segment` does not cover: point-query and row-ID direct reads of the row store, the online index build's read options and replacement metadata, ordered link compaction and the JSONB decode row count.

This commit adapts what is left to the unified reader. `get_read_time_hidden_column_value` loses the `read_row_binlog` parameter that only `SegmentIterator` used to need: direct reads answer VERSION/COMMIT_TSO of a single-version rowset without opening the segment and leave every other column, BINLOG_TSO included, to `Segment`, which synthesizes it from the same rowset version and commit TSO the row-ID fetcher and the point query now put into their `StorageReadOptions`. The point-query comment that declared read-time hidden columns unsupported on the full-row-store fast path is replaced by what `Reusable::init` does: it takes them out of the JSONB decode and the row cache.

The segment-level unit tests of this change are rebuilt on the master fixture. They still write the physical placeholder (0 or NULL) under a Bloom filter, page zone maps and an inverted index, and assert that a single-version read returns the rowset value for predicates, expression zone maps and MIN/MAX pushdown, that no physical index filters rows, and that the constant reader neither reuses nor pollutes the cached physical reader. Two expectations follow the unified reader: a forced or regular MIN/MAX over VERSION or BINLOG_TSO now runs on the statistics iterator with the read-time constant instead of falling back to `SegmentIterator`, and a BINLOG_TSO read with an unassigned commit TSO is rejected by `Segment` rather than answered with 0, which master already covers.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - `SegmentIteratorExprZonemapTest.*`, `PointQueryHiddenColumnTest.*`, `BlockSerializeTest.*`, `OrderedDataCompactionTest.*` and `IndexBuilderTest.ReplacementRowsetKeepsPublishTimeMetadata` with the adapted helper.
- Behavior changed: No
- Does this need documentation: No
mrhhsg added a commit to mrhhsg/doris that referenced this pull request Oct 19, 2026
…n test

### What problem does this PR solve?

Issue Number: None

Related PR: None

Problem Summary: Rebasing onto master picked up apache#65684, which deleted
`DefaultValueColumnIterator` and moved default-value parsing into
`Segment::get_default_value_field`, together with a new
`constant_column_iterator_test.cpp`. That file's
`NonEmptyComplexTextDefaultsAreRejected` asserted the pre-PR restriction that
a non-empty ARRAY/MAP/STRUCT literal default is rejected
(`NOT_IMPLEMENTED_ERROR`), which no longer holds once this branch's earlier
commits teach the complex SerDes to parse such literals. Replace it with
`NonEmptyComplexTextDefaultsAreParsed`, asserting that `[1]`, `{"k":7}`, and a
positional struct literal are parsed into the matching typed `Field` through
`Segment::get_default_value_field`.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - `./run-be-ut.sh --run --filter="ConstantColumnIteratorTest.*" -j 32` (34 tests, all pass)
- Behavior changed: No (test-only; the behavior change itself is in the earlier commits)
- Does this need documentation: No
csun5285 pushed a commit that referenced this pull request Oct 20, 2026
…sion zone map pruning (#67774)

Zone map pruning only fires when a predicate compares a column against a
constant. A predicate over two columns of the same table, `WHERE a != b`
or `WHERE a < b`, never participates, so every segment and every Parquet
row group is read even when the two columns' min/max ranges make the
predicate unsatisfiable.

Everything on the path except the leaf already supports this.
`ZoneMapEvalContext` is keyed per slot and the segment-level and Parquet
row-group-level callers already populate an entry for every slot a
compound expression references, which is why cross-column AND / OR
compounds prune today. What was missing is the comparison operator's
capability gate: it accepts one slot plus one literal and nothing else,
so a two-slot comparison is dropped before evaluation.

This PR adds the slot-vs-slot shape next to the existing slot-vs-literal
one and gives the six always-false tests a single implementation shared
by both. With the left operand's non-null values in `[lmin, lmax]` and
the right operand's in `[rmin, rmax]`, the comparison cannot be TRUE for
any row when:

| operator | condition |
| --- | --- |
| `=` | `lmin > rmax \|\| rmin > lmax` |
| `!=` | `lmin == lmax && rmin == rmax && lmin == rmin` |
| `<` | `lmin >= rmax` |
| `<=` | `lmin > rmax` |
| `>` | `rmin >= lmax` |
| `>=` | `rmin > lmax` |

Substituting the degenerate range `[literal, literal]` for the right
operand reduces each row to the slot-vs-literal test already in the
tree, so the single-column path keeps its exact current behaviour. The
existing tests passing unchanged is the mechanical check on that.

`kNoMatch` means "no row in this zone can make the conjunct TRUE", not
"every row is FALSE", so NULL does not weaken these rules: a WHERE
conjunct discards FALSE and NULL alike, and the bounds summarize exactly
the non-null values. A column with no non-null value at all makes the
comparison NULL on every row and returns `kNoMatch` unconditionally.

One trap for reviewers: `can_evaluate` must not be widened. It is shared
by dictionary filtering and by `can_evaluate_equality`, and both
dereference `extract_slot_and_literal` behind a `DORIS_CHECK`, so
accepting a slot-vs-slot expression there would abort. This PR adds a
separate `can_evaluate_slot_slot` and ORs it into
`can_evaluate_zonemap_filter` only; a unit test pins that down.

Three deliberate limitations: a cast around either operand is rejected,
because the bounds are raw stored values and the optimizer inserts a
cast whenever the two column types differ; on Parquet a floating column
pair does not prune at all, because Parquet bounds omit NaN without
reporting how many were skipped, which would flip the `!=` rule; and
VARIANT, JSONB, ARRAY/MAP/STRUCT and aggregate-state columns are not
admitted, because `Field` compares any two of their values as equal, and
a segment types a VARIANT path slot by its inferred leaf type, which the
expression's VARIANT type would not match.

The v1 Parquet reader is excluded from slot-vs-slot pruning entirely,
because that reader is being removed. `_process_expr_zonemap_filter`
restricts itself to single-slot conjuncts (the v1 page path already
required a single column), so column-vs-column pruning runs on native
segments and the v2 Parquet reader only. This also moots the v1-specific
slot-vs-slot review threads here (malformed fixed-width statistics,
VARBINARY mapping, and the adjusted-UTC timestamp rollback tracked by
the now-closed #68118). The v1 single-column path keeps the
decimal-domain and NaN fixes described next.

A limitation on the v1 single-column path came out of review.
`ParquetPredicate::parse_min_max_value` decodes v1 bounds in the file's
own logical type, while `_type_matches` compares only primitive types,
so a file DECIMAL at scale 3 and a table DECIMAL at scale 2 both passed
and their unscaled payloads were then compared as if they shared a
domain. The v1 reader now leaves the zone map out unless the file and
table types agree, which is the check `format_v2` already applies. That
costs pruning in three narrow places, all of them correctness-driven: a
DATETIMEV2 or TIMESTAMPTZ column whose declared scale differs from the
Parquet unit loses expression zone map pruning entirely, which is the
widest practical case and matches the policy already written down for
the slot-vs-literal path; a decimal pair differing only in precision is
domain-identical yet also skipped; and IS NULL / IS NOT NULL pruning
goes with it, because a zone map carrying only the null flags leaves
min/max at `TYPE_NULL` and any range predicate would then fail
`range_stats_usable_for_zonemap`'s type check.

This also fixes a bug it uncovered. The flag that carries "these bounds
came from Parquet, so a hidden NaN is possible" was only ever set in the
format_v2 reader; the v1 reader assigned the slot's data type and left
the flag at its default, so the NaN guard never fired on that path. Two
DOUBLE columns whose Parquet bounds both read `[1.0, 1.0]` were then
pruned by the `!=` rule even when one of them hid a NaN, dropping a row
that should have come back. The rule now lives in one setter on
`SlotZoneMap` that assigns the type and the flag together, and all three
Parquet call sites go through it.

The hidden version and TSO columns need no special handling here: since
#65684, a single-version segment reads them through a
`ConstantColumnReader` whose zone map holds the substituted value, so
pruning sees the same value the rows come back with.
csun5285 added a commit to csun5285/doris that referenced this pull request Nov 4, 2026
…cuit

### What problem does this PR solve?

Issue Number: None

Related PR: apache#65684, apache#68097

Problem Summary:

A singleton rowset stores only a placeholder for `__DORIS_VERSION_COL__` and
`__DORIS_COMMIT_TSO_COL__`; the real value comes from the rowset metadata at read time. The
short-circuit point query reads the JSONB row store, which holds that placeholder, and the BE
fast path deliberately does not resolve these columns (see `point_query_executor.cpp`). So on a
MOW table with `store_row_column = true`:

```sql
CREATE TABLE b (id INT NOT NULL, v INT) UNIQUE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES ('replication_num'='1', 'enable_unique_key_merge_on_write'='true',
            'store_row_column'='true', 'changelog.enable'='true');
INSERT INTO b VALUES (1, 7), (2, 8);
SELECT __DORIS_VERSION_COL__, __DORIS_COMMIT_TSO_COL__, v FROM b WHERE id = 1;
-- before: 0, 0, 7          after: 2, <commit tso>, 7
```

The columns can be named explicitly without `show_hidden_columns`, and `SELECT *` returns them
once `show_hidden_columns` is on. The regular scan path resolves them from the rowset correctly.

`LogicalResultSinkToShortCircuitPointQuery` now keeps any query that reads a hidden column on
the regular scan: it checks the project's input slots for `sink(project(filter(scan)))` and the
sink's input slots for `sink(filter(scan))`. Queries reading only visible columns keep the
short circuit, including a plain `SELECT *` (hidden columns are not expanded by default) and
server-side prepared statements.

### Release note

Fix point queries on row-store MOW tables returning 0 for `__DORIS_VERSION_COL__` and
`__DORIS_COMMIT_TSO_COL__`. Point queries that read hidden columns no longer use the
short-circuit path.

### Check List (For Author)

- Test: Regression test / Unit Test / Manual test
    - FE UT `ShortCircuitPointQueryTest` (10 cases, 2 new) passes.
    - New regression test `test_short_circuit_rowset_hidden_columns` fails on the unfixed FE
      (explain still shows SHORT-CIRCUIT) and passes with the fix; all 20 suites under
      `point_query_p0` pass.
    - Manual, local coupled cluster: the point query returns version 2 and the real commit TSO
      (default short circuit, `enable_short_circuit_query_access_column_store=false`, and
      server-side prepared statements); prepared statements reading only visible columns, and
      a plain `SELECT *`, still take the short circuit.
- Behavior changed: Yes. Point queries that read a hidden column (explicitly, or through
  `SELECT *` with `show_hidden_columns = true`) run as a regular scan instead of the short
  circuit. With `show_hidden_columns = true` such a query now also returns a row deleted by
  the delete sign, as a regular scan already does.
- Does this need documentation: No

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants