| File: BackEnd\BuildManager\CacheAggregator.cs | Web Access |
| Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Linq; using Microsoft.Build.BackEnd; using Microsoft.Build.Framework; #nullable disable namespace Microsoft.Build.Execution { internal class CacheAggregator { private readonly Func<int> _nextConfigurationId; private readonly List<(IConfigCache ConfigCache, IResultsCache ResultsCache)> _inputCaches = new List<(IConfigCache ConfigCache, IResultsCache ResultsCache)>(); private int _lastConfigurationId; private bool _aggregated; private ConfigCache _aggregatedConfigCache; private ResultsCache _aggregatedResultsCache; public CacheAggregator(Func<int> nextConfigurationId) { _nextConfigurationId = nextConfigurationId; } public void Add(IConfigCache configCache, IResultsCache resultsCache) { Assumed.NotNull(configCache); Assumed.NotNull(resultsCache); Assumed.False(_aggregated, "Cannot add after aggregation"); _inputCaches.Add((configCache, resultsCache)); } public CacheAggregation Aggregate() { Assumed.False(_aggregated, "Cannot aggregate twice"); _aggregated = true; _aggregatedConfigCache = new ConfigCache(); _aggregatedResultsCache = new ResultsCache(); foreach (var (configCache, resultsCache) in _inputCaches) { InsertCaches(configCache, resultsCache); } return new CacheAggregation(_aggregatedConfigCache, _aggregatedResultsCache, _lastConfigurationId); } private void InsertCaches(IConfigCache configCache, IResultsCache resultsCache) { var configs = configCache.ToArray(); var results = resultsCache.ToArray(); Assumed.Equal(configs.Length, results.Length, "Assuming 1-to-1 mapping between configs and results. Otherwise it means the caches are either not minimal or incomplete"); if (configs.Length == 0 && results.Length == 0) { return; } var seenConfigIds = new HashSet<int>(); var configIdMapping = new Dictionary<int, int>(); foreach (var config in configs) { seenConfigIds.Add(config.ConfigurationId); Assumed.Null(_aggregatedConfigCache.GetMatchingConfiguration(config), "Input caches should not contain entries for the same configuration"); _lastConfigurationId = _nextConfigurationId(); configIdMapping[config.ConfigurationId] = _lastConfigurationId; var newConfig = config.ShallowCloneWithNewId(_lastConfigurationId); newConfig.ResultsNodeId = Scheduler.InvalidNodeId; _aggregatedConfigCache.AddConfiguration(newConfig); } foreach (var result in results) { Assumed.True(seenConfigIds.Contains(result.ConfigurationId), "Each result should have a corresponding configuration. Otherwise the caches are not consistent"); _aggregatedResultsCache.AddResult( new BuildResult( result, BuildEventContext.InvalidSubmissionId, configIdMapping[result.ConfigurationId], BuildRequest.InvalidGlobalRequestId, BuildRequest.InvalidGlobalRequestId, BuildRequest.InvalidNodeRequestId)); } } } internal class CacheAggregation { public CacheAggregation(IConfigCache configCache, IResultsCache resultsCache, int lastConfigurationId) { ConfigCache = configCache; ResultsCache = resultsCache; LastConfigurationId = lastConfigurationId; } public IConfigCache ConfigCache { get; } public IResultsCache ResultsCache { get; } public int LastConfigurationId { get; } } }