public void CacheEntryGettersDefaultConstructors() { BuildItem[] buildItems = new BuildItem[2] { null, null }; BuildItemCacheEntry tice = new BuildItemCacheEntry(); Assertion.AssertEquals(null, tice.Name); Assertion.AssertEquals(null, tice.BuildItems); tice.Name = "tice"; tice.BuildItems = buildItems; Assertion.AssertEquals("tice", tice.Name); Assertion.AssertEquals(buildItems, tice.BuildItems); PropertyCacheEntry pce = new PropertyCacheEntry(); Assertion.AssertEquals(null, pce.Name); Assertion.AssertEquals(null, pce.Value); pce.Name = "pce"; pce.Value = "propertyValue"; Assertion.AssertEquals("pce", pce.Name); Assertion.AssertEquals("propertyValue", pce.Value); BuildResultCacheEntry brce = new BuildResultCacheEntry(); Assertion.AssertEquals(null, brce.Name); Assertion.AssertEquals(null, brce.BuildItems); Assertion.AssertEquals(default(bool), brce.BuildResult); brce.Name = "brce"; brce.BuildItems = buildItems; brce.BuildResult = false; Assertion.AssertEquals("brce", brce.Name); Assertion.AssertEquals(buildItems, brce.BuildItems); Assertion.AssertEquals(false, brce.BuildResult); }
internal static CacheEntry CreateFromStream(BinaryReader reader) { CacheEntryTypes entryType = (CacheEntryTypes)reader.ReadByte(); CacheEntry entry = null; switch (entryType) { case CacheEntryTypes.BuildItem: entry = new BuildItemCacheEntry(); break; case CacheEntryTypes.BuildResult: entry = new BuildResultCacheEntry(); break; case CacheEntryTypes.Property: entry = new PropertyCacheEntry(); break; default: ErrorUtilities.VerifyThrow(false, "Should not get to the default of CacheEntryCustomSerializer CreateFromStream"); break; } entry.CreateFromStream(reader); return(entry); }
public void CheckBasicOperation() { CacheManager cacheManager = new CacheManager("3.5"); CacheScope cacheScope = cacheManager.GetCacheScope("Test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items); Assert.IsNotNull(cacheScope, "Cache should not have an entry"); CacheScope cacheScope1 = cacheManager.GetCacheScope("Test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items); Assert.AreEqual(cacheScope, cacheScope1, "Expected to get the same scope"); cacheScope1 = cacheManager.GetCacheScope("Test1.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items); Assert.IsNotNull(cacheScope1, "Cache should not have an entry"); Assert.AreNotEqual(cacheScope, cacheScope1, "Expected to get different scopes"); // Add an entry and verify that it ends up in the right scope CacheEntry cacheEntry = new BuildResultCacheEntry("TestEntry", null, true); CacheEntry cacheEntry1 = new BuildResultCacheEntry("TestEntry1", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "Test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items); Assert.IsNotNull(cacheScope.GetCacheEntry("TestEntry"), "Cache should have an entry"); Assert.IsNotNull(cacheManager.GetCacheEntries(new string[] { "TestEntry" }, "Test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items)[0], "Cache should have an entry"); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry1 }, "Test1.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items); Assert.IsNotNull(cacheScope1.GetCacheEntry("TestEntry1"), "Cache should have an entry"); Assert.IsNotNull(cacheManager.GetCacheEntries(new string[] { "TestEntry1" }, "Test1.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items)[0], "Cache should have an entry"); // Try clearing the whole cache cacheManager.ClearCache(); Assert.AreNotEqual(cacheScope, cacheManager.GetCacheScope("Test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.Items), "Expected to get different scopes"); }
public void CacheEntryGetters() { BuildItem[] buildItems = new BuildItem[2] { null, null }; BuildItemCacheEntry tice = new BuildItemCacheEntry("tice", buildItems); Assertion.AssertEquals("tice", tice.Name); Assertion.AssertEquals(buildItems, tice.BuildItems); PropertyCacheEntry pce = new PropertyCacheEntry("pce", "propertyValue"); Assertion.AssertEquals("pce", pce.Name); Assertion.AssertEquals("propertyValue", pce.Value); BuildResultCacheEntry brce = new BuildResultCacheEntry("brce", buildItems, true); Assertion.AssertEquals("brce", brce.Name); Assertion.AssertEquals(buildItems, brce.BuildItems); Assertion.AssertEquals(true, brce.BuildResult); }
public void BasicCacheOperation() { BuildPropertyGroup default_scope = new BuildPropertyGroup(); CacheScope testScope = new CacheScope("Test.proj", new BuildPropertyGroup(), "2.0"); // First add a single entry and verify that it is in the cache CacheEntry cacheEntry = new BuildResultCacheEntry("TestEntry", null, true); testScope.AddCacheEntry(cacheEntry); Assert.IsTrue(testScope.ContainsCacheEntry("TestEntry"), "Expect entry in the cache"); CacheEntry inCacheEntry = testScope.GetCacheEntry("TestEntry"); Assert.IsNotNull(inCacheEntry, "Cache should have an entry"); Assert.IsTrue(inCacheEntry.IsEquivalent(cacheEntry), "Expect entry to be the same"); // Add a second entry and then remove the first entry. Verify that the first entry // is not in the cache while the second entry is still there cacheEntry = new BuildResultCacheEntry("TestEntry2", null, true); testScope.AddCacheEntry(cacheEntry); testScope.ClearCacheEntry("TestEntry"); Assert.IsFalse(testScope.ContainsCacheEntry("TestEntry"), "Didn't expect entry in the cache"); Assert.IsTrue(testScope.ContainsCacheEntry("TestEntry2"), "Expected entry in the cache"); Assert.IsNull(testScope.GetCacheEntry("TestEntry"), "Cache should not have an entry"); Assert.IsNotNull(testScope.GetCacheEntry("TestEntry2"), "Cache should have an entry"); }
internal static CacheEntry CreateFromStream(BinaryReader reader) { CacheEntryTypes entryType = (CacheEntryTypes) reader.ReadByte(); CacheEntry entry = null; switch (entryType) { case CacheEntryTypes.BuildItem: entry = new BuildItemCacheEntry(); break; case CacheEntryTypes.BuildResult: entry = new BuildResultCacheEntry(); break; case CacheEntryTypes.Property: entry = new PropertyCacheEntry(); break; default: ErrorUtilities.VerifyThrow(false, "Should not get to the default of CacheEntryCustomSerializer CreateFromStream"); break; } entry.CreateFromStream(reader); return entry; }
public void TestCacheEntryCustomSerialization() { // Stream, writer and reader where the events will be serialized and deserialized from MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); BinaryReader reader = new BinaryReader(stream); try { BuildItem buildItem1 = new BuildItem("BuildItem1", "Item1"); BuildItem buildItem2 = new BuildItem("BuildItem2", "Item2"); buildItem1.Include = "TestInclude1"; buildItem2.Include = "TestInclude2"; BuildItem[] buildItems = new BuildItem[2]; buildItems[0] = buildItem1; buildItems[1] = buildItem2; BuildItemCacheEntry buildItemEntry = new BuildItemCacheEntry("Badger", buildItems); BuildResultCacheEntry buildResultEntry = new BuildResultCacheEntry("Koi", buildItems, true); PropertyCacheEntry propertyEntry = new PropertyCacheEntry("Seagull", "bread"); stream.Position = 0; // Serialize buildItemEntry.WriteToStream(writer); // Get position of stream after write so it can be compared to the position after read long streamWriteEndPosition = stream.Position; // Deserialize and Verify stream.Position = 0; BuildItemCacheEntry newCacheEntry = new BuildItemCacheEntry(); newCacheEntry.CreateFromStream(reader); long streamReadEndPosition = stream.Position; Assert.IsTrue(streamWriteEndPosition == streamReadEndPosition, "Stream End Positions Should Match"); Assert.IsTrue(string.Compare(newCacheEntry.Name, buildItemEntry.Name, StringComparison.OrdinalIgnoreCase) == 0); BuildItem[] buildItemArray = newCacheEntry.BuildItems; Assert.IsTrue(buildItemArray.Length == 2); Assert.IsTrue(string.Compare(buildItemArray[0].Include, buildItem1.Include, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Include, buildItem2.Include, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Name, buildItem2.Name, StringComparison.OrdinalIgnoreCase) == 0); stream.Position = 0; // Serialize buildResultEntry.WriteToStream(writer); // Get position of stream after write so it can be compared to the position after read streamWriteEndPosition = stream.Position; // Deserialize and Verify stream.Position = 0; BuildResultCacheEntry newCacheEntryBuildResult = new BuildResultCacheEntry(); newCacheEntryBuildResult.CreateFromStream(reader); streamReadEndPosition = stream.Position; Assert.IsTrue(streamWriteEndPosition == streamReadEndPosition, "Stream End Positions Should Match"); Assert.IsTrue(string.Compare(newCacheEntryBuildResult.Name, buildResultEntry.Name, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(buildResultEntry.BuildResult == newCacheEntryBuildResult.BuildResult); buildItemArray = newCacheEntryBuildResult.BuildItems; Assert.IsTrue(buildItemArray.Length == 2); Assert.IsTrue(string.Compare(buildItemArray[0].Include, buildItem1.Include, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Include, buildItem2.Include, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Name, buildItem2.Name, StringComparison.OrdinalIgnoreCase) == 0); stream.Position = 0; // Serialize propertyEntry.WriteToStream(writer); // Get position of stream after write so it can be compared to the position after read streamWriteEndPosition = stream.Position; // Deserialize and Verify stream.Position = 0; PropertyCacheEntry newPropertyCacheEntry = new PropertyCacheEntry(); newPropertyCacheEntry.CreateFromStream(reader); streamReadEndPosition = stream.Position; Assert.IsTrue(streamWriteEndPosition == streamReadEndPosition, "Stream End Positions Should Match"); Assert.IsTrue(string.Compare(newPropertyCacheEntry.Name, propertyEntry.Name, StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(newPropertyCacheEntry.Value, propertyEntry.Value, StringComparison.OrdinalIgnoreCase) == 0); } finally { // Close will close the writer/reader and the underlying stream writer.Close(); reader.Close(); reader = null; stream = null; writer = null; } }
public void IsEquivalentBuildResult() { BuildResultCacheEntry e = new BuildResultCacheEntry("name", null, false); Assert.IsFalse(e.IsEquivalent(null)); Assert.IsFalse(e.IsEquivalent(new PropertyCacheEntry("name", "value"))); Assert.IsFalse(e.IsEquivalent(new BuildItemCacheEntry("name", null))); Assert.IsFalse(e.IsEquivalent(new BuildResultCacheEntry())); Assert.IsFalse(e.IsEquivalent(new BuildResultCacheEntry("naame", null, false))); Assert.IsFalse(e.IsEquivalent(new BuildResultCacheEntry("name", null, true))); Assert.IsTrue(e.IsEquivalent(new BuildResultCacheEntry("name", null, false))); }
/// <summary> /// Get a cached build result if available for the given request. This method is thread safe. /// </summary> /// <param name="buildRequest"></param> /// <param name="actuallyBuiltTargets"></param> /// <returns></returns> internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets) { actuallyBuiltTargets = null; PropertyCacheEntry defaultTargetsCacheEntry, initialTargetsCacheEntry, projectIdCacheEntry; // No writes here, but since we're reading multiple values we want to get a consistent view of the cache cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite); try { defaultTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.defaultTargetCacheName); initialTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.initialTargetCacheName); projectIdCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.projectIdCacheName); } finally { cacheScopeReaderWriterLock.ReleaseReaderLock(); } // If we ever built anything in this project we must have the default and initial targets. if (defaultTargetsCacheEntry == null && initialTargetsCacheEntry == null) { return(null); } ErrorUtilities.VerifyThrow(projectIdCacheEntry != null, "We should always have the projectId cache entry"); ErrorUtilities.VerifyThrow(defaultTargetsCacheEntry != null && initialTargetsCacheEntry != null, "We should have both the initial and default targets in the cache"); ArrayList targetsToBuild = new ArrayList(initialTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); if (buildRequest.TargetNames == null || buildRequest.TargetNames.Length == 0) { targetsToBuild.AddRange(defaultTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); } else { targetsToBuild.AddRange(buildRequest.TargetNames); } // Create variable to hold the cached outputs Hashtable outputsByTargetName = new Hashtable(targetsToBuild.Count); Hashtable resultByTarget = new Hashtable(targetsToBuild.Count, StringComparer.OrdinalIgnoreCase); bool overallSuccess = true; bool missingValues = false; // No writes here, but since we're reading multiple values we want to get a consistent view of the cache cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite); try { for (int i = 0; i < targetsToBuild.Count; i++) { string targetName = EscapingUtilities.UnescapeAll((string)targetsToBuild[i]); if (ContainsCacheEntry(targetName)) { BuildResultCacheEntry cacheEntry = (BuildResultCacheEntry)GetCacheEntry(targetName); overallSuccess = overallSuccess && cacheEntry.BuildResult; resultByTarget[targetName] = (cacheEntry.BuildResult) ? Target.BuildState.CompletedSuccessfully : Target.BuildState.CompletedUnsuccessfully; // Restore output items for successful targets if (cacheEntry.BuildResult) { outputsByTargetName[targetName] = cacheEntry.BuildItems; } // We found a failed target - cut the loop short else { break; } } else { missingValues = true; break; } } } finally { cacheScopeReaderWriterLock.ReleaseReaderLock(); } if (missingValues) { return(null); } actuallyBuiltTargets = targetsToBuild; return(new BuildResult(outputsByTargetName, resultByTarget, overallSuccess, buildRequest.HandleId, buildRequest.RequestId, int.Parse(projectIdCacheEntry.Value, CultureInfo.InvariantCulture), false /* use results cache */, defaultTargetsCacheEntry.Value, initialTargetsCacheEntry.Value, 0, 0, 0)); }
/// <summary> /// This method adds cached results for each target results for which are contained inside /// the build result. This method is thread safe. /// </summary> internal void AddCacheEntryForBuildResults(BuildResult buildResult) { ErrorUtilities.VerifyThrow(buildResult != null, "Expect a non-null build result"); // Don't cache results if they are marked as uncacheable if (!buildResult.UseResultCache) { return; } cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite); try { if (!ContainsCacheEntry(Constants.defaultTargetCacheName)) { // If the project file is malformed the build may fail without initializing the initialtargets or // the default targests fields. The retrieval code expects non-null values // so it is necessary to replace null with empty string ErrorUtilities.VerifyThrow(!buildResult.EvaluationResult || (buildResult.InitialTargets != null && buildResult.DefaultTargets != null), "Expect initial targets to be non-null for successful builds"); string defaultTargets = buildResult.DefaultTargets ?? String.Empty; PropertyCacheEntry defaultTargetsCacheEntry = new PropertyCacheEntry(Constants.defaultTargetCacheName, defaultTargets); AddCacheEntryInternal(defaultTargetsCacheEntry); string initialTargets = buildResult.InitialTargets ?? String.Empty; PropertyCacheEntry initialTargetsCacheEntry = new PropertyCacheEntry(Constants.initialTargetCacheName, initialTargets); AddCacheEntryInternal(initialTargetsCacheEntry); } if (!ContainsCacheEntry(Constants.projectIdCacheName)) { PropertyCacheEntry projectIdCacheEntry = new PropertyCacheEntry(Constants.projectIdCacheName, buildResult.ProjectId.ToString(CultureInfo.InvariantCulture)); AddCacheEntryInternal(projectIdCacheEntry); } IDictionary outputsByTargetName = buildResult.OutputsByTarget; //Create single entry for each target in the request foreach (DictionaryEntry entry in buildResult.ResultByTarget) { Target.BuildState buildState = (Target.BuildState)entry.Value; // Only cache successful and failed targets if ((buildState == Target.BuildState.CompletedSuccessfully) || (buildState == Target.BuildState.CompletedUnsuccessfully)) { BuildItem[] targetOutputs = null; // Only cache output items for successful targets if (buildState == Target.BuildState.CompletedSuccessfully) { ErrorUtilities.VerifyThrow(buildResult.OutputsByTarget.Contains(entry.Key), "We must have build results for successful targets"); BuildItem[] outputItems = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; // It's essential that we clear out any pointers to the project from the BuildItem; // otherwise the cache will hold onto the project, and not save any memory. if (outputItems != null) { for (int i = 0; i < outputItems.Length; i++) { outputItems[i] = outputItems[i].VirtualClone(true /* remove references to minimise transitive size */); } } targetOutputs = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; } BuildResultCacheEntry cacheEntry = new BuildResultCacheEntry((string)entry.Key, targetOutputs, buildState == Target.BuildState.CompletedSuccessfully); if (Engine.debugMode) { Console.WriteLine("+++Adding cache entry for " + (string)entry.Key + " in " + this.ScopeName + " result: " + (buildState == Target.BuildState.CompletedSuccessfully)); } AddCacheEntryInternal(cacheEntry); } } } finally { cacheScopeReaderWriterLock.ReleaseWriterLock(); } }
private static CacheEntry[] CreateCacheEntries() { CacheEntry[] entries = new CacheEntry[3]; BuildItem buildItem1 = new BuildItem("BuildItem1", "Item1"); BuildItem buildItem2 = new BuildItem("BuildItem2", "Item2"); buildItem1.Include = "TestInclude1"; buildItem2.Include = "TestInclude2"; BuildItem[] buildItems = new BuildItem[2]; buildItems[0] = buildItem1; buildItems[1] = buildItem2; entries[0] = new BuildItemCacheEntry("Badger", buildItems); entries[1] = new BuildResultCacheEntry("Koi", buildItems, true); entries[2] = new PropertyCacheEntry("Seagull", "bread"); return entries; }
public void TestRequestCaching() { CacheManager cacheManager = new CacheManager("3.5"); ArrayList actuallyBuiltTargets; // Test the case where we pass in null targets Dictionary<string, string> dictionary = new Dictionary<string,string>(); BuildRequest emptyRequest = new BuildRequest(1, "test.proj", null, dictionary, null, 1, true, false); Assert.IsNull(cacheManager.GetCachedBuildResult(emptyRequest, out actuallyBuiltTargets), "Expect a null return value if T=null"); // Test the case where we pass in length 0 targets BuildRequest length0Request = new BuildRequest(1, "test.proj", new string[0], dictionary, null, 1, true, false); Assert.IsNull(cacheManager.GetCachedBuildResult(length0Request, out actuallyBuiltTargets), "Expect a null return value if T.Length=0"); // Test the case when the scope doesn't exist string[] targets = new string[1]; targets[0] = "Target1"; BuildRequest length1Request = new BuildRequest(1, "test.proj", targets, new BuildPropertyGroup(), null, 1, true, false); Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if no scope"); // Test the case when the scope exists but is empty CacheScope cacheScope = cacheManager.GetCacheScope("test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if scope is empty"); // Test the case when the scope exists but contains wrong data CacheEntry cacheEntry = new BuildResultCacheEntry("Target2", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); Assert.IsNull(cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets), "Expect a null return value if scope contains wrong data"); // Test the case when everything is correct cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.defaultTargetCacheName, string.Empty)); cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.initialTargetCacheName, string.Empty)); cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.projectIdCacheName, "1")); cacheEntry = new BuildResultCacheEntry("Target1", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); BuildResult buildResult = cacheManager.GetCachedBuildResult(length1Request, out actuallyBuiltTargets); Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data"); Assert.AreEqual(1, actuallyBuiltTargets.Count); Assert.AreEqual("Target1", actuallyBuiltTargets[0]); Assert.AreEqual(1, buildResult.ResultByTarget.Count); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target1"]); // Test the case when the scope contains partially correct data targets = new string[2]; targets[0] = "Target2"; targets[1] = "Target3"; BuildRequest length2Request = new BuildRequest(1, "test.proj", targets, new BuildPropertyGroup(), null, 1, true, false); Assert.IsNull(cacheManager.GetCachedBuildResult(length2Request, out actuallyBuiltTargets), "Expect a null return value if partial data in the scope"); // Test the correctness case for multiple targets cacheEntry = new BuildResultCacheEntry("Target3", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); buildResult = cacheManager.GetCachedBuildResult(length2Request, out actuallyBuiltTargets); Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data"); Assert.AreEqual(2, actuallyBuiltTargets.Count); Assert.AreEqual("Target2", actuallyBuiltTargets[0]); Assert.AreEqual("Target3", actuallyBuiltTargets[1]); Assert.AreEqual(2, buildResult.ResultByTarget.Count); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target2"]); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target3"]); Assert.AreEqual(1, buildResult.ProjectId); }
public void TestRequestCachingDefaultInitialTargets() { CacheManager cacheManager = new CacheManager("3.5"); ArrayList actuallyBuiltTargets; CacheScope cacheScope = cacheManager.GetCacheScope("test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults); cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.defaultTargetCacheName, "Target1;Target2")); cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.initialTargetCacheName, "Initial1")); cacheScope.AddCacheEntry(new PropertyCacheEntry(Constants.projectIdCacheName, "5")); CacheEntry cacheEntry = new BuildResultCacheEntry("Initial1", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); cacheEntry = new BuildResultCacheEntry("Target1", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults); cacheEntry = new BuildResultCacheEntry("Target2", null, false); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), "3.5", CacheContentType.BuildResults); cacheEntry = new BuildResultCacheEntry("Target3", null, true); cacheManager.SetCacheEntries(new CacheEntry[] { cacheEntry }, "test.proj", new BuildPropertyGroup(), null, CacheContentType.BuildResults); // Default target BuildRequest defaultRequest = new BuildRequest(1, "test.proj", null, new BuildPropertyGroup(), null, 1, true, false); BuildResult buildResult = cacheManager.GetCachedBuildResult(defaultRequest, out actuallyBuiltTargets); Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data"); Assert.AreEqual(3, actuallyBuiltTargets.Count); Assert.AreEqual("Initial1", actuallyBuiltTargets[0]); Assert.AreEqual("Target1", actuallyBuiltTargets[1]); Assert.AreEqual("Target2", actuallyBuiltTargets[2]); Assert.AreEqual(3, buildResult.ResultByTarget.Count); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Initial1"]); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target1"]); Assert.AreEqual(Target.BuildState.CompletedUnsuccessfully, buildResult.ResultByTarget["Target2"]); Assert.AreEqual(false, buildResult.EvaluationResult); Assert.AreEqual(5, buildResult.ProjectId); // Specific target BuildRequest specificRequest = new BuildRequest(1, "test.proj", new string[] { "Target3" }, new BuildPropertyGroup(), null, 1, true, false); buildResult = cacheManager.GetCachedBuildResult(specificRequest, out actuallyBuiltTargets); Assert.IsNotNull(buildResult, "Expect a cached value if scope contains data"); Assert.AreEqual(2, actuallyBuiltTargets.Count); Assert.AreEqual("Initial1", actuallyBuiltTargets[0]); Assert.AreEqual("Target3", actuallyBuiltTargets[1]); Assert.AreEqual(2, buildResult.ResultByTarget.Count); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Initial1"]); Assert.AreEqual(Target.BuildState.CompletedSuccessfully, buildResult.ResultByTarget["Target3"]); Assert.AreEqual(true, buildResult.EvaluationResult); Assert.AreEqual(5, buildResult.ProjectId); }
/// <summary> /// This method adds cached results for each target results for which are contained inside /// the build result. This method is thread safe. /// </summary> internal void AddCacheEntryForBuildResults(BuildResult buildResult) { ErrorUtilities.VerifyThrow(buildResult != null, "Expect a non-null build result"); // Don't cache results if they are marked as uncacheable if (!buildResult.UseResultCache) { return; } cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite); try { if (!ContainsCacheEntry(Constants.defaultTargetCacheName)) { // If the project file is malformed the build may fail without initializing the initialtargets or // the default targests fields. The retrieval code expects non-null values // so it is necessary to replace null with empty string ErrorUtilities.VerifyThrow(buildResult.EvaluationResult == false || buildResult.InitialTargets != null && buildResult.DefaultTargets != null , "Expect initial targets to be non-null for successful builds"); string defaultTargets = buildResult.DefaultTargets == null ? String.Empty : buildResult.DefaultTargets; PropertyCacheEntry defaultTargetsCacheEntry = new PropertyCacheEntry(Constants.defaultTargetCacheName, defaultTargets); AddCacheEntryInternal(defaultTargetsCacheEntry); string initialTargets = buildResult.InitialTargets == null ? String.Empty : buildResult.InitialTargets; PropertyCacheEntry initialTargetsCacheEntry = new PropertyCacheEntry(Constants.initialTargetCacheName, initialTargets ); AddCacheEntryInternal(initialTargetsCacheEntry); } if (!ContainsCacheEntry(Constants.projectIdCacheName)) { PropertyCacheEntry projectIdCacheEntry = new PropertyCacheEntry(Constants.projectIdCacheName, buildResult.ProjectId.ToString(CultureInfo.InvariantCulture)); AddCacheEntryInternal(projectIdCacheEntry); } IDictionary outputsByTargetName = buildResult.OutputsByTarget; //Create single entry for each target in the request foreach (DictionaryEntry entry in buildResult.ResultByTarget) { Target.BuildState buildState = (Target.BuildState)entry.Value; // Only cache successful and failed targets if ((buildState == Target.BuildState.CompletedSuccessfully) || (buildState == Target.BuildState.CompletedUnsuccessfully)) { BuildItem[] targetOutputs = null; // Only cache output items for successful targets if (buildState == Target.BuildState.CompletedSuccessfully) { ErrorUtilities.VerifyThrow(buildResult.OutputsByTarget.Contains(entry.Key), "We must have build results for successful targets"); BuildItem[] outputItems = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; // It's essential that we clear out any pointers to the project from the BuildItem; // otherwise the cache will hold onto the project, and not save any memory. if (outputItems != null) { for (int i = 0; i < outputItems.Length; i++) { outputItems[i] = outputItems[i].VirtualClone(true /* remove references to minimise transitive size */); } } targetOutputs = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; } BuildResultCacheEntry cacheEntry = new BuildResultCacheEntry((string)entry.Key, targetOutputs, (buildState == Target.BuildState.CompletedSuccessfully)); if (Engine.debugMode) { Console.WriteLine("+++Adding cache entry for " + (string)entry.Key + " in " + this.ScopeName + " result: " + (buildState == Target.BuildState.CompletedSuccessfully)); } AddCacheEntryInternal(cacheEntry); } } } finally { cacheScopeReaderWriterLock.ReleaseWriterLock(); } }