Example #1
0
        /// <summary>
        /// This method creates a new routing context. This method is not thread safe and must be called
        /// only from the engine thread.
        /// </summary>
        internal int CreateRoutingContext
        (
            int nodeIndex,
            int parentHandleId,
            int parentNodeIndex,
            int parentRequestId,
            CacheScope cacheScope,
            BuildRequest triggeringBuildRequest,
            BuildEventContext buildEventContext
        )
        {
            int handleId = nextContextId;

            nextContextId = nextContextId + 1;

            RequestRoutingContext executionContext =
                new RequestRoutingContext(handleId, nodeIndex, parentHandleId, parentNodeIndex, parentRequestId,
                                          cacheScope, triggeringBuildRequest, buildEventContext);

            executionContexts.Add(handleId, executionContext);

            return(handleId);
        }
Example #2
0
        /// <summary>
        /// This method is used by the child node to post results of a build request back to the
        /// parent node. The parent node then decides if need to re-route the results to another node
        /// that requested the evaluation or if it will consume the result locally
        /// </summary>
        /// <param name="buildResult"></param>
        public void PostBuildResultToHost(BuildResult buildResult)
        {
            RequestRoutingContext routingContext = GetRoutingContextFromHandleId(buildResult.HandleId);

            ErrorUtilities.VerifyThrow(routingContext.CacheScope != null, "Cache scope should be created for this context");

            // Cache the results
            routingContext.CacheScope.AddCacheEntryForBuildResults(buildResult);

            if (Engine.debugMode)
            {
                Console.WriteLine("Received result for HandleId " + buildResult.HandleId + ":" + buildResult.RequestId + " mapped to " + routingContext.ParentHandleId + ":" + routingContext.ParentRequestId);
            }

            // Update the results with the original handle id and request id, so that
            buildResult.HandleId = routingContext.ParentHandleId;

            // If the build result is created from a generated build request a done notice should be posted as other targets could be waiting for this target to finish
            if (buildResult.HandleId != invalidEngineHandle)
            {
                buildResult.RequestId = routingContext.ParentRequestId;
                parentEngine.Router.PostDoneNotice(routingContext.ParentNodeIndex, buildResult);
            }
            else // The build results need to be stored into the build request so they can be sent back to the host that requested the build
            {
                routingContext.TriggeringBuildRequest.OutputsByTarget = buildResult.OutputsByTarget;
                routingContext.TriggeringBuildRequest.BuildSucceeded  = buildResult.EvaluationResult;
                routingContext.TriggeringBuildRequest.BuildCompleted  = true;
                parentEngine.PostEngineCommand(new HostBuildRequestCompletionEngineCommand());
            }

            // At this point the execution context we created for the execution of this build request can be deleted
            lock (freedContexts)
            {
                freedContexts.Add(routingContext);
            }
        }
Example #3
0
        private void ProcessBuildRequest(BuildRequest buildRequest)
        {
            ExecutionContext executionContext = GetExecutionContextFromHandleId(buildRequest.HandleId);

            // Restore the requests non-serialized data to the correct state
            buildRequest.RestoreNonSerializedDefaults();
            buildRequest.NodeIndex = executionContext.NodeIndex;

            ErrorUtilities.VerifyThrow(buildRequest.ParentBuildEventContext != null, "Should not have a null parentBuildEventContext");
            ErrorUtilities.VerifyThrow(buildRequest.IsGeneratedRequest == true, "Should not be sending a non generated request from the child node to the parent node");

            // For buildRequests originating from the TEM  - additional initialization is necessary
            TaskExecutionContext taskExecutionContext = executionContext as TaskExecutionContext;

            if (taskExecutionContext != null)
            {
                Project parentProject = taskExecutionContext.ParentProject;
                buildRequest.ParentHandleId  = taskExecutionContext.TriggeringBuildRequest.HandleId;
                buildRequest.ParentRequestId = taskExecutionContext.TriggeringBuildRequest.RequestId;

                if (buildRequest.ToolsetVersion == null && parentProject.OverridingToolsVersion)
                {
                    // If the MSBuild task (or whatever) didn't give us a specific tools version,
                    // but the parent project is using an overridden tools version, then use that one
                    buildRequest.ToolsetVersion = parentProject.ToolsVersion;
                }

                try
                {
                    if (buildRequest.GlobalProperties == null)
                    {
                        try
                        {
                            // Make sure we have a blank global properties because if there is a problem merging them we wont have a crash when we try and cache the build result.
                            buildRequest.GlobalProperties = new BuildPropertyGroup();
                            buildRequest.GlobalProperties =
                                parentEngine.MergeGlobalProperties(parentProject.GlobalProperties, null,
                                                                   buildRequest.ProjectFileName,
                                                                   buildRequest.GlobalPropertiesPassedByTask);
                        }
                        catch (ArgumentException e)
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                        catch (InvalidOperationException e)
                        {
                            ConvertToInvalidProjectException(buildRequest, parentProject, e);
                        }
                    }

                    // We need to figure out which project object this request is refering to
                    if (buildRequest.ProjectFileName == null)
                    {
                        ErrorUtilities.VerifyThrow(parentProject != null, "Parent project must be non-null");

                        // This means the caller (the MSBuild task) wants us to use the same project as the calling
                        // project.  This allows people to avoid passing in the Projects parameter on the MSBuild task.
                        Project projectToBuild = parentProject;



                        // If the parent project (the calling project) already has the same set of global properties
                        // as what is being requested, just re-use it.  Otherwise, we need to instantiate a new
                        // project object that has the same project contents but different global properties.
                        if (!projectToBuild.GlobalProperties.IsEquivalent(buildRequest.GlobalProperties) &&
                            (String.Compare(parentProject.ToolsVersion, buildRequest.ToolsetVersion, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            projectToBuild = parentEngine.GetMatchingProject(parentProject,
                                                                             parentProject.FullFileName, buildRequest.GlobalProperties,
                                                                             buildRequest.ToolsetVersion, buildRequest.TargetNames, buildRequest.ParentBuildEventContext, buildRequest.ToolsVersionPeekedFromProjectFile);
                        }
                        buildRequest.ProjectToBuild  = projectToBuild;
                        buildRequest.ProjectFileName = projectToBuild.FullFileName;
                        buildRequest.FireProjectStartedFinishedEvents = false;
                    }
                }
                catch (InvalidProjectFileException e)
                {
                    buildRequest.BuildCompleted = true;
                    // Store message so it can be logged by the engine build loop
                    buildRequest.BuildException = e;
                }
            }
            else
            {
                RequestRoutingContext requestRoutingContext = executionContext as RequestRoutingContext;
                buildRequest.ParentHandleId  = requestRoutingContext.ParentHandleId;
                buildRequest.ParentRequestId = requestRoutingContext.ParentRequestId;
            }
        }
Example #4
0
        /// <summary>
        /// For each target that has a cross node build request waiting for it to complete, iterate
        /// over the list of outstanding requests and find the matching out going request. Once
        /// the matching request is found - link the parent and child targets.
        /// </summary>
        private void LinkCrossNodeBuildRequests()
        {
            foreach (GraphNode node in dependencyGraph.Values)
            {
                TargetInProgessState.TargetIdWrapper[] parentsForBuildRequests =
                    new TargetInProgessState.TargetIdWrapper[node.targetState.ParentBuildRequests.Count];

                for (int j = 0; j < node.targetState.ParentBuildRequests.Count; j++)
                {
                    BuildRequest buildRequest = node.targetState.ParentBuildRequests[j];
                    int          nodeIndex    = buildRequest.NodeIndex;
                    int          handleId     = buildRequest.HandleId;
                    int          requestId    = buildRequest.RequestId;
                    bool         foundParent  = false;

                    // Skip requests that originated from the host
                    if (handleId == EngineCallback.invalidEngineHandle)
                    {
                        node.isRoot = true;
                        continue;
                    }

                    // If the request being analyzed came from one of the child nodes, its incoming external request's
                    // handleId will point at a routing context on the parent engine. If the outgoing request
                    // orginated from another child the two requests (outgoing and incoming) point at different
                    // routing contexts. In that case it is necessary to unwind the incoming request to the routing
                    // context of the outgoing request. If outgoing request originated from the parent node -
                    // there will be only one routing request.
                    if (node.targetState.TargetId.nodeId != 0)
                    {
                        ExecutionContext      executionContext = engineCallback.GetExecutionContextFromHandleId(buildRequest.HandleId);
                        RequestRoutingContext routingContext   = executionContext as RequestRoutingContext;
                        if (routingContext != null && routingContext.ParentHandleId != EngineCallback.invalidEngineHandle)
                        {
                            ExecutionContext nextExecutionContext = engineCallback.GetExecutionContextFromHandleId(routingContext.ParentHandleId);

                            if (nextExecutionContext is RequestRoutingContext)
                            {
                                nodeIndex = nextExecutionContext.NodeIndex;
                                handleId  = routingContext.ParentHandleId;
                                requestId = routingContext.ParentRequestId;
                            }
                        }
                        else
                        {
                            // Skip requests that originated from the host
                            node.isRoot = true;
                            continue;
                        }
                    }

                    // Iterate over all outstanding requests until a match is found
                    foreach (DictionaryEntry entry in outstandingExternalRequests)
                    {
                        BuildRequest[] externalRequests = (BuildRequest[])entry.Value;
                        for (int i = 0; i < externalRequests.Length && !foundParent; i++)
                        {
                            if (handleId == externalRequests[i].HandleId &&
                                requestId == externalRequests[i].RequestId &&
                                nodeIndex == externalRequests[i].NodeIndex)
                            {
                                // Verify that the project name is the same
                                ErrorUtilities.VerifyThrow(
                                    String.Compare(buildRequest.ProjectFileName, externalRequests[i].ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0,
                                    "The two requests should have the same project name");

                                // Link the two graph nodes together
                                GraphNode parentNode = (GraphNode)dependencyGraph[entry.Key];
                                parentNode.children.Add(node);

                                parentsForBuildRequests[j] = parentNode.targetState.TargetId;

                                foundParent = true;
                            }
                        }

                        if (foundParent)
                        {
                            break;
                        }
                    }
                }
                node.targetState.ParentTargetsForBuildRequests = parentsForBuildRequests;
            }
        }