提交 39a85dfb 编写于 作者: H Heejae Chang

clean up and refactoring around global assets.

now, it will get synched when remote host is first created rather than doing that on demand. so functionality change, so re-organized where things happening.
上级 8c36b15b
......@@ -32,7 +32,7 @@ public static async Task<RemoteHostClient> CreateAsync(Workspace workspace, bool
// make sure connection is done right
var current = $"VS ({Process.GetCurrentProcess().Id})";
var telemetrySession = default(string);
var host = await instance._rpc.InvokeAsync<string>(WellKnownRemoteHostServices.RemoteHostService_Connect, current, telemetrySession).ConfigureAwait(false);
var host = await instance._rpc.InvokeAsync<string>(nameof(IRemoteHostService.Connect), current, telemetrySession).ConfigureAwait(false);
// TODO: change this to non fatal watson and make VS to use inproc implementation
Contract.ThrowIfFalse(host == current.ToString());
......
// 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.Collections.Immutable;
using System.Linq;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
......@@ -14,7 +11,6 @@ internal class DiagnosticArguments
public bool LogAnalyzerExecutionTime;
public ProjectId ProjectId;
public Checksum OptionSetChecksum;
public Checksum[] HostAnalyzerChecksums;
public string[] AnalyzerIds;
public DiagnosticArguments()
......@@ -26,7 +22,6 @@ public DiagnosticArguments()
bool logAnalyzerExecutionTime,
ProjectId projectId,
Checksum optionSetChecksum,
ImmutableArray<Checksum> hostAnalyzerChecksums,
string[] analyzerIds)
{
ReportSuppressedDiagnostics = reportSuppressedDiagnostics;
......@@ -35,7 +30,6 @@ public DiagnosticArguments()
ProjectId = projectId;
OptionSetChecksum = optionSetChecksum;
HostAnalyzerChecksums = hostAnalyzerChecksums.ToArray();
AnalyzerIds = analyzerIds;
}
}
......
......@@ -24,37 +24,29 @@ namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2
[ExportWorkspaceServiceFactory(typeof(ICodeAnalysisDiagnosticAnalyzerExecutor)), Shared]
internal class DiagnosticAnalyzerExecutor : IWorkspaceServiceFactory
{
private readonly IDiagnosticAnalyzerService _analyzerServiceOpt;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSourceOpt;
[ImportingConstructor]
public DiagnosticAnalyzerExecutor(
[Import(AllowDefault = true)]IDiagnosticAnalyzerService analyzerService,
[Import(AllowDefault = true)]AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
public DiagnosticAnalyzerExecutor([Import(AllowDefault = true)]AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
// analyzerService, hostDiagnosticUpdateSource can be null in unit test
_analyzerServiceOpt = analyzerService;
// hostDiagnosticUpdateSource can be null in unit test
_hostDiagnosticUpdateSourceOpt = hostDiagnosticUpdateSource;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new AnalyzerExecutor(_analyzerServiceOpt, _hostDiagnosticUpdateSourceOpt);
return new AnalyzerExecutor(_hostDiagnosticUpdateSourceOpt);
}
private class AnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
{
private readonly IDiagnosticAnalyzerService _analyzerServiceOpt;
private readonly AbstractHostDiagnosticUpdateSource _hostDiagnosticUpdateSourceOpt;
// TODO: this should be removed once we move options down to compiler layer
private readonly ConcurrentDictionary<string, ValueTuple<OptionSet, CustomAsset>> _lastOptionSetPerLanguage;
public AnalyzerExecutor(
IDiagnosticAnalyzerService analyzerService,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
public AnalyzerExecutor(AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource)
{
_analyzerServiceOpt = analyzerService;
_hostDiagnosticUpdateSourceOpt = hostDiagnosticUpdateSource;
// currently option is a bit wierd since it is not part of snapshot and
......@@ -122,12 +114,11 @@ private class AnalyzerExecutor : ICodeAnalysisDiagnosticAnalyzerExecutor
}
var optionAsset = GetOptionsAsset(solution, project.Language, cancellationToken);
var hostChecksums = GetHostAnalyzerReferences(snapshotService, project.Language, _analyzerServiceOpt?.GetHostAnalyzerReferences(), cancellationToken);
var argument = new DiagnosticArguments(
analyzerDriver.AnalysisOptions.ReportSuppressedDiagnostics,
analyzerDriver.AnalysisOptions.LogAnalyzerExecutionTime,
project.Id, optionAsset.Checksum, hostChecksums, analyzerMap.Keys.ToArray());
project.Id, optionAsset.Checksum, analyzerMap.Keys.ToArray());
using (var session = await client.TryCreateCodeAnalysisServiceSessionAsync(solution, cancellationToken).ConfigureAwait(false))
{
......@@ -209,34 +200,6 @@ private void ReportAnalyzerExceptions(Project project, ImmutableDictionary<Diagn
}
}
private ImmutableArray<Checksum> GetHostAnalyzerReferences(
ISolutionSynchronizationService snapshotService, string language, IEnumerable<AnalyzerReference> references, CancellationToken cancellationToken)
{
if (references == null)
{
return ImmutableArray<Checksum>.Empty;
}
// TODO: cache this to somewhere
var builder = ImmutableArray.CreateBuilder<Checksum>();
foreach (var reference in references)
{
var analyzers = reference.GetAnalyzers(language);
if (analyzers.Length == 0)
{
// skip reference that doesn't contain any analyzers for the given language
// we do this so that we don't load analyzer dlls that MEF exported from vsix
// not related to this solution
continue;
}
var asset = snapshotService.GetGlobalAsset(reference, cancellationToken);
builder.Add(asset.Checksum);
}
return builder.ToImmutable();
}
private Dictionary<string, DiagnosticAnalyzer> CreateAnalyzerMap(IEnumerable<DiagnosticAnalyzer> analyzers)
{
// TODO: this needs to be cached. we can have 300+ analyzers
......
......@@ -150,8 +150,6 @@ public Task<RemoteHostClient> GetRemoteHostClientAsync(CancellationToken cancell
private async Task<RemoteHostClient> EnableAsync(CancellationToken cancellationToken)
{
AddGlobalAssets(cancellationToken);
// if we reached here, IRemoteHostClientFactory must exist.
// this will make VS.Next dll to be loaded
var instance = await _workspace.Services.GetRequiredService<IRemoteHostClientFactory>().CreateAsync(_workspace, cancellationToken).ConfigureAwait(false);
......@@ -162,11 +160,22 @@ private async Task<RemoteHostClient> EnableAsync(CancellationToken cancellationT
instance.ConnectionChanged += OnConnectionChanged;
// set global assets on remote host
var checksums = AddGlobalAssets(cancellationToken);
// send over global asset
await instance.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService, _workspace.CurrentSolution,
nameof(IRemoteHostService.SynchronizeGlobalAssetsAsync),
(object)checksums, cancellationToken).ConfigureAwait(false);
return instance;
}
private void AddGlobalAssets(CancellationToken cancellationToken)
private Checksum[] AddGlobalAssets(CancellationToken cancellationToken)
{
var builder = ArrayBuilder<Checksum>.GetInstance();
using (Logger.LogBlock(FunctionId.RemoteHostClientService_AddGlobalAssetsAsync, cancellationToken))
{
var snapshotService = _workspace.Services.GetService<ISolutionSynchronizationService>();
......@@ -175,9 +184,13 @@ private void AddGlobalAssets(CancellationToken cancellationToken)
foreach (var reference in _analyzerService.GetHostAnalyzerReferences())
{
var asset = assetBuilder.Build(reference, cancellationToken);
builder.Add(asset.Checksum);
snapshotService.AddGlobalAsset(reference, asset, cancellationToken);
}
}
return builder.ToArrayAndFree();
}
private void RemoveGlobalAssets()
......
......@@ -124,7 +124,7 @@ private async Task SynchronizePrimaryWorkspaceAsync(CancellationToken cancellati
await remoteHostClient.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService, solution,
WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync, checksum, cancellationToken).ConfigureAwait(false);
nameof(IRemoteHostService.SynchronizePrimaryWorkspaceAsync), checksum, cancellationToken).ConfigureAwait(false);
}
}
......
......@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
......@@ -154,7 +153,7 @@ public SnapshotJsonRpcClient(JsonRpcSession owner, Stream stream, CancellationTo
/// <summary>
/// this is callback from remote host side to get asset associated with checksum from VS.
/// </summary>
public async Task RequestAssetAsync(int sessionId, byte[][] checksums, string streamName)
public async Task RequestAssetAsync(int sessionId, Checksum[] checksums, string streamName)
{
try
{
......@@ -185,7 +184,7 @@ public async Task RequestAssetAsync(int sessionId, byte[][] checksums, string st
}
}
private async Task WriteAssetAsync(ObjectWriter writer, byte[][] checksums)
private async Task WriteAssetAsync(ObjectWriter writer, Checksum[] checksums)
{
// special case
if (checksums.Length == 0)
......@@ -209,20 +208,20 @@ private Task WriteNoAssetAsync(ObjectWriter writer)
return SpecializedTasks.EmptyTask;
}
private async Task WriteOneAssetAsync(ObjectWriter writer, byte[] checksum)
private async Task WriteOneAssetAsync(ObjectWriter writer, Checksum checksum)
{
var remotableData = PinnedScope.GetRemotableData(new Checksum(checksum), _source.Token) ?? RemotableData.Null;
var remotableData = PinnedScope.GetRemotableData(checksum, _source.Token) ?? RemotableData.Null;
writer.WriteInt32(1);
writer.WriteValue(checksum);
checksum.WriteTo(writer);
writer.WriteString(remotableData.Kind);
await remotableData.WriteObjectToAsync(writer, _source.Token).ConfigureAwait(false);
}
private async Task WriteMultipleAssetsAsync(ObjectWriter writer, byte[][] checksums)
private async Task WriteMultipleAssetsAsync(ObjectWriter writer, Checksum[] checksums)
{
var remotableDataMap = PinnedScope.GetRemotableData(checksums.Select(c => new Checksum(c)), _source.Token);
var remotableDataMap = PinnedScope.GetRemotableData(checksums, _source.Token);
writer.WriteInt32(remotableDataMap.Count);
foreach (var kv in remotableDataMap)
......
......@@ -65,13 +65,10 @@ private async Task RegisterPrimarySolutionAsync()
return;
}
await session.InvokeAsync(
WellKnownRemoteHostServices.RemoteHostService_PersistentStorageService_RegisterPrimarySolutionId,
solutionId).ConfigureAwait(false);
await session.InvokeAsync(nameof(IRemoteHostService.RegisterPrimarySolutionId), solutionId).ConfigureAwait(false);
await session.InvokeAsync(
WellKnownRemoteHostServices.RemoteHostService_PersistentStorageService_UpdateSolutionIdStorageLocation,
solutionId,
nameof(IRemoteHostService.UpdateSolutionIdStorageLocation), solutionId,
_workspace.DeferredState?.ProjectTracker.GetWorkingFolderPath(_workspace.CurrentSolution)).ConfigureAwait(false);
}
}
......@@ -103,8 +100,8 @@ public void OnSolutionRemoved()
{
await _client.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService, _workspace.CurrentSolution,
WellKnownRemoteHostServices.RemoteHostService_PersistentStorageService_UnregisterPrimarySolutionId,
new object[] { solutionId, synchronousShutdown }, CancellationToken.None).ConfigureAwait(false);
nameof(IRemoteHostService.UnregisterPrimarySolutionId), new object[] { solutionId, synchronousShutdown },
CancellationToken.None).ConfigureAwait(false);
}
public void ClearSolution() { }
......
......@@ -43,7 +43,7 @@ internal sealed partial class ServiceHubRemoteHostClient : RemoteHostClient
var instance = new ServiceHubRemoteHostClient(workspace, primary, hostGroup, remoteHostStream);
// make sure connection is done right
var host = await instance._rpc.InvokeAsync<string>(WellKnownRemoteHostServices.RemoteHostService_Connect, current, TelemetryService.DefaultSession.SerializeSettings()).ConfigureAwait(false);
var host = await instance._rpc.InvokeAsync<string>(nameof(IRemoteHostService.Connect), current, TelemetryService.DefaultSession.SerializeSettings()).ConfigureAwait(false);
// TODO: change this to non fatal watson and make VS to use inproc implementation
Contract.ThrowIfFalse(host == current.ToString());
......
......@@ -49,7 +49,6 @@ public void TestDiagnosticArguments()
logAnalyzerExecutionTime: false,
projectId: ProjectId.CreateNewId("project"),
optionSetChecksum: Checksum.Null,
hostAnalyzerChecksums: ImmutableArray.CreateRange(new[] { new Checksum(Guid.NewGuid().ToByteArray()), new Checksum(Guid.NewGuid().ToByteArray()) }),
analyzerIds: new[] { "analyzer1", "analyzer2" });
VerifyJsonSerialization(arguments, (x, y) =>
......@@ -58,8 +57,6 @@ public void TestDiagnosticArguments()
x.LogAnalyzerExecutionTime == y.LogAnalyzerExecutionTime &&
x.ProjectId == y.ProjectId &&
x.OptionSetChecksum == y.OptionSetChecksum &&
x.HostAnalyzerChecksums.Length == y.HostAnalyzerChecksums.Length &&
x.HostAnalyzerChecksums.Except(y.HostAnalyzerChecksums).Count() == 0 &&
x.AnalyzerIds.Length == y.AnalyzerIds.Length &&
x.AnalyzerIds.Except(y.AnalyzerIds).Count() == 0)
{
......
......@@ -18,6 +18,7 @@
using Microsoft.VisualStudio.LanguageServices.Remote;
using Moq;
using Roslyn.Test.Utilities;
using Roslyn.Test.Utilities.Remote;
using Roslyn.Utilities;
using Roslyn.VisualStudio.Next.UnitTests.Mocks;
using Xunit;
......@@ -72,6 +73,24 @@ public async Task GlobalAssets()
Assert.Null(noAsset);
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task SynchronizeGlobalAssets()
{
var workspace = new AdhocWorkspace(TestHostServices.CreateHostServices());
var analyzerReference = new AnalyzerFileReference(typeof(object).Assembly.Location, new NullAssemblyAnalyzerLoader());
var service = CreateRemoteHostClientService(workspace, SpecializedCollections.SingletonEnumerable<AnalyzerReference>(analyzerReference));
service.Enable();
// make sure client is ready
var client = await service.GetRemoteHostClientAsync(CancellationToken.None) as InProcRemoteHostClient;
Assert.Equal(1, client.AssetStorage.GetGlobalAssetsOfType<AnalyzerReference>(CancellationToken.None).Count());
service.Disable();
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task UpdaterService()
{
......
......@@ -58,6 +58,26 @@ public async Task TestRemoteHostSynchronize()
}
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task TestRemoteHostSynchronizeGlobalAssets()
{
var code = @"class Test { void Method() { } }";
using (var workspace = await TestWorkspace.CreateCSharpAsync(code))
{
var client = (InProcRemoteHostClient)(await InProcRemoteHostClient.CreateAsync(workspace, runCacheCleanup: false, cancellationToken: CancellationToken.None));
await client.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService,
workspace.CurrentSolution,
nameof(IRemoteHostService.SynchronizeGlobalAssetsAsync),
new object[] { new Checksum[0] { } }, CancellationToken.None);
var storage = client.AssetStorage;
Assert.Equal(0, storage.GetGlobalAssetsOfType<object>(CancellationToken.None).Count());
}
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task TestUnknownProject()
{
......@@ -219,7 +239,7 @@ private static async Task UpdatePrimaryWorkspace(InProcRemoteHostClient client,
{
await client.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService, solution,
WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync,
nameof(IRemoteHostService.SynchronizePrimaryWorkspaceAsync),
await solution.State.GetChecksumAsync(CancellationToken.None), CancellationToken.None);
}
......
......@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.Diagnostics.EngineV2;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.VisualBasic.UseNullPropagation;
......@@ -136,17 +137,18 @@ void Method()
{
var analyzerType = typeof(CSharpUseExplicitTypeDiagnosticAnalyzer);
var analyzerReference = new AnalyzerFileReference(analyzerType.Assembly.Location, new TestAnalyzerAssemblyLoader());
var mockAnalyzerService = CreateMockDiagnosticAnalyzerService(new[] { analyzerReference });
// add host analyzer as global assets
var snapshotService = workspace.Services.GetService<ISolutionSynchronizationService>();
var assetBuilder = new CustomAssetBuilder(workspace);
foreach (var reference in mockAnalyzerService.GetHostAnalyzerReferences())
{
var asset = assetBuilder.Build(reference, CancellationToken.None);
snapshotService.AddGlobalAsset(reference, asset, CancellationToken.None);
}
var asset = assetBuilder.Build(analyzerReference, CancellationToken.None);
snapshotService.AddGlobalAsset(analyzerReference, asset, CancellationToken.None);
var client = await workspace.Services.GetService<IRemoteHostClientService>().GetRemoteHostClientAsync(CancellationToken.None);
await client.RunOnRemoteHostAsync(
WellKnownRemoteHostServices.RemoteHostService, workspace.CurrentSolution,
nameof(IRemoteHostService.SynchronizeGlobalAssetsAsync), (object)(new Checksum[] { asset.Checksum }), CancellationToken.None);
// set option
workspace.Options = workspace.Options.WithChangedOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, new CodeStyleOption<bool>(false, NotificationOption.Suggestion));
......@@ -154,7 +156,7 @@ void Method()
// run analysis
var project = workspace.CurrentSolution.Projects.First();
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(mockAnalyzerService, new MyUpdateSource(workspace)).CreateService(workspace.Services);
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(new MyUpdateSource(workspace)).CreateService(workspace.Services);
var analyzerDriver = (await project.GetCompilationAsync()).WithAnalyzers(analyzerReference.GetAnalyzers(project.Language).Where(a => a.GetType() == analyzerType).ToImmutableArray());
var result = await executor.AnalyzeAsync(analyzerDriver, project, CancellationToken.None);
......@@ -168,8 +170,7 @@ void Method()
private static async Task<DiagnosticAnalysisResult> AnalyzeAsync(TestWorkspace workspace, ProjectId projectId, Type analyzerType, CancellationToken cancellationToken = default(CancellationToken))
{
var diagnosticService = workspace.ExportProvider.GetExportedValue<IDiagnosticAnalyzerService>();
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(diagnosticService, new MyUpdateSource(workspace)).CreateService(workspace.Services);
var executor = (ICodeAnalysisDiagnosticAnalyzerExecutor)new DiagnosticAnalyzerExecutor(new MyUpdateSource(workspace)).CreateService(workspace.Services);
var analyzerReference = new AnalyzerFileReference(analyzerType.Assembly.Location, new TestAnalyzerAssemblyLoader());
var project = workspace.CurrentSolution.GetProject(projectId).AddAnalyzerReference(analyzerReference);
......@@ -193,13 +194,6 @@ private async Task<TestWorkspace> CreateWorkspaceAsync(string language, string c
return workspace;
}
private IDiagnosticAnalyzerService CreateMockDiagnosticAnalyzerService(IEnumerable<AnalyzerReference> references)
{
var mock = new Mock<IDiagnosticAnalyzerService>(MockBehavior.Strict);
mock.Setup(a => a.GetHostAnalyzerReferences()).Returns(references);
return mock.Object;
}
[DiagnosticAnalyzer(LanguageNames.CSharp)]
private class MyAnalyzer : DiagnosticAnalyzer
{
......
......@@ -346,7 +346,8 @@ internal enum FunctionId
AssetService_GetAssetAsync,
SnapshotService_RequestAssetAsync,
CompilationService_GetCompilationAsync,
RemoteHostService_Synchronize,
RemoteHostService_SynchronizePrimaryWorkspaceAsync,
RemoteHostService_SynchronizeGlobalAssetsAsync,
AssetStorage_TryGetAsset,
AssetService_SynchronizeAssetsAsync,
AssetService_SynchronizeSolutionAssetsAsync,
......
// 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.Tasks;
namespace Microsoft.CodeAnalysis.Remote
{
internal interface IRemoteHostService
{
string Connect(string host, string serializedSession);
Task SynchronizePrimaryWorkspaceAsync(Checksum checksum);
Task SynchronizeGlobalAssetsAsync(Checksum[] checksums);
void RegisterPrimarySolutionId(SolutionId solutionId);
void UnregisterPrimarySolutionId(SolutionId solutionId, bool synchronousShutdown);
void UpdateSolutionIdStorageLocation(SolutionId solutionId, string storageLocation);
}
}
......@@ -93,11 +93,7 @@ public Task<Session> TryCreateServiceSessionAsync(string serviceName, Solution s
/// </summary>
public async Task<Session> TryCreateServiceSessionAsync(string serviceName, Solution solution, object callbackTarget, CancellationToken cancellationToken)
{
Contract.ThrowIfFalse(solution.Workspace == _workspace);
var service = _workspace.Services.GetService<ISolutionSynchronizationService>();
var snapshot = await service.CreatePinnedRemotableDataScopeAsync(solution, cancellationToken).ConfigureAwait(false);
var snapshot = await GetPinnedScopeAsync(solution, cancellationToken).ConfigureAwait(false);
return await TryCreateServiceSessionAsync(serviceName, snapshot, callbackTarget, cancellationToken).ConfigureAwait(false);
}
......@@ -143,6 +139,19 @@ private void OnConnectionChanged(bool connected)
ConnectionChanged?.Invoke(this, connected);
}
private async Task<PinnedRemotableDataScope> GetPinnedScopeAsync(Solution solution, CancellationToken cancellationToken)
{
if (solution == null)
{
return null;
}
Contract.ThrowIfFalse(solution.Workspace == _workspace);
var service = _workspace.Services.GetService<ISolutionSynchronizationService>();
return await service.CreatePinnedRemotableDataScopeAsync(solution, cancellationToken).ConfigureAwait(false);
}
// TODO: make this to not exposed to caller. abstract all of these under Request and Response mechanism
public abstract class Session : IDisposable
{
......
......@@ -5,11 +5,5 @@ namespace Microsoft.CodeAnalysis.Remote
internal class WellKnownRemoteHostServices
{
public const string RemoteHostService = "remoteHostService";
public const string RemoteHostService_Connect = "Connect";
public const string RemoteHostService_SynchronizePrimaryWorkspaceAsync = "SynchronizePrimaryWorkspaceAsync";
public const string RemoteHostService_PersistentStorageService_RegisterPrimarySolutionId = "PersistentStorageService_RegisterPrimarySolutionId";
public const string RemoteHostService_PersistentStorageService_UnregisterPrimarySolutionId = "PersistentStorageService_UnregisterPrimarySolutionId";
public const string RemoteHostService_PersistentStorageService_UpdateSolutionIdStorageLocation = "PersistentStorageService_UpdateSolutionIdStorageLocation";
}
}
\ No newline at end of file
......@@ -389,6 +389,7 @@
<Compile Include="PatternMatching\PatternMatcher.TextChunk.cs" />
<Compile Include="PatternMatching\PatternMatches.cs" />
<Compile Include="PatternMatching\PatternMatchKind.cs" />
<Compile Include="Remote\IRemoteHostService.cs" />
<Compile Include="Remote\RemoteSupportedLanguages.cs" />
<Compile Include="NamingStyles\Capitalization.cs" />
<Compile Include="NamingStyles\NamingRule.cs" />
......
......@@ -34,6 +34,11 @@ public T Deserialize<T>(string kind, ObjectReader reader, CancellationToken canc
return s_serializer.Deserialize<T>(kind, reader, cancellationToken);
}
public IEnumerable<T> GetGlobalAssetsOfType<T>(CancellationToken cancellationToken)
{
return _assetStorage.GetGlobalAssetsOfType<T>(cancellationToken);
}
public async Task<T> GetAssetAsync<T>(Checksum checksum, CancellationToken cancellationToken)
{
T asset;
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
......@@ -25,6 +26,9 @@ internal class AssetStorage
private readonly ConcurrentDictionary<int, AssetSource> _assetSources =
new ConcurrentDictionary<int, AssetSource>(concurrencyLevel: 4, capacity: 10);
private readonly ConcurrentDictionary<Checksum, Entry> _globalAssets =
new ConcurrentDictionary<Checksum, Entry>(concurrencyLevel: 4, capacity: 10);
private readonly ConcurrentDictionary<Checksum, Entry> _assets =
new ConcurrentDictionary<Checksum, Entry>(concurrencyLevel: 4, capacity: 10);
......@@ -63,18 +67,38 @@ public void UnregisterAssetSource(int sessionId)
_assetSources.TryRemove(sessionId, out dummy);
}
public bool TryAddGlobalAsset(Checksum checksum, object value)
{
return _globalAssets.TryAdd(checksum, new Entry(value));
}
public bool TryAddAsset(Checksum checksum, object value)
{
return _assets.TryAdd(checksum, new Entry(value));
}
public IEnumerable<T> GetGlobalAssetsOfType<T>(CancellationToken cancellationToken)
{
foreach (var asset in _globalAssets)
{
cancellationToken.ThrowIfCancellationRequested();
var value = asset.Value.Object;
if (value is T)
{
yield return (T)value;
}
}
}
public bool TryGetAsset<T>(Checksum checksum, out T value)
{
value = default(T);
using (Logger.LogBlock(FunctionId.AssetStorage_TryGetAsset, Checksum.GetChecksumLogInfo, checksum, CancellationToken.None))
{
Entry entry;
if (!_assets.TryGetValue(checksum, out entry))
if (!_globalAssets.TryGetValue(checksum, out entry) &&
!_assets.TryGetValue(checksum, out entry))
{
return false;
}
......
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote.Diagnostics;
......@@ -36,7 +33,7 @@ public async Task CalculateDiagnosticsAsync(DiagnosticArguments arguments, strin
var solution = await GetSolutionWithSpecificOptionsAsync(optionSet).ConfigureAwait(false);
var projectId = arguments.ProjectId;
var analyzers = await GetHostAnalyzerReferences(arguments.HostAnalyzerChecksums).ConfigureAwait(false);
var analyzers = RoslynServices.AssetService.GetGlobalAssetsOfType<AnalyzerReference>(CancellationToken);
var result = await (new DiagnosticComputer(solution.GetProject(projectId))).GetDiagnosticsAsync(
analyzers, arguments.AnalyzerIds, arguments.ReportSuppressedDiagnostics, arguments.LogAnalyzerExecutionTime, CancellationToken).ConfigureAwait(false);
......@@ -57,15 +54,6 @@ public async Task CalculateDiagnosticsAsync(DiagnosticArguments arguments, strin
}
}
private async Task<IEnumerable<AnalyzerReference>> GetHostAnalyzerReferences(IEnumerable<Checksum> checksums)
{
// get all (checksum, asset) list
var assets = await RoslynServices.AssetService.GetAssetsAsync<AnalyzerReference>(checksums, CancellationToken).ConfigureAwait(false);
// return just asset part
return assets.Select(t => t.Item2);
}
private async Task SerializeDiagnosticResultAsync(string streamName, DiagnosticAnalysisResultMap<string, DiagnosticAnalysisResultBuilder> result)
{
using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_SerializeDiagnosticResultAsync, GetResultLogInfo, result, CancellationToken))
......
......@@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.Remote
///
/// basically, this is used to manage lifetime of the service hub.
/// </summary>
internal class RemoteHostService : ServiceHubServiceBase
internal class RemoteHostService : ServiceHubServiceBase, IRemoteHostService
{
private const string LoggingFunctionIdTextFileName = "ServiceHubFunctionIds.txt";
......@@ -70,7 +70,7 @@ public string Connect(string host, string serializedSession)
public async Task SynchronizePrimaryWorkspaceAsync(Checksum checksum)
{
using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_Synchronize, c => c.ToString(), checksum, CancellationToken))
using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizePrimaryWorkspaceAsync, Checksum.GetChecksumLogInfo, checksum, CancellationToken))
{
try
{
......@@ -90,6 +90,50 @@ public async Task SynchronizePrimaryWorkspaceAsync(Checksum checksum)
}
}
public async Task SynchronizeGlobalAssetsAsync(Checksum[] checksums)
{
using (RoslynLogger.LogBlock(FunctionId.RemoteHostService_SynchronizeGlobalAssetsAsync, Checksum.GetChecksumsLogInfo, checksums, CancellationToken))
{
try
{
var assets = await RoslynServices.AssetService.GetAssetsAsync<object>(checksums, CancellationToken).ConfigureAwait(false);
foreach (var asset in assets)
{
AssetStorage.TryAddGlobalAsset(asset.Item1, asset.Item2);
}
}
catch (IOException)
{
// stream to send over assets has closed before we
// had chance to check cancellation
}
catch (OperationCanceledException)
{
// rpc connection has closed.
// this can happen if client side cancelled the
// operation
}
}
}
public void RegisterPrimarySolutionId(SolutionId solutionId)
{
var persistentStorageService = GetPersistentStorageService();
persistentStorageService?.RegisterPrimarySolution(solutionId);
}
public void UnregisterPrimarySolutionId(SolutionId solutionId, bool synchronousShutdown)
{
var persistentStorageService = GetPersistentStorageService();
persistentStorageService?.UnregisterPrimarySolution(solutionId, synchronousShutdown);
}
public void UpdateSolutionIdStorageLocation(SolutionId solutionId, string storageLocation)
{
RemotePersistentStorageLocationService.UpdateStorageLocation(solutionId, storageLocation);
}
private static Func<FunctionId, bool> GetLoggingChecker()
{
try
......@@ -165,14 +209,6 @@ private static TelemetrySession GetTelemetrySession(string serializedSession)
return session;
}
#region PersistentStorageService messages
public void PersistentStorageService_RegisterPrimarySolutionId(SolutionId solutionId)
{
var persistentStorageService = GetPersistentStorageService();
persistentStorageService?.RegisterPrimarySolution(solutionId);
}
private static PersistentStorageService GetPersistentStorageService()
{
// A bit slimy. We just create an adhoc workspace so it will create the singleton
......@@ -182,18 +218,5 @@ private static PersistentStorageService GetPersistentStorageService()
var persistentStorageService = workspace.Services.GetService<IPersistentStorageService>() as PersistentStorageService;
return persistentStorageService;
}
public void PersistentStorageService_UnregisterPrimarySolutionId(SolutionId solutionId, bool synchronousShutdown)
{
var persistentStorageService = GetPersistentStorageService();
persistentStorageService?.UnregisterPrimarySolution(solutionId, synchronousShutdown);
}
public void PersistentStorageService_UpdateSolutionIdStorageLocation(SolutionId solutionId, string storageLocation)
{
RemotePersistentStorageLocationService.UpdateStorageLocation(solutionId, storageLocation);
}
#endregion
}
}
\ No newline at end of file
......@@ -7,7 +7,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Internal.Log;
using Roslyn.Utilities;
using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger;
......@@ -70,7 +69,7 @@ private class JsonRpcAssetSource : AssetSource
for (var i = 0; i < count; i++)
{
var responseChecksum = new Checksum(reader.ReadArray<byte>());
var responseChecksum = Checksum.ReadFrom(reader);
Contract.ThrowIfFalse(checksums.Contains(responseChecksum));
var kind = reader.ReadString();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册