mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
* Initial commit of reliable connection port * Made ReliableSqlConnection inherit from DbConnection instead of IDbConnection * Cleanup * Fixed autocomplete service to use reliable connection * Fix copyright headers * Renamed ConnectResponse.Server to ServerInfo * Removed unused using * Addressing code review feedback
138 lines
4.6 KiB
C#
138 lines
4.6 KiB
C#
//
|
|
// 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.Concurrent;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Linq;
|
|
using Microsoft.SqlTools.EditorServices.Utility;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
|
|
{
|
|
/// <summary>
|
|
/// This class caches server information for subsequent use
|
|
/// </summary>
|
|
internal static class CachedServerInfo
|
|
{
|
|
private struct CachedInfo
|
|
{
|
|
public bool IsAzure;
|
|
public DateTime LastUpdate;
|
|
}
|
|
|
|
private static ConcurrentDictionary<string, CachedInfo> _cache;
|
|
private static object _cacheLock;
|
|
private const int _maxCacheSize = 1024;
|
|
private const int _deleteBatchSize = 512;
|
|
|
|
private const int MinimalQueryTimeoutSecondsForAzure = 300;
|
|
|
|
static CachedServerInfo()
|
|
{
|
|
_cache = new ConcurrentDictionary<string, CachedInfo>(StringComparer.OrdinalIgnoreCase);
|
|
_cacheLock = new object();
|
|
}
|
|
|
|
public static int GetQueryTimeoutSeconds(IDbConnection connection)
|
|
{
|
|
string dataSource = SafeGetDataSourceFromConnection(connection);
|
|
return GetQueryTimeoutSeconds(dataSource);
|
|
}
|
|
|
|
public static int GetQueryTimeoutSeconds(string dataSource)
|
|
{
|
|
//keep existing behavior and return the default ambient settings
|
|
//if the provided data source is null or whitespace, or the original
|
|
//setting is already 0 which means no limit.
|
|
int originalValue = AmbientSettings.QueryTimeoutSeconds;
|
|
if (string.IsNullOrWhiteSpace(dataSource)
|
|
|| (originalValue == 0))
|
|
{
|
|
return originalValue;
|
|
}
|
|
|
|
CachedInfo info;
|
|
bool hasFound = _cache.TryGetValue(dataSource, out info);
|
|
|
|
if (hasFound && info.IsAzure
|
|
&& originalValue < MinimalQueryTimeoutSecondsForAzure)
|
|
{
|
|
return MinimalQueryTimeoutSecondsForAzure;
|
|
}
|
|
else
|
|
{
|
|
return originalValue;
|
|
}
|
|
}
|
|
|
|
public static void AddOrUpdateIsAzure(IDbConnection connection, bool isAzure)
|
|
{
|
|
Validate.IsNotNull(nameof(connection), connection);
|
|
|
|
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
|
|
AddOrUpdateIsAzure(builder.DataSource, isAzure);
|
|
}
|
|
|
|
public static void AddOrUpdateIsAzure(string dataSource, bool isAzure)
|
|
{
|
|
Validate.IsNotNullOrWhitespaceString(nameof(dataSource), dataSource);
|
|
CachedInfo info;
|
|
bool hasFound = _cache.TryGetValue(dataSource, out info);
|
|
|
|
if (hasFound && info.IsAzure == isAzure)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
lock (_cacheLock)
|
|
{
|
|
if (! _cache.ContainsKey(dataSource))
|
|
{
|
|
//delete a batch of old elements when we try to add a new one and
|
|
//the capacity limitation is hit
|
|
if (_cache.Keys.Count > _maxCacheSize - 1)
|
|
{
|
|
var keysToDelete = _cache
|
|
.OrderBy(x => x.Value.LastUpdate)
|
|
.Take(_deleteBatchSize)
|
|
.Select(pair => pair.Key);
|
|
|
|
foreach (string key in keysToDelete)
|
|
{
|
|
_cache.TryRemove(key, out info);
|
|
}
|
|
}
|
|
}
|
|
|
|
info.IsAzure = isAzure;
|
|
info.LastUpdate = DateTime.UtcNow;
|
|
_cache.AddOrUpdate(dataSource, info, (key, oldValue) => info);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string SafeGetDataSourceFromConnection(IDbConnection connection)
|
|
{
|
|
if (connection == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
|
|
return builder.DataSource;
|
|
}
|
|
catch
|
|
{
|
|
Logger.Write(LogLevel.Error, String.Format(Resources.FailedToParseConnectionString, connection.ConnectionString));
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|