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

connect ProgressReport to TableControl

first working version. need some more tweaks.
上级 5a1b81db
...@@ -10,12 +10,17 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler ...@@ -10,12 +10,17 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler
internal interface ISolutionCrawlerProgressReporter internal interface ISolutionCrawlerProgressReporter
{ {
/// <summary> /// <summary>
/// Raised when there is pending work in solution crawler /// Return true if solution crawler is in progress.
/// </summary>
bool InProgress { get; }
/// <summary>
/// Raised when there is pending work in solution crawler.
/// </summary> /// </summary>
event EventHandler Started; event EventHandler Started;
/// <summary> /// <summary>
/// Raised when there is no more pending work in solutino crawler /// Raised when there is no more pending work in solutino crawler.
/// </summary> /// </summary>
event EventHandler Stopped; event EventHandler Stopped;
} }
......
...@@ -25,6 +25,14 @@ private class SolutionCrawlerProgressReporter : ISolutionCrawlerProgressReporter ...@@ -25,6 +25,14 @@ private class SolutionCrawlerProgressReporter : ISolutionCrawlerProgressReporter
private int _count = 0; private int _count = 0;
public bool InProgress
{
get
{
return _count > 0;
}
}
public event EventHandler Started public event EventHandler Started
{ {
add add
...@@ -103,6 +111,14 @@ private class NullReporter : ISolutionCrawlerProgressReporter ...@@ -103,6 +111,14 @@ private class NullReporter : ISolutionCrawlerProgressReporter
{ {
public static readonly NullReporter Instance = new NullReporter(); public static readonly NullReporter Instance = new NullReporter();
public bool InProgress
{
get
{
return false;
}
}
public event EventHandler Started public event EventHandler Started
{ {
add { } add { }
......
...@@ -14,6 +14,11 @@ private class AsyncDocumentWorkItemQueue : AsyncWorkItemQueue<DocumentId> ...@@ -14,6 +14,11 @@ private class AsyncDocumentWorkItemQueue : AsyncWorkItemQueue<DocumentId>
{ {
private readonly Dictionary<ProjectId, Dictionary<DocumentId, WorkItem>> _documentWorkQueue = new Dictionary<ProjectId, Dictionary<DocumentId, WorkItem>>(); private readonly Dictionary<ProjectId, Dictionary<DocumentId, WorkItem>> _documentWorkQueue = new Dictionary<ProjectId, Dictionary<DocumentId, WorkItem>>();
public AsyncDocumentWorkItemQueue(SolutionCrawlerProgressReporter progressReporter) :
base(progressReporter)
{
}
protected override int WorkItemCount_NoLock protected override int WorkItemCount_NoLock
{ {
get get
......
...@@ -15,6 +15,11 @@ private sealed class AsyncProjectWorkItemQueue : AsyncWorkItemQueue<ProjectId> ...@@ -15,6 +15,11 @@ private sealed class AsyncProjectWorkItemQueue : AsyncWorkItemQueue<ProjectId>
{ {
private readonly Dictionary<ProjectId, WorkItem> _projectWorkQueue = new Dictionary<ProjectId, WorkItem>(); private readonly Dictionary<ProjectId, WorkItem> _projectWorkQueue = new Dictionary<ProjectId, WorkItem>();
public AsyncProjectWorkItemQueue(SolutionCrawlerProgressReporter progressReporter) :
base(progressReporter)
{
}
protected override int WorkItemCount_NoLock protected override int WorkItemCount_NoLock
{ {
get get
......
...@@ -15,12 +15,20 @@ private partial class WorkCoordinator ...@@ -15,12 +15,20 @@ private partial class WorkCoordinator
private abstract class AsyncWorkItemQueue<TKey> : IDisposable private abstract class AsyncWorkItemQueue<TKey> : IDisposable
where TKey : class where TKey : class
{ {
private readonly AsyncSemaphore _semaphore = new AsyncSemaphore(initialCount: 0); private readonly object _gate;
private readonly AsyncSemaphore _semaphore;
private readonly SolutionCrawlerProgressReporter _progressReporter;
// map containing cancellation source for the item given out. // map containing cancellation source for the item given out.
private readonly Dictionary<object, CancellationTokenSource> _cancellationMap = new Dictionary<object, CancellationTokenSource>(); private readonly Dictionary<object, CancellationTokenSource> _cancellationMap;
private readonly object _gate = new object(); public AsyncWorkItemQueue(SolutionCrawlerProgressReporter progressReporter)
{
_gate = new object();
_semaphore = new AsyncSemaphore(initialCount: 0);
_cancellationMap = new Dictionary<object, CancellationTokenSource>();
_progressReporter = progressReporter;
}
protected abstract int WorkItemCount_NoLock { get; } protected abstract int WorkItemCount_NoLock { get; }
...@@ -38,7 +46,7 @@ public bool HasAnyWork ...@@ -38,7 +46,7 @@ public bool HasAnyWork
{ {
lock (_gate) lock (_gate)
{ {
return WorkItemCount_NoLock > 0; return HasAnyWork_NoLock;
} }
} }
} }
...@@ -72,6 +80,12 @@ public virtual Task WaitAsync(CancellationToken cancellationToken) ...@@ -72,6 +80,12 @@ public virtual Task WaitAsync(CancellationToken cancellationToken)
public bool AddOrReplace(WorkItem item) public bool AddOrReplace(WorkItem item)
{ {
if (!HasAnyWork)
{
// first work is added.
_progressReporter.Start();
}
lock (_gate) lock (_gate)
{ {
if (AddOrReplace_NoLock(item)) if (AddOrReplace_NoLock(item))
...@@ -89,6 +103,10 @@ public void Dispose() ...@@ -89,6 +103,10 @@ public void Dispose()
{ {
lock (_gate) lock (_gate)
{ {
// here we don't need to care about progress reporter since
// it will be only called when host is shutting down.
// we do the below since we want to kill any pending tasks
Dispose_NoLock(); Dispose_NoLock();
_cancellationMap.Do(p => p.Value.Cancel()); _cancellationMap.Do(p => p.Value.Cancel());
...@@ -96,6 +114,14 @@ public void Dispose() ...@@ -96,6 +114,14 @@ public void Dispose()
} }
} }
private bool HasAnyWork_NoLock
{
get
{
return WorkItemCount_NoLock > 0;
}
}
protected void Cancel_NoLock(object key) protected void Cancel_NoLock(object key)
{ {
CancellationTokenSource source; CancellationTokenSource source;
...@@ -112,6 +138,12 @@ public bool TryTake(TKey key, out WorkItem workInfo, out CancellationTokenSource ...@@ -112,6 +138,12 @@ public bool TryTake(TKey key, out WorkItem workInfo, out CancellationTokenSource
{ {
if (TryTake_NoLock(key, out workInfo)) if (TryTake_NoLock(key, out workInfo))
{ {
if (!HasAnyWork_NoLock)
{
// last work is done.
_progressReporter.Stop();
}
source = GetNewCancellationSource_NoLock(key); source = GetNewCancellationSource_NoLock(key);
workInfo.AsyncToken.Dispose(); workInfo.AsyncToken.Dispose();
return true; return true;
...@@ -131,6 +163,12 @@ public bool TryTakeAnyWork(ProjectId preferableProjectId, out WorkItem workItem, ...@@ -131,6 +163,12 @@ public bool TryTakeAnyWork(ProjectId preferableProjectId, out WorkItem workItem,
// there must be at least one item in the map when this is called unless host is shutting down. // there must be at least one item in the map when this is called unless host is shutting down.
if (TryTakeAnyWork_NoLock(preferableProjectId, out workItem)) if (TryTakeAnyWork_NoLock(preferableProjectId, out workItem))
{ {
if (!HasAnyWork_NoLock)
{
// last work is done.
_progressReporter.Stop();
}
source = GetNewCancellationSource_NoLock(workItem.Key); source = GetNewCancellationSource_NoLock(workItem.Key);
workItem.AsyncToken.Dispose(); workItem.AsyncToken.Dispose();
return true; return true;
......
...@@ -38,7 +38,7 @@ private sealed class HighPriorityProcessor : IdleProcessor ...@@ -38,7 +38,7 @@ private sealed class HighPriorityProcessor : IdleProcessor
_lazyAnalyzers = lazyAnalyzers; _lazyAnalyzers = lazyAnalyzers;
_running = SpecializedTasks.EmptyTask; _running = SpecializedTasks.EmptyTask;
_workItemQueue = new AsyncDocumentWorkItemQueue(); _workItemQueue = new AsyncDocumentWorkItemQueue(processor._registration.ProgressReporter);
Start(); Start();
} }
......
...@@ -34,7 +34,7 @@ private sealed class LowPriorityProcessor : GlobalOperationAwareIdleProcessor ...@@ -34,7 +34,7 @@ private sealed class LowPriorityProcessor : GlobalOperationAwareIdleProcessor
base(listener, processor, globalOperationNotificationService, backOffTimeSpanInMs, shutdownToken) base(listener, processor, globalOperationNotificationService, backOffTimeSpanInMs, shutdownToken)
{ {
_lazyAnalyzers = lazyAnalyzers; _lazyAnalyzers = lazyAnalyzers;
_workItemQueue = new AsyncProjectWorkItemQueue(); _workItemQueue = new AsyncProjectWorkItemQueue(processor._registration.ProgressReporter);
Start(); Start();
} }
...@@ -69,11 +69,11 @@ protected override async Task ExecuteAsync() ...@@ -69,11 +69,11 @@ protected override async Task ExecuteAsync()
await ProcessProjectAsync(this.Analyzers, workItem, projectCancellation).ConfigureAwait(false); await ProcessProjectAsync(this.Analyzers, workItem, projectCancellation).ConfigureAwait(false);
} }
} }
catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{ {
throw ExceptionUtilities.Unreachable; throw ExceptionUtilities.Unreachable;
} }
} }
public void Enqueue(WorkItem item) public void Enqueue(WorkItem item)
{ {
...@@ -135,7 +135,7 @@ private async Task ProcessProjectAsync(ImmutableArray<IIncrementalAnalyzer> anal ...@@ -135,7 +135,7 @@ private async Task ProcessProjectAsync(ImmutableArray<IIncrementalAnalyzer> anal
processedEverything = true; processedEverything = true;
} }
catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{ {
throw ExceptionUtilities.Unreachable; throw ExceptionUtilities.Unreachable;
} }
......
...@@ -51,7 +51,7 @@ private sealed class NormalPriorityProcessor : GlobalOperationAwareIdleProcessor ...@@ -51,7 +51,7 @@ private sealed class NormalPriorityProcessor : GlobalOperationAwareIdleProcessor
_lazyAnalyzers = lazyAnalyzers; _lazyAnalyzers = lazyAnalyzers;
_running = SpecializedTasks.EmptyTask; _running = SpecializedTasks.EmptyTask;
_workItemQueue = new AsyncDocumentWorkItemQueue(); _workItemQueue = new AsyncDocumentWorkItemQueue(processor._registration.ProgressReporter);
_higherPriorityDocumentsNotProcessed = new ConcurrentDictionary<DocumentId, bool>(concurrencyLevel: 2, capacity: 20); _higherPriorityDocumentsNotProcessed = new ConcurrentDictionary<DocumentId, bool>(concurrencyLevel: 2, capacity: 20);
_currentProjectProcessing = default(ProjectId); _currentProjectProcessing = default(ProjectId);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.VisualStudio.TableManager; using Microsoft.VisualStudio.TableManager;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
...@@ -36,6 +37,28 @@ public virtual void OnProjectDependencyChanged(Solution solution) ...@@ -36,6 +37,28 @@ public virtual void OnProjectDependencyChanged(Solution solution)
protected abstract AbstractTableEntriesFactory<TData> CreateTableEntryFactory(object key, TArgs data); protected abstract AbstractTableEntriesFactory<TData> CreateTableEntryFactory(object key, TArgs data);
protected void ConnectToSolutionCrawlerService(Workspace workspace)
{
var crawlerService = workspace.Services.GetService<ISolutionCrawlerService>();
var reporter = crawlerService.GetProgressReporter(workspace);
// set initial value
ChangeStableState(stable: !reporter.InProgress);
reporter.Started += OnSolutionCrawlerStarted;
reporter.Stopped += OnSolutionCrawlerStopped;
}
private void OnSolutionCrawlerStarted(object sender, EventArgs e)
{
ChangeStableState(stable: false);
}
private void OnSolutionCrawlerStopped(object sender, EventArgs e)
{
ChangeStableState(stable: true);
}
protected void OnDataAddedOrChanged(object key, TArgs data) protected void OnDataAddedOrChanged(object key, TArgs data)
{ {
// reuse factory. it is okay to re-use factory since we make sure we remove the factory before // reuse factory. it is okay to re-use factory since we make sure we remove the factory before
...@@ -88,6 +111,21 @@ protected void OnDataRemoved(object key) ...@@ -88,6 +111,21 @@ protected void OnDataRemoved(object key)
} }
} }
private void ChangeStableState(bool stable)
{
ImmutableArray<SubscriptionWithoutLock> snapshot;
lock (_gate)
{
snapshot = _subscriptions;
}
for (var i = 0; i < snapshot.Length; i++)
{
snapshot[i].IsStable = stable;
}
}
protected void RefreshAllFactories() protected void RefreshAllFactories()
{ {
ImmutableArray<SubscriptionWithoutLock> snapshot; ImmutableArray<SubscriptionWithoutLock> snapshot;
...@@ -136,6 +174,19 @@ public SubscriptionWithoutLock(AbstractTableDataSource<TArgs, TData> source, ITa ...@@ -136,6 +174,19 @@ public SubscriptionWithoutLock(AbstractTableDataSource<TArgs, TData> source, ITa
ReportInitialData(); ReportInitialData();
} }
public bool IsStable
{
get
{
return _sink.IsStable;
}
set
{
_sink.IsStable = value;
}
}
public void AddOrUpdate(ITableEntriesSnapshotFactory provider, bool newFactory) public void AddOrUpdate(ITableEntriesSnapshotFactory provider, bool newFactory)
{ {
if (newFactory) if (newFactory)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
using System.Windows.Documents; using System.Windows.Documents;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Imaging.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
...@@ -113,6 +114,8 @@ public TableDataSource(IServiceProvider serviceProvider, Workspace workspace, ID ...@@ -113,6 +114,8 @@ public TableDataSource(IServiceProvider serviceProvider, Workspace workspace, ID
_diagnosticService = diagnosticService; _diagnosticService = diagnosticService;
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated; _diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
ConnectToSolutionCrawlerService(_workspace);
} }
public override void OnProjectDependencyChanged(Solution solution) public override void OnProjectDependencyChanged(Solution solution)
...@@ -329,7 +332,7 @@ private int GetErrorRank(DiagnosticData item) ...@@ -329,7 +332,7 @@ private int GetErrorRank(DiagnosticData item)
return ErrorRank.Other; return ErrorRank.Other;
} }
switch(value) switch (value)
{ {
case nameof(ErrorRank.Lexical): case nameof(ErrorRank.Lexical):
return ErrorRank.Lexical; return ErrorRank.Lexical;
......
...@@ -50,6 +50,8 @@ public TableDataSource(Workspace workspace, ITodoListProvider todoListProvider, ...@@ -50,6 +50,8 @@ public TableDataSource(Workspace workspace, ITodoListProvider todoListProvider,
_identifier = identifier; _identifier = identifier;
_todoListProvider = todoListProvider; _todoListProvider = todoListProvider;
_todoListProvider.TodoListUpdated += OnTodoListUpdated; _todoListProvider.TodoListUpdated += OnTodoListUpdated;
ConnectToSolutionCrawlerService(_workspace);
} }
public override string DisplayName public override string DisplayName
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册