This is an automated email from the ASF dual-hosted git repository.

lzljs3620320 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 bb453c283 [core] add parallelism arguement for remove orphan files 
(#4044)
bb453c283 is described below

commit bb453c28332ecc4aa41f3db762315d254d9947ec
Author: LsomeYeah <[email protected]>
AuthorDate: Wed Sep 11 15:31:45 2024 +0800

    [core] add parallelism arguement for remove orphan files (#4044)
---
 docs/content/flink/procedures.md                   |  7 ++++--
 docs/content/maintenance/manage-snapshots.md       |  3 ++-
 docs/content/spark/procedures.md                   |  4 +++-
 .../apache/paimon/operation/OrphanFilesClean.java  | 20 ++++++++++-------
 .../procedure/RemoveOrphanFilesProcedure.java      | 26 +++++++++++++++++++++-
 .../flink/action/RemoveOrphanFilesAction.java      |  6 +++--
 .../action/RemoveOrphanFilesActionFactory.java     | 12 +++++++++-
 .../procedure/RemoveOrphanFilesProcedure.java      | 25 ++++++++++++++++++---
 .../action/RemoveOrphanFilesActionITCase.java      | 10 +++++++++
 .../procedure/RemoveOrphanFilesProcedure.java      | 18 ++++++++++++++-
 10 files changed, 111 insertions(+), 20 deletions(-)

diff --git a/docs/content/flink/procedures.md b/docs/content/flink/procedures.md
index 6c66f5411..c3018600c 100644
--- a/docs/content/flink/procedures.md
+++ b/docs/content/flink/procedures.md
@@ -214,7 +214,8 @@ All available procedures are listed below.
       <td>
          CALL [catalog.]sys.remove_orphan_files('identifier')<br/><br/>
          CALL [catalog.]sys.remove_orphan_files('identifier', 
'olderThan')<br/><br/>
-         CALL [catalog.]sys.remove_orphan_files('identifier', 'olderThan', 
'dryRun')
+         CALL [catalog.]sys.remove_orphan_files('identifier', 'olderThan', 
'dryRun')<br/><br/>
+         CALL [catalog.]sys.remove_orphan_files('identifier', 'olderThan', 
'dryRun','parallelism')
       </td>
       <td>
          To remove the orphan data files and metadata files. Arguments:
@@ -223,10 +224,12 @@ All available procedures are listed below.
                deletes orphan files older than 1 day by default. This argument 
can modify the interval.
             </li>
             <li>dryRun: when true, view only orphan files, don't actually 
remove files. Default is false.</li>
+            <li>parallelism: The maximum number of concurrent deleting files. 
By default is the number of processors available to the Java virtual 
machine.</li>
       </td>
       <td>CALL remove_orphan_files('default.T', '2023-10-31 
12:00:00')<br/><br/>
           CALL remove_orphan_files('default.*', '2023-10-31 
12:00:00')<br/><br/>
-          CALL remove_orphan_files('default.T', '2023-10-31 12:00:00', true)
+          CALL remove_orphan_files('default.T', '2023-10-31 12:00:00', 
true)<br/><br/>
+          CALL remove_orphan_files('default.T', '2023-10-31 12:00:00', false, 
'5')
       </td>
    </tr>
    <tr>
diff --git a/docs/content/maintenance/manage-snapshots.md 
b/docs/content/maintenance/manage-snapshots.md
index f7fb94d01..d25124008 100644
--- a/docs/content/maintenance/manage-snapshots.md
+++ b/docs/content/maintenance/manage-snapshots.md
@@ -314,7 +314,8 @@ CALL sys.remove_orphan_files(table => "my_db.*", 
[older_than => "2023-10-31 12:0
     --database <database-name> \ 
     --table <table-name> \
     [--older_than <timestamp>] \
-    [--dry_run <false/true>] 
+    [--dry_run <false/true>] \
+    [--parallelism <parallelism>]
 ```
 
 To avoid deleting files that are newly added by other writing jobs, this 
action only deletes orphan files older than
diff --git a/docs/content/spark/procedures.md b/docs/content/spark/procedures.md
index 249ede0e8..085e5866f 100644
--- a/docs/content/spark/procedures.md
+++ b/docs/content/spark/procedures.md
@@ -161,11 +161,13 @@ This section introduce all available spark procedures 
about paimon.
             <li>table: the target table identifier. Cannot be empty, you can 
use database_name.* to clean whole database.</li>
             <li>older_than: to avoid deleting newly written files, this 
procedure only deletes orphan files older than 1 day by default. This argument 
can modify the interval.</li>
             <li>dry_run: when true, view only orphan files, don't actually 
remove files. Default is false.</li>
+            <li>parallelism: The maximum number of concurrent deleting files. 
By default is the number of processors available to the Java virtual 
machine.</li>
       </td>
       <td>
           CALL sys.remove_orphan_files(table => 'default.T', older_than => 
'2023-10-31 12:00:00')<br/><br/>
           CALL sys.remove_orphan_files(table => 'default.*', older_than => 
'2023-10-31 12:00:00')<br/><br/>
-          CALL sys.remove_orphan_files(table => 'default.T', older_than => 
'2023-10-31 12:00:00', dry_run => true)
+          CALL sys.remove_orphan_files(table => 'default.T', older_than => 
'2023-10-31 12:00:00', dry_run => true)<br/><br/>
+          CALL sys.remove_orphan_files(table => 'default.T', older_than => 
'2023-10-31 12:00:00', dry_run => true, parallelism => '5')
       </td>
     </tr>
     <tr>
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/OrphanFilesClean.java 
b/paimon-core/src/main/java/org/apache/paimon/operation/OrphanFilesClean.java
index dd57f269c..f5a32583f 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/OrphanFilesClean.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/OrphanFilesClean.java
@@ -95,9 +95,7 @@ public class OrphanFilesClean {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(OrphanFilesClean.class);
 
-    private static final ThreadPoolExecutor EXECUTOR =
-            createCachedThreadPool(
-                    Runtime.getRuntime().availableProcessors(), 
"ORPHAN_FILES_CLEAN");
+    private final ThreadPoolExecutor executor;
 
     private static final int READ_FILE_RETRY_NUM = 3;
     private static final int READ_FILE_RETRY_INTERVAL = 5;
@@ -130,6 +128,9 @@ public class OrphanFilesClean {
                     } catch (IOException ignored) {
                     }
                 };
+        this.executor =
+                createCachedThreadPool(
+                        table.coreOptions().deleteFileThreadNum(), 
"ORPHAN_FILES_CLEAN");
     }
 
     public OrphanFilesClean olderThan(String timestamp) {
@@ -204,7 +205,7 @@ public class OrphanFilesClean {
 
         return Sets.newHashSet(
                 randomlyExecute(
-                        EXECUTOR, snapshot -> getUsedFiles(branchTable, 
snapshot), readSnapshots));
+                        executor, snapshot -> getUsedFiles(branchTable, 
snapshot), readSnapshots));
     }
 
     private List<String> getUsedFiles(FileStoreTable branchTable, Snapshot 
snapshot) {
@@ -234,7 +235,7 @@ public class OrphanFilesClean {
                                 .filter(this::oldEnough)
                                 .map(FileStatus::getPath)
                                 .collect(Collectors.toList());
-        Iterator<Path> allPaths = randomlyExecute(EXECUTOR, processor, 
fileDirs);
+        Iterator<Path> allPaths = randomlyExecute(executor, processor, 
fileDirs);
         Map<String, Path> result = new HashMap<>();
         while (allPaths.hasNext()) {
             Path next = allPaths.next();
@@ -525,7 +526,7 @@ public class OrphanFilesClean {
 
         // dive into the next partition level
         return Lists.newArrayList(
-                randomlyExecute(EXECUTOR, p -> listAndCleanDataDirs(p, level - 
1), partitionPaths));
+                randomlyExecute(executor, p -> listAndCleanDataDirs(p, level - 
1), partitionPaths));
     }
 
     private List<Path> filterAndCleanDataDirs(
@@ -581,7 +582,10 @@ public class OrphanFilesClean {
     }
 
     public static List<OrphanFilesClean> createOrphanFilesCleans(
-            Catalog catalog, String databaseName, @Nullable String tableName)
+            Catalog catalog,
+            Map<String, String> tableConfig,
+            String databaseName,
+            @Nullable String tableName)
             throws Catalog.DatabaseNotExistException, 
Catalog.TableNotExistException {
         List<OrphanFilesClean> orphanFilesCleans = new ArrayList<>();
         List<String> tableNames = Collections.singletonList(tableName);
@@ -591,7 +595,7 @@ public class OrphanFilesClean {
 
         for (String t : tableNames) {
             Identifier identifier = new Identifier(databaseName, t);
-            Table table = catalog.getTable(identifier);
+            Table table = catalog.getTable(identifier).copy(tableConfig);
             checkArgument(
                     table instanceof FileStoreTable,
                     "Only FileStoreTable supports remove-orphan-files action. 
The table type is '%s'.",
diff --git 
a/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
 
b/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
index 03a498606..47e2a56c0 100644
--- 
a/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
+++ 
b/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
@@ -18,13 +18,17 @@
 
 package org.apache.paimon.flink.procedure;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.operation.OrphanFilesClean;
 import org.apache.paimon.utils.StringUtils;
 
 import org.apache.flink.table.procedure.ProcedureContext;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static 
org.apache.paimon.operation.OrphanFilesClean.executeOrphanFilesClean;
 
@@ -58,12 +62,32 @@ public class RemoveOrphanFilesProcedure extends 
ProcedureBase {
     public String[] call(
             ProcedureContext procedureContext, String tableId, String 
olderThan, boolean dryRun)
             throws Exception {
+        return call(procedureContext, tableId, olderThan, dryRun, "");
+    }
+
+    public String[] call(
+            ProcedureContext procedureContext,
+            String tableId,
+            String olderThan,
+            boolean dryRun,
+            String parallelism)
+            throws Exception {
         Identifier identifier = Identifier.fromString(tableId);
         String databaseName = identifier.getDatabaseName();
         String tableName = identifier.getObjectName();
 
+        Map<String, String> dynamicOptions =
+                !StringUtils.isNullOrWhitespaceOnly(parallelism)
+                        ? Collections.emptyMap()
+                        : new HashMap<String, String>() {
+                            {
+                                put(CoreOptions.DELETE_FILE_THREAD_NUM.key(), 
parallelism);
+                            }
+                        };
+
         List<OrphanFilesClean> tableCleans =
-                OrphanFilesClean.createOrphanFilesCleans(catalog, 
databaseName, tableName);
+                OrphanFilesClean.createOrphanFilesCleans(
+                        catalog, dynamicOptions, databaseName, tableName);
 
         if (!StringUtils.isNullOrWhitespaceOnly(olderThan)) {
             tableCleans.forEach(clean -> clean.olderThan(olderThan));
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesAction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesAction.java
index c95db99d5..9b369a0dc 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesAction.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesAction.java
@@ -37,11 +37,13 @@ public class RemoveOrphanFilesAction extends ActionBase {
             String warehouse,
             String databaseName,
             @Nullable String tableName,
-            Map<String, String> catalogConfig)
+            Map<String, String> catalogConfig,
+            Map<String, String> dynamicOptions)
             throws Catalog.TableNotExistException, 
Catalog.DatabaseNotExistException {
         super(warehouse, catalogConfig);
         this.tableCleans =
-                OrphanFilesClean.createOrphanFilesCleans(catalog, 
databaseName, tableName);
+                OrphanFilesClean.createOrphanFilesCleans(
+                        catalog, dynamicOptions, databaseName, tableName);
     }
 
     public void olderThan(String olderThan) {
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionFactory.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionFactory.java
index 769453d4a..6ac6e7280 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionFactory.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionFactory.java
@@ -18,6 +18,9 @@
 
 package org.apache.paimon.flink.action;
 
+import org.apache.paimon.CoreOptions;
+
+import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 
@@ -29,6 +32,7 @@ public class RemoveOrphanFilesActionFactory implements 
ActionFactory {
     public static final String IDENTIFIER = "remove_orphan_files";
     private static final String OLDER_THAN = "older_than";
     private static final String DRY_RUN = "dry_run";
+    private static final String PARALLELISM = "parallelism";
 
     @Override
     public String identifier() {
@@ -44,10 +48,16 @@ public class RemoveOrphanFilesActionFactory implements 
ActionFactory {
         String table = params.get(TABLE);
 
         Map<String, String> catalogConfig = optionalConfigMap(params, 
CATALOG_CONF);
+        Map<String, String> dynamicOptions = new HashMap<>();
+        if (params.has(PARALLELISM)) {
+            dynamicOptions.put(CoreOptions.DELETE_FILE_THREAD_NUM.key(), 
params.get(PARALLELISM));
+        }
 
         RemoveOrphanFilesAction action;
         try {
-            action = new RemoveOrphanFilesAction(warehouse, database, table, 
catalogConfig);
+            action =
+                    new RemoveOrphanFilesAction(
+                            warehouse, database, table, catalogConfig, 
dynamicOptions);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
index 1d6e024b8..b7a857e45 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/RemoveOrphanFilesProcedure.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.flink.procedure;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.operation.OrphanFilesClean;
 import org.apache.paimon.utils.StringUtils;
@@ -27,7 +28,10 @@ import org.apache.flink.table.annotation.DataTypeHint;
 import org.apache.flink.table.annotation.ProcedureHint;
 import org.apache.flink.table.procedure.ProcedureContext;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static 
org.apache.paimon.operation.OrphanFilesClean.executeOrphanFilesClean;
 
@@ -56,13 +60,18 @@ public class RemoveOrphanFilesProcedure extends 
ProcedureBase {
                         name = "older_than",
                         type = @DataTypeHint("STRING"),
                         isOptional = true),
-                @ArgumentHint(name = "dry_run", type = 
@DataTypeHint("BOOLEAN"), isOptional = true)
+                @ArgumentHint(name = "dry_run", type = 
@DataTypeHint("BOOLEAN"), isOptional = true),
+                @ArgumentHint(
+                        name = "parallelism",
+                        type = @DataTypeHint("STRING"),
+                        isOptional = true)
             })
     public String[] call(
             ProcedureContext procedureContext,
             String tableId,
             String nullableOlderThan,
-            Boolean dryRun)
+            Boolean dryRun,
+            String parallelism)
             throws Exception {
         final String olderThan = notnull(nullableOlderThan);
         if (dryRun == null) {
@@ -73,8 +82,18 @@ public class RemoveOrphanFilesProcedure extends 
ProcedureBase {
         String databaseName = identifier.getDatabaseName();
         String tableName = identifier.getObjectName();
 
+        Map<String, String> dynamicOptions =
+                !StringUtils.isNullOrWhitespaceOnly(parallelism)
+                        ? Collections.emptyMap()
+                        : new HashMap<String, String>() {
+                            {
+                                put(CoreOptions.DELETE_FILE_THREAD_NUM.key(), 
parallelism);
+                            }
+                        };
+
         List<OrphanFilesClean> tableCleans =
-                OrphanFilesClean.createOrphanFilesCleans(catalog, 
databaseName, tableName);
+                OrphanFilesClean.createOrphanFilesCleans(
+                        catalog, dynamicOptions, databaseName, tableName);
 
         if (!StringUtils.isNullOrWhitespaceOnly(olderThan)) {
             tableCleans.forEach(clean -> clean.olderThan(olderThan));
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionITCase.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionITCase.java
index 844ade694..b0bd7d0d6 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionITCase.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/RemoveOrphanFilesActionITCase.java
@@ -185,6 +185,11 @@ public class RemoveOrphanFilesActionITCase extends 
ActionITCaseBase {
         RemoveOrphanFilesAction action2 = 
createAction(RemoveOrphanFilesAction.class, args);
         assertThatCode(action2::run).doesNotThrowAnyException();
 
+        args.add("--parallelism");
+        args.add("5");
+        RemoveOrphanFilesAction action3 = 
createAction(RemoveOrphanFilesAction.class, args);
+        assertThatCode(action3::run).doesNotThrowAnyException();
+
         String withoutOlderThan =
                 String.format(
                         isNamedArgument
@@ -195,6 +200,11 @@ public class RemoveOrphanFilesActionITCase extends 
ActionITCaseBase {
         CloseableIterator<Row> withoutOlderThanCollect = 
callProcedure(withoutOlderThan);
         
assertThat(ImmutableList.copyOf(withoutOlderThanCollect).size()).isEqualTo(0);
 
+        String withParallelism =
+                String.format("CALL 
sys.remove_orphan_files('%s.%s','',true,'5')", database, "*");
+        CloseableIterator<Row> withParallelismCollect = 
callProcedure(withParallelism);
+        
assertThat(ImmutableList.copyOf(withParallelismCollect).size()).isEqualTo(0);
+
         String withDryRun =
                 String.format(
                         isNamedArgument
diff --git 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/procedure/RemoveOrphanFilesProcedure.java
 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/procedure/RemoveOrphanFilesProcedure.java
index a22ec01a6..6c977e0da 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/procedure/RemoveOrphanFilesProcedure.java
+++ 
b/paimon-spark/paimon-spark-common/src/main/java/org/apache/paimon/spark/procedure/RemoveOrphanFilesProcedure.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.spark.procedure;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.operation.OrphanFilesClean;
 import org.apache.paimon.spark.catalog.WithPaimonCatalog;
 import org.apache.paimon.utils.Preconditions;
@@ -34,7 +35,10 @@ import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static 
org.apache.paimon.operation.OrphanFilesClean.executeOrphanFilesClean;
 import static org.apache.spark.sql.types.DataTypes.BooleanType;
@@ -58,7 +62,8 @@ public class RemoveOrphanFilesProcedure extends BaseProcedure 
{
             new ProcedureParameter[] {
                 ProcedureParameter.required("table", StringType),
                 ProcedureParameter.optional("older_than", StringType),
-                ProcedureParameter.optional("dry_run", BooleanType)
+                ProcedureParameter.optional("dry_run", BooleanType),
+                ProcedureParameter.optional("parallelism", StringType)
             };
 
     private static final StructType OUTPUT_TYPE =
@@ -85,6 +90,16 @@ public class RemoveOrphanFilesProcedure extends 
BaseProcedure {
     public InternalRow[] call(InternalRow args) {
         org.apache.paimon.catalog.Identifier identifier;
         String tableId = args.getString(0);
+        String parallelism = args.isNullAt(3) ? null : args.getString(3);
+        Map<String, String> dynamicOptions =
+                !StringUtils.isNullOrWhitespaceOnly(parallelism)
+                        ? Collections.emptyMap()
+                        : new HashMap<String, String>() {
+                            {
+                                put(CoreOptions.DELETE_FILE_THREAD_NUM.key(), 
parallelism);
+                            }
+                        };
+
         Preconditions.checkArgument(
                 tableId != null && !tableId.isEmpty(),
                 "Cannot handle an empty tableId for argument %s",
@@ -104,6 +119,7 @@ public class RemoveOrphanFilesProcedure extends 
BaseProcedure {
             tableCleans =
                     OrphanFilesClean.createOrphanFilesCleans(
                             ((WithPaimonCatalog) 
tableCatalog()).paimonCatalog(),
+                            dynamicOptions,
                             identifier.getDatabaseName(),
                             identifier.getObjectName());
         } catch (Exception e) {

Reply via email to