Akash3121 commented on code in PR #10101:
URL: https://github.com/apache/paimon/pull/10101#discussion_r4090111078


##########
paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexer.java:
##########
@@ -32,7 +32,7 @@ public interface FileIndexer {
 
     FileIndexWriter createWriter();
 
-    FileIndexReader createReader(SeekableInputStream inputStream, int start, 
int length);
+    FileIndexReader createReader(SeekableInputStream inputStream, long start, 
long length);

Review Comment:
   This directly replaces the method descriptor of the `FileIndexer` SPI. 
Existing index plugins are loaded through  `ServiceLoader`  and were compiled 
with  `createReader(SeekableInputStream, int, int)` ; after upgrading Paimon, 
those unchanged plugin binaries do not implement this new descriptor, so 
reading their indexes fails with  `AbstractMethodError` . Could we preserve the 
old overload and add the long overload as a default bridge? For example, keep 
the old `int`  method (deprecated), let the default `long` method range-check 
and delegate to it, and have built-ins that support large positions override 
the long method. Please add a compatibility test that compiles/loads an 
implementation exposing only the old descriptor and reads a V1 container 
through the new runtime.



##########
paimon-core/src/main/java/org/apache/paimon/io/SpillableIndexOutputStream.java:
##########
@@ -0,0 +1,111 @@
+/*
+ * 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.io;
+
+import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.fs.Path;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Keeps a small file index in memory and switches to an independent file at 
the threshold. */
+public final class SpillableIndexOutputStream extends OutputStream {
+
+    private final FileIO fileIO;
+    private final Path path;
+    private final int threshold;
+    private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+    private OutputStream fileOutput;
+    private boolean fileCreated;
+    private boolean closed;
+
+    public SpillableIndexOutputStream(FileIO fileIO, Path path, int threshold) 
{
+        this.fileIO = fileIO;
+        this.path = path;
+        this.threshold = threshold;
+    }
+
+    @Override
+    public void write(int value) throws IOException {
+        if (fileOutput == null && buffer.size() >= threshold) {
+            spill();
+        }
+        if (fileOutput == null) {
+            buffer.write(value);
+        } else {
+            fileOutput.write(value);
+        }
+    }
+
+    @Override
+    public void write(byte[] bytes, int offset, int length) throws IOException 
{
+        if (fileOutput == null && (long) buffer.size() + length > threshold) {
+            spill();
+        }
+        if (fileOutput == null) {
+            buffer.write(bytes, offset, length);
+        } else {
+            fileOutput.write(bytes, offset, length);
+        }
+    }
+
+    private void spill() throws IOException {
+        fileOutput = fileIO.newOutputStream(path, true);
+        fileCreated = true;
+        buffer.writeTo(fileOutput);
+        buffer = new ByteArrayOutputStream();
+    }
+
+    public boolean spilled() {
+        return fileCreated;
+    }
+
+    public byte[] embeddedBytes() {
+        return buffer.toByteArray();
+    }
+
+    @Override
+    public void flush() throws IOException {
+        if (fileOutput != null) {
+            fileOutput.flush();
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (!closed) {
+            closed = true;
+            if (fileOutput != null) {
+                fileOutput.close();
+            }
+        }
+    }
+
+    /** Removes an unpublished independent file after a failed write. */
+    public void abort() throws IOException {
+        try {
+            close();
+        } finally {
+            if (fileCreated) {

Review Comment:
   non-blocking nit: `FileIO.delete`  can return  `false`  instead of throwing 
when cleanup fails (the Hadoop-backed implementations propagate 
`FileSystem.delete` ), but this return value is ignored. A failed streamed 
write can therefore leave its partial index file behind while `abort()` appears 
to have completed. Could we treat  false  as a cleanup failure when the path 
still exists and attach that failure as suppressed to the original write 
exception? A small fake- `FileIO`  test returning  `false`  would cover this 
backend behavior.



-- 
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