Skip to content

Commit 67e6fa2

Browse files
committed
better README
1 parent a3e5389 commit 67e6fa2

1 file changed

Lines changed: 26 additions & 56 deletions

File tree

README.md

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,16 @@
11
# vortex-java
22

3-
> **Experimental** — not production-ready. APIs will change without notice.
3+
> **Alpha** — not production-ready. APIs will change without notice.
44
55
Pure-Java reader/writer for the [Vortex](https://github.com/spiraldb/vortex) columnar file format.
66

7-
## Performance
8-
9-
`RustVsJavaReadBenchmark` — 10M OHLC rows, JMH throughput (higher = better), Apple M5 / 32 GB, Java 25:
10-
11-
| Column | Encoding | vortex-jni | vortex-java | ratio |
12-
|------------------|------------------|-------------|--------------|---------------|
13-
| `volume` (I64) | primitive | 51.9 ops/s | ~115 ops/s | **Java 2.2×** |
14-
| `close` (F64) | ALP (multi-walk) | re-measure | 62 ops/s | re-measure |
15-
| `symbol` (UTF-8) | dict + FSST | re-measure | 7.6 ops/s | re-measure |
16-
17-
The `close` and `symbol` numbers regressed from earlier snapshots (118 and 27.8 respectively)
18-
because commit `347bc34` made the bench data realistic: 30 Nasdaq tickers with independent per-ticker
19-
price walks instead of a single global walker and a constant symbol. Rust's writer responds by
20-
picking heavier encodings — `vortex.dict` over `vortex.fsst` for `symbol`, and an ALP sub-encoding
21-
that no longer fits a single tight reference for `close`. Decode work goes up on both sides;
22-
JNI numbers above are stale and need re-measurement on the new workload.
23-
24-
Reproduce: `./benchmark.sh RustVsJavaReadBenchmark`. Hardware / JDK build / commit SHA used to produce
25-
this snapshot should be captured alongside any update (see TODO #10c).
26-
27-
`RustWritesJavaReadsBigFileBenchmark` — 3 GB file, 4 × I64 columns of random data (defeats
28-
bit-packing so segments stay large), projection on `c0`, JMH throughput:
29-
30-
| Reader | Throughput | ms/op | Decode rate |
31-
|-------------|----------------|-------|-------------|
32-
| vortex-jni | 5.9 ops/s | ~170 | ~4.7 GB/s |
33-
| vortex-java | **19.7 ops/s** | ~51 | ~15.7 GB/s — **Java 3.4×** |
34-
35-
Memory-bandwidth bound on Apple M5 / 32 GB. Reproduce: `./benchmark.sh RustWritesJavaReadsBigFileBenchmark`
36-
(adds a ~30 s fixture build for the JNI write). Pass `-Dvortex.bench.bigfile=<path>` to reuse an existing
37-
fixture between runs.
38-
39-
All columns decoded faster in pure Java than via JNI + Apache Arrow. Key optimisations:
40-
`static final` ValueLayout constants (JIT constant-folding), aligned arena allocation
41-
(`allocate(n, alignment)`), `getAtIndex()`/`setAtIndex()` (clearer stride for the
42-
auto-vectoriser), and O(1) bytes allocation for constant strings (alternating offsets
43-
into a single shared byte buffer).
7+
- ✅ Pure-Java reader for primitive, sequence, ALP, dict, FSST
8+
- ✅ Local (mmap) or Remote (HTTPS, single read of last 65K)
9+
- 🚧 Writer (in progress)
10+
- 🚧 Benchmark against Rust+JNI (in progress)
11+
- 🚧 Full encoding coverage (in progress)
12+
- 🚧 Vectorized decode paths (Panama Vector API)
13+
- ❌ No Iceberg/Spark/Flink integration yet
4414

4515
## Motivation
4616

@@ -56,6 +26,13 @@ reads, making it easier to:
5626
- build and test on any platform with a standard JDK
5727
- debug and profile with standard JVM tooling
5828

29+
## Who is this for?
30+
31+
- JVM analytics engines
32+
- JVM-based OLAP systems
33+
- Anyone who wants mmap‑backed, zero‑copy columnar reads without first decompressing
34+
the whole file (or row chunk)
35+
5936
### Why fewer layers = faster
6037

6138
```
@@ -66,10 +43,10 @@ reads, making it easier to:
6643
│ (BigIntVector.get(i)) │ │ (buffer.getAtIndex) │
6744
└────────────┬─────────────┘ └──────────┬───────────┘
6845
│ Arrow Java API │ FFM API
69-
┌────────────▼─────────────┐ │ (MemorySegment,
70-
│ Apache Arrow (Java) │ │ zero-copy slice)
71-
│ VectorSchemaRoot, │ │
72-
│ BigIntVector, … │ │
46+
┌────────────▼─────────────┐ │ (MemorySegment,
47+
│ Apache Arrow (Java) │ │ zero-copy slice)
48+
│ VectorSchemaRoot, │
49+
│ BigIntVector, … │
7350
└────────────┬─────────────┘ ┌──────────▼───────────┐
7451
│ Arrow C Data Interface │ OS mmap region │
7552
│ (ArrowArray/ArrowSchema) │ (file on disk) │
@@ -101,28 +78,21 @@ file occupies. Decoding reads bytes directly from that view with no copies, no i
10178
Arrow format, and no boundary crossings. The JIT sees the full decode path as ordinary Java
10279
bytecode.
10380

104-
## Why Vortex instead of Parquet
81+
## Design principles
10582

106-
| | Parquet | Vortex |
107-
|------------------------|----------------------------------------|------------------------------------|
108-
| Max column-chunk size | 2 GB (`int32` page offsets) | 4 GB per segment (`uint32` length) |
109-
| Max file offset | 2 GB (`int32` on some implementations) | 16 EB (`uint64` in footer) |
110-
| Encoding extensibility | Fixed codec set | Plugin registry, any encoding |
111-
112-
Files larger than 2 GB are a practical problem with Parquet: the `int32` data-page size field in the page header caps
113-
individual column chunks at 2 GB.
114-
Vortex uses `uint64` offsets throughout the footer, and this library maps files with `MemorySegment` (Java FFM API),
115-
which has no per-mapping size limit — unlike the legacy `FileChannel.map()` API that caps each mapping at 2 GB.
83+
- Zero-copy as much as possible
84+
- No JNI
85+
- No Unsafe -- don't remove safety to gain few %
86+
- Align with vortex-rust and Vortex-go semantics
87+
- Make the JIT happy (constant layouts, predictable strides, no virtual dispatch in hot loops)
88+
- Prepare for the Vector API / Valhalla
11689

11790
## Prior art and inspiration
11891

11992
| Project | Language | Notes |
12093
|-------------------------------------------------------------|----------|---------------------------------------------------------------------|
12194
| [spiraldb/vortex](https://github.com/spiraldb/vortex) | Rust | Reference implementation + JNI bindings |
12295
| [spiraldb/vortex-go](https://github.com/spiraldb/vortex-go) | Go | Pure-language port; primary inspiration for this project's approach |
123-
124-
### Further reading
125-
12696
- [FFM vs Unsafe](https://inside.java/2025/06/12/ffm-vs-unsafe/) — Maurizio Cimadamore's deep-dive on why FFM (`MemorySegment`/`Arena`) supersedes `sun.misc.Unsafe`: safety, performance, and the JVM's path forward
12797

12898
## Serialization formats

0 commit comments

Comments
 (0)