Repository navigation
Conversation
### Background MoW compaction records a source-to-destination mapping for delete bitmap conversion and inverted-index merging. Dense storage reserves a pair of uint32 values for every source row, including filtered rows, and can exhaust memory on large tablets. ### What problem does this PR solve? Issue Number: None Related PR: None PR Type: Performance Problem Summary: Add opt-in compression while constructing the mapping, using fixed 4096-source-row blocks with delta varint64 and Zstd level 1. Delete bitmap and SNII consumers use borrowed source views with fallible lookups and bounded reusable decode buffers. Existing deployments retain DENSE unless enable_compressed_rowid_conversion is enabled; CLucene, cluster keys, sequence maps and legacy index debug dumps stay on DENSE. ### Details - Change map: Approximately 1,180 production lines changed, 645 test lines and 57 documentation lines; no generated files. The storage kernel owns block directories, paged payloads and bounded codec workspaces. Source views adapt bitmap/SNII consumers and preserve complete coverage validation. Tests cover representation, corruption, accounting and consumer equivalence. - Why it was slow: The limiting resource is memory: dense conversion costs 8 bytes per source row and can repeatedly fail compaction allocation. - Optimization: Seal monotonically written source blocks during merge. EMPTY/LINEAR omit redundant values; RAW64 prevents payload expansion. Use a shared 1 MiB arena and tracked static Zstd workspaces sized for one block. Release builders/encoder before reading; retain one decode block per prepared SNII source and one shared decoder context per plan. - Results: The targeted ASAN/O0 run passes 69 tests. Four 262144-row kernel benchmarks retain 1050832-1051792 bytes versus a 2097152-byte dense array; measured allocation peaks are 1470944-1963424 bytes. The complete directory is 2048 bytes, payloads are 20273-229915 bytes, and interleaved scans decode exactly 64 blocks. Build observations are 65-75 ms; these diagnostic times are not Release throughput or actual compaction measurements. - Applicability and cost: No assumption about segment row counts and no spill. Construction requires increasing row IDs within each source. CPU cost rises for sparse/random seeks; a 1 MiB arena tail and per-source workspaces can dominate small maps. New allocations use the compaction tracker; conversion errors propagate instead of becoming deleted rows. - Behavior change: The optional compressed mode changes representation only. DENSE remains the default; bitmap and SNII correctness checks are retained. ### Testing run-be-ut.sh --run with CompressedRowIdMapTest.*, CompressedRowIdMapBenchmark.*, SniiRowIdConversionTest.*, SniiPostingCursorTest.*, SniiIndexCompactionTest.*, TestRowIdConversion.* and the Parquet build prerequisite test passes 69/69 in ASAN_UT. Tests include 262144-row complete maps, a billion-row EMPTY directory, wide ordinals, backward seeks, corruption/allocation failures, bitmap physical IDs and byte-identical SNII rebuild comparisons. The repository clang-format 16 scripts check the modified files, check-build-hygiene.sh passes, and git diff --check is clean. Actual compaction/cluster tests are deferred to a separate validation phase. clang-tidy is intentionally omitted. ### Notes for Reviewers The segment_read_ahead.cpp include makes its is_cloud_mode dependency explicit after the new source file changes unity-batch boundaries. The benchmark guide documents accounting exclusions and reproducible commands. Keep the feature disabled by default pending actual compaction validation. ### Release note An experimental enable_compressed_rowid_conversion setting can reduce row-id mapping memory for eligible MoW compactions. It is disabled by default. ### Check List (For Author) - Behavior changed: Yes (see Details) - Does this need documentation: Yes; the in-tree benchmark guide covers developer use. User documentation follows production validation. - Pre-submission status: Partially verified: targeted ASAN unit tests pass; actual compaction validation is pending. ### AI Disclosure - Tool: OpenAI Codex (GPT-6) - Generated: Implementation, unit tests, benchmark, guide and commit description. - Human review: Pending.
bobhan1
requested review from
Mryange,
airborne12,
csun5285,
eldenmoon,
gavinchou,
liaoxin01,
luwei16 and
yiguolei
as code owners
November 6, 2026 09:32
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
### Background Row-id conversion has three in-memory layouts, consumed by delete bitmap and inverted-index compaction. Storage-specific branches currently share the facade, and compression is disabled by default. ### What problem does this PR solve? Issue Number: None Related PR: None PR Type: Performance Problem Summary: Enable compression for eligible mappings whose estimated dense arrays exceed a configurable 64 MiB threshold. Compose the three concrete storage implementations and dispatch once per append batch. Include Duplicate Key SNII and isolate selection in should_compress_rowid_conversion(). ### Details - **Change map:** 654 production lines changed, 183 test lines and 18 documentation lines; no generated files. Most production changes relocate dense/lazy operations from the facade into concrete storage. The remainder implements selection/configuration and their unit tests. - **Why it was slow:** Large dense mappings consume 8 bytes per physical input row, while compressing small mappings can add avoidable memory and CPU overhead. - **Optimization:** Select storage before source registration from actual data input row counts. Use an overflow-safe strict byte threshold and retain dense-only compatibility exclusions. Separate layout ownership with a private variant and one visit per append batch. - **Results:** 83/83 ASAN tests pass, including reader/consumer equivalence, threshold boundaries and memory lifetime checks. The four existing 262,144-row compressed kernel benchmarks retain about 1 MiB versus a 2 MiB dense array; they bypass automatic selection and are not production compaction results. - **Applicability and cost:** Default compression covers eligible MoW bitmap and Duplicate Key/MoW SNII mappings above 64 MiB. The initial threshold is tunable; sparse/random decode cost and actual compaction latency remain to be measured in production-like tests. - **Behavior change:** Enable compression by default with a dynamic nonnegative byte threshold. Exactly the threshold stays dense, zero covers every nonempty eligible map, and the disable switch preserves dense. No persistent/protocol change. ### Testing 83 local ASAN_UT tests passed in 7 suites, using run-be-ut.sh with compressed map/benchmark, SNII and all TestRowIdConversion cases. The new merge-reader unit cases include Duplicate Key/MoW, horizontal/vertical, three overlap modes and delete predicates. clang-format 16, build hygiene and diff checks pass. No clang-tidy or actual cluster compaction run. ### Notes for Reviewers Dense spans and the CLucene matrix API are preserved. Storage lifetimes remain bounded by the conversion owner; per-source cursors/workspaces remain consumer-owned. The benchmark guide documents default selection and the kernel-only measurement boundary. ### Release note Large eligible row-ID mappings now use compression by default above a configurable 64 MiB dense-memory threshold. ### Check List (For Author) - Behavior changed: Yes (see Details) - Does this need documentation: Yes; the in-tree guide is updated, user documentation follows actual compaction validation. - Pre-submission status: Partially verified: ASAN unit tests pass; actual compaction/optimized performance validation is pending. ### AI Disclosure - Tool: OpenAI Codex (GPT-6) - Generated: Code, tests, documentation and this description. - Human review: Pending.
### Background Compressed row-id mapping stores fixed-size block metadata and optional bitmap/delta payloads. The encoding is internal to a compaction task. ### What problem does this PR solve? Issue Number: None Related PR: None PR Type: Refactor Problem Summary: Replace unscoped Kind/Flag enums with enum class and make flag-to-byte conversion explicit. Add local ASCII layouts and a matching encoder/decoder example so the metadata, bitmap holes and delta stream can be understood at their implementation sites. ### Details - **Moves vs. logic changes:** No code moves or encoding algorithm changes. BlockMeta stores Kind directly; mask operations use the constexpr flag_bits(Flag) conversion. Update existing test references to the scoped names. - **Behavior change:** None. Enum values, flag bits, payload bytes and the 32-byte metadata layout are preserved. - **Compatibility:** No persistent or wire format changes. Comments identify RAW64's native byte order as process-local. - **Performance impact:** Constant-expression conversions add no runtime work. Existing correctness and diagnostic benchmark cases still pass. - **Rollback:** Revert this commit without changing mappings or configuration. ### Testing 83/83 local ASAN_UT cases passed across 7 suites with run-be-ut.sh -j100, covering compressed map/benchmark, SNII and all TestRowIdConversion cases. The 32-byte BlockMeta static assertion, clang-format 16, build hygiene and git diff --check pass. No clang-tidy or actual cluster compaction tests were run. ### Notes for Reviewers The layout comment is next to BlockMeta; seal/decode share the concrete example [100, MISSING, 103, 104] encoded as [0x0d bitmap | 0x02 gap | 0x00 gap], with first=100 in metadata. Zstd wraps the bitmap and varints together only when beneficial. ### Release note None ### Check List (For Author) - Behavior changed: No - Does this need documentation: No; implementation comments are included. - Pre-submission status: Ready for this scoped-enum/comment refactor; actual compaction validation for the overall feature remains pending. ### AI Disclosure - Tool: OpenAI Codex (GPT-6) - Generated: Scoped-enum edits, test references, layout comments and this description. - Human review: Pending.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
Compaction records a mapping from each physical input row to its output segment and row ID. MoW delete bitmap conversion and inverted-index merging consume this mapping; its dense representation stores two
uint32_tvalues per input row, including filtered rows.What problem does this PR solve?
Issue Number: None
Related PR: None
PR Type: Performance
Problem Summary:
Large mappings can consume gigabytes and repeatedly fail compaction allocations. This PR compresses eligible mappings during construction with fixed 4096-source-row blocks, enabling compression by default when the estimated dense row-pair array strictly exceeds 64 MiB. Both MoW bitmap conversion and Duplicate Key/MoW SNII postings compaction can use it. Small mappings and consumers requiring the dense matrix keep DENSE.
Details
std::variant: one dispatch surrounds each append batch, with no per-row mode branches or virtual calls. Dense consumers retain direct spans and CLucene's existing matrix API.Retained allocation includes directory capacity, the full arena page and kernel metadata. The tracker includes transient allocations and reader workspaces, but these are requested bytes, not RSS. Exclusions include allocator bookkeeping, benchmark input/baseline copies, enclosing source indexes/destination prefixes and other compaction state. A billion-row EMPTY-source test separately verifies its 7,812,512-byte directory; it is not a billion-row compression run. These small benchmarks explicitly construct the compressed kernel and bypass automatic mode selection.
ASAN/O0 observations: build 67.2–74.5 ms, cold decode 5.1–10.5 ms, sequential lookup 83.8–93.0 ms, 4,096 grouped sparse lookups 31.3–409.8 ms and 4,096 random lookups 226.9–475.8 ms. Direct dense scans take 3.0–3.9 ms. Sequential UT timing includes assertions; these are not optimized production or end-to-end compaction results.
Compaction::should_compress_rowid_conversion()checks consumer/order constraints and the threshold before any source registration. It counts physical rows in actual data inputs, including rows later deleted/filtered, excluding whole changelog rowsets already removed. Comparing against a remaining row budget avoids multiplying or summing huge counts. CLucene, cluster keys, sequence maps and legacy index debug dumps remain DENSE. Random seeks may repeatedly decode blocks; per-source workspaces and arena tail space can dominate small maps. The 64 MiB default is an initial size policy, not a production-measured break-even point. No spill or external CLucene changes are introduced.enable_compressed_rowid_conversion=trueandcompressed_rowid_conversion_threshold_bytes=67108864are dynamic BE defaults. Exactly the threshold remains DENSE; zero compresses every eligible nonempty mapping and negative values are rejected. Changes affect subsequent selections, not mappings already being built. The compaction profile records the selectedRowIdConversionmode. Bitmap visibility and SNII bounds/monotonicity/uniqueness/full coverage validation remain intact; conversion errors propagate asStatus. Persistent formats and FE/BE protocols are unchanged.Testing
Locally, 83/83 ASAN_UT tests passed (7 suites):
bash run-be-ut.sh --run \ --filter='CompressedRowIdMapTest.*:CompressedRowIdMapBenchmark.*:SniiRowIdConversionTest.*:SniiPostingCursorTest.*:SniiIndexCompactionTest.*:*TestRowIdConversion*' \ -j100Coverage includes threshold boundaries, multiple data inputs, zero/disabled settings, huge row counts, rejected negative thresholds, dense-only exclusions and Duplicate Key SNII selection. Compressed merge-reader tests cover Duplicate Key/MoW, horizontal/vertical merging, overlapping/nonoverlapping/mixed segments and delete predicates. Additional cases verify all three storage lifecycles, codec corruption/allocation failure, physical segment IDs, bitmap visibility, SNII posting layouts and byte-identical in-memory index rebuilds. The existing parameterized DENSE reader suite also passes.
Repository clang-format 16 checks on changed files,
build-support/check-build-hygiene.shandgit diff --checkpassed. Actual local/cloud compaction, concurrent loading, lock-hold time and optimized production timing remain separate validation work. clang-tidy was not run.Notes for Reviewers
BlockMetauses scopedKind/Flagenums and explicitflag_bits()conversion for masks. Inline ASCII diagrams document the 32-byte directory and four payload layouts; matching encoder/decoder examples explain bitmap holes, delta-minus-one varints and optional Zstd wrapping. The in-memory layout is unchanged.See
be/test/storage/rowid_conversion_benchmark.mdfor configuration, accounting boundaries and reproduction. The single arena tail in a small benchmark must not be extrapolated as another page for every 262,144 rows in a larger shared map.The
cloud/config.hinclude insegment_read_ahead.cppmakes its directis_cloud_modedependency explicit after unity-batch changes. The codec source is excluded from unity compilation to keep Zstd's static-workspace feature macro local.Release note
Eligible MoW and Duplicate Key SNII compactions now compress row-ID mappings when their estimated dense array exceeds 64 MiB. The dynamic
compressed_rowid_conversion_threshold_bytessetting controls this threshold; settingenable_compressed_rowid_conversion=falseretains dense mappings.Check List (For Author)
AI Disclosure