Copilot commented on code in PR #3699:
URL: https://github.com/apache/celeborn/pull/3699#discussion_r3386207518


##########
common/src/main/java/org/apache/celeborn/common/meta/ReduceFileMeta.java:
##########
@@ -43,6 +44,11 @@ public ReduceFileMeta(List<Long> chunkOffsets, long 
chunkSize) {
     this.chunkSize = chunkSize;
   }
 
+  public ReduceFileMeta(List<Long> chunkOffsets, List<Boolean> 
chunkCompressed) {
+    this.chunkOffsets = chunkOffsets;
+    this.chunkCompressed = chunkCompressed;
+  }

Review Comment:
   This new constructor does not initialize `chunkSize` (or `nextBoundary`). 
Callers that rely on `ReduceFileMeta` having a meaningful chunk size (e.g., 
code paths that use `addChunkOffset`, or any logic keyed off `chunkSize`) will 
get the default `0`, which is inconsistent with other constructors. A concrete 
fix is to either (a) add a constructor that accepts `chunkSize` alongside 
`chunkCompressed`, or (b) delegate to an existing constructor and set 
`chunkSize` appropriately so metadata remains complete.



##########
worker/src/main/java/org/apache/celeborn/service/deploy/worker/storage/PartitionFilesSorter.java:
##########
@@ -234,6 +234,15 @@ public FileInfo getSortedFileInfo(
           targetBuffer);
     } else {
       DiskFileInfo diskFileInfo = ((DiskFileInfo) fileInfo);
+      if (diskFileInfo.isChunkCompressionEnabled()) {
+        // TODO this is yet to be implemented
+        //  We can read the file one chunk at a time and store chunkid + 
uncompressed offsets before
+        //  writing
+        throw new IOException(
+            "Chunk compressed shuffle file is not supported to sort, file 
path: "
+                + diskFileInfo.getFilePath()
+                + ". Disable celeborn.chunk.compression.enabled when using 
with AQE skew join enabled");
+      }

Review Comment:
   The new error message is actionable but a bit unclear/awkwardly phrased and 
mixes responsibilities (worker-side sorter mentioning Spark AQE). Consider 
rewording to (1) fix grammar ('not supported for sorting'), (2) clearly state 
the limitation ('sorting requires random/sliced reads which are unsupported for 
chunk-compressed files'), and (3) provide concise remediation ('set 
celeborn.chunk.compression.enabled=false' and/or disable the feature that 
triggers sorting) without tying it to a specific Spark feature name in the core 
error.



##########
worker/src/main/java/org/apache/celeborn/service/deploy/worker/file/chunk/compressed/ChunkCompressedFileChannelWriter.java:
##########
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.celeborn.service.deploy.worker.file.chunk.compressed;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.github.luben.zstd.Zstd;
+import com.google.common.annotations.VisibleForTesting;
+import io.netty.buffer.CompositeByteBuf;
+
+import org.apache.celeborn.common.meta.DiskFileInfo;
+import org.apache.celeborn.common.meta.ReduceFileMeta;
+import org.apache.celeborn.common.util.FileChannelUtils;
+import org.apache.celeborn.service.deploy.worker.file.FileChannelWriter;
+
+public class ChunkCompressedFileChannelWriter extends FileChannelWriter {
+  private final FileChannel channel;
+  private final DiskFileInfo diskFileInfo;
+  private final int compressionLevel;
+  private final ChunkBufferPool chunkBufferPool;
+  private final ChunkBufferPool.BufferPair bufferPair;
+  private ByteBuffer chunkBuffer;
+  private ByteBuffer compressedChunkBuffer;
+  private final List<Long> chunkOffsets;
+  private final List<Boolean> chunkCompressed;
+  private final long chunkSize;
+  private boolean closed = false;
+
+  public ChunkCompressedFileChannelWriter(
+      DiskFileInfo diskFileInfo,
+      long chunkSize,
+      int compressionLevel,
+      ChunkBufferPool chunkBufferPool)
+      throws IOException {
+    this.diskFileInfo = diskFileInfo;
+    this.chunkSize = chunkSize;
+    channel = 
FileChannelUtils.createWritableFileChannel(diskFileInfo.getFilePath());
+    this.compressionLevel = compressionLevel;
+    this.chunkBufferPool = chunkBufferPool;
+    bufferPair = chunkBufferPool.acquire(chunkSize);
+    chunkBuffer = bufferPair.chunkBuffer;
+    compressedChunkBuffer = bufferPair.compressedBuffer;
+    chunkOffsets = new ArrayList<>();
+    chunkOffsets.add(0L);
+    chunkCompressed = new ArrayList<>();
+  }
+
+  @Override
+  public void write(CompositeByteBuf buffer, boolean gatherApiEnabled) throws 
IOException {
+    if (buffer.readableBytes() > chunkSize) {
+      // Flush any pending accumulated data before writing the large record so 
file offsets
+      // remain consistent.
+      compressAndFlush();
+      flushLargeRecord(buffer);
+      return;
+    }
+
+    if (buffer.readableBytes() > chunkBuffer.remaining()) {
+      compressAndFlush();
+    }
+
+    ByteBuffer[] buffers = buffer.nioBuffers();
+    for (ByteBuffer byteBuffer : buffers) {
+      while (byteBuffer.hasRemaining()) {
+        chunkBuffer.put(byteBuffer);
+      }
+    }

Review Comment:
   The inner `while (byteBuffer.hasRemaining())` loop is redundant because 
`chunkBuffer.put(byteBuffer)` already consumes the source buffer until either 
the source is exhausted or the destination is full. Since you already ensure 
the total readable bytes fit before this loop, this can be simplified to a 
single `chunkBuffer.put(byteBuffer)` per component, reducing overhead and 
making the intent clearer.



##########
common/src/main/java/org/apache/celeborn/common/network/buffer/FileChunkBuffers.java:
##########
@@ -27,15 +27,25 @@
 public class FileChunkBuffers extends ChunkBuffers {
   private final File file;
   private final TransportConf conf;
+  private final boolean isChunkCompressed;
 
   public FileChunkBuffers(DiskFileInfo fileInfo, TransportConf conf) {
     super(fileInfo.getReduceFileMeta());
+    isChunkCompressed = fileInfo.isChunkCompressionEnabled();
     file = fileInfo.getFile();
     this.conf = conf;
   }
 
   @Override
   public ManagedBuffer chunk(int chunkIndex, int offset, int len) {
+    if (isChunkCompressed && (offset != 0 || len != Integer.MAX_VALUE)) {
+      throw new IllegalArgumentException(
+          "Sliced reads (offset="
+              + offset
+              + ", len="
+              + len
+              + ") are not supported for chunk-compressed files");
+    }

Review Comment:
   This introduces a hard runtime failure for sliced reads on chunk-compressed 
shuffle files. Since this can surface from normal reader behavior (range reads 
/ retries / partial fetch), consider making the failure mode more 
API-appropriate and easier to handle (e.g., a dedicated exception type or an 
`IOException`/`UnsupportedOperationException` message that the client can map 
to a clear user-facing error). Additionally, it would be more robust to prevent 
issuing sliced reads in the first place when `chunkCompressionConfig.enabled` 
is true (so the failure happens at request planning rather than deep in the 
fetch path).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to