Move unused forked code to external directory (#1192)

* Move unused forked code to external directory

* Fix SLN build errors

* Add back resource provider core since it's referenced by main resource provider project

* Update PackageProjects step of pipeline
This commit is contained in:
Karl Burtram
2021-04-16 15:33:35 -07:00
committed by GitHub
parent dc6555a823
commit ccf95aed77
229 changed files with 10058 additions and 10124 deletions

View File

@@ -0,0 +1,429 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.SqlTools.Hosting.Utility;
using System.Diagnostics;
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
/// <summary>
/// Main class for the Binding Queue
/// </summary>
public class BindingQueue<T> : IDisposable where T : IBindingContext, new()
{
internal const int QueueThreadStackSize = 5 * 1024 * 1024;
private CancellationTokenSource processQueueCancelToken = null;
private ManualResetEvent itemQueuedEvent = new ManualResetEvent(initialState: false);
private object bindingQueueLock = new object();
private LinkedList<QueueItem> bindingQueue = new LinkedList<QueueItem>();
private object bindingContextLock = new object();
private Task queueProcessorTask;
/// <summary>
/// Map from context keys to binding context instances
/// Internal for testing purposes only
/// </summary>
internal Dictionary<string, IBindingContext> BindingContextMap { get; set; }
/// <summary>
/// Constructor for a binding queue instance
/// </summary>
public BindingQueue()
{
this.BindingContextMap = new Dictionary<string, IBindingContext>();
this.StartQueueProcessor();
}
public void StartQueueProcessor()
{
this.queueProcessorTask = StartQueueProcessorAsync();
}
/// <summary>
/// Stops the binding queue by sending cancellation request
/// </summary>
/// <param name="timeout"></param>
public bool StopQueueProcessor(int timeout)
{
this.processQueueCancelToken.Cancel();
return this.queueProcessorTask.Wait(timeout);
}
/// <summary>
/// Returns true if cancellation is requested
/// </summary>
/// <returns></returns>
public bool IsCancelRequested
{
get
{
return this.processQueueCancelToken.IsCancellationRequested;
}
}
/// <summary>
/// Queue a binding request item
/// </summary>
public virtual QueueItem QueueBindingOperation(
string key,
Func<IBindingContext, CancellationToken, object> bindOperation,
Func<IBindingContext, object> timeoutOperation = null,
Func<Exception, object> errorHandler = null,
int? bindingTimeout = null,
int? waitForLockTimeout = null)
{
// don't add null operations to the binding queue
if (bindOperation == null)
{
return null;
}
QueueItem queueItem = new QueueItem()
{
Key = key,
BindOperation = bindOperation,
TimeoutOperation = timeoutOperation,
ErrorHandler = errorHandler,
BindingTimeout = bindingTimeout,
WaitForLockTimeout = waitForLockTimeout
};
lock (this.bindingQueueLock)
{
this.bindingQueue.AddLast(queueItem);
}
this.itemQueuedEvent.Set();
return queueItem;
}
/// <summary>
/// Checks if a particular binding context is connected or not
/// </summary>
/// <param name="key"></param>
public bool IsBindingContextConnected(string key)
{
lock (this.bindingContextLock)
{
IBindingContext context;
if (this.BindingContextMap.TryGetValue(key, out context))
{
return context.IsConnected;
}
return false;
}
}
/// <summary>
/// Gets or creates a binding context for the provided context key
/// </summary>
/// <param name="key"></param>
protected IBindingContext GetOrCreateBindingContext(string key)
{
// use a default binding context for disconnected requests
if (string.IsNullOrWhiteSpace(key))
{
key = "disconnected_binding_context";
}
lock (this.bindingContextLock)
{
if (!this.BindingContextMap.ContainsKey(key))
{
this.BindingContextMap.Add(key, new T());
}
return this.BindingContextMap[key];
}
}
protected IEnumerable<IBindingContext> GetBindingContexts(string keyPrefix)
{
// use a default binding context for disconnected requests
if (string.IsNullOrWhiteSpace(keyPrefix))
{
keyPrefix = "disconnected_binding_context";
}
lock (this.bindingContextLock)
{
return this.BindingContextMap.Where(x => x.Key.StartsWith(keyPrefix)).Select(v => v.Value);
}
}
/// <summary>
/// Checks if a binding context already exists for the provided context key
/// </summary>
protected bool BindingContextExists(string key)
{
lock (this.bindingContextLock)
{
return this.BindingContextMap.ContainsKey(key);
}
}
/// <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);
}
}
}
public bool HasPendingQueueItems
{
get
{
lock (this.bindingQueueLock)
{
return this.bindingQueue.Count > 0;
}
}
}
/// <summary>
/// Gets the next pending queue item
/// </summary>
private QueueItem GetNextQueueItem()
{
lock (this.bindingQueueLock)
{
if (this.bindingQueue.Count == 0)
{
return null;
}
QueueItem queueItem = this.bindingQueue.First.Value;
this.bindingQueue.RemoveFirst();
return queueItem;
}
}
/// <summary>
/// Starts the queue processing thread
/// </summary>
private Task StartQueueProcessorAsync()
{
if (this.processQueueCancelToken != null)
{
this.processQueueCancelToken.Dispose();
}
this.processQueueCancelToken = new CancellationTokenSource();
return Task.Factory.StartNew(
ProcessQueue,
this.processQueueCancelToken.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
/// <summary>
/// The core queue processing method
/// </summary>
/// <param name="state"></param>
private void ProcessQueue()
{
CancellationToken token = this.processQueueCancelToken.Token;
WaitHandle[] waitHandles = new WaitHandle[2]
{
this.itemQueuedEvent,
token.WaitHandle
};
while (true)
{
// wait for with an item to be queued or the a cancellation request
WaitHandle.WaitAny(waitHandles);
if (token.IsCancellationRequested)
{
break;
}
try
{
// dispatch all pending queue items
while (this.HasPendingQueueItems)
{
QueueItem queueItem = GetNextQueueItem();
if (queueItem == null)
{
continue;
}
IBindingContext bindingContext = GetOrCreateBindingContext(queueItem.Key);
if (bindingContext == null)
{
queueItem.ItemProcessed.Set();
continue;
}
bool lockTaken = false;
try
{
// 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 (!bindingContext.BindingLock.WaitOne(queueItem.WaitForLockTimeout ?? 0))
{
queueItem.Result = queueItem.TimeoutOperation != null
? queueItem.TimeoutOperation(bindingContext)
: null;
continue;
}
bindingContext.BindingLock.Reset();
lockTaken = true;
// execute the binding operation
object result = null;
CancellationTokenSource cancelToken = new CancellationTokenSource();
// run the operation in a separate thread
var bindTask = Task.Run(() =>
{
try
{
result = queueItem.BindOperation(
bindingContext,
cancelToken.Token);
}
catch (Exception ex)
{
Logger.Write(TraceEventType.Error, "Unexpected exception on the binding queue: " + ex.ToString());
if (queueItem.ErrorHandler != null)
{
result = queueItem.ErrorHandler(ex);
}
}
});
// check if the binding tasks completed within the binding timeout
if (bindTask.Wait(bindTimeout))
{
queueItem.Result = result;
}
else
{
cancelToken.Cancel();
// if the task didn't complete then call the timeout callback
if (queueItem.TimeoutOperation != null)
{
queueItem.Result = queueItem.TimeoutOperation(bindingContext);
}
lockTaken = false;
bindTask
.ContinueWith((a) => bindingContext.BindingLock.Set())
.ContinueWithOnFaulted(t => Logger.Write(TraceEventType.Error, "Binding queue threw exception " + t.Exception.ToString()));
}
}
catch (Exception ex)
{
// catch and log any exceptions raised in the binding calls
// set item processed to avoid deadlocks
Logger.Write(TraceEventType.Error, "Binding queue threw exception " + ex.ToString());
}
finally
{
if (lockTaken)
{
bindingContext.BindingLock.Set();
}
queueItem.ItemProcessed.Set();
}
// if a queue processing cancellation was requested then exit the loop
if (token.IsCancellationRequested)
{
break;
}
}
}
finally
{
lock (this.bindingQueueLock)
{
// verify the binding queue is still empty
if (this.bindingQueue.Count == 0)
{
// reset the item queued event since we've processed all the pending items
this.itemQueuedEvent.Reset();
}
}
}
}
}
/// <summary>
/// Clear queued items
/// </summary>
public void ClearQueuedItems()
{
lock (this.bindingQueueLock)
{
if (this.bindingQueue.Count > 0)
{
this.bindingQueue.Clear();
}
}
}
public void Dispose()
{
if (this.processQueueCancelToken != null)
{
this.processQueueCancelToken.Dispose();
}
if (itemQueuedEvent != null)
{
itemQueuedEvent.Dispose();
}
if (this.BindingContextMap != null)
{
foreach (var item in this.BindingContextMap)
{
if (item.Value != null && item.Value.ServerConnection != null && item.Value.ServerConnection.SqlConnectionObject != null)
{
item.Value.ServerConnection.SqlConnectionObject.Close();
}
}
}
}
}
}

View File

@@ -0,0 +1,217 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Common;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
using Microsoft.SqlTools.CoreServices.Utility;
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
/// <summary>
/// Class for the binding context for connected sessions
/// </summary>
public class ConnectedBindingContext : IBindingContext
{
private ParseOptions parseOptions;
private ManualResetEvent bindingLock;
private ServerConnection serverConnection;
/// <summary>
/// Connected binding context constructor
/// </summary>
public ConnectedBindingContext()
{
this.bindingLock = new ManualResetEvent(initialState: true);
this.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout;
this.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
}
/// <summary>
/// Gets or sets a flag indicating if the binder is connected
/// </summary>
public bool IsConnected { get; set; }
/// <summary>
/// Gets or sets the binding server connection
/// </summary>
public ServerConnection ServerConnection
{
get
{
return this.serverConnection;
}
set
{
this.serverConnection = value;
// reset the parse options so the get recreated for the current connection
this.parseOptions = null;
}
}
/// <summary>
/// Gets or sets the metadata display info provider
/// </summary>
public MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
/// <summary>
/// Gets or sets the SMO metadata provider
/// </summary>
public SmoMetadataProvider SmoMetadataProvider { get; set; }
/// <summary>
/// Gets or sets the binder
/// </summary>
public IBinder Binder { get; set; }
/// <summary>
/// Gets the binding lock object
/// </summary>
public ManualResetEvent BindingLock
{
get
{
return this.bindingLock;
}
}
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
public int BindingTimeout { get; set; }
/// <summary>
/// Gets the Language Service ServerVersion
/// </summary>
public ServerVersion ServerVersion
{
get
{
return this.ServerConnection != null
? this.ServerConnection.ServerVersion
: null;
}
}
/// <summary>
/// Gets the current DataEngineType
/// </summary>
public DatabaseEngineType DatabaseEngineType
{
get
{
return this.ServerConnection != null
? this.ServerConnection.DatabaseEngineType
: DatabaseEngineType.Standalone;
}
}
/// <summary>
/// Gets the current connections TransactSqlVersion
/// </summary>
public TransactSqlVersion TransactSqlVersion
{
get
{
return this.IsConnected
? GetTransactSqlVersion(this.ServerVersion)
: TransactSqlVersion.Current;
}
}
/// <summary>
/// Gets the current DatabaseCompatibilityLevel
/// </summary>
public DatabaseCompatibilityLevel DatabaseCompatibilityLevel
{
get
{
return this.IsConnected
? GetDatabaseCompatibilityLevel(this.ServerVersion)
: DatabaseCompatibilityLevel.Current;
}
}
/// <summary>
/// Gets the current ParseOptions
/// </summary>
public ParseOptions ParseOptions
{
get
{
if (this.parseOptions == null)
{
this.parseOptions = new ParseOptions(
batchSeparator: CommonConstants.DefaultBatchSeperator,
isQuotedIdentifierSet: true,
compatibilityLevel: DatabaseCompatibilityLevel,
transactSqlVersion: TransactSqlVersion);
}
return this.parseOptions;
}
}
/// <summary>
/// Gets the database compatibility level from a server version
/// </summary>
/// <param name="serverVersion"></param>
private static DatabaseCompatibilityLevel GetDatabaseCompatibilityLevel(ServerVersion serverVersion)
{
int versionMajor = Math.Max(serverVersion.Major, 8);
switch (versionMajor)
{
case 8:
return DatabaseCompatibilityLevel.Version80;
case 9:
return DatabaseCompatibilityLevel.Version90;
case 10:
return DatabaseCompatibilityLevel.Version100;
case 11:
return DatabaseCompatibilityLevel.Version110;
case 12:
return DatabaseCompatibilityLevel.Version120;
case 13:
return DatabaseCompatibilityLevel.Version130;
default:
return DatabaseCompatibilityLevel.Current;
}
}
/// <summary>
/// Gets the transaction sql version from a server version
/// </summary>
/// <param name="serverVersion"></param>
private static TransactSqlVersion GetTransactSqlVersion(ServerVersion serverVersion)
{
int versionMajor = Math.Max(serverVersion.Major, 9);
switch (versionMajor)
{
case 9:
case 10:
// In case of 10.0 we still use Version 10.5 as it is the closest available.
return TransactSqlVersion.Version105;
case 11:
return TransactSqlVersion.Version110;
case 12:
return TransactSqlVersion.Version120;
case 13:
return TransactSqlVersion.Version130;
default:
return TransactSqlVersion.Current;
}
}
}
}

View File

@@ -0,0 +1,231 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using Microsoft.Data.SqlClient;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlTools.CoreServices.Connection;
using Microsoft.SqlTools.DataProtocol.Contracts.Connection;
using System.Threading;
using Microsoft.SqlTools.CoreServices.Workspace;
using Microsoft.SqlTools.CoreServices.SqlContext;
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
public interface IConnectedBindingQueue
{
void CloseConnections(string serverName, string databaseName, int millisecondsTimeout);
void OpenConnections(string serverName, string databaseName, int millisecondsTimeout);
string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false);
void Dispose();
QueueItem QueueBindingOperation(
string key,
Func<IBindingContext, CancellationToken, object> bindOperation,
Func<IBindingContext, object> timeoutOperation = null,
Func<Exception, object> errorHandler = null,
int? bindingTimeout = null,
int? waitForLockTimeout = null);
}
public class SqlConnectionOpener
{
/// <summary>
/// Virtual method used to support mocking and testing
/// </summary>
public virtual SqlConnection OpenSqlConnection(ConnectionInfo connInfo, string featureName)
{
return ConnectionServiceCore.OpenSqlConnection(connInfo, featureName);
}
}
/// <summary>
/// ConnectedBindingQueue class for processing online binding requests
/// </summary>
public class ConnectedBindingQueue : BindingQueue<ConnectedBindingContext>, IConnectedBindingQueue
{
internal const int DefaultBindingTimeout = 500;
internal const int DefaultMinimumConnectionTimeout = 30;
/// <summary>
/// flag determing if the connection queue requires online metadata objects
/// it's much cheaper to not construct these objects if not needed
/// </summary>
private bool needsMetadata;
private SqlConnectionOpener connectionOpener;
/// <summary>
/// Gets the current settings
/// </summary>
internal SqlToolsSettings CurrentSettings
{
get { return SettingsService<SqlToolsSettings>.Instance.CurrentSettings; }
}
public ConnectedBindingQueue()
: this(true)
{
}
public ConnectedBindingQueue(bool needsMetadata)
{
this.needsMetadata = needsMetadata;
this.connectionOpener = new SqlConnectionOpener();
}
// For testing purposes only
internal void SetConnectionOpener(SqlConnectionOpener opener)
{
this.connectionOpener = opener;
}
/// <summary>
/// Generate a unique key based on the ConnectionInfo object
/// </summary>
/// <param name="connInfo"></param>
private string GetConnectionContextKey(ConnectionInfo connInfo)
{
ConnectionDetails details = connInfo.ConnectionDetails;
string key = string.Format("{0}_{1}_{2}_{3}",
details.ServerName ?? "NULL",
details.DatabaseName ?? "NULL",
details.UserName ?? "NULL",
details.AuthenticationType ?? "NULL"
);
if (!string.IsNullOrEmpty(details.DatabaseDisplayName))
{
key += "_" + details.DatabaseDisplayName;
}
if (!string.IsNullOrEmpty(details.GroupId))
{
key += "_" + details.GroupId;
}
return key;
}
/// <summary>
/// Generate a unique key based on the ConnectionInfo object
/// </summary>
/// <param name="connInfo"></param>
private string GetConnectionContextKey(string serverName, string databaseName)
{
return string.Format("{0}_{1}",
serverName ?? "NULL",
databaseName ?? "NULL");
}
public void CloseConnections(string serverName, string databaseName, int millisecondsTimeout)
{
string connectionKey = GetConnectionContextKey(serverName, databaseName);
var contexts = GetBindingContexts(connectionKey);
foreach (var bindingContext in contexts)
{
if (bindingContext.BindingLock.WaitOne(millisecondsTimeout))
{
bindingContext.ServerConnection.Disconnect();
}
}
}
public void OpenConnections(string serverName, string databaseName, int millisecondsTimeout)
{
string connectionKey = GetConnectionContextKey(serverName, databaseName);
var contexts = GetBindingContexts(connectionKey);
foreach (var bindingContext in contexts)
{
if (bindingContext.BindingLock.WaitOne(millisecondsTimeout))
{
try
{
bindingContext.ServerConnection.Connect();
}
catch
{
//TODO: remove the binding context?
}
}
}
}
public void RemoveBindingContext(ConnectionInfo connInfo)
{
string connectionKey = GetConnectionContextKey(connInfo);
if (BindingContextExists(connectionKey))
{
RemoveBindingContext(connectionKey);
}
}
/// <summary>
/// Use a ConnectionInfo item to create a connected binding context
/// </summary>
/// <param name="connInfo">Connection info used to create binding context</param>
/// <param name="overwrite">Overwrite existing context</param>
public virtual string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false)
{
if (connInfo == null)
{
return string.Empty;
}
// lookup the current binding context
string connectionKey = GetConnectionContextKey(connInfo);
if (BindingContextExists(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);
if (bindingContext.BindingLock.WaitOne())
{
try
{
bindingContext.BindingLock.Reset();
SqlConnection sqlConn = connectionOpener.OpenSqlConnection(connInfo, featureName);
// populate the binding context to work with the SMO metadata provider
bindingContext.ServerConnection = new ServerConnection(sqlConn);
if (this.needsMetadata)
{
bindingContext.SmoMetadataProvider = SmoMetadataProvider.CreateConnectedProvider(bindingContext.ServerConnection);
bindingContext.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider();
bindingContext.MetadataDisplayInfoProvider.BuiltInCasing =
this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value
? CasingStyle.Lowercase : CasingStyle.Uppercase;
bindingContext.Binder = BinderProvider.CreateBinder(bindingContext.SmoMetadataProvider);
}
bindingContext.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout;
bindingContext.IsConnected = true;
}
catch (Exception)
{
bindingContext.IsConnected = false;
}
finally
{
bindingContext.BindingLock.Set();
}
}
return connectionKey;
}
}
}

View File

@@ -0,0 +1,81 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Threading;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.SmoMetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlServer.Management.SqlParser.Common;
using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlServer.Management.SqlParser.Parser;
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
/// <summary>
/// The context used for binding requests
/// </summary>
public interface IBindingContext
{
/// <summary>
/// Gets or sets a flag indicating if the context is connected
/// </summary>
bool IsConnected { get; set; }
/// <summary>
/// Gets or sets the binding server connection
/// </summary>
ServerConnection ServerConnection { get; set; }
/// <summary>
/// Gets or sets the metadata display info provider
/// </summary>
MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; }
/// <summary>
/// Gets or sets the SMO metadata provider
/// </summary>
SmoMetadataProvider SmoMetadataProvider { get; set; }
/// <summary>
/// Gets or sets the binder
/// </summary>
IBinder Binder { get; set; }
/// <summary>
/// Gets the binding lock object
/// </summary>
ManualResetEvent BindingLock { get; }
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
int BindingTimeout { get; set; }
/// <summary>
/// Gets or sets the current connection parse options
/// </summary>
ParseOptions ParseOptions { get; }
/// <summary>
/// Gets or sets the current connection server version
/// </summary>
ServerVersion ServerVersion { get; }
/// <summary>
/// Gets or sets the database engine type
/// </summary>
DatabaseEngineType DatabaseEngineType { get; }
/// <summary>
/// Gets or sets the T-SQL version
/// </summary>
TransactSqlVersion TransactSqlVersion { get; }
/// <summary>
/// Gets or sets the database compatibility level
/// </summary>
DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; }
}
}

View File

@@ -0,0 +1,22 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
public static class LanguageContants {
private const int OneSecond = 1000;
internal const int DiagnosticParseDelay = 750;
internal const int HoverTimeout = 500;
internal const int BindingTimeout = 500;
internal const int OnConnectionWaitTimeout = 300 * OneSecond;
internal const int PeekDefinitionTimeout = 10 * OneSecond;
}
}

View File

@@ -0,0 +1,77 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Threading;
namespace Microsoft.SqlTools.CoreServices.LanguageServices
{
/// <summary>
/// Class that stores the state of a binding queue request item
/// </summary>
public class QueueItem
{
/// <summary>
/// QueueItem constructor
/// </summary>
public QueueItem()
{
this.ItemProcessed = new ManualResetEvent(initialState: false);
}
/// <summary>
/// Gets or sets the queue item key
/// </summary>
public string Key { get; set; }
/// <summary>
/// Gets or sets the bind operation callback method
/// </summary>
public Func<IBindingContext, CancellationToken, object> BindOperation { get; set; }
/// <summary>
/// Gets or sets the timeout operation to call if the bind operation doesn't finish within timeout period
/// </summary>
public Func<IBindingContext, object> TimeoutOperation { get; set; }
/// <summary>
/// Gets or sets the operation to call if the bind operation encounters an unexpected exception.
/// Supports returning an object in case of the exception occurring since in some cases we need to be
/// tolerant of error cases and still return some value
/// </summary>
public Func<Exception, object> ErrorHandler { get; set; }
/// <summary>
/// Gets or sets an event to signal when this queue item has been processed
/// </summary>
public virtual ManualResetEvent ItemProcessed { get; set; }
/// <summary>
/// Gets or sets the result of the queued task
/// </summary>
public object Result { get; set; }
/// <summary>
/// Gets or sets the binding operation timeout in milliseconds
/// </summary>
public int? BindingTimeout { get; set; }
/// <summary>
/// Gets or sets the timeout for how long to wait for the binding lock
/// </summary>
public int? WaitForLockTimeout { get; set; }
/// <summary>
/// Converts the result of the execution to type T
/// </summary>
public T GetResultAsT<T>() where T : class
{
//var task = this.ResultsTask;
return (this.Result != null)
? this.Result as T
: null;
}
}
}

View File

@@ -0,0 +1,100 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Microsoft.SqlTools.Hosting.Contracts;
namespace Microsoft.SqlTools.CoreServices.LanguageServices.Contracts
{
public class TelemetryProperties
{
public string EventName { get; set; }
/// <summary>
/// Telemetry properties
/// </summary>
public Dictionary<string, string> Properties { get; set; }
/// <summary>
/// Telemetry measures
/// </summary>
public Dictionary<string, double> Measures { get; set; }
}
/// <summary>
/// Parameters sent back with an IntelliSense ready event
/// </summary>
public class TelemetryParams
{
public TelemetryProperties Params { get; set; }
}
/// <summary>
/// Event sent when the language service needs to add a telemetry event
/// </summary>
public class TelemetryNotification
{
public static readonly
EventType<TelemetryParams> Type =
EventType<TelemetryParams>.Create("telemetry/sqlevent");
}
/// <summary>
/// List of telemetry events
/// </summary>
public static class TelemetryEventNames
{
/// <summary>
/// telemetry event name for auto complete response time
/// </summary>
public const string IntellisenseQuantile = "IntellisenseQuantile";
/// <summary>
/// telemetry event name for when definition is requested
/// </summary>
public const string PeekDefinitionRequested = "PeekDefinitionRequested";
/// <summary>
/// telemetry event name for when definition is requested
/// </summary>
public const string FormatCode = "FormatCode";
}
/// <summary>
/// List of properties used in telemetry events
/// </summary>
public static class TelemetryPropertyNames
{
/// <summary>
/// Is a connection to an Azure database or not
/// </summary>
public const string IsAzure = "IsAzure";
/// <summary>
/// Did an event succeed or not
/// </summary>
public const string Succeeded = "Succeeded";
/// <summary>
/// Was the action against a connected file or similar resource, or not
/// </summary>
public const string Connected = "Connected";
/// <summary>
/// Format type property - should be one of <see cref="DocumentFormatType"/> or <see cref="RangeFormatType"/>
/// </summary>
public const string FormatType = "FormatType";
/// <summary>
/// A full document format
/// </summary>
public const string DocumentFormatType = "Document";
/// <summary>
/// A document range format
/// </summary>
public const string RangeFormatType = "Range";
}
}