Add codec pipeline framework for raw forward index encoding - #18229
Add codec pipeline framework for raw forward index encoding#18229xiangfu0 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an initial “codec pipeline” framework for raw (no-dict) single-value forward index encoding, introducing a DSL (DELTA, ZSTD(N), CODEC(...)) and a new self-describing on-disk format (writer/reader v7) that persists the canonical codec spec in the file header. This is wired through ForwardIndexConfig.codecSpec and the forward-index creator/reader factories, with tests covering parsing, validation, and INT/LONG round-trips.
Changes:
- Introduce codec DSL AST + parser in
pinot-segment-spi, plusForwardIndexConfig.codecSpec(mutually exclusive withcompressionCodec) and writer-version forcing. - Add codec registry/validator/executor in
pinot-segment-localand implement v7 fixed-byte chunk writer/reader that stores the canonical spec in the header. - Wire new creator/reader paths via
ForwardIndexCreatorFactoryandForwardIndexReaderFactory, and add comprehensive unit tests.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| pinot-segment-spi/src/test/java/org/apache/pinot/segment/spi/index/ForwardIndexConfigTest.java | Adds tests for codecSpec JSON round-trip, equality, and mutual-exclusion/ordering guards. |
| pinot-segment-spi/src/test/java/org/apache/pinot/segment/spi/codec/CodecSpecParserTest.java | New unit tests for codec DSL parsing/canonicalization and invalid specs. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java | Adds codecSpec, forces raw writer version 7 when set, updates equals/hashCode and Builder guards. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecSpecParser.java | Implements structural (phase-1) recursive-descent parser for the DSL. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecPipeline.java | New AST node representing an ordered pipeline with canonical spec rendering. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecOptions.java | Marker interface for typed, validated per-codec options. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecKind.java | Enum classifying codecs as TRANSFORM vs COMPRESSION for pipeline rules. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecInvocation.java | New AST node representing a single codec invocation + args. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecDefinition.java | SPI interface describing codec parsing/validation/canonicalization. |
| pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/codec/CodecContext.java | Context object for per-column type validation during pipeline validation. |
| pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/forward/CodecPipelineForwardIndexTest.java | Integration tests for v7 writer/reader round-trip, header spec storage, factory dispatch, partial chunk. |
| pinot-segment-local/src/test/java/org/apache/pinot/segment/local/io/codec/CodecPipelineValidatorTest.java | Tests pipeline validation rules (ordering, type checks, unknown codecs, arg ranges). |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/forward/FixedByteChunkSVForwardIndexReaderV7.java | New v7 reader that reads canonical spec from header and decodes chunks via executor. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexReaderFactory.java | Dispatches fixed-width SV version-7 raw indexes to the new v7 reader. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexCreatorFactory.java | Creates codec-pipeline raw forward index creators when codecSpec is present and supported. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/creator/impl/fwd/SingleValueFixedByteCodecPipelineIndexCreator.java | New creator wiring v7 writer + executor for INT/LONG SV raw forward indexes. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/writer/impl/FixedByteChunkForwardIndexWriterV7.java | New v7 writer that embeds canonical spec in header and writes variable-size encoded chunks with long offsets. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/codec/ZstdCodecDefinition.java | Adds ZSTD codec definition with typed options and canonicalization. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/codec/DeltaCodecDefinition.java | Adds DELTA transform codec definition with INT/LONG validation and canonicalization. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/codec/CodecRegistry.java | Introduces immutable default registry + mutable registry for tests/future plugins, with reserved keyword protection. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/codec/CodecPipelineValidator.java | Validates structural rules and per-codec context compatibility for pipelines. |
| pinot-segment-local/src/main/java/org/apache/pinot/segment/local/io/codec/CodecPipelineExecutor.java | Executes the validated pipeline per chunk (DELTA + ZSTD v1 wiring) and produces canonical spec. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #18229 +/- ##
============================================
- Coverage 67.10% 57.35% -9.76%
+ Complexity 1424 7 -1417
============================================
Files 3457 2683 -774
Lines 219288 161042 -58246
Branches 34865 26488 -8377
============================================
- Hits 147148 92359 -54789
- Misses 60378 60832 +454
+ Partials 11762 7851 -3911
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
xiangfu0
left a comment
There was a problem hiding this comment.
Found one high-confidence correctness issue; see inline comment.
65be596 to
5f3d045
Compare
xiangfu0
left a comment
There was a problem hiding this comment.
Found one high-confidence backward-compatibility issue; see inline comment.
7ad9a2c to
c88cfad
Compare
e61cae3 to
a79d5a2
Compare
39596ba to
9099a0a
Compare
Codec chaining now supported (revisits the earlier single-transform constraint)Following up on the earlier discussion where we restricted pipelines to a single transform: the pipeline now supports full chaining of the form
Examples that are now valid and round-trip end-to-end (covered by
Why multi-transform is now safe (not the earlier corruption case)The original concern was that That's fixed at the root:
Still rejected (by necessity)
Wire formats: |
Introduce a composable codecSpec DSL under indexes.forward and a self-describing V7 fixed-byte forward index for RAW SV INT/LONG pipelines. Register DELTA, DELTADELTA, T64, GORILLA, ZSTD, LZ4, SNAPPY, and GZIP. Validate pipelines as typed-layout-preserving transforms, an optional packing transform, then zero or more byte-compression stages. Keep legacy-compatible single-compression specs on existing raw forward-index formats and distinguish pipeline V7 from arbitrary legacy writer-version tags with an explicit header magic. Add migration and rewrite handling, preserve DELTA and DELTADELTA reload correctness, and harden segment parsing and codec execution with fail-closed bounds, resource limits, cleanup, and corrupt-input coverage.
Jackie-Jiang
left a comment
There was a problem hiding this comment.
Can we split it into smaller PRs? It is too large for review.
I think we can first introduce the DSL and wiring of the config.
For the DSL, given it is already under _codecSpec, can we make it a list of invocation without the CODEC wrapper?
|
Also, why is variable length value reader not a goal? |
|
Thanks, Jackie. I have started splitting this into GitHub-native stacked PRs:
The V7 reader/writer, activation, and transforms will remain separate follow-up stack layers rather than returning to one large PR. Variable-length values are deferred from the first new-format slice, not a permanent non-goal. A single legacy-compatible compression spec can eventually reuse the existing variable-byte readers and writers. General chained or non-default codec pipelines need an explicit variable-width envelope because the current proposed V7 layout assumes fixed entry width, derives decoded bytes from document count times width, and uses fixed-width random access. Numeric transforms such as DELTA and packing transforms also remain INT/LONG-specific. I will keep variable-width SV/MV pipeline support as a linked follow-up after the fixed-width format contract is reviewed rather than silently freezing the current fixed-width assumptions into its future design. |
|
Closing this large umbrella as superseded by the reviewable split requested in the Aug 17 review. Complete codec stackMerged prerequisites:
Native GitHub stack (review and merge parent-first):
Chain: #19284 → #19285 → #19305 → #19306 → #19307 → #19308 → #19309. All open branches were restacked onto current master on Aug 20. Each child uses its predecessor's branch as its GitHub base, so GitHub will retarget the next PR as each parent merges. This PR remains available as the original design and review history. |
Summary
This PR adds a composable
codecSpecDSL for raw forward indexes at:It deliberately keeps two on-disk paths:
ChunkCompressionType(LZ4,SNAPPY,GZIP,ZSTD, orZSTD(3)) stays on the existing raw forward-index format.ZSTD(5)uses a self-describing fixed-byte V7 format. This V7 path is currently limited to RAW single-valueINTandLONGcolumns.Valid pipelines have this shape:
Encode runs left-to-right and decode runs right-to-left. Examples include
CODEC(DELTA,T64,LZ4)and multiple compression stages. The eight built-ins areDELTA,DELTADELTA,T64,GORILLA,ZSTD,LZ4,SNAPPY, andGZIP.Design details:
docs/design/codec-pipeline-v7.mdConfiguration
{ "fieldConfigList": [ { "name": "ts", "encodingType": "RAW", "indexes": { "forward": { "codecSpec": "CODEC(DELTADELTA,LZ4)" } } }, { "name": "userId", "encodingType": "RAW", "indexes": { "forward": { "codecSpec": "ZSTD(3)" } } } ] }codecSpecand the legacycompressionCodecare mutually exclusive. The legacy getter and enum remain supported because other column shapes and codec families still depend on them.V7 format and safety
V7 stores the canonical codec spec in the index header and uses the pair
(version 7, codec-pipeline magic)as its format discriminator. The integer version alone is not sufficient because the existing legacy fixed-byte writer accepts arbitrary version tags greater than or equal to 4, including 7.The reader and executor fail closed on malformed segment data. They validate the fixed header, format magic, codec-spec size, chunk geometry, document/chunk counts, offset-table extents, per-chunk payload bounds, exact decoded sizes, codec frame completion, and composed allocation/work limits before large allocations or native reads. Intermediate direct buffers and reader contexts are released deterministically.
Compatibility and migration
compressionCodecconfigscodecSpeccodecSpecon pre-1.6 config consumersForwardIndexReader.getCodecSpec()CompressionCodecMigratortranslates supported legacy configs. Reload parity coverage verifies that legacyDELTAandDELTADELTAsegments retain every value through migration and rewrite. Golden fixtures generated before this change lock legacy fixed-byte v6/v7 readability, and the rollback test executes a V7-to-legacy rewrite and reopens the resulting index.For a rolling upgrade, upgrade every component that validates or consumes table configs before enabling any
codecSpec. For V7-requiring specs, every server that can load the table's segments must also have the V7 reader. To downgrade, first restore a legacy-representable config and reload segments so V7 indexes are rewritten.Validation
Local validation on commit
9d12b82c55rebased onapache/master(388bc64d5c):CodecPipelineIntegrationTest: 75 tests passed across SSE and MSE, including multi-chunk boundary assertions.TableConfigUtilsTest: 78 tests passed after correcting the CI assertion to verify both the established wrapper and the semantic root cause.spotless:apply,checkstyle:check,license:format, andlicense:checkpassed forpinot-segment-spi,pinot-segment-local, andpinot-integration-tests.All existing review threads are resolved, and all 12 GitHub Actions checks passed on the amended head. Human approval is still requested.