diff --git a/src/Utilities/TrackedDependencies/CanonicalTrackedInputFiles.cs b/src/Utilities/TrackedDependencies/CanonicalTrackedInputFiles.cs
index a6281533708..be7d6f571f5 100644
--- a/src/Utilities/TrackedDependencies/CanonicalTrackedInputFiles.cs
+++ b/src/Utilities/TrackedDependencies/CanonicalTrackedInputFiles.cs
@@ -1033,6 +1033,9 @@ private void RemoveDependencyFromEntry(string rootingMarker, ITaskItem dependenc
/// Outputs that correspond ot the sources (used for same file processing)
public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[] correspondingOutputs)
{
+ // Cache of files that have been checked and exist.
+ Dictionary fileCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
if (correspondingOutputs != null)
{
ErrorUtilities.VerifyThrowArgument(source.Length == correspondingOutputs.Length, "Tracking_SourcesAndCorrespondingOutputMismatch");
@@ -1041,7 +1044,7 @@ public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[]
// construct a combined root marker for the sources and outputs to remove from the graph
string rootingMarker = FileTracker.FormatRootingMarker(source, correspondingOutputs);
- RemoveDependenciesFromEntryIfMissing(rootingMarker);
+ RemoveDependenciesFromEntryIfMissing(rootingMarker, fileCache);
// Remove entries for each individual source
for (int sourceIndex = 0; sourceIndex < source.Length; sourceIndex++)
@@ -1049,7 +1052,7 @@ public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[]
rootingMarker = correspondingOutputs != null
? FileTracker.FormatRootingMarker(source[sourceIndex], correspondingOutputs[sourceIndex])
: FileTracker.FormatRootingMarker(source[sourceIndex]);
- RemoveDependenciesFromEntryIfMissing(rootingMarker);
+ RemoveDependenciesFromEntryIfMissing(rootingMarker, fileCache);
}
}
@@ -1057,7 +1060,8 @@ public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[]
/// Remove the output graph entries for the given rooting marker
///
///
- private void RemoveDependenciesFromEntryIfMissing(string rootingMarker)
+ /// The cache used to store whether each file exists or not.
+ private void RemoveDependenciesFromEntryIfMissing(string rootingMarker, Dictionary fileCache)
{
// In the event of incomplete tracking information (i.e. this root was not present), just continue quietly
// as the user could have killed the tool being tracked, or another error occurred during its execution.
@@ -1070,8 +1074,19 @@ private void RemoveDependenciesFromEntryIfMissing(string rootingMarker)
{
if (keyIndex++ > 0)
{
- // If we are ignoring missing files, then only record those that exist
- if (FileUtilities.FileExistsNoThrow(file))
+ // Record whether or not each file exists and cache it.
+ // We do this to save time (On^2), at the expense of data O(n).
+ bool inFileCache = fileCache.TryGetValue(file, out bool fileExists);
+
+ // Have we cached the file yet? If not, cache whether or not it exists.
+ if (!inFileCache)
+ {
+ fileExists = FileUtilities.FileExistsNoThrow(file);
+ fileCache.Add(file, fileExists);
+ }
+
+ // Does the cached file exist?
+ if (fileExists)
{
dependenciesWithoutMissingFiles.Add(file, dependencies[file]);
}
diff --git a/src/Utilities/TrackedDependencies/CanonicalTrackedOutputFiles.cs b/src/Utilities/TrackedDependencies/CanonicalTrackedOutputFiles.cs
index 5c906de1683..7ca96f897c0 100644
--- a/src/Utilities/TrackedDependencies/CanonicalTrackedOutputFiles.cs
+++ b/src/Utilities/TrackedDependencies/CanonicalTrackedOutputFiles.cs
@@ -724,6 +724,9 @@ private void RemoveDependencyFromEntry(string rootingMarker, ITaskItem dependenc
/// Outputs that correspond ot the sources (used for same file processing)
public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[] correspondingOutputs)
{
+ // Cache of files and whether or not they exist.
+ Dictionary fileCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
if (correspondingOutputs != null)
{
ErrorUtilities.VerifyThrowArgument(source.Length == correspondingOutputs.Length, "Tracking_SourcesAndCorrespondingOutputMismatch");
@@ -732,21 +735,15 @@ public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[]
// construct a combined root marker for the sources and outputs to remove from the graph
string rootingMarker = FileTracker.FormatRootingMarker(source, correspondingOutputs);
- RemoveDependenciesFromEntryIfMissing(rootingMarker);
+ RemoveDependenciesFromEntryIfMissing(rootingMarker, fileCache);
// Remove entries for each individual source
for (int sourceIndex = 0; sourceIndex < source.Length; sourceIndex++)
{
- if (correspondingOutputs != null)
- {
- rootingMarker = FileTracker.FormatRootingMarker(source[sourceIndex], correspondingOutputs[sourceIndex]);
- }
- else
- {
- rootingMarker = FileTracker.FormatRootingMarker(source[sourceIndex]);
- }
-
- RemoveDependenciesFromEntryIfMissing(rootingMarker);
+ rootingMarker = correspondingOutputs != null
+ ? FileTracker.FormatRootingMarker(source[sourceIndex], correspondingOutputs[sourceIndex])
+ : FileTracker.FormatRootingMarker(source[sourceIndex]);
+ RemoveDependenciesFromEntryIfMissing(rootingMarker, fileCache);
}
}
@@ -754,7 +751,8 @@ public void RemoveDependenciesFromEntryIfMissing(ITaskItem[] source, ITaskItem[]
/// Remove the output graph entries for the given rooting marker
///
///
- private void RemoveDependenciesFromEntryIfMissing(string rootingMarker)
+ /// The cache used to store whether each file exists or not.
+ private void RemoveDependenciesFromEntryIfMissing(string rootingMarker, Dictionary fileCache)
{
// In the event of incomplete tracking information (i.e. this root was not present), just continue quietly
// as the user could have killed the tool being tracked, or another error occurred during its execution.
@@ -767,8 +765,19 @@ private void RemoveDependenciesFromEntryIfMissing(string rootingMarker)
{
if (keyIndex++ > 0)
{
- // If we are ignoring missing files, then only record those that exist
- if (FileUtilities.FileExistsNoThrow(file))
+ // Record whether or not each file exists and cache it.
+ // We do this to save time (On^2), at the expense of data O(n).
+ bool inFileCache = fileCache.TryGetValue(file, out bool fileExists);
+
+ // Have we cached the file yet? If not, cache its existence.
+ if (!inFileCache)
+ {
+ fileExists = FileUtilities.FileExistsNoThrow(file);
+ fileCache.Add(file, fileExists);
+ }
+
+ // Does the cached file exist?
+ if (fileExists)
{
dependenciesWithoutMissingFiles.Add(file, dependencies[file]);
}