diff --git a/client/trino-cli/src/main/java/io/trino/cli/StatusPrinter.java b/client/trino-cli/src/main/java/io/trino/cli/StatusPrinter.java index 373a64518778..f1feef31adb6 100644 --- a/client/trino-cli/src/main/java/io/trino/cli/StatusPrinter.java +++ b/client/trino-cli/src/main/java/io/trino/cli/StatusPrinter.java @@ -324,10 +324,14 @@ private void printQueryInfo(QueryStatusInfo results, WarningsPrinter warningsPri int progressWidth = (min(terminalWidth, 100) - 75) + 17; // progress bar is 17-42 characters wide if (stats.isScheduled()) { - String progressBar = formatProgressBar(progressWidth, - stats.getCompletedSplits(), - max(0, stats.getRunningSplits()), - stats.getTotalSplits()); + int completed = stats.getCompletedSplits(); + int running = stats.getRunningSplits(); + int total = stats.getTotalSplits(); + if (progressPercentage > 0) { + // prevent progress bar from going back and forth for fault tolerant execution + total = max(total, (completed * 100 + progressPercentage - 1) / progressPercentage); + } + String progressBar = formatProgressBar(progressWidth, completed, running, total); // 0:17 [ 103MB, 802K rows] [5.74MB/s, 44.9K rows/s] [=====>> ] 10% String progressLine = format("%s [%5s rows, %6s] [%5s rows/s, %8s] [%s] %d%%", diff --git a/client/trino-client/src/main/java/io/trino/client/StatementStats.java b/client/trino-client/src/main/java/io/trino/client/StatementStats.java index 93e02af9ddf9..f4d9b7c3c5ab 100644 --- a/client/trino-client/src/main/java/io/trino/client/StatementStats.java +++ b/client/trino-client/src/main/java/io/trino/client/StatementStats.java @@ -19,7 +19,9 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import java.util.ArrayDeque; import java.util.OptionalDouble; +import java.util.Queue; import static com.google.common.base.MoreObjects.toStringHelper; import static java.lang.Math.min; @@ -197,7 +199,33 @@ public OptionalDouble getProgressPercentage() if (!scheduled || totalSplits == 0) { return OptionalDouble.empty(); } - return OptionalDouble.of(min(100, (completedSplits * 100.0) / totalSplits)); + + double percentageSum = 0.0; + int scheduledStages = 0; + int totalStages = 0; + Queue queue = new ArrayDeque<>(); + queue.add(rootStage); + while (!queue.isEmpty()) { + StageStats stage = queue.poll(); + totalStages++; + if (stage.isDone() || stage.getState().equals("PENDING") || stage.getState().equals("RUNNING")) { + percentageSum += 100.0 * stage.getCompletedSplits() / stage.getTotalSplits(); + scheduledStages++; + } + queue.addAll(stage.getSubStages()); + } + if (scheduledStages == totalStages) { + return OptionalDouble.of(min(100, (completedSplits * 100.0) / totalSplits)); + } + else { + // Unlike pipelined execution, fault tolerant execution doesn't execute stages all at + // once and some stages will be in PLANNED state in the middle of execution. Therefore, + // we don't know the number of total splits upfront. + // + // To avoid the confusion of progress bar going back and forth, we calculate the + // progress percentage of each stage (0 if not scheduled), and average them. + return OptionalDouble.of(min(100, percentageSum / totalStages)); + } } @JsonProperty diff --git a/core/trino-main/src/main/java/io/trino/execution/QueryStateMachine.java b/core/trino-main/src/main/java/io/trino/execution/QueryStateMachine.java index 1fb5efcedfee..7090864036bf 100644 --- a/core/trino-main/src/main/java/io/trino/execution/QueryStateMachine.java +++ b/core/trino-main/src/main/java/io/trino/execution/QueryStateMachine.java @@ -618,7 +618,7 @@ private QueryStats getQueryStats(Optional rootStage, List boolean isScheduled = rootStage.isPresent() && allStages.stream() .map(StageInfo::getState) - .allMatch(state -> state == StageState.RUNNING || state == StageState.PENDING || state.isDone()); + .anyMatch(state -> state == StageState.RUNNING || state == StageState.PENDING || state.isDone()); return new QueryStats( queryStateTimer.getCreateTime(),