/// <summary> /// Constructs a response where a result should be sent or execution should be resumed. /// </summary> /// <param name="node">The node ID to which the result should be sent.</param> /// <param name="unblocker">The result to send.</param> private ScheduleResponse(int node, BuildRequestUnblocker unblocker) { Action = (unblocker.Result == null) ? ScheduleActionType.ResumeExecution : ScheduleActionType.ReportResults; NodeId = node; Unblocker = unblocker; BuildResult = unblocker.Result; }
/// <summary> /// Constructs a response indicating there is a circular dependency caused by the specified request. /// </summary> private ScheduleResponse(int nodeId, BuildRequest parentRequest, BuildRequest requestCausingCircularDependency) { Action = ScheduleActionType.CircularDependency; BuildRequest = requestCausingCircularDependency; NodeId = nodeId; Unblocker = new BuildRequestUnblocker(parentRequest, new BuildResult(requestCausingCircularDependency, true /* circularDependency */)); }
/// <summary> /// Handles the BuildResult packet. /// </summary> private void HandleBuildResult(BuildRequestUnblocker unblocker) { _buildRequestEngine.UnblockBuildRequest(unblocker); }
/// <summary> /// Reports a build result to the engine, allowing it to satisfy outstanding requests. This result /// is reported to each entry, allowing it the opportunity to determine for itself if the /// result applies. /// </summary> /// <param name="unblocker">Information needed to unblock the engine.</param> /// <remarks> /// Called by the Node. Non-overlapping with other calls from the Node. /// </remarks> public void UnblockBuildRequest(BuildRequestUnblocker unblocker) { QueueAction( () => { ErrorUtilities.VerifyThrow(_status != BuildRequestEngineStatus.Shutdown && _status != BuildRequestEngineStatus.Uninitialized, "Engine loop not yet started, status is {0}.", _status); ErrorUtilities.VerifyThrow(_requestsByGlobalRequestId.ContainsKey(unblocker.BlockedRequestId), "Request {0} is not known to the engine.", unblocker.BlockedRequestId); BuildRequestEntry entry = _requestsByGlobalRequestId[unblocker.BlockedRequestId]; // Are we resuming execution or reporting results? if (unblocker.Result == null) { // We are resuming execution. TraceEngine("Request {0}({1}) (nr {2}) is now proceeding from current state {3}.", entry.Request.GlobalRequestId, entry.Request.ConfigurationId, entry.Request.NodeRequestId, entry.State); // UNDONE: (Refactor) This is a bit icky because we still have the concept of blocking on an in-progress request // versus blocking on requests waiting for results. They come to the same thing, and its been rationalized correctly in // the scheduler, but we should remove the dichotomy in the BuildRequestEntry so that that entry directly tracks in the same // way as the SchedulableRequest does. Alternately, it could just not track at all, and assume that when the scheduler tells it // to resume it is able to do so (it has no other way of knowing anyhow.) if (entry.State == BuildRequestEntryState.Waiting) { entry.Unblock(); } ActivateBuildRequest(entry); } else { // We must be reporting results. BuildResult result = unblocker.Result; if (result.NodeRequestId == BuildRequest.ResultsTransferNodeRequestId) { TraceEngine("Request {0}({1}) (nr {2}) has retrieved the results for configuration {3} and cached them on node {4} (UBR).", entry.Request.GlobalRequestId, entry.Request.ConfigurationId, entry.Request.NodeRequestId, entry.Request.ConfigurationId, _componentHost.BuildParameters.NodeId); IResultsCache resultsCache = (IResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache); IConfigCache configCache = (IConfigCache)_componentHost.GetComponent(BuildComponentType.ConfigCache); BuildRequestConfiguration config = configCache[result.ConfigurationId]; config.RetrieveFromCache(); config.SavedEnvironmentVariables = ((IBuildResults)result).SavedEnvironmentVariables; config.SavedCurrentDirectory = ((IBuildResults)result).SavedCurrentDirectory; config.ApplyTransferredState(result.ProjectStateAfterBuild); // Don't need them anymore on the result since they were just piggybacking to get accross the wire. ((IBuildResults)result).SavedEnvironmentVariables = null; ((IBuildResults)result).SavedCurrentDirectory = null; // Our results node is now this node, since we've just cached those results resultsCache.AddResult(result); config.ResultsNodeId = _componentHost.BuildParameters.NodeId; entry.Unblock(); ActivateBuildRequest(entry); } else { TraceEngine("Request {0}({1}) (nr {2}) is no longer waiting on nr {3} (UBR). Results are {4}.", entry.Request.GlobalRequestId, entry.Request.ConfigurationId, entry.Request.NodeRequestId, result.NodeRequestId, result.OverallResult); // Update the configuration with targets information, if we received any and didn't already have it. if (result.DefaultTargets != null) { BuildRequestConfiguration configuration = _configCache[result.ConfigurationId]; if (configuration.ProjectDefaultTargets == null) { configuration.ProjectDefaultTargets = result.DefaultTargets; configuration.ProjectInitialTargets = result.InitialTargets; } } entry.ReportResult(result); } } }, isLastTask: false); }