99 comparison via ` ?source=url1,url2 ` ; then drop ` .github/workflows/benchmark.yml `
1010- [ ] Build something like hardwood.dev but for vortex files
1111
12- ## Compression ratio gaps vs Rust (NYC taxi 2024-01: Rust 42.8 MB, Parquet 47.6 MB)
13-
14- Progress: raw I64 → datetimeparts (76→53 MB), fix FOR/RLE/RunEnd accepts + sample size (53→51 MB),
15- fix ConstantEncoding encodeCascade (51→43.1 MB with Zstd; 49.7 MB without Zstd).
16- Global dict encoding for low-cardinality integer columns (VendorID, PULocationID, etc.) — completed.
17- ` WriteOptions.withZstd(true) ` — completed: adds ZstdEncoding to cascade, recovers the 43 MB level.
18-
19- Without Zstd (default, good read throughput): Java 49.7 MB — 6.5 MB above Rust.
20- With Zstd (` WriteOptions.cascading(3).withZstd(true) ` ): Java ~ 43 MB — on par with Rust.
21- Trade-off documented in ` WriteOptions ` Javadoc (6× slower Zstd decompression vs ALP+bitpack).
22-
23- Remaining gap (no-Zstd mode) — biggest to smallest:
24-
25- - [ ] ** Nullable column handling** — ` ParquetImporter ` maps nulls to 0.0/0L (type defaults) for the 9 nullable F64
26- columns in the taxi dataset (` fare_amount ` , ` extra ` , ` mta_tax ` , ` tip_amount ` , ` tolls_amount ` ,
27- ` improvement_surcharge ` , ` total_amount ` , ` congestion_surcharge ` , ` Airport_fee ` ). Rust uses ` vortex.sparse `
28- or ` vortex.masked ` to store only valid values, then ALP on clean data. Java passes zero-polluted arrays to ALP.
29- Fix: add a ` NullableData(double[] values, boolean[] validity) ` wrapper; writer detects it, compacts valid values,
30- encodes validity as a Bool child. Requires API change to ` VortexWriter.writeChunk ` and corresponding
31- ` ParquetImporter ` changes.
32-
33- - [ ] ** Global dict for F64 low-cardinality** — excluded from ` isDictCandidate ` because ALP/RLE were expected to
34- win; but for columns like ` mta_tax ` (8 unique F64 values) and ` Airport_fee ` (4 unique), dict codes are
35- ~ same size as ALP+bitpack while Rust uses dict. Measure actual gain before implementing.
36-
37- - [ ] ** FSST in CASCADE_CODECS** — ` FsstEncoding ` exists but not in the cascade; Rust uses FSST for
38- ` store_and_fwd_flag ` . Small gain on taxi (~ 0.1 MB).
39-
4012## Performance
4113
4214- [ ] Publish reproducible perf artifacts
4315 - Capture JMH JSON + JFR profile alongside README table; cite hardware (CPU model), JDK build (` java -version ` ),
4416 and benchmark commit SHA so numbers don't rot silently.
45- - [ ] performance tests must be peer reviewed
46- - [ ] run performance tests on other machines (I have access only to Apple M5)
47- - [ ] minimize ` ctx.arena().allocate(...) ` calls — prefer in-place decode when child buffer is writable (already done in
17+ - [ ] Performance tests must be peer reviewed
18+ - [ ] Run performance tests on other machines (I have access only to Apple M5)
19+ - [ ] Minimize ` ctx.arena().allocate(...) ` calls — prefer in-place decode when child buffer is writable (already done in
4820 ALP); audit all decoders for unnecessary off-heap allocs
4921- [ ] ** Evaluate Vector API (JEP 469+) for hot decode loops** — candidates: FastLanes bitpacked unpack,
5022 FrameOfReference add-base, ZigZag decode, ALP F64 reconstruction, future pco offset+base loop. Measure
5123 vs scalar baseline with JMH; only adopt where speedup is material and code stays readable. Pin against
5224 a specific JDK build since Vector API is incubating until Valhalla lands.
25+ - [ ] Review zero-copy
5326
5427## Testing
5528
@@ -76,12 +49,15 @@ Remaining gap (no-Zstd mode) — biggest to smallest:
7649 ` vortex-java ` artifact simplifies client dependency management and removes artificial module
7750 boundaries. Keep ` integration ` , ` performance ` , and ` cli ` as separate modules. Package structure
7851 (` encoding ` , ` io ` , ` writer ` ) already enforces internal boundaries without Maven.
79- - [ ] switch back to module-path, but keep in mind these 2 blockers
52+ - [ ] switch back to module-path, but keep in mind these 2 blockers:
53+ - [ ] 'dfa1' in package name is rejected by maven central
54+ - [ ] automatic module names for flatbuffers is rejected by maven central
8055
8156## Documentation
8257
8358- [ ] Format specification: byte-exact diagrams for file layout and each encoding, with annotated examples (Arrow spec
8459 style)
60+ - [ ] Review documentation for new joiners
8561
8662## Tooling
8763
@@ -93,12 +69,6 @@ Remaining gap (no-Zstd mode) — biggest to smallest:
9369 - Arrow JVM uses ` sun.misc.Unsafe ` / Netty internally; keeping it in a separate module means
9470 the core library stays Unsafe-free
9571
96- ## Large-file support
97-
98- - [ ] ** Test read/write of files > 2 GB**
99- - [ ] Parquet baseline for comparison: same data should fail or require splitting when any
100- column chunk exceeds 2 GB.
101-
10272## API
10373
10474- [ ] Use domain primitives (` UInt32 ` , ` UInt64 ` , etc.) as value classes via Project Valhalla instead of raw ` long ` /` int `
@@ -122,6 +92,22 @@ Remaining gap (no-Zstd mode) — biggest to smallest:
12292
12393See [ docs/compatibility.md] ( docs/compatibility.md ) for the full encoding support table and S3 fixture status.
12494
95+ ### Remaining gap (no-Zstd mode) — biggest to smallest:
96+ - [ ] ** Nullable column handling** — ` ParquetImporter ` maps nulls to 0.0/0L (type defaults) for the 9 nullable F64
97+ columns in the taxi dataset (` fare_amount ` , ` extra ` , ` mta_tax ` , ` tip_amount ` , ` tolls_amount ` ,
98+ ` improvement_surcharge ` , ` total_amount ` , ` congestion_surcharge ` , ` Airport_fee ` ). Rust uses ` vortex.sparse `
99+ or ` vortex.masked ` to store only valid values, then ALP on clean data. Java passes zero-polluted arrays to ALP.
100+ Fix: add a ` NullableData(double[] values, boolean[] validity) ` wrapper; writer detects it, compacts valid values,
101+ encodes validity as a Bool child. Requires API change to ` VortexWriter.writeChunk ` and corresponding
102+ ` ParquetImporter ` changes.
103+
104+ - [ ] ** Global dict for F64 low-cardinality** — excluded from ` isDictCandidate ` because ALP/RLE were expected to
105+ win; but for columns like ` mta_tax ` (8 unique F64 values) and ` Airport_fee ` (4 unique), dict codes are
106+ ~ same size as ALP+bitpack while Rust uses dict. Measure actual gain before implementing.
107+
108+ - [ ] ** FSST in CASCADE_CODECS** — ` FsstEncoding ` exists but not in the cascade; Rust uses FSST for
109+ ` store_and_fwd_flag ` . Small gain on taxi (~ 0.1 MB).
110+
125111### ` vortex.zstd ` known limitations
126112
127113- [ ] ** Multi-frame encode** — ` ZstdEncoding.Encoder ` always produces a single frame for the whole array.
0 commit comments