Ejemplo n.º 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);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This method get a result from the cache if every target is cached.
        /// If any of the target are not present in the cache null is returned. This method is not thread safe.
        /// </summary>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            if (!buildRequest.UseResultsCache)
            {
                return(null);
            }

            // Retrieve list of scopes by this name
            string projectName = buildRequest.ProjectToBuild == null ?
                                 buildRequest.ProjectFileName : buildRequest.ProjectToBuild.FullFileName;

            // If the list exists search for matching scope properties otherwise create the list
            CacheScope cacheScope = GetCacheScopeIfExists(projectName, buildRequest.GlobalProperties, buildRequest.ToolsetVersion, CacheContentType.BuildResults);

            // If there is no cache entry for this project return null
            if (cacheScope == null)
            {
                return(null);
            }

            return(cacheScope.GetCachedBuildResult(buildRequest, out actuallyBuiltTargets));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Called when the engine is in the process of sending a buildRequest to a child node. The entire purpose of this method
        /// is to switch the traversal strategy of the systems if there are nodes which do not have enough work availiable to them.
        /// </summary>
        internal void NotifyOfBuildRequest(int nodeIndex, BuildRequest currentRequest, int parentHandleId)
        {
            // This will only be null when the scheduler is instantiated on a child process in which case the initialize method
            // of the scheduler will not be called and therefore not initialize totalRequestsPerNode.
            if (totalRequestsPerNode != null)
            {
                // Check if it makes sense to switch from one traversal strategy to the other
                if (parentEngine.NodeManager.TaskExecutionModule.UseBreadthFirstTraversal == true)
                {
                    // Check if a switch to depth first traversal is in order
                    bool useBreadthFirstTraversal = false;
                    for (int i = 0; i < totalRequestsPerNode.Length; i++)
                    {
                        // Continue using breadth-first traversal as long as the non-blocked work load for this node is below
                        // the nodeWorkloadProjectCount or its postBlockCount is non-zero
                        if ((totalRequestsPerNode[i] - blockedRequestsPerNode[i]) < nodeWorkLoadProjectCount || postBlockCount[i] != 0)
                        {
                            useBreadthFirstTraversal = true;
                            break;
                        }
                    }

                    if (useBreadthFirstTraversal == false)
                    {
                        if (Engine.debugMode)
                        {
                            Console.WriteLine("Switching to depth first traversal because all node have workitems");
                        }
                        parentEngine.NodeManager.TaskExecutionModule.UseBreadthFirstTraversal = false;

                        // Switch to depth first and change the traversal strategy of the entire system by notifying all child nodes of the change
                        parentEngine.PostEngineCommand(new ChangeTraversalTypeCommand(false, false));
                    }
                }
            }
        }
Ejemplo n.º 4
0
        internal static BuildRequest CreateFromStream(BinaryReader reader)
        {
            BuildRequest request = new BuildRequest();

            request.requestId = reader.ReadInt32();
            request.handleId  = reader.ReadInt32();
            #region ProjectFileName
            if (reader.ReadByte() == 0)
            {
                request.projectFileName = null;
            }
            else
            {
                request.projectFileName = reader.ReadString();
            }
            #endregion
            #region TargetNames
            if (reader.ReadByte() == 0)
            {
                request.targetNames = null;
            }
            else
            {
                int numberOfTargetNames = reader.ReadInt32();
                request.targetNames = new string[numberOfTargetNames];
                for (int i = 0; i < numberOfTargetNames; i++)
                {
                    if (reader.ReadByte() == 0)
                    {
                        request.targetNames[i] = null;
                    }
                    else
                    {
                        request.targetNames[i] = reader.ReadString();
                    }
                }
            }
            #endregion
            #region GlobalProperties
            if (reader.ReadByte() == 0)
            {
                request.globalProperties = null;
            }
            else
            {
                request.globalProperties = new BuildPropertyGroup();
                request.globalProperties.CreateFromStream(reader);
            }
            #endregion
            #region ToolsetVersion
            if (reader.ReadByte() == 0)
            {
                request.toolsetVersion = null;
            }
            else
            {
                request.toolsetVersion = reader.ReadString();
            }
            #endregion
            request.unloadProjectsOnCompletion = reader.ReadBoolean();
            request.useResultsCache            = reader.ReadBoolean();
            #region BuildEventContext
            if (reader.ReadByte() == 0)
            {
                request.buildEventContext = null;
            }
            else
            {
                // Re create event context
                int nodeId           = reader.ReadInt32();
                int projectContextId = reader.ReadInt32();
                int targetId         = reader.ReadInt32();
                int taskId           = reader.ReadInt32();
                request.buildEventContext = new BuildEventContext(nodeId, targetId, projectContextId, taskId);
            }
            #endregion
            #region ToolsVersionPeekedFromProjectFile
            // We need to pass this over shared memory because where ever this project is being built needs to know
            // if the tools version was an override or was retreived from the project file
            if (reader.ReadByte() == 0)
            {
                request.toolsVersionPeekedFromProjectFile = false;
            }
            else
            {
                request.toolsVersionPeekedFromProjectFile = true;
            }
            #endregion
            return(request);
        }
Ejemplo n.º 5
0
Archivo: Node.cs Proyecto: 3F/IeXod
        private void NodeLocalEngineLoop()
        {
            buildInProgress = true;

            // Create a logging service for this build request
            localEngine =
                new Engine(parentGlobalProperties, toolsetSearchLocations, 1 /* cpus */, true /* child node */, this.nodeId, parentStartupDirectory, null);
            localEngine.Router.ChildMode  = true;
            localEngine.Router.ParentNode = this;

            this.outProcLoggingService = new EngineLoggingServicesOutProc(this, localEngine.FlushRequestEvent);

            if (nodeLoggers.Length != 0)
            {
                foreach (LoggerDescription loggerDescription in nodeLoggers)
                {
                    IForwardingLogger newLogger = null;
                    bool exitedDueToError       = true;
                    try
                    {
                        newLogger = loggerDescription.CreateForwardingLogger();
                        // Check if the class was not found in the assembly
                        if (newLogger == null)
                        {
                            InternalLoggerException.Throw(null, null, "FatalErrorWhileInitializingLogger", true, loggerDescription.Name);
                        }
                        newLogger.Verbosity  = loggerDescription.Verbosity;
                        newLogger.Parameters = loggerDescription.LoggerSwitchParameters;
                        newLogger.NodeId     = nodeId;
                        EventRedirector newRedirector = new EventRedirector(loggerDescription.LoggerId, outProcLoggingService);
                        newLogger.BuildEventRedirector = newRedirector;
                        exitedDueToError = false;
                    }
                    // Polite logger failure
                    catch (LoggerException e)
                    {
                        ReportUnhandledError(e);
                    }
                    // Logger class was not found
                    catch (InternalLoggerException e)
                    {
                        ReportUnhandledError(e);
                    }
                    catch (Exception e)
                    {
                        // Wrap the exception in a InternalLoggerException and send it to the parent node
                        string errorCode;
                        string helpKeyword;
                        string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "FatalErrorWhileInitializingLogger", loggerDescription.Name);
                        ReportUnhandledError(new InternalLoggerException(message, e, null, errorCode, helpKeyword, true));
                    }

                    // If there was a failure registering loggers, null out the engine pointer
                    if (exitedDueToError)
                    {
                        localEngine = null;
                        return;
                    }

                    localEngine.RegisterLogger(newLogger);
                }

                localEngine.ExternalLoggingServices = outProcLoggingService;
            }

            // Hook up logging service to forward all events to the central engine if necessary
            if (centralizedLogging)
            {
                if (nodeLoggers.Length != 0)
                {
                    localEngine.LoggingServices.ForwardingService = outProcLoggingService;
                    localEngine.ExternalLoggingServices           = outProcLoggingService;
                }
                else
                {
                    localEngine.LoggingServices = outProcLoggingService;
                }
            }

            localEngine.LoggingServices.OnlyLogCriticalEvents = this.logOnlyCriticalEvents;

            if (!useBreadthFirstTraversal)
            {
                localEngine.PostEngineCommand(new ChangeTraversalTypeCommand(useBreadthFirstTraversal, true));
            }

            // Post all the requests that passed in while the engine was being constructed
            // into the engine queue
            lock (buildRequests)
            {
                while (buildRequests.Count != 0)
                {
                    BuildRequest buildRequest = buildRequests.Dequeue();
                    localEngine.PostBuildRequest(buildRequest);
                }
            }

            try
            {
                // If there are forwarding loggers registered - generate a custom  build started
                if (nodeLoggers.Length > 0)
                {
                    localEngine.LoggingServices.LogBuildStarted(EngineLoggingServicesInProc.CENTRAL_ENGINE_EVENTSOURCE);
                    localEngine.LoggingServices.ProcessPostedLoggingEvents();
                }

                // Trigger the actual build if shutdown was not called while the engine was being initialized
                if (!nodeShutdown)
                {
                    localEngine.EngineBuildLoop(null);
                }
            }
            catch (Exception e)
            {
                // Unhandled exception during execution. The node has to be shutdown.
                ReportUnhandledError(e);
            }
            finally
            {
                if (localEngine != null)
                {
                    // Flush all the messages associated before shutting down
                    localEngine.LoggingServices.ProcessPostedLoggingEvents();

                    NodeManager nodeManager = localEngine.NodeManager;

                    // If the local engine is already shutting down, the TEM will be nulled out
                    if (nodeManager.TaskExecutionModule != null && nodeManager.TaskExecutionModule.TaskExecutionTime != 0)
                    {
                        TimeSpan taskTimeSpan = new TimeSpan(localEngine.NodeManager.TaskExecutionModule.TaskExecutionTime);
                        totalTaskTime = (int)taskTimeSpan.TotalMilliseconds;
                    }
                    localEngine.Shutdown();
                }
                // Flush all the events to the parent engine
                outProcLoggingService.ProcessPostedLoggingEvents();
                // Indicate that the node logger thread should exit
                exitNodeEvent.Set();
            }
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Post a build request to a node, the node index is an index into the list of nodes provided by all node providers
 /// registered to the node manager, the 0 in index is a local call to taskexecutionmodule
 /// </summary>
 /// <param name="nodeIndex"></param>
 /// <param name="buildRequest"></param>
 internal void PostBuildRequestToNode(int nodeIndex, BuildRequest buildRequest)
 {
     ErrorUtilities.VerifyThrow(nodeIndex != 0, "Should not use NodeManager to post to local TEM");
     nodeList[nodeIndex - 1].NodeProvider.PostBuildRequestToNode(nodeList[nodeIndex - 1].NodeIndex, buildRequest);
 }
Ejemplo n.º 7
0
        /// <summary>
        /// This function will start a node and send requests to it
        /// </summary>
        private void LaunchNodeAndPostBuildRequest()
        {
            int nodeIndex = 0;

            // Find out what node to launch
            lock (nodesToLaunch)
            {
                nodeIndex = nodesToLaunch.Dequeue();
            }

            // If the provider is shutting down - don't launch the node
            if (shuttingDown)
            {
                nodeData[nodeIndex].NodeState = NodeState.NotLaunched;
                return;
            }

            try
            {
                // Either launch node or connect to an already running node
                InitializeNode(nodeIndex);

                if (!nodeData[nodeIndex].CommunicationFailed)
                {
                    // Change the state of the node to launched
                    lock (nodeStateLock)
                    {
                        nodeData[nodeIndex].NodeState = NodeState.Launched;
                    }

                    // Send all the requests to the node. Note that the requests may end up in
                    // mixed order with the request currently being posted.
                    LinkedListNode <BuildRequest> current = nodeData[nodeIndex].TargetList.First;
                    BuildRequest[] buildRequests          = new BuildRequest[nodeData[nodeIndex].TargetList.Count];
                    int            i = 0;
                    while (current != null)
                    {
                        buildRequests[i] = current.Value;
                        i++;

                        current = current.Next;
                    }
                    LocalCallDescriptorForPostBuildRequests callDescriptor =
                        new LocalCallDescriptorForPostBuildRequests(buildRequests);
                    nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor);

                    nodeData[nodeIndex].TargetList = null;
                }
                else
                {
                    // Allow the engine to decide how to proceed since the node failed to launch
                    string message = ResourceUtilities.FormatResourceString("NodeProviderFailure");
                    ReportNodeCommunicationFailure(nodeIndex, new Exception(message), false);
                }
            }
            catch (Exception e)
            {
                // Allow the engine to deal with the exception
                ReportNodeCommunicationFailure(nodeIndex, e, false);
            }
        }
Ejemplo n.º 8
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;
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// If there is an exception in process build request we will wrap it in an invalid project file exception as any exceptions caught here are really problems with a project file
        /// this exception will be handled in the engine and logged
        /// </summary>
        private static void ConvertToInvalidProjectException(BuildRequest buildRequest, Project parentProject, Exception e)
        {
            BuildEventFileInfo fileInfo = new BuildEventFileInfo(buildRequest.ProjectFileName);

            throw new InvalidProjectFileException(parentProject.FullFileName, fileInfo.Line, fileInfo.Column, fileInfo.EndLine, fileInfo.EndColumn, e.Message, null, null, null);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// This method specifies which node a particular build request has to be evaluated on.
        /// </summary>>
        /// <returns>Id of the node on which the build request should be performed</returns>
        internal int CalculateNodeForBuildRequest(BuildRequest currentRequest, int nodeIndexCurrent)
        {
            int nodeUsed = EngineCallback.inProcNode;

            if (childMode)
            {
                // If the project is already loaded on the current node or if the request
                // was sent from the parent - evaluate the request locally. In all other
                // cases send the request over to the parent
                if (nodeIndexCurrent != localNodeId && !currentRequest.IsExternalRequest)
                {
                    // This is the same as using EngineCallback.parentNode
                    nodeUsed = -1;
                }
            }
            else
            {
                // In single proc case return the current node
                if (nodes.Length == 1)
                {
                    return(nodeUsed);
                }

                // If the project is not loaded either locally or on a remote node - calculate the best node to use
                // If there are nodes with less than "nodeWorkLoadProjectCount" projects in progress, choose the node
                // with the lowest in progress projects. Otherwise choose a node which has the least
                // number of projects loaded. Resolve a tie in number of projects loaded by looking at the number
                // of inprogress projects
                nodeUsed = nodeIndexCurrent;
                // If we have not chosen an node yet, this can happen if the node was loaded previously on a child node
                if (nodeUsed == EngineCallback.invalidNode)
                {
                    if (useLoadBalancing)
                    {
                        #region UseLoadBalancing
                        int blockedNode = EngineCallback.invalidNode;
                        int blockedNodeRemainingProjectCount = nodeWorkLoadProjectCount;
                        int leastBusyNode            = EngineCallback.invalidNode;
                        int leastBusyInProgressCount = -1;
                        int leastLoadedNode          = EngineCallback.inProcNode;
                        int leastLoadedLoadCount     = totalRequestsPerNode[EngineCallback.inProcNode];
                        int leastLoadedBlockedCount  = blockedRequestsPerNode[EngineCallback.inProcNode];

                        for (int i = 0; i < nodes.Length; i++)
                        {
                            //postBlockCount indicates the number of projects which should be sent to a node to unblock it due to the
                            //node running out of work.
                            if (postBlockCount[i] != 0 && postBlockCount[i] < blockedNodeRemainingProjectCount)
                            {
                                blockedNode = i;
                                blockedNodeRemainingProjectCount = postBlockCount[i];
                            }
                            else
                            {
                                // Figure out which node has the least ammount of in progress work
                                int perNodeInProgress = totalRequestsPerNode[i] - blockedRequestsPerNode[i];
                                if ((perNodeInProgress < nodeWorkLoadProjectCount) &&
                                    (perNodeInProgress < leastBusyInProgressCount || leastBusyInProgressCount == -1))
                                {
                                    leastBusyNode            = i;
                                    leastBusyInProgressCount = perNodeInProgress;
                                }
                                // Find the node with the least ammount of requests in total
                                // or if the number of requests are the same find the node with the
                                // node with the least number of blocked requests
                                if ((totalRequestsPerNode[i] < leastLoadedLoadCount) ||
                                    (totalRequestsPerNode[i] == leastLoadedLoadCount && blockedRequestsPerNode[i] < leastLoadedBlockedCount))
                                {
                                    leastLoadedNode         = i;
                                    leastLoadedLoadCount    = totalRequestsPerNode[i];
                                    leastLoadedBlockedCount = perNodeInProgress;
                                }
                            }
                        }

                        // Give the work to a node blocked due to having no work . If there are no nodes without work
                        // give the work to the least loaded node
                        if (blockedNode != EngineCallback.invalidNode)
                        {
                            nodeUsed = blockedNode;
                            postBlockCount[blockedNode]--;
                        }
                        else
                        {
                            nodeUsed = (leastBusyNode != EngineCallback.invalidNode) ? leastBusyNode : leastLoadedNode;
                        }
                        #endregion
                    }
                    else
                    {
                        // round robin schedule the build request
                        nodeUsed = (lastUsedNode % nodes.Length);

                        // Running total of the number of times this round robin scheduler has been called
                        lastUsedNode++;

                        if (postBlockCount[nodeUsed] != 0)
                        {
                            postBlockCount[nodeUsed]--;
                        }
                    }
                }

                // Update the internal data structure to reflect the scheduling decision
                NotifyOfSchedulingDecision(currentRequest, nodeUsed);
            }
            return(nodeUsed);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Once the buildRequests from the EngineCallback have been created they are sent to this method which will
        /// post the build requests to the parent engine and then wait on the results to come back.
        /// This method uses either a breadthFirst or depthFirst traversal strategy when sending buildRequests to the parent engine.
        /// This method will start in breadthFirst traversal. It will continue to use this strategy until one of two events occur:
        ///     1. The parent node sents a message indicating the TEM should switch to depthFirst traversal.
        ///     2. The number of buildRequests is larger than the batchRequestSize.
        /// In both of these cases the system will go from a breadthFirstTraversal to a depthFirst Traversal. In the second case
        /// a message will be sent to the parent engine to switch the system to depthFirst traversal as the system is starting to
        /// be overloaded with work.
        /// In a depth first strategy the buildRequests will be sent to the parent engine one at a time and waiting for results for
        /// each buildRequest sent. In a breadthFirst traversal strategy some number of the buildrequests will be sent to the parent engine
        /// in a batch of requests. The system will then wait on the results of ALL the build requests sent before continuing
        /// to send more build requests.
        /// </summary>
        private void WaitForBuildResults(int handleId, BuildResult[] buildResultsLocal, BuildRequest[] buildRequests)
        {
            // If the traversal strategy is breadth first and the number of requests is less than the batchRequestSize
            // or if there is only 1 build request then send ALL build requests to the parent engine and wait on the results.
            if ((breadthFirstTraversal == true && buildRequests.Length < batchRequestSize) || buildRequests.Length == 1)
            {
                engineCallback.PostBuildRequestsToHost(buildRequests);
                workerThread.WaitForResults(handleId, buildResultsLocal, buildRequests);
            }
            else
            {
                int currentRequestIndex    = 0; // Which build request is being processed
                int numberOfRequestsToSend = 0; // How many buildRequests are going to be sent based on the number of buildRequests remaining and the build request batch size.

                // Arrays that will be used to partion the buildRequests array when sending batches of builds requests at a time.
                BuildRequest[] wrapperArrayBreadthFirst = new BuildRequest[batchRequestSize];
                BuildResult[]  resultsArrayBreadthFirst = new BuildResult[batchRequestSize];

                // Pre allocate these arrays as they will always be only one element in size. They are assigned to and filled when doing a depth first traversal.
                BuildRequest[] wrapperArrayDepthFirst = new BuildRequest[1];
                BuildResult[]  resultsArrayDepthFirst = new BuildResult[1];

                // While there are still requests to send
                while (currentRequestIndex < buildRequests.Length)
                {
                    // If there is a breadth first traversal and there are more than batchRequestSize build requests, send the first batchRequestSize, then do the rest depth first
                    if (breadthFirstTraversal == true)
                    {
                        // Figure out how many requests to send, either the full batch size or only part of a batch
                        numberOfRequestsToSend = (buildRequests.Length - currentRequestIndex) < batchRequestSize ? (buildRequests.Length - currentRequestIndex) : batchRequestSize;

                        // Initialize the wrapper array to how many requests are going to be sent
                        if (numberOfRequestsToSend != wrapperArrayBreadthFirst.Length)
                        {
                            wrapperArrayBreadthFirst = new BuildRequest[numberOfRequestsToSend];
                            resultsArrayBreadthFirst = new BuildResult[numberOfRequestsToSend];
                        }

                        // Fill the wrapper array with one batch of build requests
                        for (int i = 0; i < numberOfRequestsToSend; i++)
                        {
                            wrapperArrayBreadthFirst[i]           = buildRequests[currentRequestIndex + i];
                            wrapperArrayBreadthFirst[i].RequestId = i;
                            resultsArrayBreadthFirst[i]           = null;
                        }

                        engineCallback.PostBuildRequestsToHost(wrapperArrayBreadthFirst);

                        // Only switch from breadth to depth if there are more thanbatchRequestSize items
                        if ((buildRequests.Length - currentRequestIndex) > batchRequestSize)
                        {
                            engineCallback.PostStatus(nodeId, new NodeStatus(false /* use depth first traversal*/), false /* don't block waiting on the send */);
                            breadthFirstTraversal = false;
                        }

                        workerThread.WaitForResults(handleId, resultsArrayBreadthFirst, wrapperArrayBreadthFirst);
                        Array.Copy(resultsArrayBreadthFirst, 0, buildResultsLocal, currentRequestIndex, numberOfRequestsToSend);
                        currentRequestIndex += numberOfRequestsToSend;
                    }

                    // Proceed with depth first traversal
                    while ((currentRequestIndex < buildRequests.Length) && !breadthFirstTraversal)
                    {
                        wrapperArrayDepthFirst[0] = buildRequests[currentRequestIndex];
                        buildRequests[currentRequestIndex].RequestId = 0;
                        resultsArrayDepthFirst[0] = null;

                        engineCallback.PostBuildRequestsToHost(wrapperArrayDepthFirst);
                        workerThread.WaitForResults(handleId, resultsArrayDepthFirst, wrapperArrayDepthFirst);
                        //Copy the result from an intermediate array to the full array
                        buildResultsLocal[currentRequestIndex] = resultsArrayDepthFirst[0];
                        //Check if the call failed (null result was returned)
                        if (buildResultsLocal[currentRequestIndex] == null)
                        {
                            return;
                        }

                        //Move to the next request
                        currentRequestIndex++;
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// This function implements the callback via the IBuildEngine interface
        /// </summary>
        /// <returns>result of call to engine</returns>
        virtual internal bool BuildProjectFile
        (
            int handleId,
            string[] projectFileNames,
            string[] targetNames,
            IDictionary[] globalPropertiesPerProject,
            IDictionary[] targetOutputsPerProject,
            EngineLoggingServices loggingServices,
            string [] toolsVersions,
            bool useResultsCache,
            bool unloadProjectsOnCompletion,
            BuildEventContext taskContext
        )
        {
            if (projectFileNames.Length == 0)
            {
                // Nothing to do, just return success
                return(true);
            }

            string currentDir = FileUtilities.GetCurrentDirectoryStaticBuffer(currentDirectoryBuffer);

            if (Engine.debugMode)
            {
                string targetName = targetNames == null ? "null" : targetNames[0];

                bool remoteNode = false;
                for (int r = 0; r < projectFileNames.Length; r++)
                {
                    string fullProjectName = projectFileNames[r] != null ?
                                             projectFileNames[r] : "null";
                    Console.WriteLine("RemoteNode: " + remoteNode + " Project " + fullProjectName + " T:" + targetName + " NodeProdyId# " + handleId + " Time " + DateTime.Now.ToLongTimeString());
                    if (globalPropertiesPerProject[r] != null)
                    {
                        foreach (DictionaryEntry entry in globalPropertiesPerProject[r])
                        {
                            Console.WriteLine(currentDir + " :GLOBAL " + entry.Key + "=" + entry.Value.ToString());
                        }
                    }
                }
            }

            BuildRequest[] buildRequests = new BuildRequest[projectFileNames.Length];
            for (int i = 0; i < buildRequests.Length; i++)
            {
                // We need to get the full path to the project before we call back
                // into the engine which has no control over current path
                string fullProjectName = projectFileNames[i] != null?
                                         Path.GetFullPath(projectFileNames[i]) : null;

                buildRequests[i] = new BuildRequest(handleId, fullProjectName, targetNames, globalPropertiesPerProject[i],
                                                    toolsVersions[i], i, useResultsCache, unloadProjectsOnCompletion);
                ErrorUtilities.VerifyThrow(buildRequests[i].IsGeneratedRequest == true, "Should not be sending non generated requests from TEM to engine");
                buildRequests[i].ParentBuildEventContext = taskContext;
            }

            BuildResult[] buildResultsLocal = new BuildResult[projectFileNames.Length];

            if (moduleMode == TaskExecutionModuleMode.SingleProcMode)
            {
                for (int i = 0; i < projectFileNames.Length; i++)
                {
                    // If we are running in a single threaded mode we need to
                    // re-enter the main build loop on the current thread in order
                    // to build the requested project, because the main build is below
                    // us on the stack
                    engineCallback.PostBuildRequestsToHost(new BuildRequest[] { buildRequests[i] });
                    buildResultsLocal[i] = engineCallback.GetParentEngine().EngineBuildLoop(buildRequests[i]);
                    buildResultsLocal[i].ConvertToTaskItems();
                }
            }
            else
            {
                WaitForBuildResults(handleId, buildResultsLocal, buildRequests);
            }

            // Store the outputs in the hashtables provided by the caller
            bool overallResult = true;

            for (int i = 0; i < buildResultsLocal.Length; i++)
            {
                // Users of the Object Model can pass in null targetOutputs for projects they do not want outputs for
                // therefore we need to make sure that there are targetoutputs and the users want the results
                if (buildResultsLocal[i] != null)
                {
                    if (buildResultsLocal[i].OutputsByTarget != null && targetOutputsPerProject[i] != null)
                    {
                        foreach (DictionaryEntry entry in buildResultsLocal[i].OutputsByTarget)
                        {
                            targetOutputsPerProject[i].Add(entry.Key, entry.Value);
                        }
                        overallResult = overallResult && buildResultsLocal[i].EvaluationResult;
                    }
                }
                else
                {
                    // The calculation was terminated prior to receiving the result
                    overallResult = false;
                }
            }

            // We're now returning from an IBuildEngine callback;
            // set the current directory back to what the tasks expect
            if (Directory.GetCurrentDirectory() != currentDir)
            {
                Directory.SetCurrentDirectory(currentDir);
            }

            if (Engine.debugMode)
            {
                bool   remoteNode = false;
                string targetName = targetNames == null ? "null" : targetNames[0];
                Console.WriteLine("RemoteNode: " + remoteNode + " T:" + targetName + " HandleId# " + handleId + " Result " + overallResult);
            }

            return(overallResult);
        }
Ejemplo n.º 13
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;
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Get a cached build result if available for the given request. This method is thread safe.
        /// </summary>
        /// <param name="buildRequest"></param>
        /// <param name="actuallyBuiltTargets"></param>
        /// <returns></returns>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            PropertyCacheEntry defaultTargetsCacheEntry, initialTargetsCacheEntry, projectIdCacheEntry;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                defaultTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.defaultTargetCacheName);
                initialTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.initialTargetCacheName);
                projectIdCacheEntry      = (PropertyCacheEntry)GetCacheEntry(Constants.projectIdCacheName);
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            // If we ever built anything in this project we must have the default and initial targets.
            if (defaultTargetsCacheEntry == null && initialTargetsCacheEntry == null)
            {
                return(null);
            }

            ErrorUtilities.VerifyThrow(projectIdCacheEntry != null, "We should always have the projectId cache entry");

            ErrorUtilities.VerifyThrow(defaultTargetsCacheEntry != null && initialTargetsCacheEntry != null,
                                       "We should have both the initial and default targets in the cache");

            ArrayList targetsToBuild = new ArrayList(initialTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));

            if (buildRequest.TargetNames == null || buildRequest.TargetNames.Length == 0)
            {
                targetsToBuild.AddRange(defaultTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }
            else
            {
                targetsToBuild.AddRange(buildRequest.TargetNames);
            }

            // Create variable to hold the cached outputs
            Hashtable outputsByTargetName = new Hashtable(targetsToBuild.Count);
            Hashtable resultByTarget      = new Hashtable(targetsToBuild.Count, StringComparer.OrdinalIgnoreCase);

            bool overallSuccess = true;
            bool missingValues  = false;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                for (int i = 0; i < targetsToBuild.Count; i++)
                {
                    string targetName = EscapingUtilities.UnescapeAll((string)targetsToBuild[i]);
                    if (ContainsCacheEntry(targetName))
                    {
                        BuildResultCacheEntry cacheEntry = (BuildResultCacheEntry)GetCacheEntry(targetName);
                        overallSuccess             = overallSuccess && cacheEntry.BuildResult;
                        resultByTarget[targetName] = (cacheEntry.BuildResult) ?
                                                     Target.BuildState.CompletedSuccessfully : Target.BuildState.CompletedUnsuccessfully;

                        // Restore output items for successful targets
                        if (cacheEntry.BuildResult)
                        {
                            outputsByTargetName[targetName] = cacheEntry.BuildItems;
                        }
                        // We found a failed target - cut the loop short
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        missingValues = true;
                        break;
                    }
                }
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            if (missingValues)
            {
                return(null);
            }

            actuallyBuiltTargets = targetsToBuild;

            return(new BuildResult(outputsByTargetName, resultByTarget, overallSuccess, buildRequest.HandleId, buildRequest.RequestId,
                                   int.Parse(projectIdCacheEntry.Value, CultureInfo.InvariantCulture), false /* use results cache */,
                                   defaultTargetsCacheEntry.Value, initialTargetsCacheEntry.Value, 0, 0, 0));
        }
Ejemplo n.º 15
0
 internal LocalCallDescriptorForPostBuildRequests(BuildRequest buildRequest)
     : base(LocalCallType.PostBuildRequests)
 {
     this.buildRequests    = new BuildRequest[1];
     this.buildRequests[0] = buildRequest;
 }
Ejemplo n.º 16
0
 internal void CreateFromStream(BinaryReader reader)
 {
     #region TargetId
     if (reader.ReadByte() == 0)
     {
         targetId = null;
     }
     else
     {
         targetId = new TargetIdWrapper();
         targetId.CreateFromStream(reader);
     }
     #endregion
     #region ParentTargets
     if (reader.ReadByte() == 0)
     {
         parentTargets = null;
     }
     else
     {
         int numberOfTargets = reader.ReadInt32();
         parentTargets = new List <TargetIdWrapper>(numberOfTargets);
         for (int i = 0; i < numberOfTargets; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentTargets.Add(null);
             }
             else
             {
                 TargetIdWrapper wrapper = new TargetIdWrapper();
                 wrapper.CreateFromStream(reader);
                 parentTargets.Add(wrapper);
             }
         }
     }
     #endregion
     #region ParentBuildRequests
     if (reader.ReadByte() == 0)
     {
         parentBuildRequests = null;
     }
     else
     {
         int numberOfRequests = reader.ReadInt32();
         parentBuildRequests = new List <BuildRequest>(numberOfRequests);
         for (int i = 0; i < numberOfRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentBuildRequests.Add(null);
             }
             else
             {
                 parentBuildRequests.Add(BuildRequest.CreateFromStream(reader));
             }
         }
     }
     #endregion
     #region OutstandingBuildRequests
     if (reader.ReadByte() == 0)
     {
         outstandingBuildRequests = null;
     }
     else
     {
         int numberOfBuildRequests = reader.ReadInt32();
         outstandingBuildRequests = new BuildRequest[numberOfBuildRequests];
         for (int i = 0; i < numberOfBuildRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 outstandingBuildRequests[i] = null;
             }
             else
             {
                 outstandingBuildRequests[i] = BuildRequest.CreateFromStream(reader);
             }
         }
     }
     #endregion
     #region ParentTargetsForBuildRequests
     if (reader.ReadByte() == 0)
     {
         parentTargetsForBuildRequests = null;
     }
     else
     {
         int numberOfTargetsForBuildRequests = reader.ReadInt32();
         parentTargetsForBuildRequests = new TargetIdWrapper[numberOfTargetsForBuildRequests];
         for (int i = 0; i < numberOfTargetsForBuildRequests; i++)
         {
             if (reader.ReadByte() == 0)
             {
                 parentTargetsForBuildRequests[i] = null;
             }
             else
             {
                 TargetIdWrapper wrapper = new TargetIdWrapper();
                 wrapper.CreateFromStream(reader);
                 parentTargetsForBuildRequests[i] = wrapper;
             }
         }
     }
     #endregion
     #region ProjectName
     if (reader.ReadByte() == 0)
     {
         projectName = null;
     }
     else
     {
         projectName = reader.ReadString();
     }
     #endregion
 }