Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.flink.runtime.schedule;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.api.common.JobType;
import org.apache.flink.api.common.time.Time;
import org.apache.flink.configuration.JobManagerOptions;
import org.apache.flink.runtime.event.ExecutionVertexFailoverEvent;
import org.apache.flink.runtime.event.ExecutionVertexStateChangedEvent;
import org.apache.flink.runtime.event.ResultPartitionConsumableEvent;
import org.apache.flink.runtime.execution.ExecutionState;
import org.apache.flink.runtime.executiongraph.Execution;
import org.apache.flink.runtime.executiongraph.ExecutionGraph;
import org.apache.flink.runtime.executiongraph.ExecutionVertex;
import org.apache.flink.runtime.executiongraph.IntermediateResultPartition;
import org.apache.flink.runtime.io.network.partition.ResultPartitionType;
import org.apache.flink.runtime.jobgraph.ControlType;
import org.apache.flink.runtime.jobgraph.ExecutionVertexID;
import org.apache.flink.runtime.jobgraph.IntermediateDataSet;
import org.apache.flink.runtime.jobgraph.JobControlEdge;
import org.apache.flink.runtime.jobgraph.JobEdge;
import org.apache.flink.runtime.jobgraph.JobGraph;
import org.apache.flink.runtime.jobgraph.JobVertex;
import org.apache.flink.runtime.jobgraph.JobVertexID;
import org.apache.flink.runtime.jobgraph.SchedulingMode;
import org.apache.flink.runtime.jobmaster.ExecutionSlotAllocator;
import org.apache.flink.runtime.jobmaster.GraphManager;
import org.apache.flink.runtime.jobmaster.LogicalSlot;
import org.apache.flink.util.ExceptionUtils;
import org.apache.flink.util.FlinkException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* A Scheduler plugin which schedules tasks in a concurrent group at the same time.
*/
public class ConcurrentGroupGraphManagerPlugin implements GraphManagerPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ConcurrentGroupGraphManagerPlugin.class);
private Set concurrentSchedulingGroups = new HashSet<>();
private Map executionToConcurrentSchedulingGroups = new LinkedHashMap<>();
private Map> predecessorToSuccessors = new HashMap<>();
private Map> successorToPredecessors = new HashMap<>();
private Set ignoredControlEdges = new HashSet<>();
private VertexInputTracker inputTracker;
private VertexScheduler scheduler;
private JobGraph jobGraph;
private ExecutionGraph executionGraph;
private GraphManager graphManager;
private ExecutionSlotAllocator executionSlotAllocator;
private boolean allowGroupSplit;
private Time allocationLongTimeout;
@Override
public void open(
VertexScheduler scheduler,
JobGraph jobGraph,
SchedulingConfig schedulingConfig,
ExecutionGraph eg,
GraphManager graphManager,
ExecutionSlotAllocator executionSlotAllocator) {
this.scheduler = scheduler;
this.jobGraph = jobGraph;
this.inputTracker = new VertexInputTracker(jobGraph, scheduler, schedulingConfig);
this.executionGraph = eg;
this.graphManager = graphManager;
this.allowGroupSplit = schedulingConfig.getConfiguration().getBoolean(JobManagerOptions.ALLOW_GROUP_SPLIT);
this.executionSlotAllocator = executionSlotAllocator;
this.allocationLongTimeout = Time.milliseconds(schedulingConfig.getConfiguration().getLong(JobManagerOptions.SLOT_REQUEST_LONG_TIMEOUT));
initConcurrentSchedulingGroups();
}
private void initConcurrentSchedulingGroups() {
List concurrentJobVertexGroups = new ArrayList<>();
List allJobVertices = jobGraph.getVerticesSortedTopologicallyFromSources();
if (jobGraph.getJobType() == JobType.INFINITE_STREAM) {
LOG.debug("All executions will be in one group for streaming job {}", jobGraph.getJobID());
List allExecutionVertices = new ArrayList<>(executionGraph.getRegisteredExecutions().size());
for (ExecutionVertex ev : executionGraph.getAllExecutionVertices()) {
allExecutionVertices.add(ev);
}
concurrentJobVertexGroups.add(new ConcurrentJobVertexGroup(allJobVertices, ignoredControlEdges));
this.concurrentSchedulingGroups.add(
new ConcurrentSchedulingGroup(allExecutionVertices, false));
} else {
buildStartOnFinishRelation(jobGraph);
buildConcurrentSchedulingGroups(allJobVertices, false);
}
}
@Override
public void close() {
// do nothing.
}
@Override
public void reset() {
concurrentSchedulingGroups.clear();
executionToConcurrentSchedulingGroups.clear();
predecessorToSuccessors.clear();
successorToPredecessors.clear();
ignoredControlEdges.clear();
initConcurrentSchedulingGroups();
}
@Override
public void onSchedulingStarted() {
// To avoid concurrent modification as the groups may change due to group split.
List groups = new ArrayList<>(concurrentSchedulingGroups);
groups.stream().forEach(
(group) -> {
if (!group.hasPrecedingGroup()) {
checkAndScheduleGroup(group);
}
});
}
@Override
public void onResultPartitionConsumable(ResultPartitionConsumableEvent event) {
final Set verticesToSchedule = new HashSet<>();
final IntermediateResultPartition resultPartition = executionGraph
.getAllIntermediateResults()
.get(event.getResultID())
.getPartitions()[event.getPartitionNumber()];
final Collection executionVertexIDs = executionGraph.getEdgeManager()
.getPartitionConsumers(resultPartition.getPartitionId())
.stream()
.map(ExecutionVertex::getExecutionVertexID)
.collect(Collectors.toList());
for (ExecutionVertexID executionVertexID : executionVertexIDs) {
if (isReadyToSchedule(executionVertexID)) {
verticesToSchedule.add(executionVertexID);
}
}
scheduleInConcurrentGroup(verticesToSchedule);
}
@Override
public void onExecutionVertexFailover(ExecutionVertexFailoverEvent event) {
final Set groupToSchedule = new HashSet<>();
// For streaming job, region always will be less than concurrent group.
if (jobGraph.getJobType() == JobType.INFINITE_STREAM) {
scheduler.scheduleExecutionVertices(event.getAffectedExecutionVertexIDs());
} else {
for (ExecutionVertexID executionVertexID : event.getAffectedExecutionVertexIDs()) {
if (isReadyToSchedule(executionVertexID)) {
ConcurrentSchedulingGroup groupsBelongTo = executionToConcurrentSchedulingGroups.get(executionVertexID);
groupToSchedule.add(groupsBelongTo);
}
}
for (ConcurrentSchedulingGroup group : groupToSchedule) {
if (!graphManager.cacheGroupIfReconciling(group)) {
LOG.info("Group {} is scheduled again.", group);
scheduleGroup(group);
}
}
}
}
@Override
public synchronized void onExecutionVertexStateChanged(ExecutionVertexStateChangedEvent event) {
final Set verticesToSchedule = new HashSet<>();
if (event.getNewExecutionState() == ExecutionState.FINISHED) {
if (scheduler.getExecutionJobVertexStatus(event.getExecutionVertexID().getJobVertexID()) == ExecutionState.FINISHED) {
Set successorVertices = predecessorToSuccessors.get(event.getExecutionVertexID().getJobVertexID());
if (successorVertices != null) {
for (JobVertex successor : successorVertices) {
for (int i = 0; i < successor.getParallelism(); i++) {
ExecutionVertexID executionVertexID = new ExecutionVertexID(successor.getID(), i);
if (isReadyToSchedule(executionVertexID)) {
verticesToSchedule.add(executionVertexID);
}
}
}
}
}
}
scheduleInConcurrentGroup(verticesToSchedule);
}
@Override
public boolean allowLazyDeployment() {
if (jobGraph.getJobType() == JobType.INFINITE_STREAM) {
return false;
}
return true;
}
private List buildConcurrentSchedulingGroups(
List jobVerticesTopologically,
boolean scheduled) {
List concurrentJobVertexGroups = new ArrayList<>();
List schedulingGroups = new ArrayList<>();
final Set visitedJobVertices = new HashSet<>();
for (JobVertex jobVertex : jobVerticesTopologically) {
if (visitedJobVertices.add(jobVertex)) {
List concurrentVertices = new ArrayList<>();
concurrentVertices.add(jobVertex);
for (IntermediateDataSet output : jobVertex.getProducedDataSets()) {
for (JobEdge jobEdge : output.getConsumers()) {
if (jobVerticesTopologically.contains(jobEdge.getTarget()) &&
!visitedJobVertices.contains(jobEdge.getTarget()) &&
jobEdge.getSchedulingMode() == SchedulingMode.CONCURRENT &&
!isStartOnFinishedEdge(jobEdge)) {
visitedJobVertices.add(jobEdge.getTarget());
concurrentVertices.add(jobEdge.getTarget());
concurrentVertices.addAll(
getAllConcurrentVertices(jobEdge.getTarget(), jobVerticesTopologically, visitedJobVertices));
}
}
}
concurrentJobVertexGroups.add(new ConcurrentJobVertexGroup(concurrentVertices, ignoredControlEdges));
}
}
LOG.info("{} vertex group was built with {} vertices.", concurrentJobVertexGroups.size(), jobVerticesTopologically.size());
breakCircleDependencies(concurrentJobVertexGroups);
for (ConcurrentJobVertexGroup group : concurrentJobVertexGroups) {
LOG.info("Concurrent vertex group has {} with preceding {}", group.getVertices(), group.hasPrecedingGroup());
}
for (ConcurrentJobVertexGroup regionGroup : concurrentJobVertexGroups) {
schedulingGroups.addAll(buildSchedulingGroupsFromJobVertexGroup(regionGroup, scheduled));
}
this.concurrentSchedulingGroups.addAll(schedulingGroups);
for (ConcurrentSchedulingGroup schedulingGroup: schedulingGroups) {
for (ExecutionVertex ev : schedulingGroup.getExecutionVertices()) {
executionToConcurrentSchedulingGroups.put(ev.getExecutionVertexID(), schedulingGroup);
}
}
LOG.info("{} concurrent group was built with {} vertices for job {}.",
schedulingGroups.size(), jobVerticesTopologically.size(), jobGraph.getJobID());
return schedulingGroups;
}
private void splitGroupAndContinueScheduling(
List assignedJobVertices,
List unAssignedJobVertices,
ConcurrentSchedulingGroup originalGroup) {
LOG.info("Split scheduling group {} as resource is not enough, assigned {}, unassigned {}.",
originalGroup, assignedJobVertices, unAssignedJobVertices);
concurrentSchedulingGroups.remove(originalGroup);
// 1. Update the result partition.
Set visitedJobVertices = new HashSet<>();
for (JobVertex jobVertex : assignedJobVertices) {
if (visitedJobVertices.add(jobVertex)) {
for (int i = 0; i < jobVertex.getProducedDataSets().size(); i++) {
IntermediateDataSet output = jobVertex.getProducedDataSets().get(i);
if (!output.getConsumers().isEmpty()) {
JobEdge jobEdge = output.getConsumers().get(0);
for (ExecutionVertex executionVertex : executionGraph.getJobVertex(jobEdge.getTarget().getID()).getTaskVertices()) {
if (executionVertex.getExecutionState() == ExecutionState.CREATED) {
jobEdge.setSchedulingMode(SchedulingMode.SEQUENTIAL);
executionGraph.getJobVertex(jobVertex.getID()).getProducedDataSets()[i].setResultType(ResultPartitionType.BLOCKING);
break;
}
}
}
}
}
}
// 2. Rebuild virtual relations.
buildStartOnFinishRelation(jobGraph);
// 3. Build groups for the job vertices that have been assigned resource.
List newAssignedGroups = buildConcurrentSchedulingGroups(assignedJobVertices, true);
// 4. Build groups for the job vertices that have not been assigned resource.
List newUnAssignedGroups = buildConcurrentSchedulingGroups(unAssignedJobVertices, false);
// 5. Rebuild failover region.
// 6. Deploy the tasks.
for (ConcurrentSchedulingGroup group : newAssignedGroups) {
List evs = group.getExecutionVertices();
if (evs.size() == 1 && evs.get(0).getCurrentAssignedResource() == null) {
scheduleGroup(group);
} else {
for (ExecutionVertex ev : evs) {
try {
ev.getCurrentExecutionAttempt().deploy();
} catch (Exception e) {
LOG.info("Fail to deploy execution {}", ev, e);
ev.getCurrentExecutionAttempt().fail(e);
}
}
}
}
// 7. Trigger groups that have no preceding
for (ConcurrentSchedulingGroup group : newUnAssignedGroups) {
if (!group.hasPrecedingGroup()) {
checkAndScheduleGroup(group);
} else {
List evs = group.getExecutionVertices();
for (ExecutionVertex ev : evs) {
if (isReadyToSchedule(ev.getExecutionVertexID())) {
checkAndScheduleGroup(group);
break;
}
}
}
}
}
@VisibleForTesting
Set getConcurrentSchedulingGroups() {
return concurrentSchedulingGroups;
}
@VisibleForTesting
Map> getPredecessorToSuccessors() {
return predecessorToSuccessors;
}
@VisibleForTesting
Map> getSuccessorsToPredecessor() {
return successorToPredecessors;
}
private Set getAllConcurrentVertices(
JobVertex jobVertex,
List allJobVerticesTopologically,
Set visitedJobVertices) {
Set concurrentVertices = new HashSet<>();
for (JobEdge jobEdge : jobVertex.getInputs()) {
if (jobEdge.getSchedulingMode() == SchedulingMode.CONCURRENT &&
allJobVerticesTopologically.contains(jobEdge.getSource().getProducer()) &&
!visitedJobVertices.contains(jobEdge.getSource().getProducer()) &&
!isStartOnFinishedEdge(jobEdge)) {
visitedJobVertices.add(jobEdge.getSource().getProducer());
concurrentVertices.add(jobEdge.getSource().getProducer());
concurrentVertices.addAll(getAllConcurrentVertices(
jobEdge.getSource().getProducer(), allJobVerticesTopologically, visitedJobVertices));
}
}
for (IntermediateDataSet output : jobVertex.getProducedDataSets()) {
for (JobEdge jobEdge : output.getConsumers()) {
if (allJobVerticesTopologically.contains(jobEdge.getTarget()) &&
!visitedJobVertices.contains(jobEdge.getTarget()) &&
jobEdge.getSchedulingMode() == SchedulingMode.CONCURRENT &&
!isStartOnFinishedEdge(jobEdge)) {
visitedJobVertices.add(jobEdge.getTarget());
concurrentVertices.add(jobEdge.getTarget());
concurrentVertices.addAll(
getAllConcurrentVertices(jobEdge.getTarget(), allJobVerticesTopologically, visitedJobVertices));
}
}
}
return concurrentVertices;
}
private List buildSchedulingGroupsFromJobVertexGroup(
ConcurrentJobVertexGroup jobVertexGroup, boolean scheduled) {
final List schedulingGroups = new ArrayList<>();
List jobVerticesTopologically = jobVertexGroup.getVertices();
if (jobVerticesTopologically.size() == 1) {
for (ExecutionVertex ev : executionGraph.getJobVertex(jobVerticesTopologically.get(0).getID()).getTaskVertices()) {
schedulingGroups.add(
new ConcurrentSchedulingGroup(
Collections.singletonList(ev),
jobVertexGroup.hasPrecedingGroup(),
scheduled));
}
} else {
List executionVertices = new ArrayList<>();
for (JobVertex jobVertex : jobVerticesTopologically) {
for (ExecutionVertex ev : executionGraph.getJobVertex(jobVertex.getID()).getTaskVertices()) {
executionVertices.add(ev);
}
}
schedulingGroups.add(new ConcurrentSchedulingGroup(
executionVertices,
jobVertexGroup.hasPrecedingGroup(),
scheduled));
}
return schedulingGroups;
}
private void scheduleInConcurrentGroup(Set verticesToSchedule) {
Set groupsToSchedule = new HashSet<>();
for (ExecutionVertexID vertexID : verticesToSchedule) {
ConcurrentSchedulingGroup groupsBelongTo = executionToConcurrentSchedulingGroups.get(vertexID);
if (groupsBelongTo == null) {
throw new RuntimeException("Can not find a group for " + vertexID + ", this is logic error.");
}
groupsToSchedule.add(groupsBelongTo);
}
for (ConcurrentSchedulingGroup group : groupsToSchedule) {
if (!graphManager.cacheGroupIfReconciling(group)) {
checkAndScheduleGroup(group);
}
}
}
private boolean isReadyToSchedule(ExecutionVertexID vertexID) {
ExecutionVertexStatus vertexStatus = scheduler.getExecutionVertexStatus(vertexID);
// only CREATED vertices can be scheduled
if (vertexStatus.getExecutionState() != ExecutionState.CREATED) {
return false;
}
Set predecessorIds = successorToPredecessors.get(vertexID.getJobVertexID());
if (predecessorIds != null) {
for (JobVertexID predecessorId : predecessorIds) {
if (scheduler.getExecutionJobVertexStatus(predecessorId) != ExecutionState.FINISHED) {
return false;
}
}
}
// source vertices can be scheduled at once
if (jobGraph.findVertexByID(vertexID.getJobVertexID()).isInputVertex()) {
return true;
}
// query whether the inputs are ready overall
return inputTracker.areInputsReady(vertexID);
}
private void buildStartOnFinishRelation(JobGraph jobGraph) {
successorToPredecessors.clear();
predecessorToSuccessors.clear();
ignoredControlEdges.clear();
for (JobVertex jobVertex : jobGraph.getVerticesSortedTopologicallyFromSources()) {
for (JobControlEdge controlEdge : jobVertex.getOutControlEdges()) {
LOG.debug("ControlEdge from {} to {} with type {}",
controlEdge.getSource().getID(), controlEdge.getTarget().getID(), controlEdge.getControlType());
if (controlEdge.getControlType() == ControlType.START_ON_FINISH) {
for (IntermediateDataSet output : controlEdge.getTarget().getProducedDataSets()) {
if (!output.getResultType().isBlocking()) {
LOG.warn("Vertex {} is a start on finished but not blocking.", controlEdge.getTarget().getName());
}
}
Set concurrentAncestors = getAllConcurrentAncestors(controlEdge.getTarget());
boolean hasCircleDependency = false;
for (JobVertex ancestor : concurrentAncestors) {
if (hasCircleDependencyInVertices(ancestor, jobVertex)) {
hasCircleDependency = true;
ignoredControlEdges.add(controlEdge);
break;
}
}
if (!hasCircleDependency) {
for (JobVertex ancestor : concurrentAncestors) {
Set existingPredecessors = successorToPredecessors.computeIfAbsent(ancestor.getID(), k -> new HashSet<>());
existingPredecessors.add(jobVertex.getID());
}
Set existingSuccessors = predecessorToSuccessors.putIfAbsent(jobVertex.getID(), concurrentAncestors);
if (existingSuccessors != null) {
existingSuccessors.addAll(concurrentAncestors);
}
}
}
}
}
}
private Set getAllConcurrentAncestors(JobVertex jobVertex) {
Set ancestors = new HashSet<>();
if (jobVertex.isInputVertex()) {
ancestors.add(jobVertex);
} else {
for (JobEdge jobEdge : jobVertex.getInputs()) {
if (jobEdge.getSchedulingMode() == SchedulingMode.CONCURRENT &&
!isStartOnFinishedEdge(jobEdge)) {
ancestors.addAll(getAllConcurrentAncestors(jobEdge.getSource().getProducer()));
}
}
if (ancestors.isEmpty()) {
ancestors.add(jobVertex);
}
}
return ancestors;
}
public void checkAndScheduleGroup(ConcurrentSchedulingGroup schedulingGroup) {
if (!schedulingGroup.markScheduled()) {
LOG.info("Group {} has already been scheduled, will not schedule again.", schedulingGroup);
return;
}
scheduleGroup(schedulingGroup);
}
public void scheduleGroup(ConcurrentSchedulingGroup schedulingGroup) {
List executionVertices = schedulingGroup.getExecutionVertices();
List scheduledExecutions = new ArrayList<>();
for (ExecutionVertex ev : executionVertices) {
if (ev.getCurrentExecutionAttempt().enterScheduled()) {
scheduledExecutions.add(ev.getCurrentExecutionAttempt());
} else {
LOG.info("{} is in state {} while scheduled in group {}",
ev.getTaskNameWithSubtaskIndex(), ev.getExecutionState(), schedulingGroup);
}
}
Time allocationTimeout = executionVertices.size() > 1 ? executionGraph.getAllocationTimeout() : allocationLongTimeout;
CompletableFuture> allocationFuture =
executionSlotAllocator.allocateSlotsFor(scheduledExecutions, allocationTimeout);
CompletableFuture currentSchedulingFuture = allocationFuture.handleAsync(
(Collection slots, Throwable throwable) -> {
if (throwable == null) {
if (scheduledExecutions.size() != slots.size()) {
LOG.warn("Execution state change during allocating resource.");
}
int failedNumber = 0;
for (LogicalSlot slot : slots) {
if (slot == null) {
failedNumber++;
}
}
Throwable strippedThrowable = new Exception("Batch request " + scheduledExecutions.size() +
", but " + failedNumber + " does not return.");
if (failedNumber > 0 && (!allowGroupSplit || executionVertices.size() < 2)) {
for (LogicalSlot slot : slots) {
if (slot != null) {
slot.releaseSlot(strippedThrowable);
}
}
for (Execution execution : scheduledExecutions) {
execution.fail(strippedThrowable);
}
return null;
} else if (failedNumber > 0) {
int i = 0;
int index = -1;
boolean hasFailure = false;
// Find the index from which resource is not assigned.
for (LogicalSlot slot : slots) {
if (slot == null && !hasFailure) {
hasFailure = true;
index = i;
scheduledExecutions.get(i).rollbackToCreated();
LOG.debug("The first failed slot request is {}.", index);
} else if (hasFailure) {
if (slot != null) {
slot.releaseSlot(strippedThrowable);
}
scheduledExecutions.get(i).rollbackToCreated();
}
i++;
}
if (index < 0) {
LOG.info("All allocations is assigned, but the request fail, this is strange.", throwable);
} else {
List assignedJobVertices = new ArrayList<>();
List unAssignedJobVertices = new ArrayList<>();
if (index == 0) {
assignedJobVertices.add(executionVertices.get(0).getJobVertex().getJobVertex());
for (int j = 1; j < executionVertices.size(); j++) {
JobVertexID jobVertexID = executionVertices.get(j).getJobvertexId();
if (!jobVertexID.equals(assignedJobVertices.get(assignedJobVertices.size() - 1).getID())
&& (unAssignedJobVertices.isEmpty() ||
!jobVertexID.equals(unAssignedJobVertices.get(unAssignedJobVertices.size() - 1).getID()))) {
unAssignedJobVertices.add(executionVertices.get(j).getJobVertex().getJobVertex());
}
}
} else {
boolean lastAssignedVertexFulfilled = false;
boolean firstVertexFullyAssigned = true;
if (!scheduledExecutions.get(index).getVertex().getJobvertexId().equals(
scheduledExecutions.get(index - 1).getVertex().getJobvertexId())) {
lastAssignedVertexFulfilled = true;
LOG.debug("The last assigned vertex is fully filled.");
}
if (scheduledExecutions.get(index).getVertex().getJobvertexId().equals(
executionVertices.get(0).getJobvertexId())) {
firstVertexFullyAssigned = false;
LOG.debug("The first vertex is not fully filled.");
}
i = 0;
for (LogicalSlot slot : slots) {
if (lastAssignedVertexFulfilled) {
assignResourceElseFail(scheduledExecutions.get(i), slot);
} else {
if (firstVertexFullyAssigned) {
if (executionVertices.get(i).getJobvertexId().equals(
scheduledExecutions.get(index).getVertex().getJobvertexId())) {
slot.releaseSlot(strippedThrowable);
scheduledExecutions.get(i).rollbackToCreated();
} else {
assignResourceElseFail(scheduledExecutions.get(i), slot);
}
} else {
assignResourceElseFail(scheduledExecutions.get(i), slot);
}
}
i++;
if (i >= index) {
break;
}
}
assignedJobVertices.add(executionVertices.get(0).getJobVertex().getJobVertex());
boolean enterUnAssigned = false;
for (int j = 0; j < executionVertices.size(); j++) {
JobVertex jobVertex = executionVertices.get(j).getJobVertex().getJobVertex();
if (!enterUnAssigned) {
if (jobVertex.getID().equals(
scheduledExecutions.get(index).getVertex().getJobvertexId())) {
if (!jobVertex.getID().equals(assignedJobVertices.get(0).getID())) {
unAssignedJobVertices.add(jobVertex);
}
enterUnAssigned = true;
} else if (!jobVertex.getID().equals(
assignedJobVertices.get(assignedJobVertices.size() - 1).getID())) {
assignedJobVertices.add(jobVertex);
}
} else if (!jobVertex.getID().equals(assignedJobVertices.get(0).getID()) &&
(unAssignedJobVertices.isEmpty() || !jobVertex.getID().equals(
unAssignedJobVertices.get(unAssignedJobVertices.size() - 1).getID()))) {
unAssignedJobVertices.add(jobVertex);
}
}
}
splitGroupAndContinueScheduling(assignedJobVertices, unAssignedJobVertices, schedulingGroup);
return null;
}
}
int i = 0;
for (LogicalSlot slot : slots) {
if (!scheduledExecutions.get(i).tryAssignResource(slot)) {
// release the slot
Exception e = new FlinkException("Could not assign logical slot to execution " + scheduledExecutions.get(i) + '.');
slot.releaseSlot(e);
scheduledExecutions.get(i).fail(e);
}
i++;
}
for (i = 0; i < scheduledExecutions.size(); i++) {
try {
scheduledExecutions.get(i).deploy();
} catch (Exception e) {
LOG.info("Fail to deploy execution {}", scheduledExecutions.get(i), e);
scheduledExecutions.get(i).fail(e);
}
}
}
return null;
}, executionGraph.getFutureExecutor());
executionGraph.registerSchedulingFuture(currentSchedulingFuture);
currentSchedulingFuture.whenComplete(
(Void ignored, Throwable throwable) -> {
final Throwable strippedThrowable = ExceptionUtils.stripCompletionException(throwable);
if (strippedThrowable instanceof CancellationException) {
// cancel the individual allocation futures
allocationFuture.cancel(false);
}
executionGraph.unregisterSchedulingFuture(currentSchedulingFuture);
});
}
private void assignResourceElseFail(Execution execution, LogicalSlot slot) {
if (!execution.tryAssignResource(slot)) {
// release the slot
Exception e = new FlinkException("Could not assign logical slot to execution " + execution + '.');
slot.releaseSlot(e);
execution.fail(e);
}
}
private void breakCircleDependencies(List jobVertexGroups) {
Map vertexToConcurrentGroupMap = new HashMap<>();
for (ConcurrentJobVertexGroup jobVertexGroup : jobVertexGroups) {
List vertices = jobVertexGroup.getVertices();
for (JobVertex vertex : vertices) {
vertexToConcurrentGroupMap.put(vertex, jobVertexGroup);
}
}
for (ConcurrentJobVertexGroup jobVertexGroup : jobVertexGroups) {
if (hasCircleDependencyInGroups(jobVertexGroup, vertexToConcurrentGroupMap) &&
jobVertexGroup.hasInputVertex()) {
jobVertexGroup.noPrecedingGroup();
}
}
}
private boolean hasCircleDependencyInGroups(
ConcurrentJobVertexGroup jobVertexGroup,
Map vertexToConcurrentGroupMap) {
List predecessors = jobVertexGroup.getPredecessorVertices();
if (predecessors.size() > 0) {
List ancestors = new ArrayList<>();
Set visitedGroups = new HashSet<>();
for (JobVertex predecessor : predecessors) {
ConcurrentJobVertexGroup group = vertexToConcurrentGroupMap.get(predecessor);
if (group != null) {
ancestors.addAll(group.getPredecessorVertices());
if (!visitedGroups.contains(group)) {
visitedGroups.add(group);
}
}
}
while (!ancestors.isEmpty()) {
List newAddedAncestors = new ArrayList<>();
for (JobVertex ancestor : ancestors) {
ConcurrentJobVertexGroup group = vertexToConcurrentGroupMap.get(ancestor);
if (group == jobVertexGroup) {
return true;
} else {
if (group != null && !visitedGroups.contains(group)) {
visitedGroups.add(group);
newAddedAncestors.addAll(group.getPredecessorVertices());
}
}
}
ancestors = newAddedAncestors;
}
}
return false;
}
private boolean hasCircleDependencyInVertices(JobVertex successor, JobVertex predecessor) {
List ancestors = new ArrayList<>();
Set virtualPredecessors = successorToPredecessors.get(predecessor.getID());
if (virtualPredecessors != null) {
for (JobVertexID virtualPredecessor : virtualPredecessors) {
ancestors.add(executionGraph.getJobVertex(virtualPredecessor).getJobVertex());
}
}
for (JobEdge jobEdge : predecessor.getInputs()) {
ancestors.add(jobEdge.getSource().getProducer());
}
while (!ancestors.isEmpty()) {
List newAddedAncestors = new ArrayList<>();
for (JobVertex ancestor : ancestors) {
if (ancestor.equals(successor)) {
return true;
} else {
Set newVirtualPredecessors = successorToPredecessors.get(ancestor.getID());
if (newVirtualPredecessors != null) {
for (JobVertexID newVirtualPredecessor : newVirtualPredecessors) {
newAddedAncestors.add(executionGraph.getJobVertex(newVirtualPredecessor).getJobVertex());
}
}
for (JobEdge jobEdge : ancestor.getInputs()) {
newAddedAncestors.add(jobEdge.getSource().getProducer());
}
}
}
ancestors = newAddedAncestors;
}
return false;
}
/**
* Judge whether the job edge is the later read edge of a vertex.
* @return
*/
private boolean isStartOnFinishedEdge(JobEdge jobEdge) {
JobVertex source = jobEdge.getSource().getProducer();
for (JobControlEdge controlEdge : source.getInControlEdges()) {
JobVertex controlEdgeSource = controlEdge.getSource();
for (IntermediateDataSet output : controlEdgeSource.getProducedDataSets()) {
for (JobEdge outputEdge : output.getConsumers()) {
if (outputEdge.getTarget().equals(jobEdge.getTarget())) {
return true;
}
}
}
}
return false;
}
}