Skip to content

[spark] Clean up orphan files left by Spark speculative execution - #8927

Open
hbgstc123 wants to merge 12 commits into
apache:masterfrom
hbgstc123:spark-speculative-writer-cleanup
Open

[spark] Clean up orphan files left by Spark speculative execution#8927
hbgstc123 wants to merge 12 commits into
apache:masterfrom
hbgstc123:spark-speculative-writer-cleanup

Conversation

@hbgstc123

Copy link
Copy Markdown

Purpose

Problem
When Spark speculative execution is enabled, Paimon Spark writers use useCommitCoordinator=false. Multiple task attempts can all finish writing and call prepareCommit(), but Spark only commits the winner's WriterCommitMessage. Loser attempts leave data/index files on disk that are never referenced by any snapshot — orphan files.
Why it happens
Spark kills the loser attempt by interrupting the task thread. Paimon writers do not abort prepared files on interruption today, and core abort/delete paths can fail with InterruptedIOException while the thread is interrupted, so loser files are often left behind until orphan cleanup runs (if ever).
What this PR does

  • Add task-side SparkAttemptCleanup to detect interruption and abort unprepared/prepared files before the attempt returns successfully.
  • Wire cleanup into Spark V1/V2 writers, data-evolution writes, format-table writes, and compact procedure.
  • Make core abort paths interrupt-tolerant (FileIO.deleteQuietlyIgnoringInterrupt, FileStoreCommitImpl.abort index cleanup, writer abort executors).
  • Register prepared files incrementally during prepareCommit so a mid-attempt kill can still abort already-finished files.

Tests

  • SparkAttemptCleanupTest, DataEvolutionTableDataWriteTest
  • FileStoreCommitAbortTest, FileIOTest, DeletionVectorsIndexFileTest
  • SparkSpeculativeWriteITCase (DSv2/V1 insert with speculation; loser cleanup and orphan-clean fallback)

@JingsongLi

Copy link
Copy Markdown
Contributor

cc @Zouxxyy

@JingsongLi

Copy link
Copy Markdown
Contributor

The speculative loser cleanup only deletes the main data files, not DataFileMeta.extraFiles(), leaving residual orphans in BLOB/vector/row-sidecar files. A full cleanup based on collectFiles(dataPathFactory) should be performed. Minimal reproduction has been implemented.

hbg added 8 commits August 10, 2026 01:41
Use explicit java.util.function.Consumer instead of Scala lambdas when
calling TableWriteImpl.prepareCommit so Scala 2.12/2.13 can resolve the
overload correctly.
Use DataFileMeta.collectFiles in FileStoreCommitImpl.abort so blobref,
vector, and row sidecar files are cleaned up alongside the main data file.
Register partial commit messages before maintainer work that can fail,
so task-side cleanup can abort already-drained data files.
Use DataFileMeta.collectFiles in AppendOnlyWriter.close and extend tests
to cover bloom-filter sidecar cleanup for flushed but uncommitted files.
@hbgstc123
hbgstc123 force-pushed the spark-speculative-writer-cleanup branch from d5621a0 to f7517be Compare August 9, 2026 17:43
hbg added 4 commits August 10, 2026 02:20
Convert prepareCommit results to immutable Seq before registerPrepared
and return, fixing Scala 2.13 compile errors in paimon-spark-common_2.13.
…leanup

Split prepareCommit paths so Spark onPrepared runs before maintainers while
Flink and other 2-arg callers still materialize CommitMessage after maintainer
work, preserving idle writer cleanup in WriterOperatorTest.
TableWriteImpl routes Flink prepareCommit through the 3-arg overload with a
null callback, so idle writer cleanup must not use the Spark maintainer path
unless onPrepared is non-null.
When onPrepared is null, call FileStoreWrite.prepareCommit directly so Flink
idle writer cleanup keeps the legacy maintainer ordering instead of the Spark
3-arg path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants