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

connect ProgressReport to TableControl

first working version. need some more tweaks.
上级 5a1b81db
......@@ -10,12 +10,17 @@ namespace Microsoft.CodeAnalysis.SolutionCrawler
internal interface ISolutionCrawlerProgressReporter
{
/// <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>
event EventHandler Started;
/// <summary>
/// Raised when there is no more pending work in solutino crawler
/// Raised when there is no more pending work in solutino crawler.
/// </summary>
event EventHandler Stopped;
}
......
......@@ -25,6 +25,14 @@ private class SolutionCrawlerProgressReporter : ISolutionCrawlerProgressReporter
private int _count = 0;
public bool InProgress
{
get
{
return _count > 0;
}
}
public event EventHandler Started
{
add
......@@ -103,6 +111,14 @@ private class NullReporter : ISolutionCrawlerProgressReporter
{
public static readonly NullReporter Instance = new NullReporter();
public bool InProgress
{
get
{
return false;
}
}
public event EventHandler Started
{
add { }
......
......@@ -14,6 +14,11 @@ private class AsyncDocumentWorkItemQueue : AsyncWorkItemQueue<DocumentId>
{
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
{
get
......
......@@ -15,6 +15,11 @@ private sealed class AsyncProjectWorkItemQueue : AsyncWorkItemQueue<ProjectId>
{
private readonly Dictionary<ProjectId, WorkItem> _projectWorkQueue = new Dictionary<ProjectId, WorkItem>();
public AsyncProjectWorkItemQueue(SolutionCrawlerProgressReporter progressReporter) :
base(progressReporter)
{
}
protected override int WorkItemCount_NoLock
{
get
......
......@@ -15,12 +15,20 @@ private partial class WorkCoordinator
private abstract class AsyncWorkItemQueue<TKey> : IDisposable
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.
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; }
......@@ -38,7 +46,7 @@ public bool HasAnyWork
{
lock (_gate)
{
return WorkItemCount_NoLock > 0;
return HasAnyWork_NoLock;
}
}
}
......@@ -72,6 +80,12 @@ public virtual Task WaitAsync(CancellationToken cancellationToken)
public bool AddOrReplace(WorkItem item)
{
if (!HasAnyWork)
{
// first work is added.
_progressReporter.Start();
}
lock (_gate)
{
if (AddOrReplace_NoLock(item))
......@@ -89,6 +103,10 @@ public void Dispose()
{
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();
_cancellationMap.Do(p => p.Value.Cancel());
......@@ -96,6 +114,14 @@ public void Dispose()
}
}
private bool HasAnyWork_NoLock
{
get
{
return WorkItemCount_NoLock > 0;
}
}
protected void Cancel_NoLock(object key)
{
CancellationTokenSource source;
......@@ -112,6 +138,12 @@ public bool TryTake(TKey key, out WorkItem workInfo, out CancellationTokenSource
{
if (TryTake_NoLock(key, out workInfo))
{
if (!HasAnyWork_NoLock)
{
// last work is done.
_progressReporter.Stop();
}
source = GetNewCancellationSource_NoLock(key);
workInfo.AsyncToken.Dispose();
return true;
......@@ -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.
if (TryTakeAnyWork_NoLock(preferableProjectId, out workItem))
{
if (!HasAnyWork_NoLock)
{
// last work is done.
_progressReporter.Stop();
}
source = GetNewCancellationSource_NoLock(workItem.Key);
workItem.AsyncToken.Dispose();
return true;
......
......@@ -38,7 +38,7 @@ private sealed class HighPriorityProcessor : IdleProcessor
_lazyAnalyzers = lazyAnalyzers;
_running = SpecializedTasks.EmptyTask;
_workItemQueue = new AsyncDocumentWorkItemQueue();
_workItemQueue = new AsyncDocumentWorkItemQueue(processor._registration.ProgressReporter);
Start();
}
......
......@@ -34,7 +34,7 @@ private sealed class LowPriorityProcessor : GlobalOperationAwareIdleProcessor
base(listener, processor, globalOperationNotificationService, backOffTimeSpanInMs, shutdownToken)
{
_lazyAnalyzers = lazyAnalyzers;
_workItemQueue = new AsyncProjectWorkItemQueue();
_workItemQueue = new AsyncProjectWorkItemQueue(processor._registration.ProgressReporter);
Start();
}
......@@ -69,11 +69,11 @@ protected override async Task ExecuteAsync()
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;
}
}
}
public void Enqueue(WorkItem item)
{
......@@ -135,7 +135,7 @@ private async Task ProcessProjectAsync(ImmutableArray<IIncrementalAnalyzer> anal
processedEverything = true;
}
catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{
throw ExceptionUtilities.Unreachable;
}
......
......@@ -51,7 +51,7 @@ private sealed class NormalPriorityProcessor : GlobalOperationAwareIdleProcessor
_lazyAnalyzers = lazyAnalyzers;
_running = SpecializedTasks.EmptyTask;
_workItemQueue = new AsyncDocumentWorkItemQueue();
_workItemQueue = new AsyncDocumentWorkItemQueue(processor._registration.ProgressReporter);
_higherPriorityDocumentsNotProcessed = new ConcurrentDictionary<DocumentId, bool>(concurrencyLevel: 2, capacity: 20);
_currentProjectProcessing = default(ProjectId);
......
......@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.VisualStudio.TableManager;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
......@@ -36,6 +37,28 @@ public virtual void OnProjectDependencyChanged(Solution solution)
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)
{
// 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)
}
}
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()
{
ImmutableArray<SubscriptionWithoutLock> snapshot;
......@@ -136,6 +174,19 @@ public SubscriptionWithoutLock(AbstractTableDataSource<TArgs, TData> source, ITa
ReportInitialData();
}
public bool IsStable
{
get
{
return _sink.IsStable;
}
set
{
_sink.IsStable = value;
}
}
public void AddOrUpdate(ITableEntriesSnapshotFactory provider, bool newFactory)
{
if (newFactory)
......
......@@ -10,6 +10,7 @@
using System.Windows.Documents;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Imaging.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
......@@ -113,6 +114,8 @@ public TableDataSource(IServiceProvider serviceProvider, Workspace workspace, ID
_diagnosticService = diagnosticService;
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
ConnectToSolutionCrawlerService(_workspace);
}
public override void OnProjectDependencyChanged(Solution solution)
......@@ -329,7 +332,7 @@ private int GetErrorRank(DiagnosticData item)
return ErrorRank.Other;
}
switch(value)
switch (value)
{
case nameof(ErrorRank.Lexical):
return ErrorRank.Lexical;
......
......@@ -50,6 +50,8 @@ public TableDataSource(Workspace workspace, ITodoListProvider todoListProvider,
_identifier = identifier;
_todoListProvider = todoListProvider;
_todoListProvider.TodoListUpdated += OnTodoListUpdated;
ConnectToSolutionCrawlerService(_workspace);
}
public override string DisplayName
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册