提交 fd280645 编写于 作者: H Heejae Chang

Merge branch 'primaryworkspace' of https://github.com/heejaechang/roslyn into primaryworkspace

......@@ -56,11 +56,8 @@ protected override async Task ExecuteAsync()
// wait for global operation to finish
await GlobalOperationTask.ConfigureAwait(false);
// cancel updating solution checksum if a global operation (such as loading solution, building solution and etc) has started
await UpdateSolutionChecksumAsync(_globalOperationCancellationSource.Token).ConfigureAwait(false);
// update primary solution in remote host
await SynchronizePrimaryWorkspace().ConfigureAwait(false);
await SynchronizePrimaryWorkspaceAsync(_globalOperationCancellationSource.Token).ConfigureAwait(false);
}
protected override void PauseOnGlobalOperation()
......@@ -112,26 +109,21 @@ private void EnqueueChecksumUpdate()
_event.Release();
}
private async Task UpdateSolutionChecksumAsync(CancellationToken cancellationToken)
{
await _service.Workspace.CurrentSolution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false);
}
private async Task SynchronizePrimaryWorkspace()
private async Task SynchronizePrimaryWorkspaceAsync(CancellationToken cancellationToken)
{
var remoteHostClient = await _service.GetRemoteHostClientAsync(ShutdownCancellationToken).ConfigureAwait(false);
var remoteHostClient = await _service.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false);
if (remoteHostClient == null)
{
return;
}
using (Logger.LogBlock(FunctionId.SolutionChecksumUpdater_SynchronizePrimaryWorkspace, ShutdownCancellationToken))
using (Logger.LogBlock(FunctionId.SolutionChecksumUpdater_SynchronizePrimaryWorkspace, cancellationToken))
{
var solution = _service.Workspace.CurrentSolution;
using (var session = await remoteHostClient.CreateServiceSessionAsync(WellKnownRemoteHostServices.RemoteHostService, solution, ShutdownCancellationToken).ConfigureAwait(false))
using (var session = await remoteHostClient.CreateServiceSessionAsync(WellKnownRemoteHostServices.RemoteHostService, solution, cancellationToken).ConfigureAwait(false))
{
// ask remote host to sync initial asset
var checksum = await solution.State.GetChecksumAsync(ShutdownCancellationToken).ConfigureAwait(false);
var checksum = await solution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false);
await session.InvokeAsync(WellKnownRemoteHostServices.RemoteHostService_SynchronizePrimaryWorkspaceAsync, new object[] { checksum.ToArray() }).ConfigureAwait(false);
}
}
......
......@@ -11,8 +11,20 @@ internal static class RemoteHostOptions
public static readonly Option<bool> RemoteHost = new Option<bool>(nameof(InternalFeatureOnOffOptions), nameof(RemoteHost), defaultValue: true,
storageLocations: new LocalUserProfileStorageLocation(InternalFeatureOnOffOptions.LocalRegistryPath + nameof(RemoteHost)));
// Update primary workspace on OOP every 4 seconds if VS is not running any global operation
// such as build, solution open/close, rename and etc.
// Even if primary workspace is not updated, OOP will work as expected. updating primary workspace
// on OOP should let latest data to be synched pre-emptively rather than on demand.
//
// 2 second is our usual long running interactive operation delay and
// 5 second is usual ambient long running operation delay.
// I chose one in between. among 3 and 4 seconds, I chose slower one - 4 second.
//
// When primary workspace is staled, missing data will be synced to OOP on
// demand and cached for 3 min. enough for primary workspace in OOP to be synced to latest.
[ExportOption]
public static readonly Option<int> SolutionChecksumMonitorBackOffTimeSpanInMS = new Option<int>(nameof(InternalFeatureOnOffOptions), nameof(SolutionChecksumMonitorBackOffTimeSpanInMS), defaultValue: 4000,
public static readonly Option<int> SolutionChecksumMonitorBackOffTimeSpanInMS = new Option<int>(
nameof(InternalFeatureOnOffOptions), nameof(SolutionChecksumMonitorBackOffTimeSpanInMS), defaultValue: 4000,
storageLocations: new LocalUserProfileStorageLocation(InternalFeatureOnOffOptions.LocalRegistryPath + nameof(SolutionChecksumMonitorBackOffTimeSpanInMS)));
[ExportOption]
......
......@@ -211,37 +211,37 @@ private static async Task UpdatePrimaryWorkspace(InProcRemoteHostClient client,
private static Solution Populate(Solution solution)
{
solution = AddProject(solution, LanguageNames.CSharp, new string[]
solution = AddProject(solution, LanguageNames.CSharp, new[]
{
"class CS { }",
"class CS2 { }"
}, new string[]
}, new[]
{
"cs additional file content"
}, Array.Empty<ProjectId>());
solution = AddProject(solution, LanguageNames.VisualBasic, new string[]
solution = AddProject(solution, LanguageNames.VisualBasic, new[]
{
"Class VB\r\nEnd Class",
"Class VB2\r\nEnd Class"
}, new string[]
}, new[]
{
"vb additional file content"
}, new ProjectId[] { solution.ProjectIds.First() });
solution = AddProject(solution, LanguageNames.CSharp, new string[]
solution = AddProject(solution, LanguageNames.CSharp, new[]
{
"class Top { }"
}, new string[]
}, new[]
{
"cs additional file content"
}, solution.ProjectIds.ToArray());
solution = AddProject(solution, LanguageNames.CSharp, new string[]
solution = AddProject(solution, LanguageNames.CSharp, new[]
{
"class OrphanCS { }",
"class OrphanCS2 { }"
}, new string[]
}, new[]
{
"cs additional file content",
"cs additional file content2"
......
......@@ -546,6 +546,7 @@ private void WriteTo(AnalyzerReference reference, ObjectWriter writer, bool chec
if (image != null)
{
// TODO: think a way to support this or a way to deal with this kind of situation.
// https://github.com/dotnet/roslyn/issues/15783
throw new NotSupportedException(nameof(AnalyzerImageReference));
}
......
......@@ -14,10 +14,8 @@ internal class RemoteWorkspace : Workspace
{
public const string WorkspaceKind_RemoteWorkspace = "RemoteWorkspace";
// REVIEW: I am using semaphoreSlim since workspace is using it, but not sure why it uses
// semaphore rather than just object since workspace is not using anything specific
// to semaphore
private readonly SemaphoreSlim _serializationLock = new SemaphoreSlim(initialCount: 1);
// guard to make sure host API doesn't run concurrently
private readonly object _gate = new object();
public RemoteWorkspace()
: base(RoslynServices.HostServices, workspaceKind: RemoteWorkspace.WorkspaceKind_RemoteWorkspace)
......@@ -40,7 +38,7 @@ public RemoteWorkspace()
/// </summary>
public new void ClearSolution()
{
using (_serializationLock.DisposableWait())
lock (_gate)
{
base.ClearSolution();
}
......@@ -56,7 +54,7 @@ public Solution AddSolution(SolutionInfo solutionInfo)
throw new ArgumentNullException(nameof(solutionInfo));
}
using (_serializationLock.DisposableWait())
lock (_gate)
{
this.OnSolutionAdded(solutionInfo);
this.UpdateReferencesAfterAdd();
......@@ -75,7 +73,7 @@ public Solution UpdateSolution(Solution solution)
throw new ArgumentNullException(nameof(solution));
}
using (_serializationLock.DisposableWait())
lock (_gate)
{
var oldSolution = this.CurrentSolution;
Contract.ThrowIfFalse(oldSolution.Id == solution.Id && oldSolution.FilePath == solution.FilePath);
......@@ -94,7 +92,7 @@ public Solution UpdateSolution(Solution solution)
/// </summary>
public override void OpenDocument(DocumentId documentId, bool activate = true)
{
using (_serializationLock.DisposableWait())
lock (_gate)
{
var doc = this.CurrentSolution.GetDocument(documentId);
if (doc != null)
......@@ -110,7 +108,7 @@ public override void OpenDocument(DocumentId documentId, bool activate = true)
/// </summary>
public override void CloseDocument(DocumentId documentId)
{
using (_serializationLock.DisposableWait())
lock (_gate)
{
var doc = this.CurrentSolution.GetDocument(documentId);
if (doc != null)
......@@ -128,7 +126,7 @@ public override void CloseDocument(DocumentId documentId)
/// </summary>
public override void OpenAdditionalDocument(DocumentId documentId, bool activate = true)
{
using (_serializationLock.DisposableWait())
lock (_gate)
{
var doc = this.CurrentSolution.GetAdditionalDocument(documentId);
if (doc != null)
......@@ -144,7 +142,7 @@ public override void OpenAdditionalDocument(DocumentId documentId, bool activate
/// </summary>
public override void CloseAdditionalDocument(DocumentId documentId)
{
using (_serializationLock.DisposableWait())
lock (_gate)
{
var doc = this.CurrentSolution.GetAdditionalDocument(documentId);
if (doc != null)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册