Clear and rebuild IntelliSense cache (#238)

* Stage changes to other machine

* IntelliSense cache rebuild command

* Move to other machine

* Add a test for overwriting binding queue.

* Move event handler into lanaguageservice.cs
This commit is contained in:
Karl Burtram
2017-02-16 12:23:26 -08:00
committed by GitHub
parent 6f8fc51d6f
commit 5d0c187684
8 changed files with 148 additions and 8 deletions

View File

@@ -123,6 +123,28 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
}
}
/// <summary>
/// Remove the binding queue entry
/// </summary>
protected void RemoveBindingContext(string key)
{
lock (this.bindingContextLock)
{
if (this.BindingContextMap.ContainsKey(key))
{
// disconnect existing connection
var bindingContext = this.BindingContextMap[key];
if (bindingContext.ServerConnection != null && bindingContext.ServerConnection.IsOpen)
{
bindingContext.ServerConnection.Disconnect();
}
// remove key from the map
this.BindingContextMap.Remove(key);
}
}
}
private bool HasPendingQueueItems
{
get

View File

@@ -51,8 +51,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <summary>
/// Use a ConnectionInfo item to create a connected binding context
/// </summary>
/// <param name="connInfo"></param>
public virtual string AddConnectionContext(ConnectionInfo connInfo)
/// <param name="connInfo">Connection info used to create binding context</param>
/// <param name="overwrite">Overwrite existing context</param>
public virtual string AddConnectionContext(ConnectionInfo connInfo, bool overwrite = false)
{
if (connInfo == null)
{
@@ -63,8 +64,15 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
string connectionKey = GetConnectionContextKey(connInfo);
if (BindingContextExists(connectionKey))
{
// no need to populate the context again since the context already exists
return connectionKey;
if (overwrite)
{
RemoveBindingContext(connectionKey);
}
else
{
// no need to populate the context again since the context already exists
return connectionKey;
}
}
IBindingContext bindingContext = this.GetOrCreateBindingContext(connectionKey);

View File

@@ -0,0 +1,30 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices.Contracts
{
/// <summary>
/// Parameters to be sent back with a rebuild IntelliSense event
/// </summary>
public class RebuildIntelliSenseParams
{
/// <summary>
/// URI identifying the file that should have its IntelliSense cache rebuilt
/// </summary>
public string OwnerUri { get; set; }
}
/// <summary>
/// RebuildIntelliSenseNotification notification mapping entry
/// </summary>
public class RebuildIntelliSenseNotification
{
public static readonly
EventType<RebuildIntelliSenseParams> Type =
EventType<RebuildIntelliSenseParams>.Create("textDocument/rebuildIntelliSense");
}
}

View File

@@ -212,6 +212,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
serviceHost.SetRequestHandler(HoverRequest.Type, HandleHoverRequest);
serviceHost.SetRequestHandler(CompletionRequest.Type, HandleCompletionRequest);
serviceHost.SetRequestHandler(DefinitionRequest.Type, HandleDefinitionRequest);
serviceHost.SetEventHandler(RebuildIntelliSenseNotification.Type, HandleRebuildIntelliSenseNotification);
// Register a no-op shutdown task for validation of the shutdown logic
serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) =>
@@ -442,6 +443,62 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
await Task.FromResult(true);
}
/// <summary>
/// Handle the rebuild IntelliSense cache notification
/// </summary>
public async Task HandleRebuildIntelliSenseNotification(
RebuildIntelliSenseParams configChangeParams,
EventContext eventContext)
{
Logger.Write(LogLevel.Verbose, "HandleRebuildIntelliSenseNotification");
// Skip closing this file if the file doesn't exist
var scriptFile = this.CurrentWorkspace.GetFile(configChangeParams.OwnerUri);
if (scriptFile == null)
{
return;
}
ConnectionInfo connInfo;
LanguageService.ConnectionServiceInstance.TryFindConnection(
scriptFile.ClientFilePath,
out connInfo);
await Task.Run(() =>
{
ScriptParseInfo scriptInfo = GetScriptParseInfo(connInfo.OwnerUri, createIfNotExists: false);
if (scriptInfo != null && scriptInfo.IsConnected &&
Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout))
{
try
{
this.BindingQueue.AddConnectionContext(connInfo, overwrite: true);
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error, "Unknown error " + ex.ToString());
}
finally
{
// Set Metadata Build event to Signal state.
Monitor.Exit(scriptInfo.BuildingMetadataLock);
}
}
// if not in the preview window and diagnostics are enabled then run diagnostics
if (!IsPreviewWindow(scriptFile)
&& WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings.IsDiagnositicsEnabled)
{
RunScriptDiagnostics(
new ScriptFile[] { scriptFile },
eventContext);
}
// Send a notification to signal that autocomplete is ready
ServiceHost.Instance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri});
});
}
/// <summary>
/// Handle the file configuration change notification
/// </summary>

View File

@@ -112,6 +112,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
/// List of callbacks to call when a text document is closed
/// </summary>
private List<TextDocCloseCallback> TextDocCloseCallbacks { get; set; }
#endregion
@@ -189,7 +190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
public void RegisterTextDocOpenCallback(TextDocOpenCallback task)
{
TextDocOpenCallbacks.Add(task);
}
}
#endregion
@@ -287,7 +288,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Workspace
var configUpdateTasks = ConfigChangeCallbacks.Select(
t => t(configChangeParams.Settings, CurrentSettings, eventContext));
await Task.WhenAll(configUpdateTasks);
}
}
#endregion

View File

@@ -135,5 +135,27 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.LanguageServer
SignatureHelp signatureHelp = service.GetSignatureHelp(textDocument, result.ScriptFile);
Assert.NotNull(signatureHelp);
}
/// <summary>
/// Test overwriting the binding queue context
/// </summary>
[Fact]
public void OverwriteBindingContext()
{
var result = TestObjects.InitLiveConnectionInfo();
// add a new connection context
var connectionKey = LanguageService.Instance.BindingQueue.AddConnectionContext(result.ConnectionInfo, overwrite: true);
Assert.True(LanguageService.Instance.BindingQueue.BindingContextMap.ContainsKey(connectionKey));
// cache the server connection
var orgServerConnection = LanguageService.Instance.BindingQueue.BindingContextMap[connectionKey].ServerConnection;
Assert.NotNull(orgServerConnection);
// add a new connection context
connectionKey = LanguageService.Instance.BindingQueue.AddConnectionContext(result.ConnectionInfo, overwrite: true);
Assert.True(LanguageService.Instance.BindingQueue.BindingContextMap.ContainsKey(connectionKey));
Assert.False(object.ReferenceEquals(LanguageService.Instance.BindingQueue.BindingContextMap[connectionKey].ServerConnection, orgServerConnection));
}
}
}

View File

@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
// setup binding queue mock
bindingQueue = new Mock<ConnectedBindingQueue>();
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>()))
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>(), It.IsAny<bool>()))
.Returns(this.testConnectionKey);
// inject mock instances into the Language Service

View File

@@ -82,7 +82,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.LanguageServices
// setup binding queue mock
bindingQueue = new Mock<ConnectedBindingQueue>();
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>()))
bindingQueue.Setup(q => q.AddConnectionContext(It.IsAny<ConnectionInfo>(), It.IsAny<bool>()))
.Returns(this.testConnectionKey);
// inject mock instances into the Language Service