提交 8ea9e5c4 编写于 作者: M mattwar

Move some unused code out (changeset 1211170)

上级 739b9a5e
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.WorkspaceServices;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
internal class BackgroundCompiler
{
private readonly Workspace workspace;
private readonly IWorkspaceTaskScheduler compilationScheduler;
private readonly IWorkspaceTaskScheduler notificationQueue;
// Used to keep a strong reference to the built compilations so they are not GC'd
private Compilation[] mostRecentCompilations;
private readonly object buildGate = new object();
private CancellationTokenSource cancellationSource;
public BackgroundCompiler(Workspace workspace)
{
this.workspace = workspace;
// make a scheduler that runs on the thread pool
var taskSchedulerFactory = WorkspaceService.GetService<IWorkspaceTaskSchedulerFactory>(workspace);
this.compilationScheduler = taskSchedulerFactory.CreateTaskScheduler(TaskScheduler.Default);
// default uses current (ideally UI/foreground scheduler) if possible
this.notificationQueue = taskSchedulerFactory.CreateTaskQueue();
this.cancellationSource = new CancellationTokenSource();
this.workspace.WorkspaceChanged += this.OnWorkspaceChanged;
var editorWorkspace = workspace as Workspace;
if (editorWorkspace != null)
{
editorWorkspace.DocumentOpened += OnDocumentOpened;
editorWorkspace.DocumentClosed += OnDocumentClosed;
}
}
private void OnDocumentOpened(object sender, DocumentEventArgs args)
{
this.Rebuild(args.Document.Project.Solution, args.Document.Project.Id);
}
private void OnDocumentClosed(object sender, DocumentEventArgs args)
{
this.Rebuild(args.Document.Project.Solution, args.Document.Project.Id);
}
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args)
{
switch (args.Kind)
{
case WorkspaceChangeKind.SolutionCleared:
case WorkspaceChangeKind.SolutionAdded:
case WorkspaceChangeKind.SolutionRemoved:
this.CancelBuild(releasePreviousCompilations: true);
break;
case WorkspaceChangeKind.SolutionChanged:
case WorkspaceChangeKind.ProjectRemoved:
this.Rebuild(args.NewSolution);
break;
default:
this.Rebuild(args.NewSolution, args.ProjectId);
break;
}
}
private void Rebuild(Solution solution, ProjectId initialProject = null)
{
lock (this.buildGate)
{
// Keep the previous compilations around so that we can incrementally
// build the current compilations without rebuilding the entire DeclarationTable
this.CancelBuild(releasePreviousCompilations: false);
var allProjects = this.workspace.GetOpenDocumentIds().Select(d => d.ProjectId).ToSet();
// don't even get started if there is nothing to do
if (allProjects.Count > 0)
{
BuildCompilationsAsync(solution, initialProject, allProjects);
}
}
}
private void CancelBuild(bool releasePreviousCompilations)
{
lock (buildGate)
{
this.cancellationSource.Cancel();
this.cancellationSource = new CancellationTokenSource();
if (releasePreviousCompilations)
{
mostRecentCompilations = null;
}
}
}
private void BuildCompilationsAsync(
Solution solution,
ProjectId initialProject,
ISet<ProjectId> allProjects)
{
var cancellationToken = this.cancellationSource.Token;
this.compilationScheduler.ScheduleTask(
() => BuildCompilationsAsync(solution, initialProject, allProjects, cancellationToken),
"BackgroundCompiler.BuildCompilationsAsync",
cancellationToken);
}
private Task BuildCompilationsAsync(
Solution solution,
ProjectId initialProject,
ISet<ProjectId> projectsToBuild,
CancellationToken cancellationToken)
{
var allProjectIds = new List<ProjectId>();
if (initialProject != null)
{
allProjectIds.Add(initialProject);
}
allProjectIds.AddRange(projectsToBuild.Where(p => p != initialProject));
var logger = Logger.LogBlock(FeatureId.Host, FunctionId.Host_BackgroundCompiler_BuildCompilationsAsync, cancellationToken);
var compilatonTasks = allProjectIds.Select(p => solution.GetProject(p)).Where(p => p != null).Select(p => p.GetCompilationAsync(cancellationToken)).ToArray();
return Task.WhenAll(compilatonTasks).SafeContinueWith(t =>
{
logger.Dispose();
if (t.Status == TaskStatus.RanToCompletion)
{
lock (buildGate)
{
if (!cancellationToken.IsCancellationRequested)
{
mostRecentCompilations = t.Result;
}
}
}
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.WorkspaceServices;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
internal class BackgroundParser
{
private readonly Workspace workspace;
private readonly IWorkspaceTaskScheduler taskScheduler;
private readonly ReaderWriterLockSlim stateLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private readonly object parseGate = new object();
private ImmutableDictionary<DocumentId, CancellationTokenSource> workMap = ImmutableDictionary.Create<DocumentId, CancellationTokenSource>();
public bool IsStarted { get; private set; }
public BackgroundParser(Workspace workspace)
{
this.workspace = workspace;
var taskSchedulerFactory = WorkspaceService.GetService<IWorkspaceTaskSchedulerFactory>(workspace);
this.taskScheduler = taskSchedulerFactory.CreateTaskScheduler(TaskScheduler.Default);
this.workspace.WorkspaceChanged += this.OnWorkspaceChanged;
var editorWorkspace = workspace as Workspace;
if (editorWorkspace != null)
{
editorWorkspace.DocumentOpened += this.OnDocumentOpened;
editorWorkspace.DocumentClosed += this.OnDocumentClosed;
}
}
private void OnDocumentOpened(object sender, DocumentEventArgs args)
{
this.Parse(args.Document);
}
private void OnDocumentClosed(object sender, DocumentEventArgs args)
{
this.CancelParse(args.Document.Id);
}
private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs args)
{
switch (args.Kind)
{
case WorkspaceChangeKind.SolutionCleared:
case WorkspaceChangeKind.SolutionRemoved:
case WorkspaceChangeKind.SolutionAdded:
this.CancelAllParses();
break;
case WorkspaceChangeKind.DocumentRemoved:
this.CancelParse(args.DocumentId);
break;
case WorkspaceChangeKind.DocumentChanged:
this.ParseIfOpen(args.NewSolution.GetDocument(args.DocumentId));
break;
case WorkspaceChangeKind.ProjectChanged:
foreach (var doc in args.NewSolution.GetProject(args.ProjectId).Documents)
{
this.ParseIfOpen(doc);
}
break;
}
}
public void Start()
{
using (this.stateLock.DisposableRead())
{
if (!this.IsStarted)
{
this.IsStarted = true;
}
}
}
public void Stop()
{
using (this.stateLock.DisposableWrite())
{
if (this.IsStarted)
{
this.CancelAllParses_NoLock();
this.IsStarted = false;
}
}
}
public void CancelAllParses()
{
using (this.stateLock.DisposableWrite())
{
this.CancelAllParses_NoLock();
}
}
private void CancelAllParses_NoLock()
{
this.stateLock.AssertCanWrite();
foreach (var tuple in this.workMap)
{
tuple.Value.Cancel();
}
this.workMap = ImmutableDictionary.Create<DocumentId, CancellationTokenSource>();
}
public void CancelParse(DocumentId documentId)
{
if (documentId != null)
{
using (this.stateLock.DisposableWrite())
{
CancellationTokenSource cancellationTokenSource;
if (this.workMap.TryGetValue(documentId, out cancellationTokenSource))
{
cancellationTokenSource.Cancel();
this.workMap = this.workMap.Remove(documentId);
}
}
}
}
public void Parse(Document document)
{
if (document != null)
{
lock (this.parseGate)
{
this.CancelParse(document.Id);
if (this.IsStarted)
{
ParseDocumentAsync(document);
}
}
}
}
private void ParseIfOpen(Document document)
{
if (document != null && document.IsOpen())
{
this.Parse(document);
}
}
private void ParseDocumentAsync(Document document)
{
var cancellationTokenSource = new CancellationTokenSource();
using (this.stateLock.DisposableWrite())
{
this.workMap = this.workMap.Add(document.Id, cancellationTokenSource);
}
var cancellationToken = cancellationTokenSource.Token;
var task = this.taskScheduler.ScheduleTask(
() => document.GetSyntaxTreeAsync(cancellationToken),
"BackgroundParser.ParseDocumentAsync",
cancellationToken);
// Always ensure that we mark this work as done from the workmap.
task.SafeContinueWith(
_ =>
{
using (this.stateLock.DisposableWrite())
{
this.workMap = this.workMap.Remove(document.Id);
}
}, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
}
}
}
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Immutable;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.WorkspaceServices;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
{
#if MEF
[ExportWorkspaceServiceFactory(typeof(IFileTrackingService), WorkspaceKind.Any)]
#endif
internal class FileTrackingServiceFactory : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(IWorkspaceServiceProvider workspaceServices)
{
return new FileTrackingService();
}
private class FileTrackingService : IFileTrackingService
{
public IFileTracker CreateFileTracker()
{
return new FileSetTracker();
}
}
private class FileSetTracker : IFileTracker
{
// guards watchers and actions
private readonly NonReentrantLock guard = new NonReentrantLock();
private readonly Dictionary<string, FileSystemWatcher> watchers =
new Dictionary<string, FileSystemWatcher>();
private readonly Dictionary<string, FileTracker> fileTrackers =
new Dictionary<string, FileTracker>();
public FileSetTracker()
{
}
private FileTracker GetFileTracker_NoLock(string path)
{
guard.AssertHasLock();
FileTracker tracker;
if (!this.fileTrackers.TryGetValue(path, out tracker))
{
tracker = new FileTracker(this, path);
this.fileTrackers.Add(path, tracker);
}
return tracker;
}
public bool IsTracking(string path)
{
if (path == null)
{
return false;
}
using (guard.DisposableWait())
{
return this.fileTrackers.ContainsKey(path);
}
}
public void Track(string path, Action action)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
using (guard.DisposableWait())
{
var tracker = this.GetFileTracker_NoLock(path);
tracker.AddAction_NoLock(action);
var directory = Path.GetDirectoryName(path);
if (!watchers.ContainsKey(directory))
{
var watcher = new FileSystemWatcher(directory);
watcher.Changed += OnFileChanged;
watcher.EnableRaisingEvents = true;
}
}
}
public void StopTracking(string path)
{
if (path != null)
{
using (guard.DisposableWait())
{
this.fileTrackers.Remove(path);
}
}
}
private void OnFileChanged(object sender, FileSystemEventArgs args)
{
FileTracker tracker;
using (this.guard.DisposableWait())
{
tracker = this.GetFileTracker_NoLock(args.FullPath);
}
tracker.OnFileChanged();
}
public void Dispose()
{
using (this.guard.DisposableWait())
{
foreach (var watcher in watchers.Values)
{
watcher.Dispose();
}
watchers.Clear();
fileTrackers.Clear();
}
}
private class FileTracker
{
private FileSetTracker tracker;
private readonly string path;
private ImmutableList<Action> actions;
private Task invokeTask;
public FileTracker(FileSetTracker tracker, string path)
{
this.tracker = tracker;
this.path = path;
this.actions = ImmutableList.Create<Action>();
}
public void AddAction_NoLock(Action action)
{
this.tracker.guard.AssertHasLock();
this.actions = this.actions.Add(action);
}
public void OnFileChanged()
{
using (this.tracker.guard.DisposableWait())
{
// only start invoke task if one is not already running
if (this.invokeTask == null)
{
this.invokeTask = Task.Factory.StartNew(() => { });
this.invokeTask.ContinueWithAfterDelay(() => TryInvokeActions(this.actions), CancellationToken.None, 100, TaskContinuationOptions.None, TaskScheduler.Current);
}
}
}
private void TryInvokeActions(ImmutableList<Action> actions)
{
if (actions.Count == 0)
{
return;
}
// only invoke actions if the writer that caused the event is done
// determine this by checking to see if we can read the file
using (var stream = Kernel32File.Open(this.path, FileAccess.Read, FileMode.Open, throwException: false))
{
if (stream != null)
{
stream.Close();
foreach (var action in actions)
{
action();
}
// clear invoke task so any following changes get additional invocations
using (this.tracker.guard.DisposableWait())
{
this.invokeTask = null;
}
}
else
{
// try again after a short delay
using (this.tracker.guard.DisposableWait())
{
this.invokeTask.ContinueWithAfterDelay(() => TryInvokeActions(this.actions), CancellationToken.None, 100, TaskContinuationOptions.None, TaskScheduler.Current);
}
}
}
}
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Host
{
internal interface IFileTracker : IDisposable
{
bool IsTracking(string filePath);
void Track(string filePath, Action onChanged);
void StopTracking(string filePath);
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.WorkspaceServices;
namespace Microsoft.CodeAnalysis.Host
{
internal interface IFileTrackingService : IWorkspaceService
{
IFileTracker CreateFileTracker();
}
}
\ No newline at end of file
......@@ -782,8 +782,6 @@
<Compile Include="Workspace\DocumentationComments\XmlDocumentationProvider.cs" />
<Compile Include="Workspace\DocumentEventArgs.cs" />
<Compile Include="Workspace\FileTextLoader.cs" />
<Compile Include="Workspace\Host\BackgroundCompilation\BackgroundCompiler.cs" />
<Compile Include="Workspace\Host\BackgroundParsing\BackgroundParser.cs" />
<Compile Include="Workspace\Host\Caching\CachedObjectSource.cs" />
<Compile Include="Workspace\Host\Caching\CacheId.cs" />
<Compile Include="Workspace\Host\Caching\CompilationCacheServiceFactory.cs" />
......@@ -798,9 +796,6 @@
<Compile Include="Workspace\Host\Caching\SyntaxTreeCacheServiceFactory.cs" />
<Compile Include="Workspace\Host\Caching\TextCacheServiceFactory.cs" />
<Compile Include="Workspace\Host\Caching\WeakAction.cs" />
<Compile Include="Workspace\Host\FileTracking\FileTrackingServiceFactory.cs" />
<Compile Include="Workspace\Host\FileTracking\IFileTracker.cs" />
<Compile Include="Workspace\Host\FileTracking\IFileTrackingService.cs" />
<Compile Include="Workspace\Host\Metadata\AssemblyShadowCopyProviderServiceFactory.cs" />
<Compile Include="Workspace\Host\Metadata\IMetadataReferenceProviderService.cs" />
<Compile Include="Workspace\Host\PersistentStorage\AbstractPersistentStorage.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册