Switch back to event from locks to fix blocking issues. (#111)

This commit is contained in:
Karl Burtram
2016-10-21 15:46:33 -07:00
committed by GitHub
parent b3d793dc85
commit 854a6a0eca
6 changed files with 34 additions and 25 deletions

View File

@@ -15,7 +15,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// Main class for the Binding Queue
/// </summary>
public class BindingQueue<T> where T : IBindingContext, new()
{
{
private CancellationTokenSource processQueueCancelToken = new CancellationTokenSource();
private ManualResetEvent itemQueuedEvent = new ManualResetEvent(initialState: false);
@@ -197,14 +197,18 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
// prefer the queue item binding item, otherwise use the context default timeout
int bindTimeout = queueItem.BindingTimeout ?? bindingContext.BindingTimeout;
// handle the case a previous binding operation is still running
if (!Monitor.TryEnter(bindingContext.BindingLock, bindTimeout))
// handle the case a previous binding operation is still running
if (!bindingContext.BindingLock.WaitOne(0))
{
queueItem.Result = queueItem.TimeoutOperation(bindingContext);
queueItem.ItemProcessed.Set();
queueItem.Result = queueItem.TimeoutOperation != null
? queueItem.TimeoutOperation(bindingContext)
: null;
continue;
}
bindingContext.BindingLock.Reset();
lockTaken = true;
// execute the binding operation
@@ -231,9 +235,10 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
queueItem.Result = queueItem.TimeoutOperation(bindingContext);
}
lockTaken = false;
// we'll need to wait for the task to finsh canceling otherwise future binding will fail
bindTask.Wait();
bindTask.ContinueWith((a) => bindingContext.BindingLock.Set());
}
}
catch (Exception ex)
@@ -246,7 +251,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
if (lockTaken)
{
Monitor.Exit(bindingContext.BindingLock);
bindingContext.BindingLock.Set();
}
queueItem.ItemProcessed.Set();

View File

@@ -4,6 +4,7 @@
//
using System;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
@@ -20,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
private ParseOptions parseOptions;
private object bindingLock;
private ManualResetEvent bindingLock;
private ServerConnection serverConnection;
@@ -29,7 +30,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary>
public ConnectedBindingContext()
{
this.bindingLock = new object();
this.bindingLock = new ManualResetEvent(initialState: true);
this.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout;
this.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
}
@@ -75,7 +76,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <summary>
/// Gets the binding lock object
/// </summary>
public object BindingLock
public ManualResetEvent BindingLock
{
get
{

View File

@@ -21,7 +21,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// </summary>
public class ConnectedBindingQueue : BindingQueue<ConnectedBindingContext>
{
internal const int DefaultBindingTimeout = 60000;
internal const int DefaultBindingTimeout = 500;
internal const int DefaultMinimumConnectionTimeout = 30;
@@ -63,10 +63,12 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
string connectionKey = GetConnectionContextKey(connInfo);
IBindingContext bindingContext = this.GetOrCreateBindingContext(connectionKey);
lock (bindingContext.BindingLock)
if (bindingContext.BindingLock.WaitOne())
{
try
{
bindingContext.BindingLock.Reset();
// increase the connection timeout to at least 30 seconds and and build connection string
// enable PersistSecurityInfo to handle issues in SMO where the connection context is lost in reconnections
int? originalTimeout = connInfo.ConnectionDetails.ConnectTimeout;
@@ -96,7 +98,11 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
catch (Exception)
{
bindingContext.IsConnected = false;
}
}
finally
{
bindingContext.BindingLock.Set();
}
}
return connectionKey;

View File

@@ -46,7 +46,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
/// <summary>
/// Gets the binding lock object
/// </summary>
object BindingLock { get; }
ManualResetEvent BindingLock { get; }
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds

View File

@@ -37,11 +37,9 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
internal const int DiagnosticParseDelay = 750;
internal const int HoverTimeout = 3000;
internal const int HoverTimeout = 500;
internal const int BindingTimeout = 3000;
internal const int FindCompletionStartTimeout = 50;
internal const int BindingTimeout = 500;
internal const int OnConnectionWaitTimeout = 300000;
@@ -252,7 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
await Task.FromResult(true);
}
else
{
{
// get the current list of completion items and return to client
var scriptFile = LanguageService.WorkspaceServiceInstance.Workspace.GetFile(
textDocumentPosition.TextDocument.Uri);
@@ -628,7 +626,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
ScriptParseInfo scriptParseInfo = GetScriptParseInfo(textDocumentPosition.TextDocument.Uri);
if (scriptParseInfo != null && scriptParseInfo.ParseResult != null)
{
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock, LanguageService.FindCompletionStartTimeout))
if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
{
try
{
@@ -711,8 +709,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
}
Token token = GetToken(scriptParseInfo, line, column);
if (scriptParseInfo.IsConnected
&& Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock, LanguageService.FindCompletionStartTimeout))
if (scriptParseInfo.IsConnected && Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock))
{
try
{