This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 527f2eecec [core] Fix invalid length when reading spilled data (#9183)
527f2eecec is described below

commit 527f2eececb3d0e0e72f3374da62fd57e7e8e65b
Author: tsreaper <[email protected]>
AuthorDate: Wed Aug 12 14:05:33 2026 +0800

    [core] Fix invalid length when reading spilled data (#9183)
---
 .../paimon/disk/BufferFileChannelReader.java       | 12 +++-
 .../paimon/disk/ChannelWriterOutputView.java       |  4 +-
 .../paimon/disk/ChannelWriterOutputViewTest.java   | 69 ++++++++++++++++++++++
 3 files changed, 82 insertions(+), 3 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/disk/BufferFileChannelReader.java 
b/paimon-core/src/main/java/org/apache/paimon/disk/BufferFileChannelReader.java
index 6762edeb40..15520b59ef 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/disk/BufferFileChannelReader.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/disk/BufferFileChannelReader.java
@@ -46,7 +46,7 @@ public class BufferFileChannelReader {
 
         // Read header
         header.clear();
-        fileChannel.read(header);
+        readFully(header);
         header.flip();
 
         int size = header.getInt();
@@ -60,8 +60,16 @@ public class BufferFileChannelReader {
         }
         checkArgument(buffer.getSize() == 0, "Buffer not empty");
 
-        fileChannel.read(buffer.getNioBuffer(0, size));
+        readFully(buffer.getNioBuffer(0, size));
         buffer.setSize(size);
         return fileChannel.size() - fileChannel.position() == 0;
     }
+
+    private void readFully(ByteBuffer target) throws IOException {
+        while (target.hasRemaining()) {
+            if (fileChannel.read(target) < 0) {
+                throw new IOException("Premature end of file while reading 
buffer");
+            }
+        }
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/disk/ChannelWriterOutputView.java 
b/paimon-core/src/main/java/org/apache/paimon/disk/ChannelWriterOutputView.java
index c2d3cc2051..3f759cdcca 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/disk/ChannelWriterOutputView.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/disk/ChannelWriterOutputView.java
@@ -65,7 +65,9 @@ public final class ChannelWriterOutputView extends 
AbstractPagedOutputView imple
     public void close() throws IOException {
         if (!writer.isClosed()) {
             int currentPositionInSegment = getCurrentPositionInSegment();
-            writeCompressed(currentSegment, currentPositionInSegment);
+            if (currentPositionInSegment > 0) {
+                writeCompressed(currentSegment, currentPositionInSegment);
+            }
             clear();
             this.writeBytes = writer.getSize();
             this.writer.close();
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/disk/ChannelWriterOutputViewTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/disk/ChannelWriterOutputViewTest.java
new file mode 100644
index 0000000000..9ad0c562e1
--- /dev/null
+++ 
b/paimon-core/src/test/java/org/apache/paimon/disk/ChannelWriterOutputViewTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.paimon.disk;
+
+import org.apache.paimon.compression.BlockCompressionFactory;
+import org.apache.paimon.compression.BlockCompressionType;
+import org.apache.paimon.data.serializer.BinaryRowSerializer;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Path;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link ChannelWriterOutputView}. */
+public class ChannelWriterOutputViewTest {
+
+    private static final int BLOCK_SIZE = 64 * 1024;
+
+    @TempDir Path tempDir;
+
+    @Test
+    public void testEmptyOutput() throws Exception {
+        BlockCompressionFactory compressionFactory =
+                BlockCompressionFactory.create(BlockCompressionType.LZ4);
+        try (IOManager ioManager = IOManager.create(tempDir.toString())) {
+            FileIOChannel.ID channel = ioManager.createChannel();
+            ChannelWriterOutputView output =
+                    FileChannelUtil.createOutputView(
+                            ioManager, channel, compressionFactory, 
BLOCK_SIZE);
+            output.close();
+
+            ChannelReaderInputView input =
+                    new ChannelReaderInputView(
+                            channel,
+                            ioManager,
+                            compressionFactory,
+                            BLOCK_SIZE,
+                            output.getBlockCount());
+            try {
+                assertThat(
+                                new ChannelReaderInputViewIterator(
+                                                input, null, new 
BinaryRowSerializer(1))
+                                        .next())
+                        .isNull();
+                assertThat(output.getBlockCount()).isZero();
+            } finally {
+                input.getChannel().closeAndDelete();
+            }
+        }
+    }
+}

Reply via email to