Improve `RunLengthBitPackingHybridDecoder.readNext` to avoid per-call buffer allocation and `DataInputStream` wrapping
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 74/100
Research direction
Start in parquet-column/src/main/java/org/apache/parquet/column/values/rle/RunLengthBitPackingHybridDecoder.java, focusing on the PACKED-mode path in readNext() around lines 94–98 and the existing TODO. Trace how buffers and input reads are used, then run the relevant decoder tests. Done means repeated PACKED-mode calls reuse sufficiently sized buffers without per-call DataInputStream wrappers while preserving decoding behavior.
Written by the indexing model from the issue text.
Description
Describe the enhancement requested
RunLengthBitPackingHybridDecoder.readNext() allocates a new int[] and byte[] on every PACKED-mode call. In workloads that decode many bit-packed runs (definition levels, repetition levels, RLE-encoded integers), these allocations dominate the read-side allocation profile. The upstream code even acknowledges this with a // TODO: reuse a buffer comment.
Problem 1: per-call buffer allocation
Lines 94–95 allocate fresh arrays on every PACKED-mode readNext():
currentBuffer = new int[currentCount]; // TODO: reuse a buffer
byte[] bytes = new byte[numGroups * bitWidth];
currentCount is always numGroups * 8, and numGroups is typically small (1–16 groups = 8–128 values per run). These allocations are individually modest but occur thousands of times per column chunk — once per bit-packed run. In a 180M-row merge with multiple integer/boolean columns, the cumulative allocation is substantial.
Since currentCount varies between runs (different numGroups values), the fix retains the field-level int[] and a new field-level byte[], growing them only when the next run requires a larger buffer.
Problem 2: per-call DataInputStream wrapping
Line 98 creates a new DataInputStream(in) on every PACKED-mode call:
new DataInputStream(in).readFully(bytes, 0, bytesToRead);
This allocates a DataInputStream wrapper object per call just to access readFully(). A private readFully() method on the decoder itself eliminates this allocation and the virtual dispatch through the wrapper.
Component(s)
Core
- Dominant language
- Java
- Stars
- 3.1k
- Forks
- 1.6k
- Avg merge
- 4d 12h
- Merged PRs (30d)
- 28
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from apache/parquet-java
-
Type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
apache/parquet-java#3792 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
apache/parquet-java#3767 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
apache/parquet-java#3695 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
apache/parquet-java#3667 ·
-
Type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
apache/parquet-java#3587 ·
All issues in apache/parquet-java
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
elastic/gradle-plugins#157 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
cryptomator/hub#497 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
johanhaleby/occurrent#1120 ·