New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pre cache #6107
Pre cache #6107
Changes from 7 commits
bae7d8e
5949c20
539b7a8
0f46322
e4a7fc6
a7101f4
5d2ffed
d2a9602
9a8c407
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
using Microsoft.Build.Framework; | ||
using Microsoft.Build.UnitTests; | ||
using Microsoft.Build.Utilities; | ||
using Shouldly; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using Xunit; | ||
|
||
namespace Microsoft.Build.Tasks.UnitTests | ||
{ | ||
public class RARPrecomputedCache_Tests | ||
{ | ||
[Fact] | ||
public void TestPrecomputedCacheOutput() | ||
{ | ||
using (TestEnvironment env = TestEnvironment.Create()) | ||
{ | ||
TransientTestFile standardCache = env.CreateFile(".cache"); | ||
ResolveAssemblyReference t = new ResolveAssemblyReference() | ||
{ | ||
_cache = new SystemState() | ||
}; | ||
t._cache.instanceLocalFileStateCache = new Dictionary<string, SystemState.FileState>() { | ||
{ Path.Combine(standardCache.Path, "assembly1"), new SystemState.FileState(DateTime.Now) }, | ||
{ Path.Combine(standardCache.Path, "assembly2"), new SystemState.FileState(DateTime.Now) { Assembly = new Shared.AssemblyNameExtension("hi") } } }; | ||
t._cache.IsDirty = true; | ||
t.StateFile = standardCache.Path; | ||
t.WriteStateFile(); | ||
int standardLen = File.ReadAllText(standardCache.Path).Length; | ||
File.Delete(standardCache.Path); | ||
standardLen.ShouldBeGreaterThan(0); | ||
|
||
string precomputedPath = standardCache.Path + ".cache"; | ||
t._cache.IsDirty = true; | ||
t.AssemblyInformationCacheOutputPath = precomputedPath; | ||
t.WriteStateFile(); | ||
File.Exists(standardCache.Path).ShouldBeFalse(); | ||
int preLen = File.ReadAllText(precomputedPath).Length; | ||
preLen.ShouldBeGreaterThan(0); | ||
preLen.ShouldNotBe(standardLen); | ||
} | ||
} | ||
|
||
[Fact] | ||
public void StandardCacheTakesPrecedence() | ||
{ | ||
using (TestEnvironment env = TestEnvironment.Create()) | ||
{ | ||
TransientTestFile standardCache = env.CreateFile(".cache"); | ||
ResolveAssemblyReference rarWriterTask = new ResolveAssemblyReference() | ||
{ | ||
_cache = new SystemState() | ||
}; | ||
rarWriterTask._cache.instanceLocalFileStateCache = new Dictionary<string, SystemState.FileState>(); | ||
rarWriterTask.StateFile = standardCache.Path; | ||
rarWriterTask._cache.IsDirty = true; | ||
// Write standard cache | ||
rarWriterTask.WriteStateFile(); | ||
|
||
string dllName = Path.Combine(Path.GetDirectoryName(standardCache.Path), "randomFolder", "dll.dll"); | ||
rarWriterTask._cache.instanceLocalFileStateCache.Add(dllName, | ||
new SystemState.FileState(DateTime.Now) | ||
{ | ||
Assembly = null, | ||
RuntimeVersion = "v4.0.30319", | ||
FrameworkNameAttribute = new System.Runtime.Versioning.FrameworkName(".NETFramework", Version.Parse("4.7.2"), "Profile"), | ||
scatterFiles = new string[] { "first", "second" } | ||
}); | ||
string precomputedCachePath = standardCache.Path + ".cache"; | ||
rarWriterTask.AssemblyInformationCacheOutputPath = precomputedCachePath; | ||
rarWriterTask._cache.IsDirty = true; | ||
// Write precomputed cache | ||
rarWriterTask.WriteStateFile(); | ||
|
||
ResolveAssemblyReference rarReaderTask = new ResolveAssemblyReference(); | ||
rarReaderTask.StateFile = standardCache.Path; | ||
rarReaderTask.AssemblyInformationCachePaths = new ITaskItem[] | ||
{ | ||
new TaskItem(precomputedCachePath) | ||
}; | ||
|
||
// At this point, we should have created two cache files: one "normal" one and one "precomputed" one. | ||
// When we read the state file, it should read from the caches produced in a normal build. In this case, | ||
// the normal cache does not have dll.dll, whereas the precomputed cache does, so it should not be | ||
// present when we read it. | ||
rarReaderTask.ReadStateFile(p => true); | ||
rarReaderTask._cache.instanceLocalFileStateCache.ShouldNotContainKey(dllName); | ||
} | ||
} | ||
|
||
[Fact] | ||
public void TestPreComputedCacheInputMatchesOutput() | ||
{ | ||
using (TestEnvironment env = TestEnvironment.Create()) | ||
{ | ||
TransientTestFile precomputedCache = env.CreateFile(".cache"); | ||
ResolveAssemblyReference rarWriterTask = new ResolveAssemblyReference() | ||
{ | ||
_cache = new SystemState() | ||
}; | ||
string dllName = Path.Combine(Path.GetDirectoryName(precomputedCache.Path), "randomFolder", "dll.dll"); | ||
rarWriterTask._cache.instanceLocalFileStateCache = new Dictionary<string, SystemState.FileState>() { | ||
{ Path.Combine(precomputedCache.Path, "..", "assembly1", "assembly1"), new SystemState.FileState(DateTime.Now) }, | ||
{ Path.Combine(precomputedCache.Path, "assembly2"), new SystemState.FileState(DateTime.Now) { Assembly = new Shared.AssemblyNameExtension("hi") } }, | ||
{ dllName, new SystemState.FileState(DateTime.Now) { | ||
Assembly = null, | ||
RuntimeVersion = "v4.0.30319", | ||
FrameworkNameAttribute = new System.Runtime.Versioning.FrameworkName(".NETFramework", Version.Parse("4.7.2"), "Profile"), | ||
scatterFiles = new string[] { "first", "second" } } } }; | ||
|
||
rarWriterTask.AssemblyInformationCacheOutputPath = precomputedCache.Path; | ||
rarWriterTask._cache.IsDirty = true; | ||
|
||
// Throws an exception because precomputedCache.Path already exists. | ||
Should.Throw<InvalidOperationException>(() => rarWriterTask.WriteStateFile()); | ||
File.Delete(precomputedCache.Path); | ||
rarWriterTask.WriteStateFile(); | ||
|
||
ResolveAssemblyReference rarReaderTask = new ResolveAssemblyReference(); | ||
rarReaderTask.StateFile = precomputedCache.Path.Substring(0, precomputedCache.Path.Length - 6); // Not a real path; should not be used. | ||
rarReaderTask.AssemblyInformationCachePaths = new ITaskItem[] | ||
{ | ||
new TaskItem(precomputedCache.Path) | ||
}; | ||
|
||
// At this point, the standard cache does not exist, so it defaults to reading the "precomputed" cache. | ||
// Then we verify that the information contained in that cache matches what we'd expect. | ||
rarReaderTask.ReadStateFile(p => true); | ||
rarReaderTask._cache.instanceLocalFileStateCache.ShouldContainKey(dllName); | ||
SystemState.FileState assembly3 = rarReaderTask._cache.instanceLocalFileStateCache[dllName]; | ||
assembly3.Assembly.ShouldBeNull(); | ||
assembly3.RuntimeVersion.ShouldBe("v4.0.30319"); | ||
assembly3.FrameworkNameAttribute.Version.ShouldBe(Version.Parse("4.7.2")); | ||
assembly3.scatterFiles.Length.ShouldBe(2); | ||
assembly3.scatterFiles[1].ShouldBe("second"); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,7 @@ public class ResolveAssemblyReference : TaskExtension | |
/// <summary> | ||
/// Cache of system state information, used to optimize performance. | ||
/// </summary> | ||
private SystemState _cache = null; | ||
internal SystemState _cache = null; | ||
|
||
/// <summary> | ||
/// Construct | ||
|
@@ -1884,11 +1884,16 @@ private void LogConflict(Reference reference, string fusionName, StringBuilder l | |
/// <summary> | ||
/// Reads the state file (if present) into the cache. | ||
/// </summary> | ||
private void ReadStateFile() | ||
internal void ReadStateFile(FileExists fileExists) | ||
{ | ||
_cache = SystemState.DeserializeCacheByTranslator(_stateFile, Log); | ||
|
||
// Construct the cache if necessary. | ||
// Construct the cache only if we can't find any caches. | ||
if (_cache == null && AssemblyInformationCachePaths != null && AssemblyInformationCachePaths.Length > 0) | ||
{ | ||
_cache = SystemState.DeserializePrecomputedCachesByTranslator(AssemblyInformationCachePaths, Log, fileExists); | ||
} | ||
|
||
if (_cache == null) | ||
{ | ||
_cache = new SystemState(); | ||
|
@@ -1898,9 +1903,13 @@ private void ReadStateFile() | |
/// <summary> | ||
/// Write out the state file if a state name was supplied and the cache is dirty. | ||
/// </summary> | ||
private void WriteStateFile() | ||
internal void WriteStateFile() | ||
{ | ||
if (!string.IsNullOrEmpty(_stateFile) && _cache.IsDirty) | ||
if (!String.IsNullOrEmpty(AssemblyInformationCacheOutputPath)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super-nit: |
||
{ | ||
_cache.SerializePrecomputedCacheByTranslator(AssemblyInformationCacheOutputPath, Log); | ||
} | ||
else if (!String.IsNullOrEmpty(_stateFile) && _cache.IsDirty) | ||
{ | ||
_cache.SerializeCacheByTranslator(_stateFile, Log); | ||
} | ||
|
@@ -2132,7 +2141,7 @@ ReadMachineTypeFromPEHeader readMachineTypeFromPEHeader | |
} | ||
|
||
// Load any prior saved state. | ||
ReadStateFile(); | ||
ReadStateFile(fileExists); | ||
_cache.SetGetLastWriteTime(getLastWriteTime); | ||
_cache.SetInstalledAssemblyInformation(installedAssemblyTableInfo); | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
?
Calling
DeserializePrecomputedCachesByTranslator
if there are no precomputed caches looks a bit unexpected.