/// <summary> /// This method creates a BuildResult using the information contained in a completed build request and /// then routes it to the right node. On a child process, this means either consume the result localy, /// or send it to the parent node. On a parent node, this means either consume the result locally or /// send it to a child node /// </summary> internal void PostDoneNotice(BuildRequest buildRequest) { // Create a container with the results of the evaluation BuildResult buildResult = buildRequest.GetBuildResult(); // If we're supposed to use caching and this request wasn't restored from cache, cache it if (buildRequest.UseResultsCache && !buildRequest.RestoredFromCache) { CacheScope cacheScope = parentEngine.CacheManager.GetCacheScope(buildRequest.ProjectFileName, buildRequest.GlobalProperties, buildRequest.ToolsetVersion, CacheContentType.BuildResults); cacheScope.AddCacheEntryForBuildResults(buildResult); } // an external request is any request that came from the parent engine, all requests to a child are external // unless the project was alredy loaded on the node itself if (buildRequest.IsExternalRequest) { // If the build request was send from outside the current process, // send the results to the parent engine parentNode.PostBuildResultToHost(buildResult); } else { // In the case of a child process, getting to this point means the request will be satisfied locally, the node index should be 0 // on the parent engine however, the node index can be, 0 for the local node, or can be >0 which represents a child node PostDoneNotice(buildRequest.NodeIndex, buildResult); } }
/// <summary> /// This method is called once the engine has decided to sent a build request to a child node. /// Route the given BuildRequest to the given node. If necessary a routing context is /// created to manage future communication with the node regarding the build request. /// </summary> internal void PostBuildRequest(BuildRequest currentRequest, int nodeIndex) { // if the request is to be sent to the parent node, post the request back to the host if (nodeIndex == EngineCallback.parentNode) { ParentNode.PostBuildRequestToHost(currentRequest); } else { // Dont create any contexts if the request was supposed to be processed on the current node if (nodeIndex != EngineCallback.inProcNode) { // Get the cache scope for the request (possibly creating it). The cache scope will contain the taskoutputs of the build request // which can be reused of the same project/toolsversion/globalproperties is asked for again. CacheScope cacheScope = parentEngine.CacheManager.GetCacheScope(currentRequest.ProjectFileName, currentRequest.GlobalProperties, currentRequest.ToolsetVersion, CacheContentType.BuildResults); // Create a routing context and update the request to refer to the new node handle id int parentHandleId = currentRequest.HandleId; currentRequest.HandleId = parentEngine.EngineCallback.CreateRoutingContext (nodeIndex, currentRequest.HandleId, currentRequest.NodeIndex, currentRequest.RequestId, cacheScope, currentRequest, null); if (scheduler != null) { // Check to see if we need to change the traversal strategy of the system // parentHandleId and node index are not used in the function so it can be ignored scheduler.NotifyOfBuildRequest(nodeIndex, currentRequest, parentHandleId); } nodeManager.PostBuildRequestToNode(nodeIndex, currentRequest); } } }
private CacheScope GetCacheScopeIfExists(string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { CacheScope cacheScope = null; // Default the version to the default engine version if (scopeToolsVersion == null) { scopeToolsVersion = defaultToolsVersion; } // Retrieve list of scopes by this name if (cacheContents[(int)cacheContentType].ContainsKey(scopeName)) { List <CacheScope> scopesByName = (List <CacheScope>)cacheContents[(int)cacheContentType][scopeName]; // If the list exists search for matching scope properties otherwise create the list if (scopesByName != null) { lock (cacheManagerLock) { for (int i = 0; i < scopesByName.Count; i++) { if (scopesByName[i].ScopeProperties.IsEquivalent(scopeProperties) && (String.Compare(scopeToolsVersion, scopesByName[i].ScopeToolsVersion, StringComparison.OrdinalIgnoreCase) == 0)) { cacheScope = scopesByName[i]; break; } } } } } return(cacheScope); }
/// <summary> /// This method return a cache scope with particular name and properties. If the cache /// scope doesn't exist it will be created. This method is thread safe. /// </summary> internal CacheScope GetCacheScope(string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { // If the version is not specified default to the engine version if (scopeToolsVersion == null) { scopeToolsVersion = defaultToolsVersion; } // Retrieve the cache scope if it exists CacheScope cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType); // If the scope doesn't exist create it if (cacheScope == null) { lock (cacheManagerLock) { cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType); if (cacheScope == null) { // If the list of scopes doesn't exist create it if (!cacheContents[(int)cacheContentType].ContainsKey(scopeName)) { cacheContents[(int)cacheContentType].Add(scopeName, new List <CacheScope>()); } // Create the scope and add it to the list List <CacheScope> scopesByName = (List <CacheScope>)cacheContents[(int)cacheContentType][scopeName]; cacheScope = new CacheScope(scopeName, scopeProperties, scopeToolsVersion); scopesByName.Add(cacheScope); } } } return(cacheScope); }
internal NodeRequestMapping (int handleId, int requestId, CacheScope resultsCache) { ErrorUtilities.VerifyThrow(resultsCache != null, "Expect a non-null build result"); this.handleId = handleId; this.requestId = requestId; this.resultsCache = resultsCache; }
/// <summary> /// Sets multiple cache entries for the given scope /// </summary> /// <param name="entries"></param> /// <param name="scopeName"></param> /// <param name="scopeProperties"></param> internal void SetCacheEntries(CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { // If the list exists search for matching scope properties otherwise create the list CacheScope cacheScope = GetCacheScope(scopeName, scopeProperties, scopeToolsVersion, cacheContentType); // Add the entry to the right scope cacheScope.AddCacheEntries(entries); }
/// <summary> /// Gets multiple cache entries from the given scope. /// </summary> /// <param name="names"></param> /// <param name="scopeName"></param> /// <param name="scopeProperties"></param> /// <returns></returns> internal CacheEntry[] GetCacheEntries(string[] names, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { CacheScope cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType); if (cacheScope != null) { return(cacheScope.GetCacheEntries(names)); } return(new CacheEntry[names.Length]); }
internal void PostBuildRequestToHost(BuildRequest currentRequest) { // Since this request is going back to the host the local node should not have a project object for it ErrorUtilities.VerifyThrow(currentRequest.ProjectToBuild == null, "Should not have a project object"); // Add the request to the mapping hashtable so that we can recognize the outputs CacheScope cacheScope = localEngine.CacheManager.GetCacheScope(currentRequest.ProjectFileName, currentRequest.GlobalProperties, currentRequest.ToolsetVersion, CacheContentType.BuildResults); NodeRequestMapping nodeRequestMapping = new NodeRequestMapping(currentRequest.HandleId, currentRequest.RequestId, cacheScope); lock (requestToLocalIdMapping) { requestToLocalIdMapping.Add(lastRequestIdUsed, nodeRequestMapping); // Keep the request id local for this node currentRequest.RequestId = lastRequestIdUsed; lastRequestIdUsed++; } // Find the original external request that caused us to run this task TaskExecutionContext taskExecutionContext = localEngine.EngineCallback.GetTaskContextFromHandleId(currentRequest.HandleId); while (!taskExecutionContext.BuildContext.BuildRequest.IsExternalRequest) { ErrorUtilities.VerifyThrow(taskExecutionContext.BuildContext.BuildRequest.IsGeneratedRequest, "Must be a generated request"); taskExecutionContext = localEngine.EngineCallback.GetTaskContextFromHandleId(taskExecutionContext.BuildContext.BuildRequest.HandleId); } //Modify the request with the data that is expected by the parent engine currentRequest.HandleId = taskExecutionContext.BuildContext.BuildRequest.HandleId; currentRequest.NodeIndex = taskExecutionContext.BuildContext.BuildRequest.NodeIndex; try { outProcLoggingService.ProcessPostedLoggingEvents(); parentCallback.PostBuildRequestsToHost(new BuildRequest[] { currentRequest }); } catch (Exception e) { ReportUnhandledError(e); } }
/// <summary> /// Default constructor for a routing context /// </summary> internal RequestRoutingContext ( int handleId, int nodeIndex, int parentHandleId, int parentNodeIndex, int parentRequestId, CacheScope cacheScope, BuildRequest triggeringBuildRequest, BuildEventContext buildEventContext ) : base(handleId, nodeIndex, buildEventContext) { this.parentHandleId = parentHandleId; this.parentNodeIndex = parentNodeIndex; this.parentRequestId = parentRequestId; this.cacheScope = cacheScope; this.triggeringBuildRequest = triggeringBuildRequest; }
/// <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); }
/// <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)); }