PDGGK opened a new pull request, #9233:
URL: https://github.com/apache/paimon/pull/9233

   ### Purpose
   
   `ObjectsFile#writeWithoutRolling` reads the stream position inside the 
`finally`, ahead of the close:
   
   ```java
   PositionOutputStream out = fileIO.newOutputStream(path, false);
   long pos;
   try {
       try (FormatWriter writer = writerFactory.create(out, compression)) {
           while (records.hasNext()) {
               writer.addElement(serializer.toRow(records.next()));
           }
       }
   } finally {
       pos = out.getPos();   // <- declared `throws IOException`
       out.close();          // <- skipped if it does
   }
   ```
   
   `PositionOutputStream#getPos` is `public abstract long getPos() throws 
IOException`. When it throws:
   
   * `out.close()` is never reached and the stream leaks, and
   * the `finally`'s exception **replaces** whatever the try body was throwing. 
These are not attached as suppressed — that only happens for try-with-resources 
— so the original write failure is discarded and the caller sees the `getPos` 
error in its place.
   
   The two failures are not independent. The try body usually throws because 
the underlying stream is already broken — a full disk, an object store 
rejecting the upload — and `getPos` on that same stream is then likely to throw 
as well. So the case where the position read fails is largely the same case 
where losing the write error hurts most.
   
   ### What changes
   
   `pos` is only read by the success-path `return`, so it moves there:
   
   ```java
   try {
       try (FormatWriter writer = writerFactory.create(out, compression)) {
           ...
       }
       pos = out.getPos();
   } finally {
       out.close();
   }
   return Pair.of(path.getName(), pos);
   ```
   
   One line moved. On a successful write the value is identical — it is still 
read after the `FormatWriter` has been closed and its buffers flushed. On a 
failing write, `close()` now runs and the original exception propagates.
   
   ### Tests
   
   None added, and I would rather say why than leave it unexplained. Reaching 
the branch needs a `FileIO` whose streams fail on `getPos`, and the existing 
tests build their manifest files through `table.store()...Factory().create()`, 
which supplies the catalog's own `FileIO` with no seam to substitute one. 
Building an `ObjectsFile` directly means supplying a serializer, a schema and 
reader/writer factories by hand, which is a lot of scaffolding for a one-line 
move — but I am happy to write it if you would like the coverage.
   
   `BinaryIndexManifestEntryTest` exercises the success path through this 
method and still passes (2 tests, 0 failures). `spotless:check` and 
`checkstyle:check` on `paimon-core` are clean.
   
   ### API and Format
   
   No change to any public signature, option, or on-disk format. Behaviour 
differs only on the failure path, where the stream is now closed and the 
original exception is the one that propagates.
   
   ### Note
   
   #8927 also touches this method, in the `catch (Throwable e)` block below 
(`deleteQuietly` → `deleteQuietlyIgnoringInterrupt`). Different lines and a 
different concern, but worth flagging since they are close together.
   


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