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

   ### Purpose
   
   A compaction task writes its output files before its `CompactResult` reaches 
the writer, and that
   result is the only thing that knows their names. Two paths throw it away and 
leave the files
   behind:
   
   - **The task is cancelled.** `CompactFutureManager#cancelCompaction` 
interrupts the thread and the
     future drops the result, so nothing deletes what was already written. This 
is the case the TODO
     in that method described:
   
     ```java
     // TODO this method may leave behind orphan files if compaction is 
actually finished
     //  but some CPU work still needs to be done
     ```
   
   - **A part of a merge tree compaction fails.** `MergeTreeCompactTask` calls 
the rewriter more than
     once per task: a large, non overlapping file sitting between two groups of 
overlapping sections
     flushes the accumulated candidates and is then upgraded on its own. The 
groups that already
     finished have closed their writers, so their files can only be reached 
through the result of the
     whole task, which is never returned now.
   
   `RollingFileWriterImpl` already aborts the file it is writing when the write 
itself fails, so what
   leaks is the output of *earlier completed* rewrite calls, not the in flight 
one. Those files stay
   in the bucket directory, referenced by nothing, until an orphan file clean 
runs.
   
   `CompactResult` now carries the `FileWriterAbortExecutor`s of the files it 
describes, and
   `CompactTask` takes them over as each part of it finishes. A task deletes 
them itself when it fails
   or when it notices it was cancelled; `cancelCompaction` deletes them for a 
task that never gets far
   enough to observe the interrupt.
   
   Two related leaks are out of scope here: the remote lookup files created by
   `LookupMergeTreeCompactRewriter#notifyRewriteCompactAfter`, and the unaware 
bucket dedicated
   compaction job, which has its own lifecycle and never goes through 
`CompactFutureManager`.
   
   Internal signature changes: `RollingFileWriter` gains 
`drainAbortExecutors()`, and
   `BucketedAppendCompactManager.CompactRewriter#rewrite` and 
`BaseAppendFileStoreWrite#compactRewrite`
   return `CompactResult` instead of `List<DataFileMeta>`. No public API or 
format change.
   
   ### Tests
   
   `CompactOrphanFileTest` reproduces the leak end to end on a real merge tree, 
with real files in a
   real bucket directory. Five level 0 files are laid out so that a single 
`MergeTreeCompactTask` makes
   two separate rewrite calls:
   
   | level 0 file | key range | role |
   |---|---|---|
   | 1 | `[1, 10]` | small, overlaps the next one |
   | 2 | `[5, 15]` | small, closes the first section (2 sorted runs) |
   | 3 | `[100, 700]` | large, its own section, flushes the accumulated 
candidates and is then upgraded |
   | 4 | `[2000, 2010]` | small, overlaps the next one |
   | 5 | `[2005, 2015]` | small, closes the last section (2 sorted runs) |
   
   The second rewrite call is then broken, once by cancelling the compaction 
and once by throwing, and
   the test asserts that the bucket directory holds nothing beyond the five 
input files.
   
   **Before this change** (the same test run against the parent commit):
   
   ```
   CompactOrphanFileTest.testCancelledCompactionLeavesNoOrphanFile  <<< FAILURE!
   Expecting empty but was: 
["data-853a7215-e4de-492c-907c-3600d783fc99-6.parquet"]
   
   CompactOrphanFileTest.testFailedCompactionLeavesNoOrphanFile  <<< FAILURE!
   Expecting empty but was: 
["data-8a2661d2-a0b1-4f00-a313-01b3d64da1e4-6.parquet"]
   
   Tests run: 3, Failures: 2, Errors: 0, Skipped: 0
   ```
   
   Each leaked file is the real output of the first rewrite call, left in the 
bucket directory with
   nothing referencing it.
   
   **After this change:**
   
   ```
   Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
   ```
   
   The third case is the control: a compaction that runs to the end must keep 
its files, so the test
   does not pass simply by deleting everything.
   
   `CompactTaskCancelTest` covers the `CompactTask` bookkeeping directly, 
including that a task which
   succeeds keeps its files.
   
   Existing suites: 291 tests across the compaction, append, merge tree, lookup 
and clustering
   packages of `paimon-core` pass, and `paimon-flink-common`, 
`paimon-flink-cdc` and
   `paimon-spark-common` still compile.
   


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