ProjectRootElementCache.Clear do not clear immutable files (#8540)

For `msbuild -restore` scenarios `ProjectRootElementCache` cache used to be cleared for restore could have modified or added some project files (like *.directory.props etc...). 

We can optimize it by keeping ProjectRootElements from immutable locations (like SDK) in that cache as those will be used by build following that restore.
This commit is contained in:
Roman Konecny 2023-03-28 20:59:41 +02:00 коммит произвёл GitHub
Родитель e13070a7f8
Коммит e221fb1bb0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 38 добавлений и 6 удалений

Просмотреть файл

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Build.Collections;
using Microsoft.Build.Construction;
@ -458,13 +459,44 @@ namespace Microsoft.Build.Evaluation
{
lock (_locker)
{
LinkedList<ProjectRootElement> oldStrongCache = _strongCache;
_weakCache = new WeakValueDictionary<string, ProjectRootElement>(StringComparer.OrdinalIgnoreCase);
_strongCache = new LinkedList<ProjectRootElement>();
foreach (ProjectRootElement projectRootElement in oldStrongCache)
if (Traits.Instance.EscapeHatches.AlwaysDoImmutableFilesUpToDateCheck)
{
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
LinkedList<ProjectRootElement> oldStrongCache = _strongCache;
_weakCache = new WeakValueDictionary<string, ProjectRootElement>(StringComparer.OrdinalIgnoreCase);
_strongCache = new LinkedList<ProjectRootElement>();
foreach (ProjectRootElement projectRootElement in oldStrongCache)
{
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
}
}
else
{
// Manually iterate through LinkedList so we can remove items during this iteration
for (var listNode = _strongCache.First; listNode != null;)
{
var nextNode = listNode.Next;
ProjectRootElement projectRootElement = listNode.Value;
// Do not remove cache of files from immutable locations.
// Those are mostly SDK project files and will be most probably needed in next builds.
if (!FileClassifier.Shared.IsNonModifiable(projectRootElement.FullPath))
{
_weakCache.Remove(projectRootElement.FullPath);
_strongCache.Remove(listNode);
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
}
listNode = nextNode;
}
// From weak list remove all which is not in strong list anymore
IList<string> toBeRemovedFromWeakRefs = _weakCache.Keys.Except(_strongCache.Select(i => i.FullPath)).ToList();
foreach (string victim in toBeRemovedFromWeakRefs)
{
_weakCache.Remove(victim);
}
_weakCache.Scavenge();
}
}
}