internal GraphNode(TargetInProgessState targetState) { this.targetState = targetState; this.children = new List <GraphNode>(); this.traversalIndex = InvalidIndex; this.isRoot = false; }
/// <summary> /// Find all the build contexts that connects child to parent. The only time multiple contexts are possible /// is if the connection is formed by an IBuildEngine callback which requests the same target in the /// same project to be build in parallel multiple times. /// </summary> internal List <ProjectBuildState> FindConnectingContexts ( TargetInProgessState child, TargetInProgessState parent, Target childTarget, List <ProjectBuildState> waitingStates, ProjectBuildState initiatingBuildContext ) { List <ProjectBuildState> connectingContexts = new List <ProjectBuildState>(); // Since the there is a cycle formed at the child there must be at least two requests // since the edge between the parent and the child is a backward edge ErrorUtilities.VerifyThrow(waitingStates != null, "There must be a at least two requests at the child"); for (int i = 0; i < waitingStates.Count; i++) { if (child.CheckBuildContextForParentMatch(parentEngine.EngineCallback, parent.TargetId, childTarget, waitingStates[i])) { connectingContexts.Add(waitingStates[i]); } } if (child.CheckBuildContextForParentMatch(parentEngine.EngineCallback, parent.TargetId, childTarget, initiatingBuildContext)) { connectingContexts.Add(initiatingBuildContext); } return(connectingContexts); }
/// <summary> /// This function is called to break the link between two targets that creates a cycle. The link could be /// due to depends/onerror relationship between parent and child. In that case both parent and child are /// on the same node and within the same project. Or the link could be formed by an IBuildEngine callback /// (made such by tasks such as MSBuild or CallTarget) in which case there maybe multiple requests forming /// same link between parent and child. Also in that case parent and child maybe on different nodes and/or in /// different projects. In either case the break is forced by finding the correct builds states and causing /// them to fail. /// </summary> internal void BreakCycle(TargetInProgessState child, TargetInProgessState parent) { ErrorUtilities.VerifyThrow(child.TargetId.nodeId == parentEngine.NodeId, "Expect the child target to be on the node"); Project parentProject = projectManager.GetProject(child.TargetId.projectId); ErrorUtilities.VerifyThrow(parentProject != null, "Expect the parent project to be on the node"); Target childTarget = parentProject.Targets[child.TargetId.name]; List <ProjectBuildState> parentStates = FindConnectingContexts(child, parent, childTarget, childTarget.ExecutionState.GetWaitingBuildContexts(), childTarget.ExecutionState.InitiatingBuildContext); ErrorUtilities.VerifyThrow(parentStates.Count > 0, "Must find at least one matching context"); for (int i = 0; i < parentStates.Count; i++) { parentStates[i].CurrentBuildContextState = ProjectBuildState.BuildContextState.CycleDetected; TaskExecutionContext taskExecutionContext = new TaskExecutionContext(parentProject, childTarget, null, parentStates[i], EngineCallback.invalidEngineHandle, EngineCallback.inProcNode, null); parentEngine.PostTaskOutputUpdates(taskExecutionContext); } }
public void PostIntrospectorCommand(int nodeIndex, TargetInProgessState child, TargetInProgessState parent) { // Send the updated settings once the node has initialized LocalCallDescriptorForPostIntrospectorCommand callDescriptor = new LocalCallDescriptorForPostIntrospectorCommand(child, parent); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); }
internal override void CreateFromStream(BinaryReader reader) { base.CreateFromStream(reader); child = new TargetInProgessState(); child.CreateFromStream(reader); parent = new TargetInProgessState(); parent.CreateFromStream(reader); }
/// <summary> /// Add a information about a given inprogress target to the graph /// </summary> private void AddTargetToGraph(TargetInProgessState inProgressTarget) { // Check if the target is already in the graph in which // case reuse the current object GraphNode targetNode = (GraphNode)dependencyGraph[inProgressTarget.TargetId]; if (targetNode == null) { targetNode = new GraphNode(inProgressTarget); dependencyGraph.Add(inProgressTarget.TargetId, targetNode); } else { ErrorUtilities.VerifyThrow(targetNode.targetState == null, "Target should only be added once"); targetNode.targetState = inProgressTarget; } // For each parent target - add parent links creating parent targets if necessary foreach (TargetInProgessState.TargetIdWrapper parentTarget in inProgressTarget.ParentTargets) { GraphNode parentNode = (GraphNode)dependencyGraph[parentTarget]; if (parentNode == null) { parentNode = new GraphNode(null); dependencyGraph.Add(parentTarget, parentNode); } parentNode.children.Add(targetNode); } // For all outgoing requests add them to the list of outstanding requests for the system if (inProgressTarget.OutstandingBuildRequests != null) { // Since the nodeIndex is not serialized it is necessary to restore it after the request // travels across the wire for (int i = 0; i < inProgressTarget.OutstandingBuildRequests.Length; i++) { inProgressTarget.OutstandingBuildRequests[i].NodeIndex = inProgressTarget.TargetId.nodeId; } outstandingExternalRequests.Add(inProgressTarget.TargetId, inProgressTarget.OutstandingBuildRequests); } // If the target has no parents mark it as root (such targets are created due to host requests) if (inProgressTarget.RequestedByHost) { targetNode.isRoot = true; } }
internal static NodeStatus CreateFromStream(BinaryReader reader) { NodeStatus status = new NodeStatus(null); status.traversalType = reader.ReadBoolean(); status.statusTimeStamp = reader.ReadInt64(); status.requestId = reader.ReadInt32(); status.isActive = reader.ReadBoolean(); status.isLaunchInProgress = reader.ReadBoolean(); status.queueDepth = reader.ReadInt32(); status.lastTaskActivityTimeStamp = reader.ReadInt64(); status.lastEngineActivityTimeStamp = reader.ReadInt64(); if (reader.ReadByte() == 0) { status.stateOfInProgressTargets = null; } else { int numberOfInProgressTargets = reader.ReadInt32(); status.stateOfInProgressTargets = new TargetInProgessState[numberOfInProgressTargets]; for (int i = 0; i < numberOfInProgressTargets; i++) { if (reader.ReadByte() == 0) { status.stateOfInProgressTargets[i] = null; } else { TargetInProgessState state = new TargetInProgessState(); state.CreateFromStream(reader); status.stateOfInProgressTargets[i] = state; } } } if (reader.ReadByte() == 0) { status.unhandledException = null; } else { status.unhandledException = (Exception)formatter.Deserialize(reader.BaseStream); } return(status); }
internal void PostCycleNotification ( int nodeId, TargetInProgessState child, TargetInProgessState parent) { if (nodeId == 0) { parentEngine.Introspector.BreakCycle(child, parent); } for (int i = 0; i < nodeList.Count; i++) { if (nodeList[i].NodeId == nodeId) { nodeList[i].NodeProvider.PostIntrospectorCommand(nodeList[i].NodeIndex, child, parent); break; } } }
internal LocalCallDescriptorForPostIntrospectorCommand(TargetInProgessState child, TargetInProgessState parent) : base(LocalCallType.PostIntrospectorCommand) { this.child = child; this.parent = parent; }