Skip to content

Fold PhysicalColumnIndexContainer's IndexTypeMap into a presence mask and a dense reader array - #19475

Open
xiangfu0 wants to merge 1 commit into
xiangfu0/data-3221-3-datasource-adapterfrom
xiangfu0/data-3221-4-index-container-mask
Open

xiangfu0 wants to merge 1 commit into
xiangfu0/data-3221-3-datasource-adapterfrom
xiangfu0/data-3221-4-index-container-mask

Conversation

@xiangfu0

@xiangfu0 xiangfu0 commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

What

PhysicalColumnIndexContainer stored its readers in an IndexTypeMap holding a span-sized IndexReader[]: with forward index at numeric id 2 and null vector at 8, a column with two readers allocated seven slots. It now keeps a long presence mask plus a densely packed, exactly sized reader array, so getIndex is a shift, mask and Long.bitCount instead of a range check, at the same O(1) cost. Construction also drops the transient per-column ArrayLists.

A Preconditions.checkState rejects a numeric index id of 64 or above at construction rather than silently misbehaving; OSS uses 13 ids today.

Tests

PhysicalColumnIndexContainerTest: forward only, forward plus null vector, and a mix spanning the lowest and a high id, asserting getIndex returns the created reader for present types and null for absent ones, that forwardIndexOnly filtering still applies, and that close closes each reader exactly once.

Why

A server keeps one metadata object graph per (segment, column) for as long as the segment is loaded, so on wide tables the per-column footprint decides how many segments a server can hold. Measured end to end on a 1000-column segment, this series takes the heap retained at load from 4.08 MB to 0.175 MB per segment (4,080 to 174 bytes per column), with a fully compacting collector on both sides. No on-disk format change, the /tables/{table}/segments/{segment}/metadata JSON stays byte-identical, and every public and SPI signature keeps working.

Stack

Based on #19474. Review this PR against its base for this layer's changes.

Current open chain; #19480 (lazy index-size storage) is already merged, and #19476 is absorbed into #19473.

  1. Share FieldSpecs and repeated values across segment metadata loads #19473 shared FieldSpecs, canonical default-null values, and interned strings
  2. Delegate immutable DataSourceMetadata to ColumnMetadata instead of snapshotting it #19474 delegating immutable DataSourceMetadata
  3. Fold PhysicalColumnIndexContainer's IndexTypeMap into a presence mask and a dense reader array #19475 presence-mask index container
  4. Materialize immutable-segment columns lazily behind an opt-in instance config (default off) #19477 opt-in lazy column materialization
  5. Slim ColumnMetadataImpl to 72 bytes and derive the per-segment Schema lazily #19478 slim ColumnMetadataImpl and lazy per-segment Schema
  6. Store numeric column min/max as primitives instead of boxed Comparables #19479 primitive numeric min/max
  7. Hold segment column metadata in sorted arrays and derive the map on demand #19481 sorted-array column metadata storage
  8. Stop the segment preprocess from building a Schema per segment #19486 segment preprocessing without building a Schema
  9. Prune segments from column metadata instead of materializing them #19511 segment pruning directly from column metadata

@codecov-commenter

codecov-commenter commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.93939% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.75%. Comparing base (caac249) to head (e068c8a).

Files with missing lines Patch % Lines
...ent/index/column/PhysicalColumnIndexContainer.java 93.93% 2 Missing ⚠️
Additional details and impacted files
@@                              Coverage Diff                              @@
##             xiangfu0/data-3221-3-datasource-adapter   #19475      +/-   ##
=============================================================================
+ Coverage                                      67.71%   67.75%   +0.03%     
  Complexity                                      1450     1450              
=============================================================================
  Files                                           3490     3490              
  Lines                                         225025   225009      -16     
  Branches                                       35529    35527       -2     
=============================================================================
+ Hits                                          152384   152452      +68     
+ Misses                                         60614    60528      -86     
- Partials                                       12027    12029       +2     
Flag Coverage Δ
integration 100.00% <ø> (ø)
integration1 100.00% <ø> (ø)
integration2 0.00% <ø> (ø)
java-25 67.75% <93.93%> (+0.03%) ⬆️
lane-a 100.00% <ø> (ø)
lane-b 0.00% <ø> (ø)
temurin 67.75% <93.93%> (+0.03%) ⬆️
unittests 67.75% <93.93%> (+0.03%) ⬆️
unittests1 57.83% <72.72%> (+0.01%) ⬆️
unittests2 39.51% <93.93%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-4-index-container-mask branch from 0bbde43 to 19ae462 Compare September 11, 2026 09:12
@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-4-index-container-mask branch from 19ae462 to 5d1ebde Compare September 11, 2026 20:26
@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-4-index-container-mask branch from 5d1ebde to 440d13d Compare September 13, 2026 01:13
@xiangfu0
xiangfu0 removed this pull request from stack #19484 September 13, 2026 01:16
@xiangfu0
xiangfu0 added this pull request to stack #19540 September 13, 2026 01:17
… plus dense readers

A server holding tens of thousands of wide segments (1000+ columns) creates one
PhysicalColumnIndexContainer per (segment, column) at load time. Each one held a
package-private IndexTypeMap object plus an IndexReader[] spanning the numeric-id
range of the present readers: the common forward_index (id 2) + nullvalue_vector
(id 8) shape paid for 7 slots to hold 2 readers, i.e. 24 B container + 24 B map +
48 B array = 96 B per column.

The container now stores a `long _presentMask` (bit i set when the index type with
numeric id i has a reader) and an exactly-sized `IndexReader[] _readers` ordered by
numeric id, sharing one empty array for columns without readers. getIndex(type) is
a shift, a mask and a popcount into the dense array, so it stays O(1) on the query
path; the forward + null-vector shape drops to 32 B container + 24 B array = 56 B,
and no shape regresses because a dense array is never larger than a span array.
Construction also writes straight into a scratch array instead of two ArrayLists
and a ShortArrayList per column. Numeric ids are validated against the 64-bit mask
at construction with a clear IllegalStateException (13 index types in OSS today),
rather than adding an unreachable fallback path.

Behaviour is otherwise unchanged: getIndex returns null for absent types, the
forwardIndexOnly filtering, IndexReaderConstraintException handling and
init-failure cleanup are kept, close() closes every reader exactly once in id order,
and the multi-column text reader setter/getter are untouched.

Compatibility: IndexTypeMap was package-private with no references outside this
file, ColumnIndexContainer and IndexService numeric ids are unchanged, and there is
no SPI, on-disk, wire or REST JSON impact, so mixed-version deployments are
unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@xiangfu0
xiangfu0 force-pushed the xiangfu0/data-3221-4-index-container-mask branch from 440d13d to e068c8a Compare September 13, 2026 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

memory Related to memory usage or optimization performance Related to performance optimization refactor Code restructuring without changing behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants