提交 cf3e22c3 编写于 作者: R Ravi Chande

Revert "Merge pull request #21274 from heejaechang/removeTracking"

This reverts commit ad828aad, reversing
changes made to 5d82127f.
上级 a526dba8
......@@ -321,6 +321,8 @@ private async Task ProcessDocumentAsync(ImmutableArray<IIncrementalAnalyzer> ana
if (document != null)
{
await TrackSemanticVersionsAsync(document, workItem, cancellationToken).ConfigureAwait(false);
// if we are called because a document is opened, we invalidate the document so that
// it can be re-analyzed. otherwise, since newly opened document has same version as before
// analyzer will simply return same data back
......@@ -370,6 +372,33 @@ private async Task ProcessDocumentAsync(ImmutableArray<IIncrementalAnalyzer> ana
}
}
private async Task TrackSemanticVersionsAsync(Document document, WorkItem workItem, CancellationToken cancellationToken)
{
if (workItem.IsRetry ||
workItem.InvocationReasons.Contains(PredefinedInvocationReasons.DocumentAdded) ||
!workItem.InvocationReasons.Contains(PredefinedInvocationReasons.SyntaxChanged))
{
return;
}
var service = document.Project.Solution.Workspace.Services.GetService<ISemanticVersionTrackingService>();
if (service == null)
{
return;
}
// we already reported about this project for same snapshot, don't need to do it again
if (_currentSnapshotVersionTrackingSet.Contains(document.Project.Id))
{
return;
}
await service.RecordSemanticVersionsAsync(document.Project, cancellationToken).ConfigureAwait(false);
// mark this project as already processed.
_currentSnapshotVersionTrackingSet.Add(document.Project.Id);
}
private async Task ProcessOpenDocumentIfNeeded(ImmutableArray<IIncrementalAnalyzer> analyzers, WorkItem workItem, Document document, bool isOpen, CancellationToken cancellationToken)
{
if (!isOpen || !workItem.InvocationReasons.Contains(PredefinedInvocationReasons.DocumentOpened))
......
......@@ -296,6 +296,7 @@ private void ProcessProjectEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncTo
switch (e.Kind)
{
case WorkspaceChangeKind.ProjectAdded:
OnProjectAdded(e.NewSolution.GetProject(e.ProjectId));
EnqueueEvent(e.NewSolution, e.ProjectId, InvocationReasons.DocumentAdded, asyncToken);
break;
case WorkspaceChangeKind.ProjectRemoved:
......@@ -315,6 +316,7 @@ private void ProcessSolutionEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncT
switch (e.Kind)
{
case WorkspaceChangeKind.SolutionAdded:
OnSolutionAdded(e.NewSolution);
EnqueueEvent(e.NewSolution, InvocationReasons.DocumentAdded, asyncToken);
break;
case WorkspaceChangeKind.SolutionRemoved:
......@@ -332,6 +334,32 @@ private void ProcessSolutionEvent(WorkspaceChangeEventArgs e, IAsyncToken asyncT
}
}
private void OnSolutionAdded(Solution solution)
{
var asyncToken = _listener.BeginAsyncOperation("OnSolutionAdded");
_eventProcessingQueue.ScheduleTask(() =>
{
var semanticVersionTrackingService = solution.Workspace.Services.GetService<ISemanticVersionTrackingService>();
if (semanticVersionTrackingService != null)
{
semanticVersionTrackingService.LoadInitialSemanticVersions(solution);
}
}, _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void OnProjectAdded(Project project)
{
var asyncToken = _listener.BeginAsyncOperation("OnProjectAdded");
_eventProcessingQueue.ScheduleTask(() =>
{
var semanticVersionTrackingService = project.Solution.Workspace.Services.GetService<ISemanticVersionTrackingService>();
if (semanticVersionTrackingService != null)
{
semanticVersionTrackingService.LoadInitialSemanticVersions(project);
}
}, _shutdownToken).CompletesAsyncOperation(asyncToken);
}
private void EnqueueEvent(Solution oldSolution, Solution newSolution, IAsyncToken asyncToken)
{
_eventProcessingQueue.ScheduleTask(
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Versions;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Versions
{
/// <summary>
/// this service tracks semantic version changes as solution changes and provide a way to get back to initial project/semantic version
/// pairs at the solution load
/// </summary>
[ExportWorkspaceService(typeof(ISemanticVersionTrackingService), ServiceLayer.Host), Shared]
internal class SemanticVersionTrackingService : ISemanticVersionTrackingService
{
private const int SerializationFormat = 1;
private const string SemanticVersion = nameof(SemanticVersion);
private const string DependentSemanticVersion = nameof(DependentSemanticVersion);
private static readonly ConditionalWeakTable<ProjectId, Versions> s_initialSemanticVersions = new ConditionalWeakTable<ProjectId, Versions>();
private static readonly ConditionalWeakTable<ProjectId, Versions> s_initialDependentSemanticVersions = new ConditionalWeakTable<ProjectId, Versions>();
public VersionStamp GetInitialProjectVersionFromSemanticVersion(Project project, VersionStamp semanticVersion)
{
if (!TryGetInitialVersions(s_initialSemanticVersions, project, SemanticVersion, out var versions))
{
return VersionStamp.Default;
}
if (!VersionStamp.CanReusePersistedVersion(semanticVersion, versions.SemanticVersion))
{
return VersionStamp.Default;
}
return versions.ProjectVersion;
}
public VersionStamp GetInitialDependentProjectVersionFromDependentSemanticVersion(Project project, VersionStamp dependentSemanticVersion)
{
if (!TryGetInitialVersions(s_initialDependentSemanticVersions, project, DependentSemanticVersion, out var versions))
{
return VersionStamp.Default;
}
if (!VersionStamp.CanReusePersistedVersion(dependentSemanticVersion, versions.SemanticVersion))
{
return VersionStamp.Default;
}
return versions.ProjectVersion;
}
private bool TryGetInitialVersions(ConditionalWeakTable<ProjectId, Versions> initialVersionMap, Project project, string keyName, out Versions versions)
{
// if we already loaded this, return it.
if (initialVersionMap.TryGetValue(project.Id, out versions))
{
return true;
}
// otherwise, load it
return TryLoadInitialVersions(initialVersionMap, project, keyName, out versions);
}
public void LoadInitialSemanticVersions(Solution solution)
{
foreach (var project in solution.Projects)
{
LoadInitialSemanticVersions(project);
}
}
public void LoadInitialSemanticVersions(Project project)
{
if (!s_initialSemanticVersions.TryGetValue(project.Id, out var unused))
{
PersistedVersionStampLogger.LogProject();
if (TryLoadInitialVersions(s_initialSemanticVersions, project, SemanticVersion, out unused))
{
PersistedVersionStampLogger.LogInitialSemanticVersion();
}
}
if (!s_initialDependentSemanticVersions.TryGetValue(project.Id, out unused) &&
TryLoadInitialVersions(s_initialDependentSemanticVersions, project, DependentSemanticVersion, out unused))
{
PersistedVersionStampLogger.LogInitialDependentSemanticVersion();
}
}
private bool TryLoadInitialVersions(ConditionalWeakTable<ProjectId, Versions> initialVersionMap, Project project, string keyName, out Versions versions)
{
var result = TryReadFrom(project, keyName, out versions);
if (result)
{
Versions save = versions;
initialVersionMap.GetValue(project.Id, _ => save);
return true;
}
initialVersionMap.GetValue(project.Id, _ => Versions.Default);
return false;
}
private static bool TryReadFrom(Project project, string keyName, out Versions versions)
{
versions = default(Versions);
var service = project.Solution.Workspace.Services.GetService<IPersistentStorageService>();
if (service == null)
{
return false;
}
try
{
using (var storage = service.GetStorage(project.Solution))
using (var stream = storage.ReadStreamAsync(keyName, CancellationToken.None).WaitAndGetResult(CancellationToken.None))
using (var reader = ObjectReader.TryGetReader(stream))
{
if (reader != null)
{
var formatVersion = reader.ReadInt32();
if (formatVersion == SerializationFormat)
{
var persistedProjectVersion = VersionStamp.ReadFrom(reader);
var persistedSemanticVersion = VersionStamp.ReadFrom(reader);
versions = new Versions(persistedProjectVersion, persistedSemanticVersion);
return true;
}
}
}
}
catch (Exception e) when (IOUtilities.IsNormalIOException(e))
{
}
return false;
}
public async Task RecordSemanticVersionsAsync(Project project, CancellationToken cancellationToken)
{
var service = project.Solution.Workspace.Services.GetService<IPersistentStorageService>();
if (service == null)
{
return;
}
using (var storage = service.GetStorage(project.Solution))
{
// first update semantic and dependent semantic version of this project
await WriteToSemanticVersionAsync(storage, project, cancellationToken).ConfigureAwait(false);
await WriteToDependentSemanticVersionAsync(storage, project, cancellationToken).ConfigureAwait(false);
// next update dependent semantic version fo all projects that depend on this project.
var projectIds = project.Solution.GetProjectDependencyGraph().GetProjectsThatTransitivelyDependOnThisProject(project.Id);
foreach (var projectId in projectIds)
{
cancellationToken.ThrowIfCancellationRequested();
var currentProject = project.Solution.GetProject(projectId);
if (currentProject == null)
{
continue;
}
await WriteToDependentSemanticVersionAsync(storage, currentProject, cancellationToken).ConfigureAwait(false);
}
}
}
private static async Task WriteToSemanticVersionAsync(IPersistentStorage storage, Project project, CancellationToken cancellationToken)
{
var projectVersion = await project.GetVersionAsync(cancellationToken).ConfigureAwait(false);
var semanticVersion = await project.GetSemanticVersionAsync(cancellationToken).ConfigureAwait(false);
await WriteToVersionAsync(storage, SemanticVersion, projectVersion, semanticVersion, cancellationToken).ConfigureAwait(false);
}
private static async Task WriteToDependentSemanticVersionAsync(IPersistentStorage storage, Project project, CancellationToken cancellationToken)
{
var projectVersion = await project.GetDependentVersionAsync(cancellationToken).ConfigureAwait(false);
var semanticVersion = await project.GetDependentSemanticVersionAsync(cancellationToken).ConfigureAwait(false);
await WriteToVersionAsync(storage, DependentSemanticVersion, projectVersion, semanticVersion, cancellationToken).ConfigureAwait(false);
}
private static async Task WriteToVersionAsync(
IPersistentStorage storage, string keyName, VersionStamp projectVersion, VersionStamp semanticVersion, CancellationToken cancellationToken)
{
using (var stream = SerializableBytes.CreateWritableStream())
using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken))
{
writer.WriteInt32(SerializationFormat);
projectVersion.WriteTo(writer);
semanticVersion.WriteTo(writer);
stream.Position = 0;
await storage.WriteStreamAsync(keyName, stream, cancellationToken).ConfigureAwait(false);
}
}
private class Versions
{
public static readonly Versions Default = new Versions(VersionStamp.Default, VersionStamp.Default);
public readonly VersionStamp ProjectVersion;
public readonly VersionStamp SemanticVersion;
public Versions(VersionStamp projectVersion, VersionStamp semanticVersion)
{
this.ProjectVersion = projectVersion;
this.SemanticVersion = semanticVersion;
}
}
}
}
......@@ -159,6 +159,7 @@
<Compile Include="Implementation\Utilities\AutomationDelegatingListView.cs" />
<Compile Include="Implementation\Utilities\HyperlinkStyleHelper.cs" />
<Compile Include="Implementation\Venus\VenusTaskExtensions.cs" />
<Compile Include="Implementation\Versions\SemanticVersionTrackingService.cs" />
<Compile Include="Implementation\ContainedLanguageRefactorNotifyService.cs" />
<Compile Include="Implementation\VirtualMemoryNotificationListener.cs" />
<Compile Include="Implementation\Watson\WatsonReporter.cs" />
......@@ -345,7 +346,7 @@
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop150DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0">
......@@ -450,9 +451,9 @@
<PackageReference Include="Newtonsoft.Json">
<Version>$(NewtonsoftJsonVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime">
<Version>$(MicrosoftVisualStudioShellInterop153DesignTimeVersion)</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Include="CodeMarkers\ManagedCodeMarkers.cs" />
......
......@@ -37,5 +37,40 @@ public static bool CanReusePersistedDependentProjectVersion(this Project project
PersistedVersionStampLogger.LogPersistedDependentProjectVersionUsage(canReuse);
return canReuse;
}
public static bool CanReusePersistedSemanticVersion(
this Project project, VersionStamp projectVersion, VersionStamp semanticVersion, VersionStamp persistedVersion)
{
var canReuse = CanReusePersistedSemanticVersionInternal(
project, projectVersion, semanticVersion, persistedVersion, (s, p, v) => s.GetInitialProjectVersionFromSemanticVersion(p, v));
PersistedVersionStampLogger.LogPersistedSemanticVersionUsage(canReuse);
return canReuse;
}
public static bool CanReusePersistedDependentSemanticVersion(
this Project project, VersionStamp dependentProjectVersion, VersionStamp dependentSemanticVersion, VersionStamp persistedVersion)
{
var canReuse = CanReusePersistedSemanticVersionInternal(
project, dependentProjectVersion, dependentSemanticVersion, persistedVersion, (s, p, v) => s.GetInitialDependentProjectVersionFromDependentSemanticVersion(p, v));
PersistedVersionStampLogger.LogPersistedDependentSemanticVersionUsage(canReuse);
return canReuse;
}
private static bool CanReusePersistedSemanticVersionInternal(
Project project,
VersionStamp projectVersion,
VersionStamp semanticVersion,
VersionStamp persistedVersion,
Func<ISemanticVersionTrackingService, Project, VersionStamp, VersionStamp> versionGetter)
{
// * NOTE *
// Disabled semantic version tracking
// we need better version for it to reliably work.
//
// see tracking issue here : https://github.com/dotnet/roslyn/issues/2311
return VersionStamp.CanReusePersistedVersion(semanticVersion, persistedVersion);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Versions
{
/// <summary>
/// A service that knows how to convert semantic version to project version
/// </summary>
internal interface ISemanticVersionTrackingService : IWorkspaceService
{
VersionStamp GetInitialProjectVersionFromSemanticVersion(Project project, VersionStamp semanticVersion);
VersionStamp GetInitialDependentProjectVersionFromDependentSemanticVersion(Project project, VersionStamp dependentSemanticVersion);
void LoadInitialSemanticVersions(Solution solution);
void LoadInitialSemanticVersions(Project project);
Task RecordSemanticVersionsAsync(Project project, CancellationToken cancellationToken);
}
}
......@@ -11,6 +11,12 @@ internal static class PersistedVersionStampLogger
private const string SyntaxTree = nameof(SyntaxTree);
private const string Project = nameof(Project);
private const string DependentProject = nameof(DependentProject);
private const string Semantic = nameof(Semantic);
private const string DependentSemantic = nameof(DependentSemantic);
private const string ProjectCount = nameof(ProjectCount);
private const string InitialSemanticVersionCount = nameof(InitialSemanticVersionCount);
private const string InitialDependentSemanticVersionCount = nameof(InitialDependentSemanticVersionCount);
private static readonly LogAggregator s_logAggregator = new LogAggregator();
......@@ -54,14 +60,55 @@ public static void LogPersistedDependentProjectVersionUsage(bool succeeded)
s_logAggregator.IncreaseCount(DependentProject);
}
public static void LogPersistedSemanticVersionUsage(bool succeeded)
{
if (!succeeded)
{
return;
}
s_logAggregator.IncreaseCount(Semantic);
}
public static void LogPersistedDependentSemanticVersionUsage(bool succeeded)
{
if (!succeeded)
{
return;
}
s_logAggregator.IncreaseCount(DependentSemantic);
}
public static void LogProject()
{
s_logAggregator.IncreaseCount(ProjectCount);
}
public static void LogInitialSemanticVersion()
{
s_logAggregator.IncreaseCount(InitialSemanticVersionCount);
}
public static void LogInitialDependentSemanticVersion()
{
s_logAggregator.IncreaseCount(InitialDependentSemanticVersionCount);
}
public static void LogSummary()
{
Logger.Log(FunctionId.PersistedSemanticVersion_Info, KeyValueLogMessage.Create(m =>
{
m[ProjectCount] = s_logAggregator.GetCount(ProjectCount);
m[InitialSemanticVersionCount] = s_logAggregator.GetCount(InitialSemanticVersionCount);
m[InitialDependentSemanticVersionCount] = s_logAggregator.GetCount(InitialDependentSemanticVersionCount);
m[Text] = s_logAggregator.GetCount(Text);
m[SyntaxTree] = s_logAggregator.GetCount(SyntaxTree);
m[Project] = s_logAggregator.GetCount(Project);
m[DependentProject] = s_logAggregator.GetCount(DependentProject);
m[Semantic] = s_logAggregator.GetCount(Semantic);
m[DependentSemantic] = s_logAggregator.GetCount(DependentSemantic);
}));
}
}
......
......@@ -636,6 +636,7 @@
<Compile Include="Utilities\ValuesSources\CachedWeakValueSource.cs" />
<Compile Include="Utilities\WeakEventHandler.cs" />
<Compile Include="Versions\Extensions.cs" />
<Compile Include="Versions\ISemanticVersionTrackingService.cs" />
<Compile Include="Versions\PersistedVersionStampLogger.cs" />
<Compile Include="Workspace\AdhocWorkspace.cs" />
<Compile Include="Workspace\DocumentActiveContextChangedEventArgs.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册