Skip to content

Storages: introduce trim min-max index for DATE/DATETIME/TIMESTAMP rough set filtering - #10981

Open
JaySon-Huang wants to merge 7 commits into
pingcap:masterfrom
JaySon-Huang:jayson/trim_datetime_minmax_index
Open

Storages: introduce trim min-max index for DATE/DATETIME/TIMESTAMP rough set filtering#10981
JaySon-Huang wants to merge 7 commits into
pingcap:masterfrom
JaySon-Huang:jayson/trim_datetime_minmax_index

Conversation

@JaySon-Huang

@JaySon-Huang JaySon-Huang commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

backport #10982 to master branch

What problem does this PR solve?

Issue Number: close #10989

Problem Summary:

Applications sometimes use a far-future temporal value, such as 2100-01-01 00:00:00, as a sentinel for an unsettled record while normal DATE, DATETIME, or TIMESTAMP values remain concentrated in a recent range.

Although such sentinels are sparse, they pollute the ordinary pack-level min-max index. With 8,192 rows per pack and an independently distributed sentinel probability of 1/10000, about 55.9% of packs contain at least one sentinel. Their ordinary maximum is extended to 2100, so narrow recent-time predicates cannot exclude those packs and must read and filter more data.

The ordinary min-max index cannot simply ignore a particular application value because queries may intentionally access it. TiFlash needs an optional temporal index that improves pruning for eligible predicates without changing SQL semantics or weakening the ordinary fallback path.

What is changed and how it works?

Storages: introduce trim min-max index for DATE/DATETIME/TIMESTAMP rough set filtering

This PR adds an optional pack-level trim min-max index for user DATE, DATETIME, and TIMESTAMP columns in DeltaMerge DMFile V3 / MetaV2.

The effective interval for format V1 is the half-open range [1900-01-01 00:00:00, 2099-12-01 00:00:00). The ordinary min-max index remains unchanged and continues to cover every non-NULL, non-deleted value. The trim index covers only values inside the effective interval and records directional per-pack marks when values are trimmed below or above it.

Write path and disk format

  • Build the ordinary and trim min-max indexes in the same pack scan when dt_enable_trim_minmax=true.
  • Keep the ordinary .idx payload and its byte format unchanged.
  • Persist trim data in a separate deterministic <column-stream>.trim.idx merged subfile only when the DMFile contains trimmed outliers.
  • Store format version, the type-packed lower/upper bounds, and pack count in the independent optional protobuf field ColumnStat.trim_minmax_index = 105.
  • Reuse the existing min-max pack-mark byte: bit 0 is has_null, bit 1 is has_trimmed_low, and bit 2 is has_trimmed_high.
  • Treat logical metadata absence or mismatch as a soft fallback, while preserving the existing hard-failure policy for impossible merged-file geometry, checksum failure, or corrupt/reserved pack-mark bits.

Query-domain analysis and read path

  • Normalize supported temporal predicates into a query domain, including eligible Equal, IN, bounded ranges, and one-sided ranges.
  • Merge same-column top-level AND range bounds without sharing eligibility across OR or NOT branches.
  • Select trim min-max per predicate and per DMFile using the bounds persisted by that DMFile. A different predicate on the same column can still load and use the ordinary min-max index.
  • Convert TIMESTAMP constants through the request time zone into UTC-packed values before eligibility checks; compare DATETIME and DATE using calendar-value semantics.
  • Conservatively correct trim rough-check results using the directional pack marks, including None -> Some and All -> Some when trimmed values can invalidate the uncorrected result.
  • Fall back to ordinary min-max when the switch is disabled, metadata or the trim subfile is absent, the version or pack count is unsupported, the predicate is outside the persisted interval, or the expression shape is not supported.

Configuration and observability

  • Add the unified dt_enable_trim_minmax setting, defaulting to false. It controls both generation and query use of trim min-max indexes.
  • Add Prometheus counters for trim selection/fallback reasons, trim rough-check All/Some/None/AllNull results, and conservative correction counts.
  • Do not add SQL syntax or DDL. The feature is transparent to SQL results and is enabled only through the TiFlash profile setting.

Compatibility

  • Old readers ignore protobuf field 105 and the additional merged subfile, then continue using the unchanged ordinary min-max index.
  • New and old DMFiles can coexist; each predicate independently selects trim or falls back to ordinary min-max for each DMFile.
  • An old-version metadata rewrite may drop field 105. A new reader then ignores the orphan trim subfile and safely falls back to ordinary min-max.
  • Downgrading to a binary that predates dt_enable_trim_minmax requires removing that unknown setting from tiflash.toml before startup.

See the design document for the correctness proof, format details, and rollout constraints.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

Unit coverage includes:

  • trim pack marks, protobuf round trips, unknown-field compatibility, metadata validation/fallback reasons, file naming, and cache-key separation;
  • ordinary/trim index construction in one pass, NULL/delete/empty packs, invalid masks, persistence only when outliers exist, and disabled-write behavior;
  • DATE, fractional DATETIME, and TIMESTAMP packed bounds and time-zone conversion;
  • query-domain eligibility and normalization, inclusive/exclusive and empty ranges, per-column parse failures, unsupported/NULL-sensitive shapes, mixed AND/OR trees, and per-predicate eligibility;
  • the complete RSResult correction matrix, trim/ordinary pack-filter selection, missing attribute types, and DMFile MetaV2 persistence/drop behavior.

The PR unit-test and integration-test CI jobs pass.

Manual validation used the same generated 500-million-row data set in two tables with different import/DMFile layouts: test.bc_bet_records_500m and test.bc_bet_records_500m_stream.

  1. Correctness: Ran Q01-Q33 through TiKV, TiFlash with trim disabled, and TiFlash with trim enabled. Q01-Q31 compare exact row counts and checksums, Q32 compares grouped rows, and Q33 compares a deterministic complete 100-row TopN result. All 133 normalized result rows matched exactly. The enabled run exercised trim selection, outside-range fallback, All/Some/None, none_to_some, and all_to_some; the disabled run exercised only fallback_disabled. See the 500M correctness report.
  2. Performance: For each table, ran one warm-up and five measured P01-P06 suites per setting, then disabled trim again for three reverse-order confirmation suites. The complete-suite median improved by 24.1% (2,125.5 ms -> 1,613.2 ms) on the regular-import table and by 24.9% (2,066.3 ms -> 1,552.7 ms) on the stream-import table. P04 physical scanned rows decreased by 52.4% and 52.6%, respectively. The P05 outside-range control had unchanged scanned rows and no meaningful benefit, as expected. See the 500M benchmark report.
  3. Downgrade read compatibility: After newer code generated and read trim indexes, downgraded the TiFlash node to 5d56de051244ac7c893de5ac029f0013098f95dc, removed the unknown dt_enable_trim_minmax setting, and forced both tables through TiFlash MPP. Both 500-million-row invariant scans and complete Q01-Q33 suites passed with zero differences from the TiKV oracle, and no post-start DMFile/index/checksum/corruption error was logged. This validates read compatibility only; it does not cover old-version writes or metadata rewrites. See the downgrade report.

The data generator, distributions, import paths, and SQL suites are documented in the dbgen trim min-max example.

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

The feature is disabled by default. When enabled, DMFile writing performs additional min/max comparisons and may persist one optional trim subfile per eligible temporal column with outliers. Eligible reads load the trim index in preference to ordinary min-max; fallback queries retain the ordinary path.

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Introduce trim min-max index to enhance tiflash's table scan filtering performance when DATE/DATETIME/TIMESTAMP defaults to future times

Summary by CodeRabbit

  • New Features
    • Added optional trim min-max indexing for DATE, DATETIME, and TIMESTAMP columns.
    • Enabled eligible temporal filters, including equality, IN, and range predicates, to use optimized index data.
    • Added the dt_enable_trim_minmax setting, disabled by default.
    • Added safe fallback to standard indexes for unsupported queries or unavailable metadata.
  • Monitoring
    • Added metrics for index selection, filtering results, corrections, and rough-set pack counts.
  • Documentation
    • Added design documentation covering behavior, compatibility, and rollout considerations.

Signed-off-by: JaySon-Huang <tshent@qq.com>
Add ColumnStat field 105, pack-mark accessors, trim subfile naming, and
default-off read/write settings so Readers can safely ignore or fall back
without changing ordinary min-max behavior.
Build ordinary and trim indexes in one pack scan for V3 MyDate/MyDateTime
columns, and persist .trim.idx only when trimmed outliers exist.
Normalize temporal ranges into DateRange, select trim indexes per DMFile stored E, and apply conservative low/high flag corrections in roughCheck.
@ti-chi-bot

ti-chi-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note-none Denotes a PR that doesn't merit a release note. labels Jul 15, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign lidezhu, likidu for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds optional trim min-max indexes for temporal columns. It persists trim metadata and subfiles, normalizes eligible predicates, selects trim indexes during reads, corrects rough-check results, and falls back to ordinary indexes when required.

Changes

Temporal trim min-max filtering

Layer / File(s) Summary
Trim-index contracts and pack metadata
dbms/src/Storages/DeltaMerge/Index/*, dbms/src/Storages/DeltaMerge/File/ColumnStat.h, dbms/src/Storages/DeltaMerge/dtpb/dmfile.proto
Adds temporal trim-index metadata, pack-mark flags, fallback reasons, and trim-aware index structures.
DMFile trim-index persistence
dbms/src/Storages/DeltaMerge/File/DMFile*, dbms/src/Storages/DeltaMerge/File/DMFileWriter*
Writes eligible temporal trim indexes to separate .trim.idx subfiles and persists their metadata.
Temporal query domains and rough checks
dbms/src/Storages/DeltaMerge/Filter/*, dbms/src/Storages/DeltaMerge/FilterParser/*
Normalizes supported temporal predicates, requests trim indexes, and corrects rough-check results for trimmed values.
Read-path selection and configuration
dbms/src/Storages/DeltaMerge/File/DMFilePackFilter*, dbms/src/Storages/DeltaMerge/File/DMFileBlock*, dbms/src/Storages/DeltaMerge/Segment.cpp
Propagates the setting and read tags, validates trim payloads, selects trim or ordinary indexes, and records metrics.
Validation and design specification
dbms/src/Storages/DeltaMerge/Index/tests/*, dbms/src/Storages/tests/gtest_filter_parser.cpp, docs/design/*
Adds coverage for persistence, normalization, fallback behavior, rough-check semantics, and temporal edge cases. Documents the design and rollout boundaries.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • pingcap/tiflash#10982: Implements the same trim min-max feature across overlapping storage, filtering, settings, metrics, and index code.

Sequence Diagram(s)

sequenceDiagram
  participant Query
  participant FilterParser
  participant DMFilePackFilter
  participant TrimMinMaxIndex
  participant OrdinaryMinMaxIndex
  Query->>FilterParser: parse temporal predicates
  FilterParser->>DMFilePackFilter: provide trim-preferred index requests
  DMFilePackFilter->>TrimMinMaxIndex: validate and load trim payload
  alt Trim index is eligible
    TrimMinMaxIndex-->>DMFilePackFilter: return trim pack marks and bounds
  else Trim index is unavailable or ineligible
    DMFilePackFilter->>OrdinaryMinMaxIndex: load ordinary index
    OrdinaryMinMaxIndex-->>DMFilePackFilter: return ordinary rough-check data
  end
Loading

Poem

A rabbit found dates in a burrowed row,
Trimmed the extremes where sentinels grow.
Packs marked low and packs marked high,
Kept ordinary bounds standing by.
Safe fallbacks hopped when checks could not tell—
“Good filtering,” said Bunny, “all is well!”

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements the main index and fallback objectives, but its date interval and unified setting conflict with linked issue requirements. Align the effective interval with the issue and provide independent read and write controls for rolling upgrades and rollback.
Docstring Coverage ⚠️ Warning Docstring coverage is 13.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: trim min-max indexes for temporal rough-set filtering.
Description check ✅ Passed The description follows the template and provides the problem, implementation, tests, side effects, documentation, and release note.
Out of Scope Changes check ✅ Passed The changes are related to trim min-max indexing, including implementation, compatibility handling, tests, metrics, and design documentation.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ti-chi-bot ti-chi-bot Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jul 15, 2026
@JaySon-Huang
JaySon-Huang force-pushed the jayson/trim_datetime_minmax_index branch from dd5bd76 to d142197 Compare July 22, 2026 07:58
Prevent same-column OR branches from incorrectly sharing a loaded trim
index when only some query domains are trim-eligible, avoiding false
None pack pruning.
Gate trim range normalization behind dt_enable_trim_minmax_read, keep
original operators when bounds cannot be parsed, and never return All
for an empty DateRange domain.
@JaySon-Huang
JaySon-Huang force-pushed the jayson/trim_datetime_minmax_index branch from d142197 to 0a5609f Compare July 22, 2026 08:49
@ti-chi-bot ti-chi-bot Bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. labels Jul 22, 2026
@JaySon-Huang JaySon-Huang changed the title [WIP] Storages: introduce trim min-max index for DATE/DATETIME/TIMESTAMP rough set filtering Jul 22, 2026
M(SettingFloat, dt_bg_gc_delta_delete_ratio_to_trigger_gc, 0.3, "Trigger segment's gc when the ratio of delta delete range to stable exceeds this ratio.") \
M(SettingBool, dt_enable_logical_split, false, "Enable logical split or not in DeltaTree Engine.") \
M(SettingBool, dt_enable_rough_set_filter, true, "Whether to parse where expression as Rough Set Index filter or not.") \
M(SettingBool, dt_enable_trim_minmax, false, "Whether to generate and use trim min-max index for DATE/DATETIME/TIMESTAMP Rough Set filtering.") \

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

default to false in master branch

Record trim min-max metrics only on Query reads after the cherry-pick
left an undeclared read_tag reference on this branch's load() API.
@JaySon-Huang
JaySon-Huang marked this pull request as ready for review August 10, 2026 06:31
@ti-chi-bot ti-chi-bot Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (8)
dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp (2)

141-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use UInt8 for pack-mark loop variables.

  • dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp#L141-L141: Replace unsigned char pack_mark with UInt8 packMark.
  • dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.cpp#L285-L285: Replace unsigned char pack_mark with UInt8 packMark.

As per coding guidelines, use explicit width types from dbms/src/Core/Types.h.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp` at line 141, Replace the
pack-mark loop variable with the explicit UInt8 type and packMark naming in
MinMaxIndex.cpp:141-141 and TrimMinMaxIndex.cpp:285-285, ensuring the relevant
code uses the UInt8 definition from Core/Types.h.

Source: Coding guidelines


117-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use DB::Exception for pack validation errors.

Lines 117-122 add RUNTIME_CHECK failure paths. Replace them with throw Exception(ErrorCodes::<code>, "… {}", …);. Use an error code declared in dbms/src/Common/ErrorCodes.cpp and errors.toml.

As per coding guidelines, use DB::Exception for error handling with the fmt-style constructor.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp` around lines 117 - 122,
Replace the pack validation RUNTIME_CHECK calls in the MinMaxIndex validation
flow with DB::Exception using the fmt-style constructor. Use an existing error
code declared in ErrorCodes.cpp and errors.toml, preserve the invalid pack_mark
and missing-column conditions, and include the relevant values in each exception
message.

Source: Coding guidelines

dbms/src/Storages/DeltaMerge/File/ColumnStat.h (1)

49-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Use camelCase for new C++ identifiers.

  • dbms/src/Storages/DeltaMerge/File/ColumnStat.h#L49-L50: Rename trim_minmax_index to a camelCase C++ member. Keep the generated protobuf accessor unchanged.
  • dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.h#L43-L174: Rename new fields and parameters such as pack_mark, format_version, and expected_pack_count.
  • dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.h#L35-L171: Rename new fields and parameters such as pack_marks, has_value, and allowed_mask.
  • dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp#L109-L147: Rename the matching implementation identifiers.
  • dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.cpp#L100-L291: Rename new local variables and parameters to camelCase.
  • dbms/src/Storages/DeltaMerge/File/DMFileWriter.h#L120-L158: Rename trim_minmaxes, trim_lower, trim_upper, and enable_trim_minmax.

As per coding guidelines, method and variable names should use camelCase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/File/ColumnStat.h` around lines 49 - 50, Rename
the newly introduced C++ fields, parameters, and locals to camelCase while
preserving generated protobuf accessor names: update trim_minmax_index in
dbms/src/Storages/DeltaMerge/File/ColumnStat.h (lines 49-50), identifiers
including pack_mark, format_version, and expected_pack_count in
dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.h (lines 43-174), pack_marks,
has_value, and allowed_mask in dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.h
(lines 35-171), their matching implementations in
dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp (lines 109-147) and
dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.cpp (lines 100-291), and
trim_minmaxes, trim_lower, trim_upper, and enable_trim_minmax in
dbms/src/Storages/DeltaMerge/File/DMFileWriter.h (lines 120-158). Update all
references consistently.

Source: Coding guidelines

docs/design/2026-07-14-trim-minmax-for-date-types.md (1)

343-393: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the sketch and the field-number wording with the implementation.

Two documentation accuracy gaps:

  • The sketch at lines 346-355 names the wrapper TrimMinMaxIndex with a single minmax member. The implementation uses TrimRSIndex with type, minmax, and meta members, as shown in dbms/src/Storages/DeltaMerge/Index/tests/gtest_dm_trim_minmax_index.cpp lines 1036-1043.
  • Line 393 states the field number will be assigned during implementation. Lines 371, 671, 724, and 973 state field 105 definitively. Remove the deferral sentence now that 105 is fixed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/2026-07-14-trim-minmax-for-date-types.md` around lines 343 - 393,
Update the documentation sketch to use the implemented TrimRSIndex name and
reflect its type, minmax, and meta members instead of the simplified
TrimMinMaxIndex shape. Also replace the statement that the protobuf field number
will be assigned during implementation with a definitive reference to field 105,
keeping the existing ColumnStat.trim_minmax_index contract unchanged.
dbms/src/Storages/tests/gtest_filter_parser.cpp (1)

788-791: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the timezone after the test mutates it.

Line 791 sets the context timezone to America/Chicago and never restores it. If TiFlashTestEnv::getContext() returns a shared context, the setting leaks into later tests in the same binary. GoogleTest does not guarantee test order, so this creates an ordering dependency. Save the previous timezone and restore it at the end of the test, or reset it in TearDown.

♻️ Proposed restore using a scope guard
     const auto & time_zone_utc = DateLUT::instance("UTC");
     auto ctx = TiFlashTestEnv::getContext();
     auto & timezone_info = ctx->getTimezoneInfo();
+    const TimezoneInfo saved_timezone_info = timezone_info;
+    SCOPE_EXIT({ timezone_info = saved_timezone_info; });
     timezone_info.resetByTimezoneName("America/Chicago");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/tests/gtest_filter_parser.cpp` around lines 788 - 791,
Update the test that uses timezone_info.resetByTimezoneName to capture the
existing timezone before switching to America/Chicago, then restore that
timezone when the test exits, including early-return or failure paths; use a
scope guard or equivalent cleanup tied to the test’s lifetime.
dbms/src/Storages/DeltaMerge/Filter/DateQueryDomain.cpp (1)

362-384: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the emitted DateRange order deterministic.

bounds is a std::unordered_map<ColId, BoundAccumulator>. The loop appends one DateRange per column in unspecified order. When a query has two or more temporal columns, the resulting And children order can vary between runs and between builds. This changes toDebugString() and toJSONObject() output, which the filter-parser tests compare as text. Use an ordered container, or sort by col_id before appending.

♻️ Proposed fix
-    std::unordered_map<ColId, BoundAccumulator> bounds;
+    std::map<ColId, BoundAccumulator> bounds;

Then remove the now-unneeded include of <unordered_map> and add <map>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/Filter/DateQueryDomain.cpp` around lines 362 -
384, Make the iteration over bounds deterministic by replacing the unordered
container with an ordered container keyed by ColId, preserving the existing
DateRange construction logic in the bounds loop. Remove the unused unordered_map
include and add the map include.
dbms/src/Storages/DeltaMerge/File/DMFileBlockInputStream.h (1)

237-241: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move enable_trim_minmax out of the clean-read field group.

Line 241 places enable_trim_minmax under the // clean read comment, next to enable_handle_clean_read, is_fast_scan, and enable_del_clean_read. The flag controls trim min-max index selection, not clean read. Place it with the other filter-related fields, or give it its own comment.

♻️ Proposed fix
     // clean read
     bool enable_handle_clean_read = false;
     bool is_fast_scan = false;
     bool enable_del_clean_read = false;
-    bool enable_trim_minmax = false;
     UInt64 max_data_version = std::numeric_limits<UInt64>::max();
+    // trim min-max index selection
+    bool enable_trim_minmax = false;
     // packs filter (filter by pack index)
     IdSetPtr read_packs;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/File/DMFileBlockInputStream.h` around lines 237
- 241, Move the enable_trim_minmax field out of the // clean read group and
place it with the other filter-related fields, or add a separate comment
identifying its trim min-max index selection purpose. Keep the clean-read group
limited to enable_handle_clean_read, is_fast_scan, and enable_del_clean_read.
dbms/src/Storages/DeltaMerge/Segment.cpp (1)

1035-1045: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Tag query-driven pack-filter loads as Query.

ReadMode::Fast and ReadMode::Bitmap dispatch through getBitmapFilterInputStream and apply executor->rs_operator; mapping both to ReadTag::MVCC makes record_trim_metrics stay false in DMFilePackFilter::load, so trim-selection, fallback, and rough-check metrics remain blind. Use ReadTag::Query for query paths and keep ReadTag::MVCC for internal/bitmap build paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/Segment.cpp` around lines 1035 - 1045, The
pack-filter tag selection in the surrounding read flow must classify
query-driven paths as ReadTag::Query, including ReadMode::Fast and
ReadMode::Bitmap when they use executor->rs_operator through
getBitmapFilterInputStream. Reserve ReadTag::MVCC for internal bitmap-building
paths, and preserve the existing DMFilePackFilter::loadFrom arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.h`:
- Around line 211-212: Add direct includes for TrimMinMaxIndex.h and
DateQueryDomain.h in DMFilePackFilter.h so RSIndexRequest, DateQueryDomain, and
TrimMinMaxFallbackReason are visible where tryLoadIndexByRequest() and
tryLoadTrimIndex() are declared; use an existing transitive header only if it
reliably provides all required types.

In `@docs/design/2026-07-14-trim-minmax-for-date-types.md`:
- Around line 572-576: Update the equality/IN/bounded-range row in the
predicate-type table to escape both pipe characters in the
trimmed_nonmatch_exists condition, preserving the displayed logical OR
expression while keeping the row at three cells.

---

Nitpick comments:
In `@dbms/src/Storages/DeltaMerge/File/ColumnStat.h`:
- Around line 49-50: Rename the newly introduced C++ fields, parameters, and
locals to camelCase while preserving generated protobuf accessor names: update
trim_minmax_index in dbms/src/Storages/DeltaMerge/File/ColumnStat.h (lines
49-50), identifiers including pack_mark, format_version, and expected_pack_count
in dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.h (lines 43-174),
pack_marks, has_value, and allowed_mask in
dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.h (lines 35-171), their matching
implementations in dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp (lines
109-147) and dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.cpp (lines
100-291), and trim_minmaxes, trim_lower, trim_upper, and enable_trim_minmax in
dbms/src/Storages/DeltaMerge/File/DMFileWriter.h (lines 120-158). Update all
references consistently.

In `@dbms/src/Storages/DeltaMerge/File/DMFileBlockInputStream.h`:
- Around line 237-241: Move the enable_trim_minmax field out of the // clean
read group and place it with the other filter-related fields, or add a separate
comment identifying its trim min-max index selection purpose. Keep the
clean-read group limited to enable_handle_clean_read, is_fast_scan, and
enable_del_clean_read.

In `@dbms/src/Storages/DeltaMerge/Filter/DateQueryDomain.cpp`:
- Around line 362-384: Make the iteration over bounds deterministic by replacing
the unordered container with an ordered container keyed by ColId, preserving the
existing DateRange construction logic in the bounds loop. Remove the unused
unordered_map include and add the map include.

In `@dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp`:
- Line 141: Replace the pack-mark loop variable with the explicit UInt8 type and
packMark naming in MinMaxIndex.cpp:141-141 and TrimMinMaxIndex.cpp:285-285,
ensuring the relevant code uses the UInt8 definition from Core/Types.h.
- Around line 117-122: Replace the pack validation RUNTIME_CHECK calls in the
MinMaxIndex validation flow with DB::Exception using the fmt-style constructor.
Use an existing error code declared in ErrorCodes.cpp and errors.toml, preserve
the invalid pack_mark and missing-column conditions, and include the relevant
values in each exception message.

In `@dbms/src/Storages/DeltaMerge/Segment.cpp`:
- Around line 1035-1045: The pack-filter tag selection in the surrounding read
flow must classify query-driven paths as ReadTag::Query, including
ReadMode::Fast and ReadMode::Bitmap when they use executor->rs_operator through
getBitmapFilterInputStream. Reserve ReadTag::MVCC for internal bitmap-building
paths, and preserve the existing DMFilePackFilter::loadFrom arguments.

In `@dbms/src/Storages/tests/gtest_filter_parser.cpp`:
- Around line 788-791: Update the test that uses
timezone_info.resetByTimezoneName to capture the existing timezone before
switching to America/Chicago, then restore that timezone when the test exits,
including early-return or failure paths; use a scope guard or equivalent cleanup
tied to the test’s lifetime.

In `@docs/design/2026-07-14-trim-minmax-for-date-types.md`:
- Around line 343-393: Update the documentation sketch to use the implemented
TrimRSIndex name and reflect its type, minmax, and meta members instead of the
simplified TrimMinMaxIndex shape. Also replace the statement that the protobuf
field number will be assigned during implementation with a definitive reference
to field 105, keeping the existing ColumnStat.trim_minmax_index contract
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 88f47dac-ecc1-448d-b507-4aec7f839ce9

📥 Commits

Reviewing files that changed from the base of the PR and between 3d986e3 and 496c094.

📒 Files selected for processing (40)
  • dbms/src/Common/TiFlashMetrics.h
  • dbms/src/Interpreters/Settings.h
  • dbms/src/Storages/DeltaMerge/File/ColumnStat.h
  • dbms/src/Storages/DeltaMerge/File/DMFile.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFile.h
  • dbms/src/Storages/DeltaMerge/File/DMFileBlockInputStream.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileBlockInputStream.h
  • dbms/src/Storages/DeltaMerge/File/DMFileBlockOutputStream.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileMeta.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileMetaV2.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileMetaV2.h
  • dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.h
  • dbms/src/Storages/DeltaMerge/File/DMFileUtil.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileUtil.h
  • dbms/src/Storages/DeltaMerge/File/DMFileWriter.cpp
  • dbms/src/Storages/DeltaMerge/File/DMFileWriter.h
  • dbms/src/Storages/DeltaMerge/File/tests/gtest_dm_meta_version.cpp
  • dbms/src/Storages/DeltaMerge/Filter/DateQueryDomain.cpp
  • dbms/src/Storages/DeltaMerge/Filter/DateQueryDomain.h
  • dbms/src/Storages/DeltaMerge/Filter/DateRange.h
  • dbms/src/Storages/DeltaMerge/Filter/Equal.h
  • dbms/src/Storages/DeltaMerge/Filter/In.h
  • dbms/src/Storages/DeltaMerge/Filter/Not.h
  • dbms/src/Storages/DeltaMerge/Filter/PushDownExecutor.cpp
  • dbms/src/Storages/DeltaMerge/Filter/RSOperator.cpp
  • dbms/src/Storages/DeltaMerge/Filter/RSOperator.h
  • dbms/src/Storages/DeltaMerge/FilterParser/FilterParser.cpp
  • dbms/src/Storages/DeltaMerge/FilterParser/FilterParser.h
  • dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.cpp
  • dbms/src/Storages/DeltaMerge/Index/MinMaxIndex.h
  • dbms/src/Storages/DeltaMerge/Index/RSIndex.h
  • dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.cpp
  • dbms/src/Storages/DeltaMerge/Index/TrimMinMaxIndex.h
  • dbms/src/Storages/DeltaMerge/Index/tests/gtest_dm_trim_minmax_index.cpp
  • dbms/src/Storages/DeltaMerge/Segment.cpp
  • dbms/src/Storages/DeltaMerge/dtpb/dmfile.proto
  • dbms/src/Storages/StorageDisaggregatedRemote.cpp
  • dbms/src/Storages/tests/gtest_filter_parser.cpp
  • docs/design/2026-07-14-trim-minmax-for-date-types.md

Comment on lines +211 to +212
void tryLoadIndexByRequest(RSCheckParam & param, const RSIndexRequest & request);
TrimMinMaxFallbackReason tryLoadTrimIndex(RSCheckParam & param, ColId col_id, const DateQueryDomain & query_domain);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check the include list of DMFilePackFilter.h for the trim-index and date-domain declarations.
set -euo pipefail

fd -t f 'DMFilePackFilter.h' dbms/src/Storages/DeltaMerge/File --exec rg -n '^`#include`' {}

fd -t f 'RSOperator.h' dbms/src/Storages/DeltaMerge/Filter --exec rg -n '^`#include`' {}

Repository: pingcap/tiflash

Length of output: 1101


🏁 Script executed:

#!/bin/bash
# Description: Map and inspect declarations/includes for DMFilePackFilter.h and header inclusion chains.
set -euo pipefail

echo "== DMFilePackFilter.h outline =="
ast-grep outline dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.h --view compact || true

echo "== DMFilePackFilter.h relevant lines =="
sed -n '1,250p' dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.h

echo "== Header declarations =="
rg -n "class\\s+DateQueryDomain\\b|class\\s+TrimMinMaxFallbackReason\\b|enum class\\s+DateQueryDomain\\b|enum class\\s+TrimMinMaxFallbackReason\\b|struct\\s+DateQueryDomain\\b|struct\\s+TrimMinMaxFallbackReason\\b" dbms/src/Storages/DeltaMerge/Index dbms/src/Storages/DeltaMerge/Filter dbms/src/Storages/DeltaMerge/File -g '*.h' -g '*.hpp' | head -n 200

echo "== direct includes with RSIndexTrim/DateQueryDomain =="
fd -t f 'DMFilePackFilter_fwd.h|RSOperator_fwd.h|ReadMode.h|TrimMinMaxIndex.h|DateQueryDomain.h|ReadMode.h|RSIndex.h|DMFilePackFilterResult.h' dbms/src/Storages/DeltaMerge -x sh -c 'echo "--- $1"; sed -n "1,180p" "$1"' sh {}

Repository: pingcap/tiflash

Length of output: 26287


Add includes for the new header types.

ReadMode.h only defines read modes, so tryLoadIndexByRequest() and tryLoadTrimIndex() are declared in DMFilePackFilter.h without RSIndexRequest, DateQueryDomain, or TrimMinMaxFallbackReason visible. Add direct includes for Storages/DeltaMerge/Index/TrimMinMaxIndex.h and Storages/DeltaMerge/Filter/DateQueryDomain.h, or include a header that itself includes them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dbms/src/Storages/DeltaMerge/File/DMFilePackFilter.h` around lines 211 - 212,
Add direct includes for TrimMinMaxIndex.h and DateQueryDomain.h in
DMFilePackFilter.h so RSIndexRequest, DateQueryDomain, and
TrimMinMaxFallbackReason are visible where tryLoadIndexByRequest() and
tryLoadTrimIndex() are declared; use an existing transitive header only if it
reliably provides all required types.

Comment on lines +572 to +576
| Predicate type | `trimmed_match_exists` | `trimmed_nonmatch_exists` |
| --- | --- | --- |
| Equality / IN / bounded range with `Q ⊆ E` | false | `has_trimmed_low || has_trimmed_high` |
| Lower-bounded range with bound in `E` | `has_trimmed_high` | `has_trimmed_low` |
| Upper-bounded range with bound in `E` | `has_trimmed_low` | `has_trimmed_high` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Escape the pipes in the table cell.

Line 574 contains || inside a table cell. Markdown parses each | as a cell separator, so the row produces five cells against a three-column header. The rendered table drops the condition text. markdownlint reports this as MD056.

Escape both pipes.

🐛 Proposed fix for the broken table row
 | Predicate type | `trimmed_match_exists` | `trimmed_nonmatch_exists` |
 | --- | --- | --- |
-| Equality / IN / bounded range with `Q ⊆ E` | false | `has_trimmed_low || has_trimmed_high` |
+| Equality / IN / bounded range with `Q ⊆ E` | false | `has_trimmed_low \|\| has_trimmed_high` |
 | Lower-bounded range with bound in `E` | `has_trimmed_high` | `has_trimmed_low` |
 | Upper-bounded range with bound in `E` | `has_trimmed_low` | `has_trimmed_high` |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Predicate type | `trimmed_match_exists` | `trimmed_nonmatch_exists` |
| --- | --- | --- |
| Equality / IN / bounded range with `Q ⊆ E` | false | `has_trimmed_low || has_trimmed_high` |
| Lower-bounded range with bound in `E` | `has_trimmed_high` | `has_trimmed_low` |
| Upper-bounded range with bound in `E` | `has_trimmed_low` | `has_trimmed_high` |
| Predicate type | `trimmed_match_exists` | `trimmed_nonmatch_exists` |
| --- | --- | --- |
| Equality / IN / bounded range with `Q ⊆ E` | false | `has_trimmed_low \|\| has_trimmed_high` |
| Lower-bounded range with bound in `E` | `has_trimmed_high` | `has_trimmed_low` |
| Upper-bounded range with bound in `E` | `has_trimmed_low` | `has_trimmed_high` |
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)

[warning] 574-574: Table column count
Expected: 3; Actual: 5; Too many cells, extra data will be missing

(MD056, table-column-count)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/design/2026-07-14-trim-minmax-for-date-types.md` around lines 572 - 576,
Update the equality/IN/bounded-range row in the predicate-type table to escape
both pipe characters in the trimmed_nonmatch_exists condition, preserving the
displayed logical OR expression while keeping the row at three cells.

Source: Linters/SAST tools

@ti-chi-bot

ti-chi-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

@JaySon-Huang: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-integration-next-gen 496c094 link true /test pull-integration-next-gen
pull-integration-test 496c094 link true /test pull-integration-test
pull-integration-next-gen-columnar 496c094 link true /test pull-integration-next-gen-columnar

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve rough set filtering for temporal columns with sparse extreme values

1 participant