Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait until solution load before we kick off all our nuget work. #9663

Merged
merged 5 commits into from
May 17, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ internal static class ServiceComponentOnOffOptions

public static readonly Option<bool> DiagnosticProvider = new Option<bool>(OptionName, "Diagnostic Provider", defaultValue: true);

public static readonly Option<bool> PackageSearch = new Option<bool>(OptionName, nameof(PackageSearch), defaultValue: false);
public static readonly Option<bool> PackageSearch = new Option<bool>(OptionName, nameof(PackageSearch), defaultValue: true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ internal abstract class VisualStudioWorkspaceImpl : VisualStudioWorkspace

private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject();

private PackageInstallerService _packageInstallerService;
private PackageSearchService _packageSearchService;

public VisualStudioWorkspaceImpl(
SVsServiceProvider serviceProvider,
WorkspaceBackgroundWork backgroundWork)
Expand Down Expand Up @@ -108,11 +105,6 @@ protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider servic

// Ensure the options factory services are initialized on the UI thread
this.Services.GetService<IOptionService>();

// Ensure the nuget package services are initialized on the UI thread.
_packageSearchService = this.Services.GetService<IPackageSearchService>() as PackageSearchService;
_packageInstallerService = (PackageInstallerService)this.Services.GetService<IPackageInstallerService>();
_packageInstallerService.Connect(this);
}

/// <summary>NOTE: Call only from derived class constructor</summary>
Expand Down Expand Up @@ -1006,9 +998,6 @@ internal void StopSolutionCrawler()

protected override void Dispose(bool finalize)
{
_packageInstallerService?.Disconnect(this);
_packageSearchService?.Dispose();

// workspace is going away. unregister this workspace from work coordinator
StopSolutionCrawler();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Packaging;
Expand Down Expand Up @@ -41,13 +42,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging
internal partial class PackageInstallerService : ForegroundThreadAffinitizedObject, IPackageInstallerService, IVsSearchProviderCallback
{
private readonly object _gate = new object();
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService;

/// <summary>
/// The workspace we're connected to. When we're disconnected this will become 'null'.
/// That's our signal to stop working.
/// </summary>
private VisualStudioWorkspaceImpl _workspace;
private IVsPackageInstallerServices _packageInstallerServices;
private IVsPackageInstaller _packageInstaller;
private IVsPackageUninstaller _packageUninstaller;
Expand All @@ -66,34 +63,28 @@ internal partial class PackageInstallerService : ForegroundThreadAffinitizedObje

[ImportingConstructor]
public PackageInstallerService(
VisualStudioWorkspaceImpl workspace,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService)
{
_workspace = workspace;
_editorAdaptersFactoryService = editorAdaptersFactoryService;
}

public ImmutableArray<PackageSource> PackageSources { get; private set; } = ImmutableArray<PackageSource>.Empty;

public event EventHandler PackageSourcesChanged;

internal void Connect(VisualStudioWorkspaceImpl workspace)
internal void Start()
{
this.AssertIsForeground();

var options = workspace.Options;
var options = _workspace.Options;
if (!options.GetOption(ServiceComponentOnOffOptions.PackageSearch))
{
return;
}

ConnectWorker(workspace);
}

// Don't inline this method. The references to nuget types will cause the nuget packages
// to load.
[MethodImpl(MethodImplOptions.NoInlining)]
private void ConnectWorker(VisualStudioWorkspaceImpl workspace)
{
var componentModel = workspace.GetVsService<SComponentModel, IComponentModel>();
var componentModel = _workspace.GetVsService<SComponentModel, IComponentModel>();
_packageInstallerServices = componentModel.GetExtensions<IVsPackageInstallerServices>().FirstOrDefault();
_packageInstaller = componentModel.GetExtensions<IVsPackageInstaller>().FirstOrDefault();
_packageUninstaller = componentModel.GetExtensions<IVsPackageUninstaller>().FirstOrDefault();
Expand All @@ -105,7 +96,6 @@ private void ConnectWorker(VisualStudioWorkspaceImpl workspace)
}

// Start listening to workspace changes.
_workspace = workspace;
_workspace.WorkspaceChanged += OnWorkspaceChanged;
_packageSourceProvider.SourcesChanged += OnSourceProviderSourcesChanged;

Expand All @@ -118,7 +108,7 @@ private void ConnectWorker(VisualStudioWorkspaceImpl workspace)
_packageUninstaller != null &&
_packageSourceProvider != null;

internal void Disconnect(VisualStudioWorkspaceImpl workspace)
internal void Stop()
{
this.AssertIsForeground();

Expand All @@ -127,11 +117,8 @@ internal void Disconnect(VisualStudioWorkspaceImpl workspace)
return;
}

Debug.Assert(workspace == _workspace);
_packageSourceProvider.SourcesChanged -= OnSourceProviderSourcesChanged;
_workspace.WorkspaceChanged -= OnWorkspaceChanged;

_workspace = null;
}

private void OnSourceProviderSourcesChanged(object sender, EventArgs e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,6 @@ internal partial class PackageSearchService
private readonly IPackageSearchDatabaseFactoryService _databaseFactoryService;
private readonly Func<Exception, bool> _reportAndSwallowException;

public void Dispose()
{
// Cancel any existing work.
_cancellationTokenSource.Cancel();
}

private void LogInfo(string text) => _logService.LogInfo(text);

private void LogException(Exception e, string text) => _logService.LogException(e, text);
Expand Down
74 changes: 54 additions & 20 deletions src/VisualStudio/Core/Def/Packaging/PackageSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Elfie.Model;
using Microsoft.CodeAnalysis.Elfie.Model.Structures;
using Microsoft.CodeAnalysis.Elfie.Model.Tree;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.Internal.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Settings;
Expand All @@ -29,12 +32,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging
/// This implementation also spawns a task which will attempt to keep that database up to
/// date by downloading patches on a daily basis.
/// </summary>
internal partial class PackageSearchService : ForegroundThreadAffinitizedObject, IPackageSearchService, IDisposable
[ExportWorkspaceService(typeof(IPackageSearchService)), Shared]
internal partial class PackageSearchService : ForegroundThreadAffinitizedObject, IPackageSearchService
{
private ConcurrentDictionary<string, AddReferenceDatabase> _sourceToDatabase = new ConcurrentDictionary<string, AddReferenceDatabase>();
private readonly VisualStudioWorkspaceImpl _workspace;
private readonly ConcurrentDictionary<string, AddReferenceDatabase> _sourceToDatabase = new ConcurrentDictionary<string, AddReferenceDatabase>();

public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackageInstallerService installerService)
: this(installerService,
private bool _started;

[ImportingConstructor]
public PackageSearchService(
VisualStudioWorkspaceImpl workspace,
VSShell.SVsServiceProvider serviceProvider)
: this(workspace.Services.GetService<IPackageInstallerService>(),
CreateRemoteControlService(serviceProvider),
new LogService((IVsActivityLog)serviceProvider.GetService(typeof(SVsActivityLog))),
new DelayService(),
Expand All @@ -46,20 +56,7 @@ public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackage
FatalError.ReportWithoutCrash,
new CancellationTokenSource())
{
installerService.PackageSourcesChanged += OnPackageSourcesChanged;
OnPackageSourcesChanged(this, EventArgs.Empty);
}

private static IPackageSearchRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider)
{
var vsService = serviceProvider.GetService(typeof(SVsRemoteControlService));
if (vsService == null)
{
// If we can't access the file update service, then there's nothing we can do.
return null;
}

return new RemoteControlService(vsService);
_workspace = workspace;
}

/// <summary>
Expand Down Expand Up @@ -94,12 +91,49 @@ internal PackageSearchService(

_cacheDirectoryInfo = new DirectoryInfo(Path.Combine(
localSettingsDirectory, "PackageCache", string.Format(Invariant($"Format{_dataFormatVersion}"))));
// _databaseFileInfo = new FileInfo(Path.Combine(_cacheDirectoryInfo.FullName, "NuGetCache.txt"));

_cancellationTokenSource = cancellationTokenSource;
_cancellationToken = _cancellationTokenSource.Token;
}

internal void Start()
{
var options = _workspace.Options;
if (!options.GetOption(ServiceComponentOnOffOptions.PackageSearch))
{
return;
}

// Start the whole process once we're connected
_installerService.PackageSourcesChanged += OnPackageSourcesChanged;
OnPackageSourcesChanged(this, EventArgs.Empty);
_started = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this happen before the call to OnPackageSourcesChanged in case anything in that method looks at it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, i just realized this isn't even necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. Scratch that. Still necessary.

This boolean is just so we know if we've actually done the event hookup. That way we know if we should disconnect on 'Stop' down below. Where it comes here shouldn't really matter.

}

internal void Stop()
{
if (!_started)
{
return;
}

_installerService.PackageSourcesChanged -= OnPackageSourcesChanged;
// Cancel any existing work.
_cancellationTokenSource.Cancel();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should _started be reset to false?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. This type is a single "start -> stop" type. It's not restartable. _started coudl be renamed to "hasStartBeenCalled" to better convey that it's just to let us know if we're stopping after the initial start was called.

}

private static IPackageSearchRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider)
{
var vsService = serviceProvider.GetService(typeof(SVsRemoteControlService));
if (vsService == null)
{
// If we can't access the file update service, then there's nothing we can do.
return null;
}

return new RemoteControlService(vsService);
}

public IEnumerable<PackageWithTypeResult> FindPackagesWithType(
string source, string name, int arity, CancellationToken cancellationToken)
{
Expand Down
52 changes: 0 additions & 52 deletions src/VisualStudio/Core/Def/Packaging/PackageSearchServiceFactory.cs

This file was deleted.

16 changes: 16 additions & 0 deletions src/VisualStudio/Core/Def/RoslynPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
using Task = System.Threading.Tasks.Task;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interactive;
using static Microsoft.CodeAnalysis.Utilities.ForegroundThreadDataKind;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.VisualStudio.LanguageServices.Packaging;

namespace Microsoft.VisualStudio.LanguageServices.Setup
{
Expand All @@ -40,6 +42,9 @@ internal class RoslynPackage : Package
private RuleSetEventHandler _ruleSetEventHandler;
private IDisposable _solutionEventMonitor;

private PackageInstallerService _packageInstallerService;
private PackageSearchService _packageSearchService;

protected override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -161,6 +166,14 @@ private void LoadComponents()

LoadAnalyzerNodeComponents();

// Ensure the nuget package services are initialized after we've loaded
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new MEF import will be also perf impacting thing for solution open.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, sorry, git collapsed region and it looked like code belong to initialize.

if possible, importing and running from background thread will be even better.

// the solution.
_packageInstallerService = _workspace.Services.GetService<IPackageInstallerService>() as PackageInstallerService;
_packageSearchService = _workspace.Services.GetService<IPackageSearchService>() as PackageSearchService;

_packageInstallerService?.Start();
_packageSearchService?.Start();

Task.Run(() => LoadComponentsBackground());
}

Expand Down Expand Up @@ -202,6 +215,9 @@ internal IComponentModel ComponentModel

protected override void Dispose(bool disposing)
{
_packageInstallerService?.Stop();
_packageSearchService?.Stop();

UnregisterFindResultsLibraryManager();

DisposeVisualStudioDocumentTrackingService();
Expand Down
1 change: 0 additions & 1 deletion src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@
<Compile Include="Packaging\PackageSearchService.IOService.cs" />
<Compile Include="Packaging\PackageSearchService.LogService.cs" />
<Compile Include="Packaging\PackageSearchService.RemoteControlService.cs" />
<Compile Include="Packaging\PackageSearchServiceFactory.cs" />
<Compile Include="Packaging\Patching\Delta.cs" />
<Compile Include="RoslynPackage.cs" />
<Compile Include="ServicesVSResources.Designer.cs">
Expand Down