| File: BackEnd\BuildManager\CacheSerialization.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.IO; using System.Linq; using Microsoft.Build.BackEnd; using Microsoft.Build.Framework; using Microsoft.Build.Shared; #nullable disable namespace Microsoft.Build.Execution { internal static class CacheSerialization { public static string SerializeCaches( IConfigCache configCache, IResultsCache resultsCache, string outputCacheFile, ProjectIsolationMode projectIsolationMode) { Assumed.NotNull(outputCacheFile); try { if (string.IsNullOrWhiteSpace(outputCacheFile)) { return ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("EmptyOutputCacheFile"); } var fullPath = FileUtilities.NormalizePath(outputCacheFile); Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); // Use FileStream constructor (File.OpenWrite should not be used as it doesn't reset the length of the file!) using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None)) { var translator = BinaryTranslator.GetWriteTranslator(fileStream); var configCacheToSerialize = configCache switch { ConfigCache asConfigCache => asConfigCache, ConfigCacheWithOverride configCacheWithOverride => configCacheWithOverride.CurrentCache, _ => Assumed.Unreachable<ConfigCache>(), }; var resultsCacheToSerialize = resultsCache switch { ResultsCache asResultsCache => asResultsCache, ResultsCacheWithOverride resultsCacheWithOverride => resultsCacheWithOverride.CurrentCache, _ => Assumed.Unreachable<ResultsCache>(), }; // Avoid creating new config and results caches if no projects were built in violation // of isolation mode. if (configCacheToSerialize.Count() > 1) { // We need to preserve all configurations to enable the scheduler to dump them and their // associated requests, so create new caches to serialize storing solely data // associated with the project specified to be built in isolation (and not any // data associated with referenced projects needed for said project to complete // its build). var tempConfigCacheToSerialize = new ConfigCache(); // The project that was built in isolation mode has the // smallest configuration id. int smallestCacheConfigId = configCacheToSerialize.GetSmallestConfigId(); tempConfigCacheToSerialize.AddConfiguration(configCacheToSerialize[smallestCacheConfigId]); configCacheToSerialize = tempConfigCacheToSerialize; var tempResultsCacheToSerialize = new ResultsCache(); tempResultsCacheToSerialize.AddResult(resultsCacheToSerialize.GetResultsForConfiguration(smallestCacheConfigId)); resultsCacheToSerialize = tempResultsCacheToSerialize; } if (projectIsolationMode == ProjectIsolationMode.MessageUponIsolationViolation) { int smallestConfigId = configCacheToSerialize.GetSmallestConfigId(); // In MessageUponIsolationViolation mode, only keep the TargetResults for // top-level targets to mitigate the chances of an isolation- // violating target on a dependency project using incorrect state // due to its dependency on a cached target whose side effects would // not be taken into account. (E.g., the definition of a property.) resultsCacheToSerialize.GetResultsForConfiguration(smallestConfigId) .KeepSpecificTargetResults(configCacheToSerialize[smallestConfigId].RequestedTargets); } translator.Translate(ref configCacheToSerialize); translator.Translate(ref resultsCacheToSerialize); } } catch (Exception e) { return ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("ErrorWritingCacheFile", outputCacheFile, e.Message); } return null; } public static (IConfigCache ConfigCache, IResultsCache ResultsCache, Exception exception) DeserializeCaches(string inputCacheFile) { try { ConfigCache configCache = null; ResultsCache resultsCache = null; using (var fileStream = File.OpenRead(inputCacheFile)) { using var translator = BinaryTranslator.GetReadTranslator(fileStream, InterningBinaryReader.PoolingBuffer); translator.Translate(ref configCache); translator.Translate(ref resultsCache); } Assumed.NotNull(configCache); Assumed.NotNull(resultsCache); return (configCache, resultsCache, null); } catch (Exception e) { return (null, null, e); } } } }