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

baiyangtx pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/amoro.git


The following commit(s) were added to refs/heads/master by this push:
     new dd930a1ca  Use SimpleFuture to refactor TaskRuntime (#3399)
dd930a1ca is described below

commit dd930a1ca61272fd7d98be29cdc5591708a84858
Author: majin1102 <[email protected]>
AuthorDate: Fri Jan 10 10:15:17 2025 +0800

     Use SimpleFuture to refactor TaskRuntime (#3399)
    
    * [AMORO-3258] Use SimpleFuture to refactor TaskRuntime and eliminate task 
lock
    
    * [AMORO-3265] fix ut test
    
    * Optimize logics
    
    * Spotless apply
    
    * Fix ut issues
    
    ---------
    
    Co-authored-by: majin.nathan <[email protected]>
---
 .../amoro/server/DefaultOptimizingService.java     |  2 +-
 .../amoro/server/optimizing/OptimizingQueue.java   | 81 ++++++++++++----------
 .../amoro/server/optimizing/TaskRuntime.java       | 51 ++++++--------
 .../server/persistence/StatedPersistentBase.java   | 22 +-----
 .../amoro/server/table/DefaultTableService.java    |  4 +-
 .../apache/amoro/server/table/TableRuntime.java    | 57 +++++++++------
 .../amoro/server/TestDefaultOptimizingService.java |  8 +--
 .../server/optimizing/TestOptimizingQueue.java     |  6 +-
 .../org/apache/amoro/process/OptimizingStages.java |  2 +-
 .../org/apache/amoro/process/OptimizingState.java  |  1 +
 .../org/apache/amoro/process/ProcessStage.java     |  6 ++
 .../org/apache/amoro/process/ProcessStatus.java    |  8 ++-
 .../org/apache/amoro/process/SimpleFuture.java     |  9 ++-
 .../apache/amoro/process/TableProcessState.java    |  4 ++
 .../apache/amoro/optimizing/RewriteStageTask.java  |  2 +-
 15 files changed, 134 insertions(+), 129 deletions(-)

diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/DefaultOptimizingService.java 
b/amoro-ams/src/main/java/org/apache/amoro/server/DefaultOptimizingService.java
index 5a9d0c052..5d13c6dfb 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/DefaultOptimizingService.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/DefaultOptimizingService.java
@@ -199,7 +199,7 @@ public class DefaultOptimizingService extends 
StatedPersistentBase
   }
 
   private OptimizingTask extractOptimizingTask(
-      TaskRuntime task, String authToken, int threadId, OptimizingQueue queue) 
{
+      TaskRuntime<?> task, String authToken, int threadId, OptimizingQueue 
queue) {
     try {
       OptimizerThread optimizerThread = 
getAuthenticatedOptimizer(authToken).getThread(threadId);
       task.schedule(optimizerThread);
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/OptimizingQueue.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/OptimizingQueue.java
index 64267b8c5..2ef3b550f 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/OptimizingQueue.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/OptimizingQueue.java
@@ -79,7 +79,7 @@ public class OptimizingQueue extends PersistentBase {
 
   private final QuotaProvider quotaProvider;
   private final Queue<TableOptimizingProcess> tableQueue = new 
LinkedTransferQueue<>();
-  private final Queue<TaskRuntime<RewriteStageTask>> retryTaskQueue = new 
LinkedTransferQueue<>();
+  private final Queue<TaskRuntime<?>> retryTaskQueue = new 
LinkedTransferQueue<>();
   private final SchedulingPolicy scheduler;
   private final TableManager tableManager;
   private final Executor planExecutor;
@@ -151,6 +151,14 @@ public class OptimizingQueue extends PersistentBase {
 
   public void releaseTable(TableRuntime tableRuntime) {
     scheduler.removeTable(tableRuntime);
+    List<OptimizingProcess> processList =
+        tableQueue.stream()
+            .filter(process -> process.tableRuntime == tableRuntime)
+            .collect(Collectors.toList());
+    for (OptimizingProcess process : processList) {
+      process.close();
+      clearProcess(process);
+    }
     LOG.info(
         "Release queue {} with table {}",
         optimizerGroup.getName(),
@@ -161,15 +169,15 @@ public class OptimizingQueue extends PersistentBase {
     return scheduler.getTableRuntime(identifier) != null;
   }
 
-  private void clearProcess(TableOptimizingProcess optimizingProcess) {
+  private void clearProcess(OptimizingProcess optimizingProcess) {
     tableQueue.removeIf(process -> process.getProcessId() == 
optimizingProcess.getProcessId());
     retryTaskQueue.removeIf(
         taskRuntime -> taskRuntime.getTaskId().getProcessId() == 
optimizingProcess.getProcessId());
   }
 
-  public TaskRuntime pollTask(long maxWaitTime) {
+  public TaskRuntime<?> pollTask(long maxWaitTime) {
     long deadline = calculateDeadline(maxWaitTime);
-    TaskRuntime task = fetchTask();
+    TaskRuntime<?> task = fetchTask();
     while (task == null && waitTask(deadline)) {
       task = fetchTask();
     }
@@ -196,11 +204,12 @@ public class OptimizingQueue extends PersistentBase {
     }
   }
 
-  private TaskRuntime fetchTask() {
-    return 
Optional.ofNullable(retryTaskQueue.poll()).orElseGet(this::fetchScheduledTask);
+  private TaskRuntime<?> fetchTask() {
+    TaskRuntime<?> task = retryTaskQueue.poll();
+    return task != null ? task : fetchScheduledTask();
   }
 
-  private TaskRuntime fetchScheduledTask() {
+  private TaskRuntime<?> fetchScheduledTask() {
     return tableQueue.stream()
         .map(TableOptimizingProcess::poll)
         .filter(Objects::nonNull)
@@ -307,7 +316,7 @@ public class OptimizingQueue extends PersistentBase {
         .collect(Collectors.toList());
   }
 
-  public void retryTask(TaskRuntime taskRuntime) {
+  public void retryTask(TaskRuntime<?> taskRuntime) {
     taskRuntime.reset();
     retryTaskQueue.offer(taskRuntime);
   }
@@ -349,7 +358,9 @@ public class OptimizingQueue extends PersistentBase {
     return scheduler;
   }
 
-  private class TableOptimizingProcess implements OptimizingProcess, 
TaskRuntime.TaskOwner {
+  private class TableOptimizingProcess implements OptimizingProcess {
+
+    private final Lock lock = new ReentrantLock();
     private final long processId;
     private final OptimizingType optimizingType;
     private final TableRuntime tableRuntime;
@@ -358,7 +369,6 @@ public class OptimizingQueue extends PersistentBase {
     private final long targetChangeSnapshotId;
     private final Map<OptimizingTaskId, TaskRuntime<RewriteStageTask>> taskMap 
= Maps.newHashMap();
     private final Queue<TaskRuntime<RewriteStageTask>> taskQueue = new 
LinkedList<>();
-    private final Lock lock = new ReentrantLock();
     private volatile ProcessStatus status = ProcessStatus.RUNNING;
     private volatile String failedReason;
     private long endTime = AmoroServiceConstants.INVALID_TIME;
@@ -366,10 +376,12 @@ public class OptimizingQueue extends PersistentBase {
     private Map<String, Long> toSequence = Maps.newHashMap();
     private boolean hasCommitted = false;
 
-    public TaskRuntime poll() {
+    public TaskRuntime<?> poll() {
       lock.lock();
       try {
-        return taskQueue.poll();
+        return status != ProcessStatus.CLOSED && status != ProcessStatus.FAILED
+            ? taskQueue.poll()
+            : null;
       } finally {
         lock.unlock();
       }
@@ -431,16 +443,13 @@ public class OptimizingQueue extends PersistentBase {
         }
         this.status = ProcessStatus.CLOSED;
         this.endTime = System.currentTimeMillis();
-        persistProcessCompleted(false);
-        clearProcess(this);
+        persistAndSetCompleted(false);
       } finally {
         lock.unlock();
       }
-      releaseResourcesIfNecessary();
     }
 
-    @Override
-    public void acceptResult(TaskRuntime taskRuntime) {
+    private void acceptResult(TaskRuntime<?> taskRuntime) {
       lock.lock();
       try {
         try {
@@ -452,6 +461,10 @@ public class OptimizingQueue extends PersistentBase {
               taskRuntime.getTaskId(),
               throwable);
         }
+        // task cancel means persistAndSetCompleted has been called
+        if (taskRuntime.getStatus() == TaskRuntime.Status.CANCELED) {
+          return;
+        }
         if (isClosed()) {
           throw new OptimizingClosedException(processId);
         }
@@ -461,7 +474,6 @@ public class OptimizingQueue extends PersistentBase {
               && tableRuntime.getOptimizingStatus().isProcessing()
               && tableRuntime.getOptimizingStatus() != 
OptimizingStatus.COMMITTING) {
             tableRuntime.beginCommitting();
-            clearProcess(this);
           }
         } else if (taskRuntime.getStatus() == TaskRuntime.Status.FAILED) {
           if (taskRuntime.getRetry() < tableRuntime.getMaxExecuteRetryCount()) 
{
@@ -471,11 +483,10 @@ public class OptimizingQueue extends PersistentBase {
                 taskRuntime.getFailReason());
             retryTask(taskRuntime);
           } else {
-            clearProcess(this);
             this.failedReason = taskRuntime.getFailReason();
             this.status = ProcessStatus.FAILED;
             this.endTime = taskRuntime.getEndTime();
-            persistProcessCompleted(false);
+            persistAndSetCompleted(false);
           }
         }
       } finally {
@@ -483,14 +494,6 @@ public class OptimizingQueue extends PersistentBase {
       }
     }
 
-    // the cleanup of task should be done after unlock to avoid deadlock
-    @Override
-    public void releaseResourcesIfNecessary() {
-      if (this.status == ProcessStatus.FAILED || this.status == 
ProcessStatus.CLOSED) {
-        cancelTasks();
-      }
-    }
-
     @Override
     public boolean isClosed() {
       return status == ProcessStatus.CLOSED;
@@ -572,15 +575,13 @@ public class OptimizingQueue extends PersistentBase {
           buildCommit().commit();
           status = ProcessStatus.SUCCESS;
           endTime = System.currentTimeMillis();
-          persistProcessCompleted(true);
+          persistAndSetCompleted(true);
         } catch (Exception e) {
           LOG.error("{} Commit optimizing failed ", 
tableRuntime.getTableIdentifier(), e);
           status = ProcessStatus.FAILED;
           failedReason = ExceptionUtil.getErrorMessage(e, 4000);
           endTime = System.currentTimeMillis();
-          persistProcessCompleted(false);
-        } finally {
-          clearProcess(this);
+          persistAndSetCompleted(false);
         }
       } finally {
         lock.unlock();
@@ -654,8 +655,13 @@ public class OptimizingQueue extends PersistentBase {
           () -> tableRuntime.beginProcess(this));
     }
 
-    private void persistProcessCompleted(boolean success) {
+    private void persistAndSetCompleted(boolean success) {
       doAsTransaction(
+          () -> {
+            if (!success) {
+              cancelTasks();
+            }
+          },
           () ->
               doAs(
                   OptimizingMapper.class,
@@ -667,10 +673,10 @@ public class OptimizingQueue extends PersistentBase {
                           endTime,
                           getSummary(),
                           getFailedReason())),
-          () -> tableRuntime.completeProcess(success));
+          () -> tableRuntime.completeProcess(success),
+          () -> clearProcess(this));
     }
 
-    /** The cancellation should be invoked outside the process lock to avoid 
deadlock. */
     private void cancelTasks() {
       taskMap.values().forEach(TaskRuntime::tryCanceling);
     }
@@ -686,7 +692,7 @@ public class OptimizingQueue extends PersistentBase {
         Map<Integer, RewriteFilesInput> inputs = 
TaskFilesPersistence.loadTaskInputs(processId);
         taskRuntimes.forEach(
             taskRuntime -> {
-              taskRuntime.claimOwnership(this);
+              taskRuntime.getCompletedFuture().whenCompleted(() -> 
acceptResult(taskRuntime));
               taskRuntime
                   .getTaskDescriptor()
                   .setInput(inputs.get(taskRuntime.getTaskId().getTaskId()));
@@ -716,7 +722,8 @@ public class OptimizingQueue extends PersistentBase {
             tableRuntime.getTableIdentifier(),
             taskRuntime.getTaskId(),
             taskRuntime.getSummary());
-        taskMap.put(taskRuntime.getTaskId(), taskRuntime.claimOwnership(this));
+        taskRuntime.getCompletedFuture().whenCompleted(() -> 
acceptResult(taskRuntime));
+        taskMap.put(taskRuntime.getTaskId(), taskRuntime);
         taskQueue.offer(taskRuntime);
       }
     }
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/TaskRuntime.java 
b/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/TaskRuntime.java
index 85adbdcdd..59339dece 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/TaskRuntime.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/optimizing/TaskRuntime.java
@@ -23,8 +23,8 @@ import org.apache.amoro.api.OptimizingTask;
 import org.apache.amoro.api.OptimizingTaskId;
 import org.apache.amoro.api.OptimizingTaskResult;
 import org.apache.amoro.exception.IllegalTaskStateException;
-import org.apache.amoro.exception.OptimizingClosedException;
 import org.apache.amoro.exception.TaskRuntimeException;
+import org.apache.amoro.process.SimpleFuture;
 import org.apache.amoro.process.StagedTaskDescriptor;
 import org.apache.amoro.server.AmoroServiceConstants;
 import org.apache.amoro.server.persistence.StatedPersistentBase;
@@ -39,10 +39,11 @@ import java.util.Set;
 
 public class TaskRuntime<T extends StagedTaskDescriptor<?, ?, ?>> extends 
StatedPersistentBase {
 
+  private final SimpleFuture future = new SimpleFuture();
+  private final TaskStatusMachine statusMachine = new TaskStatusMachine();
   private OptimizingTaskId taskId;
   private T taskDescriptor;
   @StateField private Status status = Status.PLANNED;
-  private final TaskStatusMachine statusMachine = new TaskStatusMachine();
   @StateField private int runTimes = 0;
   @StateField private long startTime = AmoroServiceConstants.INVALID_TIME;
   @StateField private long endTime = AmoroServiceConstants.INVALID_TIME;
@@ -50,7 +51,6 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, ?, 
?>> extends Stated
   @StateField private String token;
   @StateField private int threadId = -1;
   @StateField private String failReason;
-  private TaskOwner owner;
 
   private TaskRuntime() {}
 
@@ -63,6 +63,10 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, 
?, ?>> extends Stated
     return taskDescriptor;
   }
 
+  public SimpleFuture getCompletedFuture() {
+    return future;
+  }
+
   public void complete(OptimizerThread thread, OptimizingTaskResult result) {
     invokeConsistency(
         () -> {
@@ -78,16 +82,18 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, 
?, ?>> extends Stated
           costTime += endTime - startTime;
           runTimes += 1;
           persistTaskRuntime();
-          owner.acceptResult(this);
+          future.complete();
           token = null;
           threadId = -1;
         });
-    owner.releaseResourcesIfNecessary();
   }
 
   void reset() {
     invokeConsistency(
         () -> {
+          if (status == Status.PLANNED) {
+            return;
+          }
           statusMachine.accept(Status.PLANNED);
           startTime = AmoroServiceConstants.INVALID_TIME;
           endTime = AmoroServiceConstants.INVALID_TIME;
@@ -95,6 +101,7 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, 
?, ?>> extends Stated
           threadId = -1;
           failReason = null;
           taskDescriptor.reset();
+          future.reset();
           // The cost time should not be reset since it is the total cost time 
of all runs.
           persistTaskRuntime();
         });
@@ -129,15 +136,11 @@ public class TaskRuntime<T extends 
StagedTaskDescriptor<?, ?, ?>> extends Stated
               costTime += endTime - startTime;
             }
             persistTaskRuntime();
+            future.complete();
           }
         });
   }
 
-  public TaskRuntime<T> claimOwnership(TaskOwner owner) {
-    this.owner = owner;
-    return this;
-  }
-
   public boolean finished() {
     return this.status == Status.SUCCESS
         || this.status == Status.FAILED
@@ -262,25 +265,19 @@ public class TaskRuntime<T extends 
StagedTaskDescriptor<?, ?, ?>> extends Stated
 
   private static final Map<Status, Set<Status>> nextStatusMap =
       ImmutableMap.<Status, Set<Status>>builder()
-          .put(Status.PLANNED, ImmutableSet.of(Status.PLANNED, 
Status.SCHEDULED, Status.CANCELED))
-          .put(
-              Status.SCHEDULED,
-              ImmutableSet.of(Status.PLANNED, Status.SCHEDULED, Status.ACKED, 
Status.CANCELED))
+          .put(Status.PLANNED, ImmutableSet.of(Status.SCHEDULED, 
Status.CANCELED))
+          .put(Status.SCHEDULED, ImmutableSet.of(Status.PLANNED, Status.ACKED, 
Status.CANCELED))
           .put(
               Status.ACKED,
-              ImmutableSet.of(
-                  Status.PLANNED, Status.ACKED, Status.SUCCESS, Status.FAILED, 
Status.CANCELED))
-          .put(Status.FAILED, ImmutableSet.of(Status.PLANNED, Status.FAILED))
-          .put(Status.SUCCESS, ImmutableSet.of(Status.SUCCESS))
-          .put(Status.CANCELED, ImmutableSet.of(Status.CANCELED))
+              ImmutableSet.of(Status.PLANNED, Status.SUCCESS, Status.FAILED, 
Status.CANCELED))
+          .put(Status.FAILED, ImmutableSet.of(Status.PLANNED))
+          .put(Status.CANCELED, ImmutableSet.of())
+          .put(Status.SUCCESS, ImmutableSet.of())
           .build();
 
   private class TaskStatusMachine {
 
     public void accept(Status targetStatus) {
-      if (owner.isClosed()) {
-        throw new OptimizingClosedException(taskId.getProcessId());
-      }
       if (!getNext().contains(targetStatus)) {
         throw new IllegalTaskStateException(taskId, status.name(), 
targetStatus.name());
       }
@@ -321,7 +318,7 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, 
?, ?>> extends Stated
 
     public TaskQuota() {}
 
-    public TaskQuota(TaskRuntime task) {
+    public TaskQuota(TaskRuntime<?> task) {
       this.startTime = task.getStartTime();
       this.endTime = task.getEndTime();
       this.processId = task.getTaskId().getProcessId();
@@ -367,12 +364,4 @@ public class TaskRuntime<T extends StagedTaskDescriptor<?, 
?, ?>> extends Stated
       return endTime <= validTime;
     }
   }
-
-  public interface TaskOwner {
-    void acceptResult(TaskRuntime taskRuntime);
-
-    void releaseResourcesIfNecessary();
-
-    boolean isClosed();
-  }
 }
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/StatedPersistentBase.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/StatedPersistentBase.java
index fad12dbe4..fc551d2c6 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/StatedPersistentBase.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/StatedPersistentBase.java
@@ -27,8 +27,6 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
@@ -37,45 +35,29 @@ public abstract class StatedPersistentBase extends 
PersistentBase {
   private static final Map<Class<? extends PersistentBase>, Field[]> metaCache 
=
       Maps.newConcurrentMap();
   private static final Object NULL_VALUE = new Object();
-  private final Lock stateLock = new ReentrantLock();
   private final Field[] consistentFields;
 
   protected StatedPersistentBase() {
     consistentFields = getOrCreateConsistentFields();
   }
 
-  protected final void invokeConsistency(Runnable runnable) {
-    stateLock.lock();
+  protected void invokeConsistency(Runnable runnable) {
     Map<Field, Object> states = retainStates();
     try {
       doAsTransaction(runnable);
     } catch (Throwable throwable) {
       restoreStates(states);
       throw throwable;
-    } finally {
-      stateLock.unlock();
     }
   }
 
-  protected final <T> T invokeConsistency(Supplier<T> supplier) {
-    stateLock.lock();
+  protected <T> T invokeConsistency(Supplier<T> supplier) {
     Map<Field, Object> states = retainStates();
     try {
       return supplier.get();
     } catch (Throwable throwable) {
       restoreStates(states);
       throw throwable;
-    } finally {
-      stateLock.unlock();
-    }
-  }
-
-  protected final void invokeInStateLock(Runnable runnable) {
-    stateLock.lock();
-    try {
-      runnable.run();
-    } finally {
-      stateLock.unlock();
     }
   }
 
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/table/DefaultTableService.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/table/DefaultTableService.java
index 565cce4e0..a43e91724 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/table/DefaultTableService.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/table/DefaultTableService.java
@@ -44,7 +44,7 @@ import org.apache.amoro.server.catalog.InternalCatalog;
 import org.apache.amoro.server.catalog.ServerCatalog;
 import org.apache.amoro.server.manager.MetricManager;
 import org.apache.amoro.server.optimizing.OptimizingStatus;
-import org.apache.amoro.server.persistence.StatedPersistentBase;
+import org.apache.amoro.server.persistence.PersistentBase;
 import org.apache.amoro.server.persistence.TableRuntimeMeta;
 import org.apache.amoro.server.persistence.mapper.CatalogMetaMapper;
 import org.apache.amoro.server.persistence.mapper.TableBlockerMapper;
@@ -84,7 +84,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
-public class DefaultTableService extends StatedPersistentBase implements 
TableService {
+public class DefaultTableService extends PersistentBase implements 
TableService {
 
   public static final Logger LOG = 
LoggerFactory.getLogger(DefaultTableService.class);
   private static final int TABLE_BLOCKER_RETRY = 3;
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/table/TableRuntime.java 
b/amoro-ams/src/main/java/org/apache/amoro/server/table/TableRuntime.java
index a21967d76..f6733af83 100644
--- a/amoro-ams/src/main/java/org/apache/amoro/server/table/TableRuntime.java
+++ b/amoro-ams/src/main/java/org/apache/amoro/server/table/TableRuntime.java
@@ -57,11 +57,13 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 public class TableRuntime extends StatedPersistentBase {
 
   private static final Logger LOG = 
LoggerFactory.getLogger(TableRuntime.class);
-
+  private final Lock tableLock = new ReentrantLock();
   private final TableRuntimeHandler tableHandler;
   private final ServerTableIdentifier tableIdentifier;
   private final List<TaskRuntime.TaskQuota> taskQuotas = new 
CopyOnWriteArrayList<>();
@@ -90,14 +92,10 @@ public class TableRuntime extends StatedPersistentBase {
   private final TableOptimizingMetrics optimizingMetrics;
   private final TableOrphanFilesCleaningMetrics orphanFilesCleaningMetrics;
   private final TableSummaryMetrics tableSummaryMetrics;
-
   private long targetSnapshotId;
-
   private long targetChangeSnapshotId;
-
   private Map<String, Long> fromSequence;
   private Map<String, Long> toSequence;
-
   private OptimizingType optimizingType;
 
   public TableRuntime(
@@ -176,15 +174,17 @@ public class TableRuntime extends StatedPersistentBase {
   }
 
   public void dispose() {
-    invokeInStateLock(
-        () -> {
-          doAsTransaction(
-              () -> 
Optional.ofNullable(optimizingProcess).ifPresent(OptimizingProcess::close),
-              () ->
-                  doAs(
-                      TableMetaMapper.class,
-                      mapper -> 
mapper.deleteOptimizingRuntime(tableIdentifier.getId())));
-        });
+    tableLock.lock();
+    try {
+      doAsTransaction(
+          () -> 
Optional.ofNullable(optimizingProcess).ifPresent(OptimizingProcess::close),
+          () ->
+              doAs(
+                  TableMetaMapper.class,
+                  mapper -> 
mapper.deleteOptimizingRuntime(tableIdentifier.getId())));
+    } finally {
+      tableLock.unlock();
+    }
     optimizingMetrics.unregister();
     orphanFilesCleaningMetrics.unregister();
     tableSummaryMetrics.unregister();
@@ -318,15 +318,16 @@ public class TableRuntime extends StatedPersistentBase {
    * @param startTimeMills
    */
   public void resetTaskQuotas(long startTimeMills) {
-    invokeInStateLock(
-        () -> {
-          taskQuotas.clear();
-          taskQuotas.addAll(
-              getAs(
-                  OptimizingMapper.class,
-                  mapper ->
-                      mapper.selectTaskQuotasByTime(tableIdentifier.getId(), 
startTimeMills)));
-        });
+    tableLock.lock();
+    try {
+      taskQuotas.clear();
+      taskQuotas.addAll(
+          getAs(
+              OptimizingMapper.class,
+              mapper -> mapper.selectTaskQuotasByTime(tableIdentifier.getId(), 
startTimeMills)));
+    } finally {
+      tableLock.unlock();
+    }
   }
 
   public void completeProcess(boolean success) {
@@ -646,4 +647,14 @@ public class TableRuntime extends StatedPersistentBase {
                     System.currentTimeMillis()));
     return TableBlocker.conflict(operation, tableBlockers);
   }
+
+  @Override
+  protected void invokeConsistency(Runnable runnable) {
+    tableLock.lock();
+    try {
+      super.invokeConsistency(runnable);
+    } finally {
+      tableLock.unlock();
+    }
+  }
 }
diff --git 
a/amoro-ams/src/test/java/org/apache/amoro/server/TestDefaultOptimizingService.java
 
b/amoro-ams/src/test/java/org/apache/amoro/server/TestDefaultOptimizingService.java
index b780f6107..a5c406766 100644
--- 
a/amoro-ams/src/test/java/org/apache/amoro/server/TestDefaultOptimizingService.java
+++ 
b/amoro-ams/src/test/java/org/apache/amoro/server/TestDefaultOptimizingService.java
@@ -186,7 +186,7 @@ public class TestDefaultOptimizingService extends 
AMSTableTestBase {
     optimizingService().ackTask(token, THREAD_ID, task.getTaskId());
     assertTaskStatus(TaskRuntime.Status.ACKED);
 
-    TaskRuntime taskRuntime =
+    TaskRuntime<?> taskRuntime =
         optimizingService().listTasks(defaultResourceGroup().getName()).get(0);
     optimizingService().completeTask(token, 
buildOptimizingTaskResult(task.getTaskId()));
     assertTaskCompleted(taskRuntime);
@@ -310,7 +310,7 @@ public class TestDefaultOptimizingService extends 
AMSTableTestBase {
     reload();
     assertTaskStatus(TaskRuntime.Status.ACKED);
 
-    TaskRuntime taskRuntime =
+    TaskRuntime<?> taskRuntime =
         optimizingService().listTasks(defaultResourceGroup().getName()).get(0);
     optimizingService().completeTask(token, 
buildOptimizingTaskResult(task.getTaskId()));
     assertTaskCompleted(taskRuntime);
@@ -658,12 +658,10 @@ public class TestDefaultOptimizingService extends 
AMSTableTestBase {
         
optimizingService().listTasks(defaultResourceGroup().getName()).get(0).getStatus());
   }
 
-  private void assertTaskCompleted(TaskRuntime taskRuntime) {
+  private void assertTaskCompleted(TaskRuntime<?> taskRuntime) {
     if (taskRuntime != null) {
       Assertions.assertEquals(TaskRuntime.Status.SUCCESS, 
taskRuntime.getStatus());
     }
-    Assertions.assertEquals(
-        0, 
optimizingService().listTasks(defaultResourceGroup().getName()).size());
     Assertions.assertEquals(
         ProcessStatus.RUNNING,
         tableService()
diff --git 
a/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/TestOptimizingQueue.java
 
b/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/TestOptimizingQueue.java
index bf668fbcf..eeeba78c3 100644
--- 
a/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/TestOptimizingQueue.java
+++ 
b/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/TestOptimizingQueue.java
@@ -174,12 +174,12 @@ public class TestOptimizingQueue extends AMSTableTestBase 
{
     OptimizingQueue queue = buildOptimizingGroupService(tableRuntimeMeta);
 
     // 1.poll task
-    TaskRuntime task = queue.pollTask(MAX_POLLING_TIME);
+    TaskRuntime<?> task = queue.pollTask(MAX_POLLING_TIME);
     Assert.assertNotNull(task);
 
     for (int i = 0; i < 
TableProperties.SELF_OPTIMIZING_EXECUTE_RETRY_NUMBER_DEFAULT; i++) {
       queue.retryTask(task);
-      TaskRuntime retryTask = queue.pollTask(MAX_POLLING_TIME);
+      TaskRuntime<?> retryTask = queue.pollTask(MAX_POLLING_TIME);
       Assert.assertEquals(retryTask.getTaskId(), task.getTaskId());
       retryTask.schedule(optimizerThread);
       retryTask.ack(optimizerThread);
@@ -190,7 +190,7 @@ public class TestOptimizingQueue extends AMSTableTestBase {
     }
 
     queue.retryTask(task);
-    TaskRuntime retryTask = queue.pollTask(MAX_POLLING_TIME);
+    TaskRuntime<?> retryTask = queue.pollTask(MAX_POLLING_TIME);
     Assert.assertEquals(retryTask.getTaskId(), task.getTaskId());
     retryTask.schedule(optimizerThread);
     retryTask.ack(optimizerThread);
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/OptimizingStages.java 
b/amoro-common/src/main/java/org/apache/amoro/process/OptimizingStages.java
index 6049621cd..f4bec4a2a 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/OptimizingStages.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/OptimizingStages.java
@@ -48,7 +48,7 @@ public class OptimizingStages {
   private static final Map<String, ProcessStage> STAGES =
       ImmutableMap.<String, ProcessStage>builder()
           .put(MINOR.getDesc(), MINOR)
-          .put(MINOR.getDesc(), MAJOR)
+          .put(MAJOR.getDesc(), MAJOR)
           .put(FULL.getDesc(), FULL)
           .put(COMMITTING.getDesc(), COMMITTING)
           .put(PLANNING.getDesc(), PLANNING)
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/OptimizingState.java 
b/amoro-common/src/main/java/org/apache/amoro/process/OptimizingState.java
index 99691cf84..c4a900dca 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/OptimizingState.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/OptimizingState.java
@@ -60,6 +60,7 @@ public abstract class OptimizingState extends 
TableProcessState {
     return watermark;
   }
 
+  @Override
   public ProcessStage getStage() {
     return stage;
   }
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/ProcessStage.java 
b/amoro-common/src/main/java/org/apache/amoro/process/ProcessStage.java
index 47be213ce..ee74627e2 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/ProcessStage.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/ProcessStage.java
@@ -20,6 +20,12 @@ package org.apache.amoro.process;
 
 public class ProcessStage {
 
+  /**
+   * An arbitrary stage belongs to processes which only contain one stage For 
those one stage
+   * processes, should transform ${@link ProcessStage} to ProcessStage for 
displaying
+   */
+  public static final ProcessStage ARBITRARY = new ProcessStage("", 0);
+
   /**
    * Action Stage description value, normally this value should be identical 
within certain actions
    */
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/ProcessStatus.java 
b/amoro-common/src/main/java/org/apache/amoro/process/ProcessStatus.java
index 77d2ae023..43f9471b5 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/ProcessStatus.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/ProcessStatus.java
@@ -22,9 +22,13 @@ package org.apache.amoro.process;
 public enum ProcessStatus {
   UNKNOWN,
   PENDING,
-  RUNNING,
   SUBMITTED,
+  RUNNING,
   SUCCESS,
   CLOSED,
-  FAILED
+  FAILED;
+
+  public ProcessStage toStage() {
+    return new ProcessStage(name(), ordinal());
+  }
 }
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/SimpleFuture.java 
b/amoro-common/src/main/java/org/apache/amoro/process/SimpleFuture.java
index ce1332bfd..f69e5e9a2 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/SimpleFuture.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/SimpleFuture.java
@@ -71,18 +71,21 @@ public class SimpleFuture {
   public void reset() {
     triggerFuture = new CompletableFuture<>();
     callbackFuture = triggerFuture;
-    whenCompleted(() -> {});
     callbackMap.keySet().forEach(this::whenCompleted);
   }
 
   /**
    * This method will trigger all callback functions in the same thread and 
wait until all callback
-   * functions are completed. If throws exception, completedFuture is not done.
+   * functions are completed. If throws exception, completedFuture is not 
done. Pay attention that
+   * reset could be called during whenCompleted runnable, should ignore waiting
    */
   public void complete() {
     try {
+      CompletableFuture<?> originalFuture = triggerFuture;
       if (triggerFuture.complete(null)) {
-        callbackFuture.get();
+        if (triggerFuture == originalFuture) {
+          callbackFuture.get();
+        }
       }
     } catch (Throwable throwable) {
       throw normalize(throwable);
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/process/TableProcessState.java 
b/amoro-common/src/main/java/org/apache/amoro/process/TableProcessState.java
index c58a6f4d0..335ab82b5 100644
--- a/amoro-common/src/main/java/org/apache/amoro/process/TableProcessState.java
+++ b/amoro-common/src/main/java/org/apache/amoro/process/TableProcessState.java
@@ -126,6 +126,10 @@ public class TableProcessState implements ProcessState {
     this.endTime = System.currentTimeMillis();
   }
 
+  public ProcessStage getStage() {
+    return status.toStage();
+  }
+
   protected void setId(long processId) {
     this.id = processId;
   }
diff --git 
a/amoro-format-iceberg/src/main/java/org/apache/amoro/optimizing/RewriteStageTask.java
 
b/amoro-format-iceberg/src/main/java/org/apache/amoro/optimizing/RewriteStageTask.java
index 363b1042e..60c5fba77 100644
--- 
a/amoro-format-iceberg/src/main/java/org/apache/amoro/optimizing/RewriteStageTask.java
+++ 
b/amoro-format-iceberg/src/main/java/org/apache/amoro/optimizing/RewriteStageTask.java
@@ -95,7 +95,7 @@ public class RewriteStageTask
   }
 
   private static long getRecordCnt(ContentFile<?>[] contentFiles) {
-    int recordCnt = 0;
+    long recordCnt = 0;
     if (contentFiles != null) {
       for (ContentFile<?> contentFile : contentFiles) {
         recordCnt += contentFile.recordCount();

Reply via email to