This is an automated email from the ASF dual-hosted git repository.
SteNicholas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git
The following commit(s) were added to refs/heads/main by this push:
new 02daddede [CELEBORN-2421] Avoid redundant ByteBuffer allocation in
LocalPartitionDataReader
02daddede is described below
commit 02daddede2be4f0cd66a5392aa2de66d2475262e
Author: r7raul1984 <[email protected]>
AuthorDate: Thu Aug 20 22:56:03 2026 +0800
[CELEBORN-2421] Avoid redundant ByteBuffer allocation in
LocalPartitionDataReader
### What changes were proposed in this pull request?
Replace the temporary heap `ByteBuffer` allocation in
`readBufferIntoReadBuffer` with a direct write loop using
`ByteBuf.writeBytes(FileChannel, pos, len)`, which writes from the channel
straight into the output `ByteBuf` with no intermediate allocation. The channel
position is advanced manually since the absolute-read API does not move the
cursor.
Additionally, fix two correctness issues in the read loop:
- Throw `EOFException` when `writeBytes` returns `-1` (premature EOF due to
file truncation) instead of silently breaking and returning a partially filled
`ByteBuf` to the caller.
- Throw `IOException` when `writeBytes` returns `0` to prevent the loop
from spinning indefinitely.
### Why are the changes needed?
Previously, `readBufferIntoReadBuffer` allocated a temporary heap
`ByteBuffer` on every call, performed a `FileChannel` read into it, then copied
the data into the output `ByteBuf` — two copies and one allocation per read.
The new approach eliminates the intermediate allocation and one copy.
The original loop also had two correctness issues: `dataFileSize` is cached
at construction time, so a subsequent file truncation could cause `writeBytes`
to return `-1` after the integrity check passes, resulting in the caller
receiving partial data without any error. A return value of `0` would cause an
infinite spin.
### Does this PR resolve a correctness bug?
- [x] Yes
### Does this PR introduce _any_ user-facing change?
- [ ] Yes
### How was this patch tested?
Benchmarks at 1 MB buffer size over 500 iterations show ~2x throughput
improvement and ~40% fewer GC collections compared to the previous
implementation.
Closes #3800 from r7raul1984/jj_fix.
Authored-by: r7raul1984 <[email protected]>
Signed-off-by: Nicholas Jiang <[email protected]>
---
.../worker/storage/LocalPartitionDataReader.java | 25 +++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git
a/worker/src/main/java/org/apache/celeborn/service/deploy/worker/storage/LocalPartitionDataReader.java
b/worker/src/main/java/org/apache/celeborn/service/deploy/worker/storage/LocalPartitionDataReader.java
index 6777c525f..e15e2c8f1 100644
---
a/worker/src/main/java/org/apache/celeborn/service/deploy/worker/storage/LocalPartitionDataReader.java
+++
b/worker/src/main/java/org/apache/celeborn/service/deploy/worker/storage/LocalPartitionDataReader.java
@@ -17,6 +17,7 @@
package org.apache.celeborn.service.deploy.worker.storage;
+import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
@@ -71,12 +72,26 @@ public class LocalPartitionDataReader extends
PartitionDataReader {
public void readBufferIntoReadBuffer(ByteBuf buf, long fileSize, int length,
String filePath)
throws IOException {
Utils.checkFileIntegrity(fileSize - dataFileChanel.position(), length,
filePath);
- ByteBuffer tmpBuffer = ByteBuffer.allocate(length);
- while (tmpBuffer.hasRemaining()) {
- dataFileChanel.read(tmpBuffer);
+ long position = dataFileChanel.position();
+ int totalRead = 0;
+ while (totalRead < length) {
+ int read = buf.writeBytes(dataFileChanel, position + totalRead, length -
totalRead);
+ if (read < 0) {
+ throw new EOFException(
+ "Unexpected EOF in "
+ + filePath
+ + ": expected "
+ + length
+ + " bytes but only read "
+ + totalRead);
+ }
+ if (read == 0) {
+ throw new IOException(
+ "Zero bytes read from " + filePath + ", file may be corrupted or
truncated");
+ }
+ totalRead += read;
}
- tmpBuffer.flip();
- buf.writeBytes(tmpBuffer);
+ dataFileChanel.position(position + totalRead);
}
@Override