Configuration¶
Faster GZIP with libdeflate (Java 22+)¶
Hardwood can use libdeflate for GZIP decompression, which is significantly faster than the built-in Java implementation. This feature requires Java 22 or newer (it uses the Foreign Function & Memory API which became stable in Java 22).
Enabling libdeflate is two steps: a JVM flag to allow native access, plus the native library installed on the system.
1. JVM flag (allow Hardwood to bind native functions):
2. Native library — install on your system:
Or download from GitHub releases.
When libdeflate is installed and available on the library path, Hardwood will automatically use it for GZIP decompression. To disable libdeflate and use the built-in Java implementation instead, set the system property:
SIMD Acceleration with Vector API (Java 22+)¶
Hardwood can use the Java Vector API (SIMD) to accelerate certain decoding operations like counting non-null values, marking nulls, and dictionary lookups. This feature requires Java 22 or newer and is enabled automatically when available.
To enable the Vector API incubator module, add this JVM argument:
When SIMD is available and enabled, you'll see an INFO log message at startup:
The vector width depends on your CPU (128-bit for SSE/NEON, 256-bit for AVX2, 512-bit for AVX-512).
SIMD engages only when the incubator module is added, so to run scalar operations (for debugging or comparison) simply omit the --add-modules jdk.incubator.vector argument.
JFR (Java Flight Recorder) Events¶
Hardwood emits JFR events during file reading, enabling detailed performance profiling with zero overhead when recording is off. Start a JFR recording to capture them:
Or attach dynamically via jcmd <pid> JFR.start.
Available events:
| Event | Category | Description |
|---|---|---|
dev.hardwood.FileOpened |
I/O | File opened and metadata read. Fields: file, fileSize, rowGroupCount, columnCount |
dev.hardwood.FileMapping |
I/O | Memory-mapping of a file region. Fields: file, offset, size |
dev.hardwood.RowGroupScanned |
Decode | Page boundaries scanned in a column chunk. Fields: file, rowGroupIndex, column, pageCount, scanStrategy (sequential or offset-index) |
dev.hardwood.PageDecoded |
Decode | Single data page decoded. Fields: column, compressedSize, uncompressedSize |
dev.hardwood.RowGroupFilter |
Filter | Row groups dropped by statistics/bloom predicate pushdown. Fields: file, totalRowGroups, rowGroupsKept, rowGroupsSkipped, rowGroupsFullyMatching |
dev.hardwood.RowGroupByteRangeFilter |
Filter | Row groups selected by a byte-range split predicate (split-aware reading). Fields: file, totalRowGroups, rowGroupsKept, rowGroupsSkipped |
dev.hardwood.PageFilter |
Filter | Pages filtered by Column Index predicate pushdown, one event per column chunk considered. Fields: file, rowGroupIndex, column, totalPages, pagesKept, pagesSkipped |
dev.hardwood.RecordFilter |
Filter | Records filtered by record-level predicate evaluation, one event per file read. Fields: file, totalRecords, recordsKept, recordsSkipped |
dev.hardwood.BatchWait |
Pipeline | Consumer blocked waiting for the assembly pipeline; the event's duration is the stall. Fields: column |
Events appear under the Hardwood category in JDK Mission Control (JMC) or any JFR analysis tool. Use them to identify:
- I/O bottlenecks — large
FileMappingdurations - Filter effectiveness —
RowGroupFiltershows how many row groups were dropped by statistics/bloom pushdown andRowGroupByteRangeFilterhow many were excluded by split selection;PageFiltershows how many of a column chunk's pages survived the Column Index within a row group that was kept, with no event for a column chunk the Column Index did not narrow — including a chunk that has no Column Index, whose pages are instead dropped from page-header statistics and are not reported;RecordFiltershows how many individual records the predicate decided on per file once that pruning is done - Decode hotspots —
PageDecodedevents with large uncompressed sizes or high frequency - Pipeline stalls —
BatchWaitevents indicate the reader is waiting for decoded data
Reader Options¶
Read-time behaviour is configured with an immutable ReaderConfig, passed to ParquetFileReader.open(...). It is separate from HardwoodContext, which holds the shared runtime resources (the decode thread pool and native decompression pools): a single context can back reads with different ReaderConfigs, so a behaviour knob never forces a fresh thread pool.
import dev.hardwood.HardwoodContext;
import dev.hardwood.reader.ParquetFileReader;
import dev.hardwood.reader.ReaderConfig;
ReaderConfig config = ReaderConfig.builder()
.option("hardwood.fixed-list-fast-path", "true")
.build();
try (HardwoodContext context = HardwoodContext.create();
ParquetFileReader reader = ParquetFileReader.open(inputFile, context, config)) {
// ...
}
Obtain the defaults with ReaderConfig.defaults(). The open(inputFile) and open(inputFile, context) overloads use the defaults.
Write-time behaviour is configured separately, with a WriterConfig passed to ParquetFileWriter.create(...) — see the Writer Reference.
Options are string-keyed and keys are matched case-sensitively; boolean option values are compared case-insensitively. An unrecognised key is ignored (so a transitional flag can be retired without breaking callers) but logged at WARNING, so a typo in a live key surfaces rather than silently taking the default.
| Option | Default | Description |
|---|---|---|
hardwood.fixed-list-fast-path |
false |
Set to "true" to decode fixed-size LIST columns (e.g. embedding vectors, where every row holds the same number of non-null elements) without reconstructing per-row definition and repetition levels. Off by default, so every column takes the general nested-decode path unless the option is enabled. |
hardwood.metadata-filtering |
true |
Set to "false" to disable metadata-based filtering: no row groups or pages are skipped from min/max statistics, bloom filters, dictionary pages, or page indexes, and filter predicates are instead evaluated against every decoded row. Filtered results then depend only on the data pages, for files whose footer or page-index metadata is unreliable. |
System Properties Reference¶
| Property | Default | Description |
|---|---|---|
hardwood.uselibdeflate |
true |
Set to false to disable libdeflate for GZIP decompression |