From df6860379a763d474e2aaa3e81deed07bc333cc3 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 21 Dec 2023 10:14:15 +0100 Subject: [PATCH 01/10] fix missed build data on BuildRequestDataFlags provided --- .../BackEnd/ResultsCache_Tests.cs | 69 +++++++++++++++++++ .../BuildRequestEngine/BuildRequestEngine.cs | 5 +- .../Components/Caching/ResultsCache.cs | 13 ++-- .../RequestBuilder/TargetBuilder.cs | 2 + src/Build/BackEnd/Shared/BuildResult.cs | 6 ++ 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs index 7bcca24e739..8801e87db84 100644 --- a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs +++ b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs @@ -190,6 +190,75 @@ public void TestRetrieveSubsetTargetsFromResult() Assert.Equal(BuildResultCode.Success, response.Results.OverallResult); } + [Fact] + public void TestCacheOnDifferentBuildFlagsPerRequest() + { + string targetName = "testTarget1"; + int submissionId = 1; + int nodeRequestId = 0; + int configurationId = 1; + + BuildRequest requestWithNoBuildDataFlags = new BuildRequest( + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.None); + + BuildRequest requestWithProvideProjectStateAfterBuildFlag = new BuildRequest( + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.ProvideProjectStateAfterBuild); + + BuildRequest requestWithNoBuildDataFlags2 = new BuildRequest( + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.None); + + BuildResult resultForRequestWithNoBuildDataFlags = new(requestWithNoBuildDataFlags); + resultForRequestWithNoBuildDataFlags.AddResultsForTarget(targetName, BuildResultUtilities.GetEmptySucceedingTargetResult()); + ResultsCache cache = new(); + cache.AddResult(resultForRequestWithNoBuildDataFlags); + + ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags = cache.SatisfyRequest( + requestWithNoBuildDataFlags, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + ResultsCacheResponse cacheResponseWithProvideProjectStateAfterBuild = cache.SatisfyRequest( + requestWithProvideProjectStateAfterBuildFlag, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags2 = cache.SatisfyRequest( + requestWithNoBuildDataFlags2, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags.Type); + + // Because ProvideProjectStateAfterBuildFlag was provided as a part of BuildRequest + Assert.Equal(ResultsCacheResponseType.NotSatisfied, cacheResponseWithProvideProjectStateAfterBuild.Type); + + Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags2.Type); + } + [Fact] public void TestClearResultsCache() { diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index ef42f9fe895..52e9866dbf1 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -331,7 +331,10 @@ public void SubmitBuildRequest(BuildRequest request) // Grab the results from the requested configuration IResultsCache cache = (IResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache); BuildResult result = cache.GetResultsForConfiguration(request.ConfigurationId); - BuildResult resultToReport = new BuildResult(request, result, null); + BuildResult resultToReport = new BuildResult(request, result, null) + { + BuildRequestDataFlags = request.BuildRequestDataFlags, + }; BuildRequestConfiguration config = ((IConfigCache)_componentHost.GetComponent(BuildComponentType.ConfigCache))[request.ConfigurationId]; // Retrieve the config if it has been cached, since this would contain our instance data. It is safe to do this outside of a lock diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index 41013a9701e..dbcb732750a 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -163,7 +163,7 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co if (_resultsByConfiguration.TryGetValue(request.ConfigurationId, out BuildResult allResults)) { // Check for targets explicitly specified. - bool explicitTargetsSatisfied = CheckResults(allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); + bool explicitTargetsSatisfied = CheckResults(request.BuildRequestDataFlags, allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); if (explicitTargetsSatisfied) { @@ -171,7 +171,7 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co response.Type = ResultsCacheResponseType.Satisfied; // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied. - if (configInitialTargets == null || !CheckResults(allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) + if (configInitialTargets == null || !CheckResults(request.BuildRequestDataFlags, allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) { response.Type = ResultsCacheResponseType.NotSatisfied; } @@ -181,7 +181,7 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co { // Check for the default target, if necessary. If we don't know what the default targets are, we // assume they are not satisfied. - if (configDefaultTargets == null || !CheckResults(allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) + if (configDefaultTargets == null || !CheckResults(request.BuildRequestDataFlags, allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) { response.Type = ResultsCacheResponseType.NotSatisfied; } @@ -295,18 +295,21 @@ internal static IBuildComponent CreateComponent(BuildComponentType componentType /// /// Looks for results for the specified targets. /// + /// The current request build flags. /// The result to examine /// The targets to search for /// An optional list to be populated with missing targets /// If true, a status of "skipped" counts as having valid results /// for that target. Otherwise, a skipped target is treated as equivalent to a missing target. /// False if there were missing results, true otherwise. - private static bool CheckResults(BuildResult result, List targets, HashSet targetsMissingResults, bool skippedResultsAreOK) + private static bool CheckResults(BuildRequestDataFlags buildRequestDataFlags, BuildResult result, List targets, HashSet targetsMissingResults, bool skippedResultsAreOK) { bool returnValue = true; foreach (string target in targets) { - if (!result.HasResultsForTarget(target) || (result[target].ResultCode == TargetResultCode.Skipped && !skippedResultsAreOK)) + if (!result.HasResultsForTarget(target) + || (result[target].ResultCode == TargetResultCode.Skipped && !skippedResultsAreOK) + || result.BuildRequestDataFlags != buildRequestDataFlags) { if (targetsMissingResults != null) { diff --git a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs index 537660af9bf..0cd810771b0 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -188,6 +189,7 @@ public async Task BuildTargets(ProjectLoggingContext loggingContext BuildResult resultsToReport = new BuildResult(_buildResult, targetNames); // Return after-build project state if requested. + Debugger.Launch(); if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild)) { resultsToReport.ProjectStateAfterBuild = _projectInstance; diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 149ec426518..6bf8c8a627e 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -380,6 +380,12 @@ public ProjectInstance ProjectStateAfterBuild set => _projectStateAfterBuild = value; } + /// + /// Gets or sets the flags that provide additional control over the build request. + /// See for examples of the available flags. + /// + public BuildRequestDataFlags BuildRequestDataFlags { get; set; } + /// /// Returns the node packet type. /// From fb3293d61eb1df2cb99a6d599dc49e4db9a08612 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 21 Dec 2023 10:19:46 +0100 Subject: [PATCH 02/10] code cleanup --- src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs index 0cd810771b0..537660af9bf 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TargetBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -189,7 +188,6 @@ public async Task BuildTargets(ProjectLoggingContext loggingContext BuildResult resultsToReport = new BuildResult(_buildResult, targetNames); // Return after-build project state if requested. - Debugger.Launch(); if (_requestEntry.Request.BuildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideProjectStateAfterBuild)) { resultsToReport.ProjectStateAfterBuild = _projectInstance; From 475e215a1e6a54fd859e40532d2766538e1d8ceb Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 2 Jan 2024 09:59:15 +0100 Subject: [PATCH 03/10] fix review comments --- .../BuildRequestEngine/BuildRequestEngine.cs | 5 +--- .../Components/Caching/ResultsCache.cs | 25 ++++++++++++------- src/Build/BackEnd/Shared/BuildResult.cs | 3 ++- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 52e9866dbf1..ef42f9fe895 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -331,10 +331,7 @@ public void SubmitBuildRequest(BuildRequest request) // Grab the results from the requested configuration IResultsCache cache = (IResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache); BuildResult result = cache.GetResultsForConfiguration(request.ConfigurationId); - BuildResult resultToReport = new BuildResult(request, result, null) - { - BuildRequestDataFlags = request.BuildRequestDataFlags, - }; + BuildResult resultToReport = new BuildResult(request, result, null); BuildRequestConfiguration config = ((IConfigCache)_componentHost.GetComponent(BuildComponentType.ConfigCache))[request.ConfigurationId]; // Retrieve the config if it has been cached, since this would contain our instance data. It is safe to do this outside of a lock diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index dbcb732750a..04a546b936c 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -163,15 +163,16 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co if (_resultsByConfiguration.TryGetValue(request.ConfigurationId, out BuildResult allResults)) { // Check for targets explicitly specified. - bool explicitTargetsSatisfied = CheckResults(request.BuildRequestDataFlags, allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); + bool explicitTargetsSatisfied = CheckResults(allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); + bool buildDataFlagsSatisfied = CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags); - if (explicitTargetsSatisfied) + if (explicitTargetsSatisfied && buildDataFlagsSatisfied) { // All of the explicit targets, if any, have been satisfied response.Type = ResultsCacheResponseType.Satisfied; // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied. - if (configInitialTargets == null || !CheckResults(request.BuildRequestDataFlags, allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) + if (configInitialTargets == null || !CheckResults(allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) { response.Type = ResultsCacheResponseType.NotSatisfied; } @@ -181,7 +182,7 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co { // Check for the default target, if necessary. If we don't know what the default targets are, we // assume they are not satisfied. - if (configDefaultTargets == null || !CheckResults(request.BuildRequestDataFlags, allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) + if (configDefaultTargets == null || !CheckResults(allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) { response.Type = ResultsCacheResponseType.NotSatisfied; } @@ -295,21 +296,18 @@ internal static IBuildComponent CreateComponent(BuildComponentType componentType /// /// Looks for results for the specified targets. /// - /// The current request build flags. /// The result to examine /// The targets to search for /// An optional list to be populated with missing targets /// If true, a status of "skipped" counts as having valid results /// for that target. Otherwise, a skipped target is treated as equivalent to a missing target. /// False if there were missing results, true otherwise. - private static bool CheckResults(BuildRequestDataFlags buildRequestDataFlags, BuildResult result, List targets, HashSet targetsMissingResults, bool skippedResultsAreOK) + private static bool CheckResults(BuildResult result, List targets, HashSet targetsMissingResults, bool skippedResultsAreOK) { bool returnValue = true; foreach (string target in targets) { - if (!result.HasResultsForTarget(target) - || (result[target].ResultCode == TargetResultCode.Skipped && !skippedResultsAreOK) - || result.BuildRequestDataFlags != buildRequestDataFlags) + if (!result.HasResultsForTarget(target) || (result[target].ResultCode == TargetResultCode.Skipped && !skippedResultsAreOK)) { if (targetsMissingResults != null) { @@ -335,6 +333,15 @@ private static bool CheckResults(BuildRequestDataFlags buildRequestDataFlags, Bu return returnValue; } + /// + /// Checks results for the specified build flags. + /// + /// The current request build flags. + /// The existing build result data flags. + /// False if there is any difference in the data flags that can cause missed build data, true otherwise. + private static bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => + buildRequestDataFlags != BuildRequestDataFlags.ProvideProjectStateAfterBuild || buildResultDataFlags == buildRequestDataFlags; + public IEnumerator GetEnumerator() { return _resultsByConfiguration.Values.GetEnumerator(); diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 6bf8c8a627e..38811e87f02 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -204,6 +204,7 @@ internal BuildResult(BuildRequest request, BuildResult existingResults, string[] _nodeRequestId = request.NodeRequestId; _circularDependency = false; _baseOverallResult = true; + BuildRequestDataFlags = request.BuildRequestDataFlags; if (existingResults == null) { @@ -384,7 +385,7 @@ public ProjectInstance ProjectStateAfterBuild /// Gets or sets the flags that provide additional control over the build request. /// See for examples of the available flags. /// - public BuildRequestDataFlags BuildRequestDataFlags { get; set; } + public BuildRequestDataFlags BuildRequestDataFlags { get; } /// /// Returns the node packet type. From fe546dc1e47f58cb4a5c87d565027110d8c98512 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Tue, 2 Jan 2024 16:58:06 +0100 Subject: [PATCH 04/10] fix review comments --- .../BackEnd/ResultsCache_Tests.cs | 2 - .../Components/Caching/ResultsCache.cs | 85 ++++++++++--------- .../Components/ProjectCache/CacheResult.cs | 3 + src/Build/BackEnd/Shared/BuildResult.cs | 10 ++- 4 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs index 8801e87db84..68be7cd5fe6 100644 --- a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs +++ b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs @@ -13,8 +13,6 @@ using Shouldly; using Xunit; - - #nullable disable namespace Microsoft.Build.UnitTests.BackEnd diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index 04a546b936c..178d0e4aa7e 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -17,6 +17,11 @@ namespace Microsoft.Build.BackEnd /// internal class ResultsCache : IResultsCache { + /// + /// The presence of any of these flags affects build result for the specified request. + /// + private readonly BuildRequestDataFlags _flagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild | BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild; + /// /// The table of all build results. This table is indexed by configuration id and /// contains BuildResult objects which have all of the target information. @@ -139,13 +144,14 @@ public BuildResult GetResultsForConfiguration(int configurationId) /// /// Attempts to satisfy the request from the cache. The request can be satisfied only if: - /// 1. All specified targets in the request have successful results in the cache or if the sequence of target results + /// 1. The passed BuildRequestDataFlags can not affect the result data. + /// 2. All specified targets in the request have successful results in the cache or if the sequence of target results /// includes 0 or more successful targets followed by at least one failed target. - /// 2. All initial targets in the configuration for the request have non-skipped results in the cache. - /// 3. If there are no specified targets, then all default targets in the request must have non-skipped results + /// 3. All initial targets in the configuration for the request have non-skipped results in the cache. + /// 4. If there are no specified targets, then all default targets in the request must have non-skipped results /// in the cache. /// - /// The request whose results we should return + /// The request whose results we should return. /// The initial targets for the request's configuration. /// The default targets for the request's configuration. /// If false, a cached skipped target will cause this method to return "NotSatisfied". @@ -156,61 +162,60 @@ public BuildResult GetResultsForConfiguration(int configurationId) public ResultsCacheResponse SatisfyRequest(BuildRequest request, List configInitialTargets, List configDefaultTargets, bool skippedResultsDoNotCauseCacheMiss) { ErrorUtilities.VerifyThrow(request.IsConfigurationResolved, "UnresolvedConfigurationInRequest"); - ResultsCacheResponse response = new ResultsCacheResponse(ResultsCacheResponseType.NotSatisfied); + ResultsCacheResponse response = new(ResultsCacheResponseType.NotSatisfied); lock (_resultsByConfiguration) { if (_resultsByConfiguration.TryGetValue(request.ConfigurationId, out BuildResult allResults)) { - // Check for targets explicitly specified. - bool explicitTargetsSatisfied = CheckResults(allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); bool buildDataFlagsSatisfied = CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags); - if (explicitTargetsSatisfied && buildDataFlagsSatisfied) + if (buildDataFlagsSatisfied) { - // All of the explicit targets, if any, have been satisfied - response.Type = ResultsCacheResponseType.Satisfied; + // Check for targets explicitly specified. + bool explicitTargetsSatisfied = CheckResults(allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss); - // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied. - if (configInitialTargets == null || !CheckResults(allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) + if (explicitTargetsSatisfied) { - response.Type = ResultsCacheResponseType.NotSatisfied; - } + // All of the explicit targets, if any, have been satisfied + response.Type = ResultsCacheResponseType.Satisfied; - // We could still be missing implicit targets, so check those... - if (request.Targets.Count == 0) - { - // Check for the default target, if necessary. If we don't know what the default targets are, we - // assume they are not satisfied. - if (configDefaultTargets == null || !CheckResults(allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) + // Check for the initial targets. If we don't know what the initial targets are, we assume they are not satisfied. + if (configInitialTargets == null || !CheckResults(allResults, configInitialTargets, null, skippedResultsDoNotCauseCacheMiss)) { response.Type = ResultsCacheResponseType.NotSatisfied; } - } - // Now report those results requested, if they are satisfied. - if (response.Type == ResultsCacheResponseType.Satisfied) - { - List targetsToAddResultsFor = new List(configInitialTargets); - - // Now report either the explicit targets or the default targets - if (request.Targets.Count > 0) + // We could still be missing implicit targets, so check those... + if (request.Targets.Count == 0) { - targetsToAddResultsFor.AddRange(request.Targets); + // Check for the default target, if necessary. If we don't know what the default targets are, we + // assume they are not satisfied. + if (configDefaultTargets == null || !CheckResults(allResults, configDefaultTargets, null, skippedResultsDoNotCauseCacheMiss)) + { + response.Type = ResultsCacheResponseType.NotSatisfied; + } } - else + + // Now report those results requested, if they are satisfied. + if (response.Type == ResultsCacheResponseType.Satisfied) { - targetsToAddResultsFor.AddRange(configDefaultTargets); + List targetsToAddResultsFor = new List(configInitialTargets); + + // Now report either the explicit targets or the default targets + if (request.Targets.Count > 0) + { + targetsToAddResultsFor.AddRange(request.Targets); + } + else + { + targetsToAddResultsFor.AddRange(configDefaultTargets); + } + + response.Results = new BuildResult(request, allResults, targetsToAddResultsFor.ToArray(), null); } - - response.Results = new BuildResult(request, allResults, targetsToAddResultsFor.ToArray(), null); } } - else - { - // Some targets were not satisfied. - response.Type = ResultsCacheResponseType.NotSatisfied; - } } } @@ -339,8 +344,8 @@ private static bool CheckResults(BuildResult result, List targets, HashS /// The current request build flags. /// The existing build result data flags. /// False if there is any difference in the data flags that can cause missed build data, true otherwise. - private static bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => - buildRequestDataFlags != BuildRequestDataFlags.ProvideProjectStateAfterBuild || buildResultDataFlags == buildRequestDataFlags; + private bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => + (buildRequestDataFlags & _flagsAffectingBuildResults) == (buildResultDataFlags & _flagsAffectingBuildResults); public IEnumerator GetEnumerator() { diff --git a/src/Build/BackEnd/Components/ProjectCache/CacheResult.cs b/src/Build/BackEnd/Components/ProjectCache/CacheResult.cs index 3a954dec21b..fb23fdf63e8 100644 --- a/src/Build/BackEnd/Components/ProjectCache/CacheResult.cs +++ b/src/Build/BackEnd/Components/ProjectCache/CacheResult.cs @@ -47,8 +47,11 @@ public enum CacheResultType public class CacheResult { public CacheResultType ResultType { get; } + public BuildResult? BuildResult { get; } + public ProxyTargets? ProxyTargets { get; } + internal Exception? Exception { get; } private CacheResult( diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 38811e87f02..8626d6c405c 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -116,6 +116,8 @@ public class BuildResult : INodePacket, IBuildResults /// private ProjectInstance _projectStateAfterBuild; + private BuildRequestDataFlags _buildRequestDataFlags; + private string _schedulerInducedError; private HashSet _projectTargets; @@ -204,7 +206,7 @@ internal BuildResult(BuildRequest request, BuildResult existingResults, string[] _nodeRequestId = request.NodeRequestId; _circularDependency = false; _baseOverallResult = true; - BuildRequestDataFlags = request.BuildRequestDataFlags; + _buildRequestDataFlags = request.BuildRequestDataFlags; if (existingResults == null) { @@ -385,7 +387,11 @@ public ProjectInstance ProjectStateAfterBuild /// Gets or sets the flags that provide additional control over the build request. /// See for examples of the available flags. /// - public BuildRequestDataFlags BuildRequestDataFlags { get; } + public BuildRequestDataFlags BuildRequestDataFlags + { + get => _buildRequestDataFlags; + set => _buildRequestDataFlags = value; + } /// /// Returns the node packet type. From 988b4de5cd7d035f8067550121af0be7bc8680da Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Wed, 3 Jan 2024 10:49:36 +0100 Subject: [PATCH 05/10] fix review comments --- src/Build/BackEnd/Shared/BuildRequest.cs | 5 +++++ src/Build/BackEnd/Shared/BuildResult.cs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/Build/BackEnd/Shared/BuildRequest.cs b/src/Build/BackEnd/Shared/BuildRequest.cs index 428eea19656..8951500b8d6 100644 --- a/src/Build/BackEnd/Shared/BuildRequest.cs +++ b/src/Build/BackEnd/Shared/BuildRequest.cs @@ -119,6 +119,11 @@ private BuildRequest( _nodeRequestId = nodeRequestId; _buildRequestDataFlags = buildRequestDataFlags; _requestedProjectState = requestedProjectState; + + if (_requestedProjectState != null) + { + _buildRequestDataFlags |= BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild; + } } /// diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 8626d6c405c..e50f9d2559b 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -594,6 +594,7 @@ void ITranslatable.Translate(ITranslator translator) translator.Translate(ref _savedCurrentDirectory); translator.Translate(ref _schedulerInducedError); translator.TranslateDictionary(ref _savedEnvironmentVariables, StringComparer.OrdinalIgnoreCase); + translator.TranslateEnum(ref _buildRequestDataFlags, (int)_buildRequestDataFlags); } /// From 10106f168ad9e393dba6471c3d8796796e6d02c2 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 4 Jan 2024 11:53:13 +0100 Subject: [PATCH 06/10] handle ProvideSubsetOfStateAfterBuild case + put changes under change wave --- .../BackEnd/ResultsCache_Tests.cs | 122 +++++++++++++----- .../Components/Caching/ResultsCache.cs | 13 +- src/Framework/ChangeWaves.cs | 3 +- 3 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs index 68be7cd5fe6..d51b7337c30 100644 --- a/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs +++ b/src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs @@ -189,7 +189,7 @@ public void TestRetrieveSubsetTargetsFromResult() } [Fact] - public void TestCacheOnDifferentBuildFlagsPerRequest() + public void TestCacheOnDifferentBuildFlagsPerRequest_ProvideProjectStateAfterBuild() { string targetName = "testTarget1"; int submissionId = 1; @@ -197,16 +197,75 @@ public void TestCacheOnDifferentBuildFlagsPerRequest() int configurationId = 1; BuildRequest requestWithNoBuildDataFlags = new BuildRequest( - submissionId, - nodeRequestId, - configurationId, - new string[1] { targetName } /* escapedTargets */, - null /* hostServices */, - BuildEventContext.Invalid /* parentBuildEventContext */, - null /* parentRequest */, - BuildRequestDataFlags.None); + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.None); + + BuildRequest requestWithProjectStateFlag = new BuildRequest( + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.ProvideProjectStateAfterBuild); + + BuildRequest requestWithNoBuildDataFlags2 = new BuildRequest( + submissionId, + nodeRequestId, + configurationId, + new string[1] { targetName } /* escapedTargets */, + null /* hostServices */, + BuildEventContext.Invalid /* parentBuildEventContext */, + null /* parentRequest */, + BuildRequestDataFlags.None); - BuildRequest requestWithProvideProjectStateAfterBuildFlag = new BuildRequest( + BuildResult resultForRequestWithNoBuildDataFlags = new(requestWithNoBuildDataFlags); + resultForRequestWithNoBuildDataFlags.AddResultsForTarget(targetName, BuildResultUtilities.GetEmptySucceedingTargetResult()); + ResultsCache cache = new(); + cache.AddResult(resultForRequestWithNoBuildDataFlags); + + ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags = cache.SatisfyRequest( + requestWithNoBuildDataFlags, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + ResultsCacheResponse cachedResponseForProjectState = cache.SatisfyRequest( + requestWithProjectStateFlag, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + ResultsCacheResponse cacheResponseForNoBuildDataFlags2 = cache.SatisfyRequest( + requestWithNoBuildDataFlags2, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); + + Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags.Type); + + // Because ProvideProjectStateAfterBuildFlag was provided as a part of BuildRequest + Assert.Equal(ResultsCacheResponseType.NotSatisfied, cachedResponseForProjectState.Type); + + Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForNoBuildDataFlags2.Type); + } + + [Fact] + public void TestCacheOnDifferentBuildFlagsPerRequest_ProvideSubsetOfStateAfterBuild() + { + string targetName = "testTarget1"; + int submissionId = 1; + int nodeRequestId = 0; + int configurationId = 1; + + BuildRequest requestWithSubsetFlag1 = new BuildRequest( submissionId, nodeRequestId, configurationId, @@ -214,9 +273,9 @@ public void TestCacheOnDifferentBuildFlagsPerRequest() null /* hostServices */, BuildEventContext.Invalid /* parentBuildEventContext */, null /* parentRequest */, - BuildRequestDataFlags.ProvideProjectStateAfterBuild); + BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild); - BuildRequest requestWithNoBuildDataFlags2 = new BuildRequest( + BuildRequest requestWithSubsetFlag2 = new BuildRequest( submissionId, nodeRequestId, configurationId, @@ -224,37 +283,30 @@ public void TestCacheOnDifferentBuildFlagsPerRequest() null /* hostServices */, BuildEventContext.Invalid /* parentBuildEventContext */, null /* parentRequest */, - BuildRequestDataFlags.None); + BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild); - BuildResult resultForRequestWithNoBuildDataFlags = new(requestWithNoBuildDataFlags); - resultForRequestWithNoBuildDataFlags.AddResultsForTarget(targetName, BuildResultUtilities.GetEmptySucceedingTargetResult()); + BuildResult resultForRequestWithSubsetFlag1 = new(requestWithSubsetFlag1); + resultForRequestWithSubsetFlag1.AddResultsForTarget(targetName, BuildResultUtilities.GetEmptySucceedingTargetResult()); ResultsCache cache = new(); - cache.AddResult(resultForRequestWithNoBuildDataFlags); - - ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags = cache.SatisfyRequest( - requestWithNoBuildDataFlags, - new List(), - new List(new string[] { targetName }), - skippedResultsDoNotCauseCacheMiss: false); + cache.AddResult(resultForRequestWithSubsetFlag1); - ResultsCacheResponse cacheResponseWithProvideProjectStateAfterBuild = cache.SatisfyRequest( - requestWithProvideProjectStateAfterBuildFlag, - new List(), - new List(new string[] { targetName }), - skippedResultsDoNotCauseCacheMiss: false); + ResultsCacheResponse cachedResponseWithSubsetFlag1 = cache.SatisfyRequest( + requestWithSubsetFlag1, + new List(), + new List(new string[] { targetName }), + skippedResultsDoNotCauseCacheMiss: false); - ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags2 = cache.SatisfyRequest( - requestWithNoBuildDataFlags2, + ResultsCacheResponse cachedResponseWithSubsetFlag2 = cache.SatisfyRequest( + requestWithSubsetFlag2, new List(), new List(new string[] { targetName }), skippedResultsDoNotCauseCacheMiss: false); - Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags.Type); - - // Because ProvideProjectStateAfterBuildFlag was provided as a part of BuildRequest - Assert.Equal(ResultsCacheResponseType.NotSatisfied, cacheResponseWithProvideProjectStateAfterBuild.Type); - - Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags2.Type); + // It was agreed not to return cache results if ProvideSubsetOfStateAfterBuild is passed, + // because RequestedProjectState may have different user filters defined. + // It is more reliable to ignore the cached value. + Assert.Equal(ResultsCacheResponseType.NotSatisfied, cachedResponseWithSubsetFlag1.Type); + Assert.Equal(ResultsCacheResponseType.NotSatisfied, cachedResponseWithSubsetFlag2.Type); } [Fact] diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index 178d0e4aa7e..92c61ccd109 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -6,6 +6,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using Microsoft.Build.Execution; +using Microsoft.Build.Framework; using Microsoft.Build.Shared; #nullable disable @@ -20,7 +21,7 @@ internal class ResultsCache : IResultsCache /// /// The presence of any of these flags affects build result for the specified request. /// - private readonly BuildRequestDataFlags _flagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild | BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild; + private readonly BuildRequestDataFlags _flagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild; /// /// The table of all build results. This table is indexed by configuration id and @@ -168,7 +169,8 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co { if (_resultsByConfiguration.TryGetValue(request.ConfigurationId, out BuildResult allResults)) { - bool buildDataFlagsSatisfied = CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags); + bool buildDataFlagsSatisfied = ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_9) + ? CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags) : true; if (buildDataFlagsSatisfied) { @@ -345,7 +347,12 @@ private static bool CheckResults(BuildResult result, List targets, HashS /// The existing build result data flags. /// False if there is any difference in the data flags that can cause missed build data, true otherwise. private bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => - (buildRequestDataFlags & _flagsAffectingBuildResults) == (buildResultDataFlags & _flagsAffectingBuildResults); + + // Even if both buildRequestDataFlags and buildResultDataFlags have ProvideSubsetOfStateAfterBuild flag, + // the underlying RequestedProjectState may have different user filters defined. + // It is more reliable to ignore the cached value. + !buildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild) + & (buildRequestDataFlags & _flagsAffectingBuildResults) == (buildResultDataFlags & _flagsAffectingBuildResults); public IEnumerator GetEnumerator() { diff --git a/src/Framework/ChangeWaves.cs b/src/Framework/ChangeWaves.cs index 00507237987..90d775c93d5 100644 --- a/src/Framework/ChangeWaves.cs +++ b/src/Framework/ChangeWaves.cs @@ -27,7 +27,8 @@ internal class ChangeWaves internal static readonly Version Wave17_4 = new Version(17, 4); internal static readonly Version Wave17_6 = new Version(17, 6); internal static readonly Version Wave17_8 = new Version(17, 8); - internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8 }; + internal static readonly Version Wave17_9 = new Version(17, 9); + internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8, Wave17_9 }; /// /// Special value indicating that all features behind all Change Waves should be enabled. From ce44202fcea5caad86cbe2cfc4627b9340580319 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Thu, 4 Jan 2024 12:10:25 +0100 Subject: [PATCH 07/10] update change wave --- src/Build/BackEnd/Components/Caching/ResultsCache.cs | 2 +- src/Framework/ChangeWaves.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index 30451e26a58..b928c117636 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -169,7 +169,7 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List co { if (_resultsByConfiguration.TryGetValue(request.ConfigurationId, out BuildResult allResults)) { - bool buildDataFlagsSatisfied = ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_9) + bool buildDataFlagsSatisfied = ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_10) ? CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags) : true; if (buildDataFlagsSatisfied) diff --git a/src/Framework/ChangeWaves.cs b/src/Framework/ChangeWaves.cs index b5ca682c090..b6479c3698e 100644 --- a/src/Framework/ChangeWaves.cs +++ b/src/Framework/ChangeWaves.cs @@ -28,9 +28,8 @@ internal static class ChangeWaves internal static readonly Version Wave17_4 = new Version(17, 4); internal static readonly Version Wave17_6 = new Version(17, 6); internal static readonly Version Wave17_8 = new Version(17, 8); - internal static readonly Version Wave17_9 = new Version(17, 9); internal static readonly Version Wave17_10 = new Version(17, 10); - internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8, Wave17_9, Wave17_10 }; + internal static readonly Version[] AllWaves = { Wave17_4, Wave17_6, Wave17_8, Wave17_10 }; /// /// Special value indicating that all features behind all Change Waves should be enabled. From 0795c2f254cef7437f527a420afac72867b1b35d Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 5 Jan 2024 12:45:07 +0100 Subject: [PATCH 08/10] fix review comments --- src/Build/BackEnd/Components/Caching/ResultsCache.cs | 6 +++--- src/Build/BackEnd/Shared/BuildResult.cs | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index b928c117636..27f4d8fd515 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -21,7 +21,7 @@ internal class ResultsCache : IResultsCache /// /// The presence of any of these flags affects build result for the specified request. /// - private readonly BuildRequestDataFlags _flagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild; + private const BuildRequestDataFlags FlagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild; /// /// The table of all build results. This table is indexed by configuration id and @@ -346,13 +346,13 @@ private static bool CheckResults(BuildResult result, List targets, HashS /// The current request build flags. /// The existing build result data flags. /// False if there is any difference in the data flags that can cause missed build data, true otherwise. - private bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => + private static bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) => // Even if both buildRequestDataFlags and buildResultDataFlags have ProvideSubsetOfStateAfterBuild flag, // the underlying RequestedProjectState may have different user filters defined. // It is more reliable to ignore the cached value. !buildRequestDataFlags.HasFlag(BuildRequestDataFlags.ProvideSubsetOfStateAfterBuild) - & (buildRequestDataFlags & _flagsAffectingBuildResults) == (buildResultDataFlags & _flagsAffectingBuildResults); + && (buildRequestDataFlags & FlagsAffectingBuildResults) == (buildResultDataFlags & FlagsAffectingBuildResults); public IEnumerator GetEnumerator() { diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 2d5dacf2a3f..cee4212033e 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -116,6 +116,9 @@ public class BuildResult : INodePacket, IBuildResults /// private ProjectInstance _projectStateAfterBuild; + /// + /// The flags provide additional control over the build results and may affect the cached value. + /// private BuildRequestDataFlags _buildRequestDataFlags; private string _schedulerInducedError; @@ -384,14 +387,10 @@ public ProjectInstance ProjectStateAfterBuild } /// - /// Gets or sets the flags that provide additional control over the build request. + /// Gets the flags that were used in the build request to which these results are associated. /// See for examples of the available flags. /// - public BuildRequestDataFlags BuildRequestDataFlags - { - get => _buildRequestDataFlags; - set => _buildRequestDataFlags = value; - } + public BuildRequestDataFlags BuildRequestDataFlags => _buildRequestDataFlags; /// /// Returns the node packet type. From d6bd816ce0fdeeecd527c37a245fbc1bc00b8dab Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 5 Jan 2024 13:21:36 +0100 Subject: [PATCH 09/10] add the change to ChangeWave.md --- documentation/wiki/ChangeWaves.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/wiki/ChangeWaves.md b/documentation/wiki/ChangeWaves.md index f7d92318dc7..b4b9ae2d540 100644 --- a/documentation/wiki/ChangeWaves.md +++ b/documentation/wiki/ChangeWaves.md @@ -31,6 +31,7 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t - [Change Version switch output to finish with a newline](https://github.com/dotnet/msbuild/pull/9485) - [Load Microsoft.DotNet.MSBuildSdkResolver into default load context (MSBuild.exe only)](https://github.com/dotnet/msbuild/pull/9439) - [Load NuGet.Frameworks into secondary AppDomain (MSBuild.exe only)](https://github.com/dotnet/msbuild/pull/9446) +- [ResultsCache ignores some of the BuildRequest data, may return incorrect results](https://github.com/dotnet/msbuild/pull/9565) ### 17.8 - [[RAR] Don't do I/O on SDK-provided references](https://github.com/dotnet/msbuild/pull/8688) From 01f30b20d813ab8669da2dd593d4f9197e1a55c4 Mon Sep 17 00:00:00 2001 From: YuliiaKovalova Date: Fri, 5 Jan 2024 16:06:52 +0100 Subject: [PATCH 10/10] fix review comment --- src/Build/BackEnd/Components/Caching/ResultsCache.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Build/BackEnd/Components/Caching/ResultsCache.cs b/src/Build/BackEnd/Components/Caching/ResultsCache.cs index 27f4d8fd515..ec5c888265a 100644 --- a/src/Build/BackEnd/Components/Caching/ResultsCache.cs +++ b/src/Build/BackEnd/Components/Caching/ResultsCache.cs @@ -21,7 +21,11 @@ internal class ResultsCache : IResultsCache /// /// The presence of any of these flags affects build result for the specified request. /// - private const BuildRequestDataFlags FlagsAffectingBuildResults = BuildRequestDataFlags.ProvideProjectStateAfterBuild; + private const BuildRequestDataFlags FlagsAffectingBuildResults = + BuildRequestDataFlags.ProvideProjectStateAfterBuild + | BuildRequestDataFlags.SkipNonexistentTargets + | BuildRequestDataFlags.IgnoreMissingEmptyAndInvalidImports + | BuildRequestDataFlags.FailOnUnresolvedSdk; /// /// The table of all build results. This table is indexed by configuration id and