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 f218528437 [core] Clean up index files on aborted commits (#8572)
f218528437 is described below

commit f218528437bbd697f3ff63261ebefb7d414a1c0e
Author: QuakeWang <[email protected]>
AuthorDate: Mon Jul 13 10:17:48 2026 +0800

    [core] Clean up index files on aborted commits (#8572)
    
    `FileStoreCommitImpl.abort` deleted uncommitted data and changelog files
    but ignored `newIndexFiles` from both data and compact increments.
    Aborted commits could therefore leave index files behind, including
    files stored at external paths.
    
    Clean up both sets of new index files through `IndexFilePathFactories`.
    Keep `deletedIndexFiles` untouched because they still belong to the
    active snapshot when the commit is aborted.
---
 .../paimon/operation/FileStoreCommitImpl.java      | 34 ++++++++++----
 .../paimon/operation/FileStoreCommitTest.java      | 53 ++++++++++++++++++++++
 2 files changed, 77 insertions(+), 10 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/FileStoreCommitImpl.java
 
b/paimon-core/src/main/java/org/apache/paimon/operation/FileStoreCommitImpl.java
index cb2357eabe..07505fa3e4 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/FileStoreCommitImpl.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/FileStoreCommitImpl.java
@@ -27,6 +27,8 @@ import org.apache.paimon.data.BinaryRow;
 import org.apache.paimon.data.InternalRow;
 import org.apache.paimon.disk.IOManager;
 import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.index.IndexFileMeta;
+import org.apache.paimon.index.IndexPathFactory;
 import org.apache.paimon.io.DataFileMeta;
 import org.apache.paimon.io.DataFilePathFactory;
 import org.apache.paimon.manifest.FileEntry;
@@ -75,6 +77,7 @@ import org.apache.paimon.types.RowType;
 import org.apache.paimon.utils.DataFilePathFactories;
 import org.apache.paimon.utils.FileStorePathFactory;
 import org.apache.paimon.utils.IOUtils;
+import org.apache.paimon.utils.IndexFilePathFactories;
 import org.apache.paimon.utils.InternalRowPartitionComputer;
 import org.apache.paimon.utils.ListUtils;
 import org.apache.paimon.utils.Pair;
@@ -670,18 +673,29 @@ public class FileStoreCommitImpl implements 
FileStoreCommit {
 
     @Override
     public void abort(List<CommitMessage> commitMessages) {
-        DataFilePathFactories factories = new 
DataFilePathFactories(pathFactory);
+        DataFilePathFactories dataFactories = new 
DataFilePathFactories(pathFactory);
+        IndexFilePathFactories indexFactories = new 
IndexFilePathFactories(pathFactory);
         for (CommitMessage message : commitMessages) {
-            DataFilePathFactory pathFactory = 
factories.get(message.partition(), message.bucket());
+            DataFilePathFactory dataPathFactory =
+                    dataFactories.get(message.partition(), message.bucket());
+            IndexPathFactory indexPathFactory =
+                    indexFactories.get(message.partition(), message.bucket());
             CommitMessageImpl commitMessage = (CommitMessageImpl) message;
-            List<DataFileMeta> toDelete = new ArrayList<>();
-            toDelete.addAll(commitMessage.newFilesIncrement().newFiles());
-            
toDelete.addAll(commitMessage.newFilesIncrement().changelogFiles());
-            toDelete.addAll(commitMessage.compactIncrement().compactAfter());
-            toDelete.addAll(commitMessage.compactIncrement().changelogFiles());
-
-            for (DataFileMeta file : toDelete) {
-                fileIO.deleteQuietly(pathFactory.toPath(file));
+            List<DataFileMeta> dataFilesToDelete = new ArrayList<>();
+            
dataFilesToDelete.addAll(commitMessage.newFilesIncrement().newFiles());
+            
dataFilesToDelete.addAll(commitMessage.newFilesIncrement().changelogFiles());
+            
dataFilesToDelete.addAll(commitMessage.compactIncrement().compactAfter());
+            
dataFilesToDelete.addAll(commitMessage.compactIncrement().changelogFiles());
+
+            for (DataFileMeta file : dataFilesToDelete) {
+                fileIO.deleteQuietly(dataPathFactory.toPath(file));
+            }
+
+            List<IndexFileMeta> indexFilesToDelete = new ArrayList<>();
+            
indexFilesToDelete.addAll(commitMessage.newFilesIncrement().newIndexFiles());
+            
indexFilesToDelete.addAll(commitMessage.compactIncrement().newIndexFiles());
+            for (IndexFileMeta file : indexFilesToDelete) {
+                fileIO.deleteQuietly(indexPathFactory.toPath(file));
             }
         }
     }
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/operation/FileStoreCommitTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/operation/FileStoreCommitTest.java
index e3903b5077..97f4a5b804 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/operation/FileStoreCommitTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/operation/FileStoreCommitTest.java
@@ -34,6 +34,7 @@ import org.apache.paimon.fs.local.LocalFileIO;
 import org.apache.paimon.index.GlobalIndexMeta;
 import org.apache.paimon.index.IndexFileHandler;
 import org.apache.paimon.index.IndexFileMeta;
+import org.apache.paimon.index.IndexPathFactory;
 import org.apache.paimon.io.CompactIncrement;
 import org.apache.paimon.io.DataFileMeta;
 import org.apache.paimon.io.DataIncrement;
@@ -960,6 +961,58 @@ public class FileStoreCommitTest {
         assertThat(dvs.get("f2").isDeleted(3)).isTrue();
     }
 
+    @Test
+    public void testAbortIndexFiles() throws Exception {
+        Map<String, String> options = new HashMap<>();
+        options.put(CoreOptions.INDEX_FILE_IN_DATA_FILE_DIR.key(), "true");
+        TestAppendFileStore store = 
TestAppendFileStore.createAppendStore(tempDir, options);
+        BinaryRow partition = gen.getPartition(gen.next());
+        IndexPathFactory indexPathFactory = 
store.pathFactory().indexFileFactory(partition, 0);
+
+        Path dataNewPath = indexPathFactory.newPath();
+        IndexFileMeta dataNew = createIndexFile(store, dataNewPath, false);
+        Path compactNewPath = new 
Path(tempDir.resolve("external-new-index").toUri());
+        IndexFileMeta compactNew = createIndexFile(store, compactNewPath, 
true);
+        Path dataDeletedPath = indexPathFactory.newPath();
+        IndexFileMeta dataDeleted = createIndexFile(store, dataDeletedPath, 
false);
+        Path compactDeletedPath = indexPathFactory.newPath();
+        IndexFileMeta compactDeleted = createIndexFile(store, 
compactDeletedPath, false);
+
+        CommitMessage commitMessage =
+                new CommitMessageImpl(
+                        partition,
+                        0,
+                        store.options().bucket(),
+                        new DataIncrement(
+                                Collections.emptyList(),
+                                Collections.emptyList(),
+                                Collections.emptyList(),
+                                Collections.singletonList(dataNew),
+                                Collections.singletonList(dataDeleted)),
+                        new CompactIncrement(
+                                Collections.emptyList(),
+                                Collections.emptyList(),
+                                Collections.emptyList(),
+                                Collections.singletonList(compactNew),
+                                Collections.singletonList(compactDeleted)));
+
+        try (FileStoreCommitImpl commit = store.newCommit()) {
+            commit.abort(Collections.singletonList(commitMessage));
+        }
+
+        assertThat(store.fileIO().exists(dataNewPath)).isFalse();
+        assertThat(store.fileIO().exists(compactNewPath)).isFalse();
+        assertThat(store.fileIO().exists(dataDeletedPath)).isTrue();
+        assertThat(store.fileIO().exists(compactDeletedPath)).isTrue();
+    }
+
+    private static IndexFileMeta createIndexFile(
+            TestAppendFileStore store, Path path, boolean external) throws 
Exception {
+        store.fileIO().newOutputStream(path, false).close();
+        return new IndexFileMeta(
+                HASH_INDEX, path.getName(), 0, 0, null, external ? 
path.toString() : null, null);
+    }
+
     @Test
     public void testRollbackToAsLatestFileLevelDeleteIsVisibleToStreaming() 
throws Exception {
         // Contrast with the DV-only case: when a rollback removes whole data 
files, the delete is

Reply via email to