private void schedule() { try (SetThreadName ignored = new SetThreadName("Query-%s", queryStateMachine.getQueryId())) { Set<StageId> completedStages = new HashSet<>(); ExecutionSchedule executionSchedule = executionPolicy.createExecutionSchedule(stages.values()); while (!executionSchedule.isFinished()) { List<CompletableFuture<?>> blockedStages = new ArrayList<>(); for (SqlStageExecution stage : executionSchedule.getStagesToSchedule()) { stage.beginScheduling(); // perform some scheduling work ScheduleResult result = stageSchedulers.get(stage.getStageId()).schedule(); // modify parent and children based on the results of the scheduling if (result.isFinished()) { stage.schedulingComplete(); } else if (!result.getBlocked().isDone()) { blockedStages.add(result.getBlocked()); } stageLinkages .get(stage.getStageId()) .processScheduleResults(stage.getState(), result.getNewTasks()); } // make sure to update stage linkage at least once per loop to catch async state changes // (e.g., partial cancel) for (SqlStageExecution stage : stages.values()) { if (!completedStages.contains(stage.getStageId()) && stage.getState().isDone()) { stageLinkages .get(stage.getStageId()) .processScheduleResults(stage.getState(), ImmutableSet.of()); completedStages.add(stage.getStageId()); } } // wait for a state change and then schedule again if (!blockedStages.isEmpty()) { tryGetFutureValue(firstCompletedFuture(blockedStages), 100, MILLISECONDS); for (CompletableFuture<?> blockedStage : blockedStages) { blockedStage.cancel(true); } } } for (SqlStageExecution stage : stages.values()) { StageState state = stage.getState(); if (state != SCHEDULED && state != RUNNING && !state.isDone()) { throw new PrestoException( INTERNAL_ERROR, format( "Scheduling is complete, but stage %s is in state %s", stage.getStageId(), state)); } } } catch (Throwable t) { queryStateMachine.transitionToFailed(t); throw Throwables.propagate(t); } finally { RuntimeException closeError = new RuntimeException(); for (StageScheduler scheduler : stageSchedulers.values()) { try { scheduler.close(); } catch (Throwable t) { queryStateMachine.transitionToFailed(t); closeError.addSuppressed(t); } } if (closeError.getSuppressed().length > 0) { throw closeError; } } }