From a0cc7a9d9f1445ea91a7ff3aeb574dcac0ac649c Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 28 Jun 2021 18:22:51 +0500 Subject: [PATCH 01/16] Interface of connection handler will be extended later on with async variants if needed --- .../Orm/ConnectionErrorEventData.cs | 24 ++++++++++++++ Orm/Xtensive.Orm/Orm/ConnectionEventData.cs | 28 ++++++++++++++++ .../Orm/ConnectionInitEventData.cs | 23 +++++++++++++ .../Orm/Interfaces/IConnectionHandler.cs | 33 +++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs create mode 100644 Orm/Xtensive.Orm/Orm/ConnectionEventData.cs create mode 100644 Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs create mode 100644 Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs diff --git a/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs new file mode 100644 index 0000000000..83c295beaa --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs @@ -0,0 +1,24 @@ +using System; +using System.Data.Common; +using Xtensive.Core; + +namespace Xtensive.Orm +{ + /// + /// Extended with error happend during connection opening, restoration or initialization. + /// + public class ConnectionErrorEventData : ConnectionEventData + { + /// + /// The exception appeared. + /// + public Exception Exception { get; } + + public ConnectionErrorEventData(Exception exception, DbConnection connection, bool reconnect = false) + : base(connection, reconnect) + { + ArgumentValidator.EnsureArgumentNotNull(exception, nameof(exception)); + Exception = exception; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs new file mode 100644 index 0000000000..770212195d --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs @@ -0,0 +1,28 @@ +using System.Data.Common; +using Xtensive.Core; + +namespace Xtensive.Orm +{ + /// + /// Contains general data for methods. + /// + public class ConnectionEventData + { + /// + /// The connection for which event triggered. + /// + public DbConnection Connection { get; } + + /// + /// Indicates whether event happened during an attempt to restore connection. + /// + public bool Reconnect { get; } + + public ConnectionEventData(DbConnection connection, bool reconnect = false) + { + ArgumentValidator.EnsureArgumentNotNull(connection, nameof(connection)); + Connection = connection; + Reconnect = reconnect; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs new file mode 100644 index 0000000000..b2c9e1cb76 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs @@ -0,0 +1,23 @@ +using System.Data.Common; +using Xtensive.Core; + +namespace Xtensive.Orm +{ + /// + /// Extended with connection initialization script + /// + public class ConnectionInitEventData : ConnectionEventData + { + /// + /// Gets the script which will be used for connection initializatin + /// + public string InitializationScript { get; } + + public ConnectionInitEventData(string initializationScript, DbConnection connection, bool reconnect = false) + : base(connection, reconnect) + { + ArgumentValidator.EnsureArgumentNotNullOrEmpty(initializationScript, nameof(initializationScript)); + InitializationScript = initializationScript; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs b/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs new file mode 100644 index 0000000000..39708d3d29 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs @@ -0,0 +1,33 @@ +namespace Xtensive.Orm +{ + /// + /// Offers event-like methods to access native database connection on different stages + /// + public interface IConnectionHandler + { + /// + /// Executes before connection opening. + /// + /// Information connected with this event. + void ConnectionOpening(ConnectionEventData eventData) { } + + /// + /// Executes when connection is already opened but initialization script + /// hasn't been executed yet. + /// + /// Information connected with this event. + void ConnectionInitialization(ConnectionInitEventData eventData) { } + + /// + /// Executes when connection is successfully opened and initialized + /// + /// Information connected with this event + void ConnectionOpened(ConnectionEventData eventData) { } + + /// + /// Executes if an error appeared on either connection opening or connection initialization. + /// + /// Information connected with this event + void ConnectionOpeningFailed(ConnectionErrorEventData eventData) { } + } +} From ceac4a0cd18becc610c2a50839b44946c71518f3 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 9 Jul 2021 17:25:41 +0500 Subject: [PATCH 02/16] Support for connection hanlders on high level --- .../Orm/Configuration/DomainTypeRegistry.cs | 45 ++++++++++++- .../Orm/Providers/StorageDriver.Operations.cs | 13 ++-- .../Orm/Providers/StorageDriver.cs | 64 +++++++++++++++++-- .../Sql/ConnectionHandlersExtension.cs | 25 ++++++++ 4 files changed, 134 insertions(+), 13 deletions(-) create mode 100644 Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs index 38daf86a8a..8e1b3fb949 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs @@ -25,7 +25,11 @@ public class DomainTypeRegistry : TypeRegistry private readonly static Type iModuleType = typeof(IModule); private readonly static Type iUpgradeHandlerType = typeof(IUpgradeHandler); private readonly static Type keyGeneratorType = typeof(KeyGenerator); - private static readonly Type ifulltextCatalogNameBuilder = typeof(IFullTextCatalogNameBuilder); + private readonly static Type ifulltextCatalogNameBuilder = typeof(IFullTextCatalogNameBuilder); + private readonly static Type iConnectionHandlerType = typeof(IConnectionHandler); + + private Type[] connectionHandlers; + /// /// Gets all the registered persistent types. @@ -68,6 +72,27 @@ public class DomainTypeRegistry : TypeRegistry /// public IEnumerable FullTextCatalogResolvers => this.Where(IsFullTextCatalogNameBuilder); + /// + /// Gets all the registered implementations. + /// + public IEnumerable ConnectionHandlers + { + get { + // a lot of access to this property. better to have items cached; + if (IsLocked) { + if(connectionHandlers == null) { + var container = new List(10);// not so many handlers expected + foreach (var type in this.Where(IsConnectionHandler)) + container.Add(type); + connectionHandlers = container.Count == 0 ? Array.Empty() : container.ToArray(); + } + return connectionHandlers; + } + // if instacne is not locked then there is a chance of new handlers appeared + return this.Where(IsConnectionHandler); + } + } + #region IsXxx method group /// @@ -85,7 +110,8 @@ public static bool IsInterestingType(Type type) => IsUpgradeHandler(type) || IsKeyGenerator(type) || IsCompilerContainer(type) || - IsFullTextCatalogNameBuilder(type); + IsFullTextCatalogNameBuilder(type) || + IsConnectionHandler(type); /// /// Determines whether a @@ -201,6 +227,21 @@ public static bool IsFullTextCatalogNameBuilder(Type type) return ifulltextCatalogNameBuilder.IsAssignableFrom(type) && ifulltextCatalogNameBuilder != type; } + /// + /// Determines whether the is + /// a connection handler. + /// + /// The type to check. + /// Check result. + public static bool IsConnectionHandler(Type type) + { + if (type.IsAbstract) { + return false; + } + + return iConnectionHandlerType.IsAssignableFrom(type) && iConnectionHandlerType != type; + } + #endregion #region ICloneable members diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs index 3d6eecce26..9c76a00aff 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs @@ -14,7 +14,7 @@ namespace Xtensive.Orm.Providers { - partial class StorageDriver + public partial class StorageDriver { private sealed class InitializationSqlExtension { @@ -50,6 +50,10 @@ public SqlConnection CreateConnection(Session session) catch (Exception exception) { throw ExceptionBuilder.BuildException(exception); } + if (handlerFactoriesCache != null) { + connection.Extensions.Set( + new ConnectionHandlersExtension(CreateHandlersForConnection(configuration.Types.ConnectionHandlers))); + } var sessionConfiguration = GetConfiguration(session); connection.CommandTimeout = sessionConfiguration.DefaultCommandTimeout; @@ -76,7 +80,7 @@ public void OpenConnection(Session session, SqlConnection connection) var script = extension?.Script; try { if (!string.IsNullOrEmpty(script)) { - connection.OpenAndInitialize(extension.Script); + connection.OpenAndInitialize(script); } else { connection.Open(); @@ -100,8 +104,9 @@ public async Task OpenConnectionAsync(Session session, SqlConnection connection, var extension = connection.Extensions.Get(); try { - if (!string.IsNullOrEmpty(extension?.Script)) { - await connection.OpenAndInitializeAsync(extension.Script, cancellationToken).ConfigureAwait(false); + var script = extension?.Script; + if (!string.IsNullOrEmpty(script)) { + await connection.OpenAndInitializeAsync(script, cancellationToken).ConfigureAwait(false); } else { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs index 57f4d10ff1..aece04d371 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs @@ -18,6 +18,10 @@ using Xtensive.Sql.Info; using Xtensive.Sql.Model; using Xtensive.Tuples; +using System.Collections.Concurrent; +using Xtensive.Linq; +using System.Linq.Expressions; +using System.Reflection; namespace Xtensive.Orm.Providers { @@ -26,6 +30,8 @@ namespace Xtensive.Orm.Providers /// public sealed partial class StorageDriver { + private static readonly MethodInfo FactoryCreatorMethod = typeof(StorageDriver).GetMethod(nameof(NewFactory), BindingFlags.Static | BindingFlags.NonPublic); + private readonly DomainConfiguration configuration; private readonly SqlDriver underlyingDriver; private readonly SqlTranslator translator; @@ -33,6 +39,8 @@ public sealed partial class StorageDriver private readonly bool isLoggingEnabled; private readonly bool hasSavepoints; + private readonly ConcurrentDictionary> handlerFactoriesCache; + public ProviderInfo ProviderInfo { get; private set; } public StorageExceptionBuilder ExceptionBuilder { get; private set; } @@ -97,7 +105,7 @@ public DbDataReaderAccessor GetDataReaderAccessor(TupleDescriptor descriptor) public StorageDriver CreateNew(Domain domain) { ArgumentValidator.EnsureArgumentNotNull(domain, "domain"); - return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain)); + return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain), handlerFactoriesCache); } private static DomainModel GetNullModel() @@ -151,6 +159,42 @@ private void FixExtractionResultSqlServerFamily(SqlExtractionResult result) } } + private IReadOnlyCollection CreateHandlersForConnection(IEnumerable connectionHandlerTypes) + { + if (handlerFactoriesCache == null) + return Array.Empty(); + var instances = new List(handlerFactoriesCache.Count); + foreach (var type in connectionHandlerTypes) { + if (handlerFactoriesCache.TryGetValue(type, out var factory)) + instances.Add(factory()); + } + return instances.ToArray(); + } + + // used on driver creation so it is very first time handlers are created. + // great place to create and cache factories for faster initialization on session opening later + private static IReadOnlyCollection CreateConnectionHandlers(IEnumerable connectionHandlerTypes, + out ConcurrentDictionary> factories) + { + var instances = new List(); + factories = new ConcurrentDictionary>(); + foreach (var item in connectionHandlerTypes) { + var handlerFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(item).Invoke(null, null); + instances.Add(handlerFactory()); + factories[item] = handlerFactory; + } + if (factories.Count == 0) + factories = null; + return instances.ToArray(); + } + + private static Func NewFactory() where T : IConnectionHandler + { + return FastExpression.Lambda>( + Expression.Convert(Expression.New(typeof(T)), typeof(IConnectionHandler))) + .Compile(); + } + // Constructors public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfiguration configuration) @@ -158,7 +202,8 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu ArgumentValidator.EnsureArgumentNotNull(driverFactory, nameof(driverFactory)); ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - var driverConfiguration = new SqlDriverConfiguration { + var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories); + var driverConfiguration = new SqlDriverConfiguration(handlers) { ForcedServerVersion = configuration.ForcedServerVersion, ConnectionInitializationSql = configuration.ConnectionInitializationSql, EnsureConnectionIsAlive = configuration.EnsureConnectionIsAlive, @@ -167,7 +212,7 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu var driver = driverFactory.GetDriver(configuration.ConnectionInfo, driverConfiguration); var providerInfo = ProviderInfoBuilder.Build(configuration.ConnectionInfo.Provider, driver); - return new StorageDriver(driver, providerInfo, configuration, GetNullModel); + return new StorageDriver(driver, providerInfo, configuration, GetNullModel, factories); } public static async Task CreateAsync( @@ -176,7 +221,8 @@ public static async Task CreateAsync( ArgumentValidator.EnsureArgumentNotNull(driverFactory, nameof(driverFactory)); ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - var driverConfiguration = new SqlDriverConfiguration { + var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories); + var driverConfiguration = new SqlDriverConfiguration(handlers) { ForcedServerVersion = configuration.ForcedServerVersion, ConnectionInitializationSql = configuration.ConnectionInitializationSql, EnsureConnectionIsAlive = configuration.EnsureConnectionIsAlive, @@ -186,11 +232,14 @@ public static async Task CreateAsync( .ConfigureAwait(false); var providerInfo = ProviderInfoBuilder.Build(configuration.ConnectionInfo.Provider, driver); - return new StorageDriver(driver, providerInfo, configuration, GetNullModel); + return new StorageDriver(driver, providerInfo, configuration, GetNullModel, factories); } - private StorageDriver( - SqlDriver driver, ProviderInfo providerInfo, DomainConfiguration configuration, Func modelProvider) + private StorageDriver(SqlDriver driver, + ProviderInfo providerInfo, + DomainConfiguration configuration, + Func modelProvider, + ConcurrentDictionary> factoryCache) { underlyingDriver = driver; ProviderInfo = providerInfo; @@ -201,6 +250,7 @@ private StorageDriver( hasSavepoints = underlyingDriver.ServerInfo.ServerFeatures.Supports(ServerFeatures.Savepoints); isLoggingEnabled = SqlLog.IsLogged(LogLevel.Info); // Just to cache this value ServerInfo = underlyingDriver.ServerInfo; + handlerFactoriesCache = factoryCache; } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs b/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs new file mode 100644 index 0000000000..03e2abc199 --- /dev/null +++ b/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Collections.Generic; +using Xtensive.Orm; + +namespace Xtensive.Sql +{ + /// + /// Wrapper to pass handlers to connection. + /// + public sealed class ConnectionHandlersExtension + { + /// + /// Collection of instances. + /// + public IReadOnlyCollection Handlers { get; } + + internal ConnectionHandlersExtension(IReadOnlyCollection handlers) + { + Handlers = handlers; + } + } +} From 3dd92516e5c1bc2c6250573aa5e32a6e3af6868e Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 9 Jul 2021 17:31:13 +0500 Subject: [PATCH 03/16] Low-level support for all providers --- .../Sql.Drivers.Firebird/DriverFactory.cs | 57 ++++++++++++++-- .../Sql.Drivers.MySql/DriverFactory.cs | 65 +++++++++++++++++-- .../Sql.Drivers.Oracle/DriverFactory.cs | 63 ++++++++++++++++-- .../Sql.Drivers.PostgreSql/DriverFactory.cs | 63 ++++++++++++++++-- .../Sql.Drivers.SqlServer/Connection.cs | 57 ++++++++++++++-- .../Sql.Drivers.SqlServer/DriverFactory.cs | 45 ++++++++++--- .../Sql.Drivers.Sqlite/DriverFactory.cs | 63 ++++++++++++++++-- Orm/Xtensive.Orm/Sql/SqlConnection.cs | 53 ++++++++++++--- Orm/Xtensive.Orm/Sql/SqlDriver.cs | 15 ++++- .../Sql/SqlDriverConfiguration.cs | 26 +++++++- Orm/Xtensive.Orm/Sql/SqlHelper.cs | 62 ++++++++++++++++++ 11 files changed, 522 insertions(+), 47 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs index 90c07849ca..b520cf48c0 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs @@ -33,8 +33,10 @@ public class DriverFactory : SqlDriverFactory protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new FbConnection(connectionString); - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + if (configuration.ConnectionHandlers.Count > 0) + OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + else + OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var defaultSchema = GetDefaultSchema(connection); return CreateDriverInstance( connectionString, GetVersionFromServerVersionString(connection.ServerVersion), defaultSchema); @@ -45,8 +47,10 @@ protected override async Task CreateDriverAsync( { var connection = new FbConnection(connectionString); await using (connection.ConfigureAwait(false)) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count > 0) + await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + else + await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var defaultSchema = await GetDefaultSchemaAsync(connection, token: token).ConfigureAwait(false); return CreateDriverInstance( connectionString, GetVersionFromServerVersionString(connection.ServerVersion), defaultSchema); @@ -118,6 +122,51 @@ protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => SqlHelper.ReadDatabaseAndSchemaAsync(DatabaseAndSchemaQuery, connection, transaction, token); + private async ValueTask OpenConnectionFast(FbConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, configuration); + } + else { + await connection.OpenAsync().ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask OpenConnectionWithNotifications(FbConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) + { + var handlers = configuration.ConnectionHandlers; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch(Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + await connection.OpenAsync(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + } + private static Version GetVersionFromServerVersionString(string serverVersionString) { var matcher = new Regex(ServerVersionParser); diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index d50eb049c7..605dffaf67 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2020 Xtensive LLC. +// Copyright (C) 2011-2020 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube @@ -70,8 +70,10 @@ private static Version ParseVersion(string version) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using (var connection = new MySqlConnection(connectionString)) { - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + if (configuration.ConnectionHandlers.Count > 0) + OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + else + OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var versionString = string.IsNullOrEmpty(configuration.ForcedServerVersion) ? connection.ServerVersion : configuration.ForcedServerVersion; @@ -88,8 +90,10 @@ protected override async Task CreateDriverAsync( { var connection = new MySqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count > 0) + await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + else + await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var versionString = string.IsNullOrEmpty(configuration.ForcedServerVersion) ? connection.ServerVersion : configuration.ForcedServerVersion; @@ -131,5 +135,56 @@ protected override DefaultSchemaInfo ReadDefaultSchema(DbConnection connection, protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => SqlHelper.ReadDatabaseAndSchemaAsync(DatabaseAndSchemaQuery, connection, transaction, token); + + private async ValueTask OpenConnectionFast(MySqlConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, configuration); + } + else { + await connection.OpenAsync().ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask OpenConnectionWithNotifications(MySqlConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + var handlers = configuration.ConnectionHandlers; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + await connection.OpenAsync(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs index 41b0f471b2..1d47092386 100644 --- a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs @@ -71,8 +71,10 @@ protected override string BuildConnectionString(UrlInfo url) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new OracleConnection(connectionString); - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + if (configuration.ConnectionHandlers.Count > 0) + OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + else + OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var version = string.IsNullOrEmpty(configuration.ForcedServerVersion) ? ParseVersion(connection.ServerVersion) : new Version(configuration.ForcedServerVersion); @@ -86,8 +88,10 @@ protected override async Task CreateDriverAsync( { var connection = new OracleConnection(connectionString); await using (connection.ConfigureAwait(false)) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count > 0) + await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + else + await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var version = string.IsNullOrEmpty(configuration.ForcedServerVersion) ? ParseVersion(connection.ServerVersion) : new Version(configuration.ForcedServerVersion); @@ -124,5 +128,56 @@ protected override DefaultSchemaInfo ReadDefaultSchema(DbConnection connection, protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => SqlHelper.ReadDatabaseAndSchemaAsync(DatabaseAndSchemaQuery, connection, transaction, token); + + private async ValueTask OpenConnectionFast(OracleConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, configuration); + } + else { + await connection.OpenAsync().ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask OpenConnectionWithNotifications(OracleConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + var handlers = configuration.ConnectionHandlers; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + await connection.OpenAsync(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs index 3a55931398..0c9bc86e9d 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs @@ -61,8 +61,10 @@ protected override string BuildConnectionString(UrlInfo url) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new NpgsqlConnection(connectionString); - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + if (configuration.ConnectionHandlers.Count > 0) + OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + else + OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var version = GetVersion(configuration, connection); var defaultSchema = GetDefaultSchema(connection); return CreateDriverInstance(connectionString, version, defaultSchema); @@ -74,8 +76,10 @@ protected override async Task CreateDriverAsync( { var connection = new NpgsqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count > 0) + await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + else + await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var version = GetVersion(configuration, connection); var defaultSchema = await GetDefaultSchemaAsync(connection, token: token).ConfigureAwait(false); return CreateDriverInstance(connectionString, version, defaultSchema); @@ -130,5 +134,56 @@ protected override DefaultSchemaInfo ReadDefaultSchema(DbConnection connection, protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => SqlHelper.ReadDatabaseAndSchemaAsync(DatabaseAndSchemaQuery, connection, transaction, token); + + private async ValueTask OpenConnectionFast(NpgsqlConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, configuration); + } + else { + await connection.OpenAsync().ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask OpenConnectionWithNotifications(NpgsqlConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + var handlers = configuration.ConnectionHandlers; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + await connection.OpenAsync(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + } } } diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs index cf4c7813c9..fe9f497067 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs @@ -39,7 +39,7 @@ public override void Open() base.Open(); } else { - OpenWithCheck(DefaultCheckConnectionQuery); + OpenWithCheckFast(DefaultCheckConnectionQuery); } } @@ -65,7 +65,11 @@ public override void OpenAndInitialize(string initializationScript) var script = string.IsNullOrEmpty(initializationScript.Trim()) ? DefaultCheckConnectionQuery : initializationScript; - OpenWithCheck(script); + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) + OpenWithCheckFast(script); + else + OpenWithChecksAndNotifications(script, connectionHandlers); } /// @@ -194,7 +198,7 @@ public override void ReleaseSavepoint(string name) /// protected override void ClearActiveTransaction() => activeTransaction = null; - private void OpenWithCheck(string checkQueryString) + private void OpenWithCheckFast(string checkQueryString) { var connectionChecked = false; var restoreTriggered = false; @@ -203,7 +207,7 @@ private void OpenWithCheck(string checkQueryString) try { using (var command = underlyingConnection.CreateCommand()) { command.CommandText = checkQueryString; - command.ExecuteNonQuery(); + _ = command.ExecuteNonQuery(); } connectionChecked = true; } @@ -230,6 +234,49 @@ private void OpenWithCheck(string checkQueryString) } } + private void OpenWithChecksAndNotifications(string checkQueryString, ConnectionHandlersExtension connectionHandlers) + { + var connectionChecked = false; + var restoreTriggered = false; + var handlers = connectionHandlers.Handlers; + while (!connectionChecked) { + SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + underlyingConnection.Open(); + //base.Open(); + try { + SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered)); + using (var command = underlyingConnection.CreateCommand()) { + command.CommandText = checkQueryString; + _ = command.ExecuteNonQuery(); + } + connectionChecked = true; + SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + } + catch (Exception exception) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered)); + if (InternalHelpers.ShouldRetryOn(exception)) { + if (restoreTriggered) { + throw; + } + + var newConnection = new SqlServerConnection(underlyingConnection.ConnectionString); + try { + underlyingConnection.Close(); + underlyingConnection.Dispose(); + } + catch { } + + underlyingConnection = newConnection; + restoreTriggered = true; + continue; + } + + throw; + } + } + } + + private async Task OpenWithCheckAsync(string checkQueryString, CancellationToken cancellationToken) { var connectionChecked = false; @@ -242,7 +289,7 @@ private async Task OpenWithCheckAsync(string checkQueryString, CancellationToken var command = underlyingConnection.CreateCommand(); await using (command.ConfigureAwait(false)) { command.CommandText = checkQueryString; - await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + _ = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); } connectionChecked = true; } diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs index 5775af9eef..e2a30e8fe4 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs @@ -230,15 +230,27 @@ private static SqlServerConnection CreateAndOpenConnection( { var connection = new SqlServerConnection(connectionString); if (!configuration.EnsureConnectionIsAlive) { - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + var handlers = configuration.ConnectionHandlers; + SqlHelper.NotifyConnectionOpening(handlers, connection); + + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch(Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } return connection; } var testQuery = string.IsNullOrEmpty(configuration.ConnectionInitializationSql) ? CheckConnectionQuery : configuration.ConnectionInitializationSql; - return EnsureConnectionIsAlive(connection, testQuery); + return EnsureConnectionIsAlive(connection, configuration.ConnectionHandlers, testQuery); } private static async Task CreateAndOpenConnectionAsync( @@ -257,17 +269,25 @@ private static async Task CreateAndOpenConnectionAsync( return await EnsureConnectionIsAliveAsync(connection, testQuery, token).ConfigureAwait(false); } - private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection connection, string query) + private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection connection, IReadOnlyCollection handlers, string query) { try { + SqlHelper.NotifyConnectionOpening(handlers, connection); connection.Open(); + SqlHelper.NotifyConnectionInitializing(handlers, connection, query); + using var command = connection.CreateCommand(); command.CommandText = query; - command.ExecuteNonQuery(); + _ = command.ExecuteNonQuery(); + SqlHelper.NotifyConnectionOpened(handlers, connection); return connection; } catch (Exception exception) { + var retryToConnect = InternalHelpers.ShouldRetryOn(exception); + if(!retryToConnect) + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception); + var connectionString = connection.ConnectionString; try { connection.Close(); @@ -278,7 +298,7 @@ private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection c } if (InternalHelpers.ShouldRetryOn(exception)) { - var (isReconnected, newConnection) = TryReconnect(connectionString, query); + var (isReconnected, newConnection) = TryReconnect(connectionString, query, handlers); if (isReconnected) { return newConnection; } @@ -322,18 +342,23 @@ private static async Task EnsureConnectionIsAliveAsync( } private static (bool isReconnected, SqlServerConnection connection) TryReconnect( - string connectionString, string query) + string connectionString, string query, IReadOnlyCollection handlers) { + var connection = new SqlServerConnection(connectionString); try { - var connection = new SqlServerConnection(connectionString); + SqlHelper.NotifyConnectionOpening(handlers, connection, true); connection.Open(); + SqlHelper.NotifyConnectionInitializing(handlers, connection, query, true); using (var command = connection.CreateCommand()) { command.CommandText = query; - command.ExecuteNonQuery(); + _ = command.ExecuteNonQuery(); } + SqlHelper.NotifyConnectionOpened(handlers, connection, true); return (true, connection); } - catch { + catch(Exception exception) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception, true); + connection.Dispose(); return (false, null); } } diff --git a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs index 7978498454..3d2718140f 100644 --- a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs @@ -43,8 +43,10 @@ private static string GetDataSource(string connectionString) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new SQLiteConnection(connectionString); - connection.Open(); - SqlHelper.ExecuteInitializationSql(connection, configuration); + if (configuration.ConnectionHandlers.Count > 0) + OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + else + OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var defaultSchema = GetDefaultSchema(connection); var version = new Version(connection.ServerVersion ?? string.Empty); return CreateDriverInstance(connectionString, version, defaultSchema); @@ -56,8 +58,10 @@ protected override async Task CreateDriverAsync( { var connection = new SQLiteConnection(connectionString); await using (connection.ConfigureAwait(false)) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count > 0) + await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + else + await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var defaultSchema = await GetDefaultSchemaAsync(connection, token: token).ConfigureAwait(false); var version = new Version(connection.ServerVersion ?? string.Empty); return CreateDriverInstance(connectionString, version, defaultSchema); @@ -103,5 +107,56 @@ protected override DefaultSchemaInfo ReadDefaultSchema(DbConnection connection, protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => Task.FromResult(new DefaultSchemaInfo(GetDataSource(connection.ConnectionString), Extractor.DefaultSchemaName)); + + private async ValueTask OpenConnectionFast(SQLiteConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, configuration); + } + else { + await connection.OpenAsync().ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + } + } + + private async ValueTask OpenConnectionWithNotifications(SQLiteConnection connection, + SqlDriverConfiguration configuration, + bool isAsync, + CancellationToken cancellationToken = default) + { + var handlers = configuration.ConnectionHandlers; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.ExecuteInitializationSql(connection, configuration); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + await connection.OpenAsync(); + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/SqlConnection.cs b/Orm/Xtensive.Orm/Sql/SqlConnection.cs index 8dab85a83d..bacbc36ad6 100644 --- a/Orm/Xtensive.Orm/Sql/SqlConnection.cs +++ b/Orm/Xtensive.Orm/Sql/SqlConnection.cs @@ -166,7 +166,21 @@ public virtual IBinaryLargeObject CreateBinaryLargeObject() => public virtual void Open() { EnsureIsNotDisposed(); - UnderlyingConnection.Open(); + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) + UnderlyingConnection.Open(); + else { + var handlers = connectionHandlers.Handlers; + SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection); + try { + UnderlyingConnection.Open(); + SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex); + throw; + } + } } /// @@ -176,14 +190,37 @@ public virtual void Open() public virtual void OpenAndInitialize(string initializationScript) { EnsureIsNotDisposed(); - UnderlyingConnection.Open(); - if (string.IsNullOrEmpty(initializationScript)) { - return; - } + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) { + UnderlyingConnection.Open(); + if (string.IsNullOrEmpty(initializationScript)) { + return; + } - using var command = UnderlyingConnection.CreateCommand(); - command.CommandText = initializationScript; - command.ExecuteNonQuery(); + using var command = UnderlyingConnection.CreateCommand(); + command.CommandText = initializationScript; + _ = command.ExecuteNonQuery(); + } + else { + var handlers = connectionHandlers.Handlers; + SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection); + try { + UnderlyingConnection.Open(); + if (string.IsNullOrEmpty(initializationScript)) { + SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection); + return; + } + + SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, initializationScript); + using var command = UnderlyingConnection.CreateCommand(); + command.CommandText = initializationScript; + _ = command.ExecuteNonQuery(); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex); + throw; + } + } } /// diff --git a/Orm/Xtensive.Orm/Sql/SqlDriver.cs b/Orm/Xtensive.Orm/Sql/SqlDriver.cs index 8711470403..e1ce488783 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriver.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriver.cs @@ -45,6 +45,11 @@ public abstract class SqlDriver /// public SqlTranslator Translator { get; private set; } + /// + /// Gets s collection. + /// + public IReadOnlyCollection ConnectionHandlers { get; private set; } + /// /// Gets connection string for the specified . /// @@ -297,6 +302,8 @@ public SqlConnection CreateConnection() { var result = DoCreateConnection(); result.ConnectionInfo = originConnectionInfo; + if (ConnectionHandlers.Count != 0) + result.Extensions.Set(new ConnectionHandlersExtension(ConnectionHandlers)); return result; } @@ -309,6 +316,8 @@ public SqlConnection CreateConnection(ConnectionInfo connectionInfo) { var result = DoCreateConnection(); result.ConnectionInfo = connectionInfo; + if (ConnectionHandlers.Count != 0) + result.Extensions.Set(new ConnectionHandlersExtension(ConnectionHandlers)); return result; } @@ -373,10 +382,14 @@ protected virtual void RegisterCustomReverseMappings(TypeMappingRegistryBuilder #region Private / internal methods - internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo) + internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo) => + Initialize(creator, creatorConnectionInfo, Array.Empty()); + + internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo, IReadOnlyCollection connectionHandlers) { origin = creator; originConnectionInfo = creatorConnectionInfo; + ConnectionHandlers = connectionHandlers; var serverInfoProvider = CreateServerInfoProvider(); ServerInfo = ServerInfo.Build(serverInfoProvider); diff --git a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs index 9dcebec5af..b6a469daea 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs @@ -1,9 +1,14 @@ -// Copyright (C) 2003-2012 Xtensive LLC. +// Copyright (C) 2003-2012 Xtensive LLC. // All rights reserved. // For conditions of distribution and use, see license. // Created by: Denis Krjuchkov // Created: 2012.12.27 +using System; +using System.Collections.Generic; +using Xtensive.Core; +using Xtensive.Orm; + namespace Xtensive.Sql { /// @@ -26,16 +31,27 @@ public sealed class SqlDriverConfiguration /// public bool EnsureConnectionIsAlive { get; set; } + /// + /// Gets connection handlers that should be notified about connection events. + /// + public IReadOnlyCollection ConnectionHandlers { get; private set; } + /// /// Clones this instance. /// /// Clone of this instance. public SqlDriverConfiguration Clone() { + // no deep cloning + var interceptors = (ConnectionHandlers.Count == 0) + ? Array.Empty() + : ConnectionHandlers.ToArray(ConnectionHandlers.Count); + return new SqlDriverConfiguration { ForcedServerVersion = ForcedServerVersion, ConnectionInitializationSql = ConnectionInitializationSql, - EnsureConnectionIsAlive = EnsureConnectionIsAlive + EnsureConnectionIsAlive = EnsureConnectionIsAlive, + ConnectionHandlers = interceptors }; } @@ -44,6 +60,12 @@ public SqlDriverConfiguration Clone() /// public SqlDriverConfiguration() { + ConnectionHandlers = Array.Empty(); + } + + public SqlDriverConfiguration(IReadOnlyCollection connectionInterceptors) + { + ConnectionHandlers = connectionInterceptors; } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/SqlHelper.cs b/Orm/Xtensive.Orm/Sql/SqlHelper.cs index f27601527b..9bc6cef33c 100644 --- a/Orm/Xtensive.Orm/Sql/SqlHelper.cs +++ b/Orm/Xtensive.Orm/Sql/SqlHelper.cs @@ -490,5 +490,67 @@ public static NotSupportedException NotSupported(ServerFeatures feature) { return NotSupported(feature.ToString()); } + + /// + /// Notifies all the that + /// is about to be opened. + /// + /// The handlers that should be notified. + /// The connection that is opening. + /// if event happened on attemp to restore connection, otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NotifyConnectionOpening( + IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) + { + foreach (var handler in connectionHandlers) + handler.ConnectionOpening(new ConnectionEventData(connection, reconnect)); + } + + /// + /// Notifies all the that + /// opened connection is about to be initialized with . + /// + /// The handlers that should be notified. + /// Opened but not initialized connection + /// The script that will run to initialize connection + /// if event happened on attemp to restore connection, otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NotifyConnectionInitializing( + IEnumerable connectionHandlers, DbConnection connection, string initializationScript, bool reconnect = false) + { + foreach (var handler in connectionHandlers) + handler.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect)); + } + + /// + /// Notifies all the about + /// successful connection opening. + /// + /// The handlers that should be notified. + /// The connection that is completely opened and initialized. + /// if event happened on attemp to restore connection, otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NotifyConnectionOpened( + IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) + { + foreach (var handler in connectionHandlers) + handler.ConnectionOpened(new ConnectionEventData(connection, reconnect)); + } + + /// + /// Notifies all the about + /// connection opening failure. + /// + /// The handlers that should be notified. + /// Connection that failed to be opened or properly initialized. + /// The exception which appeared. + /// if event happened on attemp to restore connection, otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void NotifyConnectionOpeningFailed( + IEnumerable connectionHandlers, DbConnection connection, Exception exception, bool reconnect = false) + { + foreach (var handler in connectionHandlers) + handler.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect)); + } } } From 00ff76edcdd589933494e2a45d40efa62d6cc4ed Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 9 Jul 2021 17:33:09 +0500 Subject: [PATCH 04/16] Add test of connection handlers for driver factory --- .../DriverFactoryTest.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs index 493576c3b2..2782f9be73 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs @@ -8,6 +8,44 @@ using Xtensive.Orm; using Xtensive.Orm.Building.Builders; using Xtensive.Sql; +using Xtensive.Orm.Tests.Sql.DriverFactoryTestTypes; + +namespace Xtensive.Orm.Tests.Sql.DriverFactoryTestTypes +{ + public class TestConnectionHandler : IConnectionHandler + { + public int OpeningCounter = 0; + public int OpenedCounter = 0; + public int OpeningInitCounter = 0; + public int OpeningFailedCounter = 0; + + public void ConnectionOpening(ConnectionEventData eventData) + { + OpeningCounter++; + } + + public void ConnectionOpened(ConnectionEventData eventData) + { + OpenedCounter++; + } + + public void ConnectionInitialization(ConnectionInitEventData eventData) + { + OpeningInitCounter++; + } + + public void ConnectionOpeningFailed(ConnectionErrorEventData eventData) + { + OpeningFailedCounter++; + } + } + + public static class StaticCounter + { + public static int OpeningReached; + public static int OpenedReached; + } +} namespace Xtensive.Orm.Tests.Sql { @@ -95,6 +133,61 @@ public void SqlServerConnectionCheckTest() Assert.That(GetCheckConnectionIsAliveFlag(driver), Is.False); } + [Test] + public void ConnectionHandlerTest() + { + var handlerInstance = new TestConnectionHandler(); + var handlersArray = new[] { handlerInstance }; + var descriptor = ProviderDescriptor.Get(provider); + var factory = (SqlDriverFactory) Activator.CreateInstance(descriptor.DriverFactory); + + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + + var configuration = new SqlDriverConfiguration(handlersArray); + _ = factory.GetDriver(new ConnectionInfo(Url), configuration); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { EnsureConnectionIsAlive = true }; + _ = factory.GetDriver(new ConnectionInfo(Url), configuration); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(2)); + if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); + else + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; + _ = factory.GetDriver(new ConnectionInfo(Url), configuration); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(3)); + if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); + else + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = "dummy string to trigger error" }; + try { + _ = factory.GetDriver(new ConnectionInfo(Url), configuration); + } + catch { + //skip it + } + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(4)); + if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(3)); + else + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(1)); + } private static void TestProvider(string providerName, string connectionString, string connectionUrl) { @@ -109,5 +202,18 @@ private static bool GetCheckConnectionIsAliveFlag(SqlDriver driver) return (bool) type.GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) .GetValue(driver); } + + private static string InitQueryPerProvider(string currentProvider) + { + switch (currentProvider) { + case WellKnown.Provider.Firebird: return "select current_timestamp from RDB$DATABASE;"; + case WellKnown.Provider.MySql: return "SELECT 0"; + case WellKnown.Provider.Oracle: return "select current_timestamp from DUAL"; + case WellKnown.Provider.PostgreSql: return "SELECT 0"; + case WellKnown.Provider.SqlServer: return "SELECT 0"; + case WellKnown.Provider.Sqlite: return "SELECT 0"; + default: throw new ArgumentOutOfRangeException(currentProvider); + } + } } } \ No newline at end of file From 5c8eb41222c706e78cb20d01a1c693230ec1116f Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 12 Jul 2021 19:13:52 +0500 Subject: [PATCH 05/16] Check for any parameterless constructor --- Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs | 11 ++++++++--- Orm/Xtensive.Orm/Strings.Designer.cs | 9 +++++++++ Orm/Xtensive.Orm/Strings.resx | 5 ++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs index aece04d371..51c34a7e8a 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs @@ -178,10 +178,15 @@ private static IReadOnlyCollection CreateConnectionHandlers( { var instances = new List(); factories = new ConcurrentDictionary>(); - foreach (var item in connectionHandlerTypes) { - var handlerFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(item).Invoke(null, null); + foreach (var type in connectionHandlerTypes) { + var ctor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); + if (ctor == null) { + throw new NotSupportedException(string.Format(Strings.ExConnectionHandlerXHasNoParameterlessConstructor, type)); + } + + var handlerFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(type).Invoke(null, null); instances.Add(handlerFactory()); - factories[item] = handlerFactory; + factories[type] = handlerFactory; } if (factories.Count == 0) factories = null; diff --git a/Orm/Xtensive.Orm/Strings.Designer.cs b/Orm/Xtensive.Orm/Strings.Designer.cs index 34c0659ebd..0956e187d7 100644 --- a/Orm/Xtensive.Orm/Strings.Designer.cs +++ b/Orm/Xtensive.Orm/Strings.Designer.cs @@ -1524,6 +1524,15 @@ internal static string ExConfigurationWithXNameAlreadyRegistered { } } + /// + /// Looks up a localized string similar to Connection handler '{0}' has no parameterless constructor.. + /// + internal static string ExConnectionHandlerXHasNoParameterlessConstructor { + get { + return ResourceManager.GetString("ExConnectionHandlerXHasNoParameterlessConstructor", resourceCulture); + } + } + /// /// Looks up a localized string similar to ConnectionInfo is missing. If you are using configuration file you should specify either 'connectionUrl' element or 'connectionString' and 'provider' elements. /// diff --git a/Orm/Xtensive.Orm/Strings.resx b/Orm/Xtensive.Orm/Strings.resx index add3536034..a2983a39e0 100644 --- a/Orm/Xtensive.Orm/Strings.resx +++ b/Orm/Xtensive.Orm/Strings.resx @@ -3470,4 +3470,7 @@ Error: {1} Can't modify Active or Disposed scope. - + + Connection handler '{0}' has no parameterless constructor. + + \ No newline at end of file From d1d6441412ffb742ded209053469726185fbf6e2 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Mon, 12 Jul 2021 19:42:49 +0500 Subject: [PATCH 06/16] Add high-level test for handlers --- .../Storage/ConnectionHandlerTest.cs | 279 ++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs diff --git a/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs b/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs new file mode 100644 index 0000000000..9b8f38eed5 --- /dev/null +++ b/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs @@ -0,0 +1,279 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Xtensive.Core; +using Xtensive.Orm.Providers; +using Xtensive.Sql; +using Xtensive.Orm.Tests.Storage.ConnectionHandlersModel; + +namespace Xtensive.Orm.Tests.Storage.ConnectionHandlersModel +{ + public class MyConnectionHandler : IConnectionHandler + { + private Guid instanceMarker; + + public readonly Guid UniqueInstanceIdentifier; + + public int ConnectionOpeningCounter; + public int ConnectionInitializationCounter; + public int ConnectionOpenedCounter; + public int ConnectionOpeningFailedCounter; + + public void ConnectionOpening(ConnectionEventData eventData) + { + instanceMarker = UniqueInstanceIdentifier; + ConnectionOpeningCounter++; + } + + public void ConnectionInitialization(ConnectionInitEventData eventData) + { + ConnectionInitializationCounter++; + if (instanceMarker != UniqueInstanceIdentifier) { + throw new Exception("Not the same instance"); + } + } + + public void ConnectionOpened(ConnectionEventData eventData) + { + ConnectionOpenedCounter++; + if (instanceMarker != UniqueInstanceIdentifier) { + throw new Exception("Not the same instance"); + } + } + + public void ConnectionOpeningFailed(ConnectionErrorEventData eventData) + { + ConnectionOpeningFailedCounter++; + if (instanceMarker != UniqueInstanceIdentifier) { + throw new Exception("Not the same instance"); + } + } + + public MyConnectionHandler() + { + UniqueInstanceIdentifier = Guid.NewGuid(); + } + } + + public class NoDefaultConstructorHandler : IConnectionHandler + { +#pragma warning disable IDE0060 // Remove unused parameter + public NoDefaultConstructorHandler(int dummyParameter) +#pragma warning restore IDE0060 // Remove unused parameter + { + } + } + + public class NonPublicDefaultConstructorHandler : IConnectionHandler + { + private NonPublicDefaultConstructorHandler() + { + } + } + + #region Performance Test handlers + + public class PerfHandler1 : IConnectionHandler { } + public class PerfHandler2 : IConnectionHandler { } + public class PerfHandler3 : IConnectionHandler { } + public class PerfHandler4 : IConnectionHandler { } + public class PerfHandler5 : IConnectionHandler { } + public class PerfHandler6 : IConnectionHandler { } + public class PerfHandler7 : IConnectionHandler { } + public class PerfHandler8 : IConnectionHandler { } + public class PerfHandler9 : IConnectionHandler { } + public class PerfHandler10 : IConnectionHandler { } + public class PerfHandler11 : IConnectionHandler { } + public class PerfHandler12 : IConnectionHandler { } + public class PerfHandler13 : IConnectionHandler { } + public class PerfHandler14 : IConnectionHandler { } + public class PerfHandler15 : IConnectionHandler { } + public class PerfHandler16 : IConnectionHandler { } + public class PerfHandler17 : IConnectionHandler { } + public class PerfHandler18 : IConnectionHandler { } + public class PerfHandler19 : IConnectionHandler { } + public class PerfHandler20 : IConnectionHandler { } + public class PerfHandler21 : IConnectionHandler { } + public class PerfHandler22 : IConnectionHandler { } + public class PerfHandler23 : IConnectionHandler { } + public class PerfHandler24 : IConnectionHandler { } + public class PerfHandler25 : IConnectionHandler { } + + #endregion + + public static class StaticCounter + { + public static int OpeningReached; + public static int OpenedReached; + } + + public class DummyEntity : Entity + { + [Field, Key] + public int Id { get; private set; } + + [Field] + public int Value { get; set; } + + public DummyEntity(Session session) + : base(session) + { + } + } +} + +namespace Xtensive.Orm.Tests.Storage +{ + public class ConnectionHandlerTest + { + [Test] + public void DomainRegistryTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(MyConnectionHandler)); + + Assert.That(domainConfig.Types.ConnectionHandlers.Count(), Is.EqualTo(1)); + } + + [Test] + public void NoDefaultConstructorTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(NoDefaultConstructorHandler)); + + Domain domain = null; + _ = Assert.Throws(() => domain = Domain.Build(domainConfig)); + domain.DisposeSafely(); + } + + [Test] + public void NonPublicDefaultConstructorTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(NonPublicDefaultConstructorHandler)); + + using var domain = Domain.Build(domainConfig); + } + + [Test] + public void SessionConnectionHandlersTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(MyConnectionHandler)); + + Guid? first = null; + using (var domain = Domain.Build(domainConfig)) + using (var session = domain.OpenSession()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extension = nativeHandler.Connection.Extensions.Get(); + var handlerInstance = (MyConnectionHandler)extension.Handlers.First(); + Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + first = handlerInstance.UniqueInstanceIdentifier; + } + + Guid? second = null; + using (var domain = Domain.Build(domainConfig)) + using (var session = domain.OpenSession()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extension = nativeHandler.Connection.Extensions.Get(); + var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); + Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + second = handlerInstance.UniqueInstanceIdentifier; + } + + Assert.That(first != null && second != null && first != second, Is.True); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void ConnectionExtensionExistanceTest(int includeHandlersCount) + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + + foreach (var handler in GetHandlers(includeHandlersCount)) { + domainConfig.Types.Register(handler); + } + + using (var domain = Domain.Build(domainConfig)) + using (var session = domain.OpenSession()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extensions = nativeHandler.Connection.Extensions; + if (includeHandlersCount > 0) { + Assert.That(extensions.Count, Is.EqualTo(1)); + var extension = extensions.Get(); + Assert.That(extension, Is.Not.Null); + Assert.That(extension.Handlers.Count, Is.EqualTo(includeHandlersCount)); + } + else { + Assert.That(extensions.Count, Is.EqualTo(0)); + } + } + } + + [Explicit] + [TestCase(0)] + [TestCase(5)] + [TestCase(10)] + [TestCase(15)] + [TestCase(20)] + [TestCase(25)] + public void SessionOpeningPerformanceTest(int includeHandlersCount) + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + + foreach (var handler in GetHandlers(includeHandlersCount)) { + domainConfig.Types.Register(handler); + } + + var watch = new Stopwatch(); + using (var domain = Domain.Build(domainConfig)) { + watch.Start(); + for (var i = 0; i < 1000000; i++) { + domain.OpenSession().Dispose(); + } + watch.Stop(); + } + Console.WriteLine(watch.ElapsedTicks / 1000000); + } + + private IEnumerable GetHandlers(int neededCount) + { + if (neededCount > 25) { + throw new Exception(); + } + + var all = new Type[] { + typeof(PerfHandler1), typeof(PerfHandler2), typeof(PerfHandler3), typeof(PerfHandler4), + typeof(PerfHandler5), typeof(PerfHandler6), typeof(PerfHandler7), typeof(PerfHandler8), + typeof(PerfHandler9), typeof(PerfHandler10), typeof(PerfHandler11), typeof(PerfHandler12), + typeof(PerfHandler13), typeof(PerfHandler14), typeof(PerfHandler15), typeof(PerfHandler16), + typeof(PerfHandler17), typeof(PerfHandler18), typeof(PerfHandler19), typeof(PerfHandler20), + typeof(PerfHandler21), typeof(PerfHandler22), typeof(PerfHandler23), typeof(PerfHandler24), + typeof(PerfHandler25) + }; + for (var i = 0; i < neededCount; i++) { + yield return all[i]; + } + } + } +} From 9ded135722b0cb87637d2ad682f7a00704272d40 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 15 Jul 2021 12:44:21 +0500 Subject: [PATCH 07/16] Async methods in IConnectionHandler + default abstract implementor + async async tests --- .../DriverFactoryTest.cs | 185 ++++++++++++++++-- .../Storage/ConnectionHandlerTest.cs | 153 +++++++++++---- .../Orm/Interfaces/ConnectionHandler.cs | 63 ++++++ .../Orm/Interfaces/IConnectionHandler.cs | 56 +++++- 4 files changed, 403 insertions(+), 54 deletions(-) create mode 100644 Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs diff --git a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs index 2782f9be73..7fb9ed1d66 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs @@ -9,35 +9,68 @@ using Xtensive.Orm.Building.Builders; using Xtensive.Sql; using Xtensive.Orm.Tests.Sql.DriverFactoryTestTypes; +using System.Threading.Tasks; +using System.Threading; namespace Xtensive.Orm.Tests.Sql.DriverFactoryTestTypes { - public class TestConnectionHandler : IConnectionHandler + public class TestConnectionHandler : ConnectionHandler { public int OpeningCounter = 0; - public int OpenedCounter = 0; + public int OpeningAsyncCounter = 0; + public int OpeningInitCounter = 0; + public int OpeningInitAsyncCounter = 0; + + public int OpenedCounter = 0; + public int OpenedAsyncCounter = 0; + public int OpeningFailedCounter = 0; + public int OpeningFailedAsyncCounter = 0; - public void ConnectionOpening(ConnectionEventData eventData) + public override void ConnectionOpening(ConnectionEventData eventData) { OpeningCounter++; } - public void ConnectionOpened(ConnectionEventData eventData) + public override Task ConnectionOpeningAsync(ConnectionEventData eventData, CancellationToken cancellationToken) { - OpenedCounter++; + OpeningAsyncCounter++; + return base.ConnectionOpeningAsync(eventData, cancellationToken); } - public void ConnectionInitialization(ConnectionInitEventData eventData) + public override void ConnectionInitialization(ConnectionInitEventData eventData) { OpeningInitCounter++; } - public void ConnectionOpeningFailed(ConnectionErrorEventData eventData) + public override Task ConnectionInitializationAsync(ConnectionInitEventData eventData, CancellationToken cancellationToken) + { + OpeningInitAsyncCounter++; + return base.ConnectionInitializationAsync(eventData, cancellationToken); + } + + public override void ConnectionOpened(ConnectionEventData eventData) + { + OpenedCounter++; + } + + public override Task ConnectionOpenedAsync(ConnectionEventData eventData, CancellationToken cancellationToken) + { + OpenedAsyncCounter++; + return base.ConnectionOpenedAsync(eventData, cancellationToken); + } + + public override void ConnectionOpeningFailed(ConnectionErrorEventData eventData) { OpeningFailedCounter++; } + + public override Task ConnectionOpeningFailedAsync(ConnectionErrorEventData eventData, CancellationToken cancellationToken) + { + OpeningFailedAsyncCounter++; + return base.ConnectionOpeningFailedAsync(eventData, cancellationToken); + } } public static class StaticCounter @@ -142,36 +175,62 @@ public void ConnectionHandlerTest() var factory = (SqlDriverFactory) Activator.CreateInstance(descriptor.DriverFactory); Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); var configuration = new SqlDriverConfiguration(handlersArray); _ = factory.GetDriver(new ConnectionInfo(Url), configuration); Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); configuration = new SqlDriverConfiguration(handlersArray) { EnsureConnectionIsAlive = true }; _ = factory.GetDriver(new ConnectionInfo(Url), configuration); Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(2)); - if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + + if (provider == WellKnown.Provider.SqlServer) { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); - else + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + else { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; _ = factory.GetDriver(new ConnectionInfo(Url), configuration); Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(3)); - if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + + if (provider == WellKnown.Provider.SqlServer) { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); - else + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + else { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = "dummy string to trigger error" }; try { @@ -181,12 +240,112 @@ public void ConnectionHandlerTest() //skip it } Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(4)); - if (provider == WellKnown.Provider.SqlServer) + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + + if (provider == WellKnown.Provider.SqlServer) { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(3)); - else + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + else { Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + } + + [Test] + public async Task ConnectionHandlerAsyncTest() + { + var handlerInstance = new TestConnectionHandler(); + var handlersArray = new[] { handlerInstance }; + var descriptor = ProviderDescriptor.Get(provider); + var factory = (SqlDriverFactory) Activator.CreateInstance(descriptor.DriverFactory); + + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + var configuration = new SqlDriverConfiguration(handlersArray); + _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { EnsureConnectionIsAlive = true }; + _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(2)); + + if (provider == WellKnown.Provider.SqlServer) { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); + } + else { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + } + + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; + _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(3)); + if (provider == WellKnown.Provider.SqlServer) { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); + } + else { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); + } + + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = "dummy string to trigger error" }; + try { + _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); + } + catch { + //skip it + } + + Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(4)); + Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(4)); + + if (provider == WellKnown.Provider.SqlServer) { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(3)); + } + else { + Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); + } + Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(3)); Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(1)); + Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(1)); } private static void TestProvider(string providerName, string connectionString, string connectionUrl) diff --git a/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs b/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs index 9b8f38eed5..0aa5edf81e 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs @@ -12,10 +12,11 @@ using Xtensive.Orm.Providers; using Xtensive.Sql; using Xtensive.Orm.Tests.Storage.ConnectionHandlersModel; +using System.Threading.Tasks; namespace Xtensive.Orm.Tests.Storage.ConnectionHandlersModel { - public class MyConnectionHandler : IConnectionHandler + public class MyConnectionHandler : ConnectionHandler { private Guid instanceMarker; @@ -26,13 +27,13 @@ public class MyConnectionHandler : IConnectionHandler public int ConnectionOpenedCounter; public int ConnectionOpeningFailedCounter; - public void ConnectionOpening(ConnectionEventData eventData) + public override void ConnectionOpening(ConnectionEventData eventData) { instanceMarker = UniqueInstanceIdentifier; ConnectionOpeningCounter++; } - public void ConnectionInitialization(ConnectionInitEventData eventData) + public override void ConnectionInitialization(ConnectionInitEventData eventData) { ConnectionInitializationCounter++; if (instanceMarker != UniqueInstanceIdentifier) { @@ -40,7 +41,7 @@ public void ConnectionInitialization(ConnectionInitEventData eventData) } } - public void ConnectionOpened(ConnectionEventData eventData) + public override void ConnectionOpened(ConnectionEventData eventData) { ConnectionOpenedCounter++; if (instanceMarker != UniqueInstanceIdentifier) { @@ -48,7 +49,7 @@ public void ConnectionOpened(ConnectionEventData eventData) } } - public void ConnectionOpeningFailed(ConnectionErrorEventData eventData) + public override void ConnectionOpeningFailed(ConnectionErrorEventData eventData) { ConnectionOpeningFailedCounter++; if (instanceMarker != UniqueInstanceIdentifier) { @@ -62,7 +63,7 @@ public MyConnectionHandler() } } - public class NoDefaultConstructorHandler : IConnectionHandler + public class NoDefaultConstructorHandler : ConnectionHandler { #pragma warning disable IDE0060 // Remove unused parameter public NoDefaultConstructorHandler(int dummyParameter) @@ -71,7 +72,7 @@ public NoDefaultConstructorHandler(int dummyParameter) } } - public class NonPublicDefaultConstructorHandler : IConnectionHandler + public class NonPublicDefaultConstructorHandler : ConnectionHandler { private NonPublicDefaultConstructorHandler() { @@ -80,31 +81,31 @@ private NonPublicDefaultConstructorHandler() #region Performance Test handlers - public class PerfHandler1 : IConnectionHandler { } - public class PerfHandler2 : IConnectionHandler { } - public class PerfHandler3 : IConnectionHandler { } - public class PerfHandler4 : IConnectionHandler { } - public class PerfHandler5 : IConnectionHandler { } - public class PerfHandler6 : IConnectionHandler { } - public class PerfHandler7 : IConnectionHandler { } - public class PerfHandler8 : IConnectionHandler { } - public class PerfHandler9 : IConnectionHandler { } - public class PerfHandler10 : IConnectionHandler { } - public class PerfHandler11 : IConnectionHandler { } - public class PerfHandler12 : IConnectionHandler { } - public class PerfHandler13 : IConnectionHandler { } - public class PerfHandler14 : IConnectionHandler { } - public class PerfHandler15 : IConnectionHandler { } - public class PerfHandler16 : IConnectionHandler { } - public class PerfHandler17 : IConnectionHandler { } - public class PerfHandler18 : IConnectionHandler { } - public class PerfHandler19 : IConnectionHandler { } - public class PerfHandler20 : IConnectionHandler { } - public class PerfHandler21 : IConnectionHandler { } - public class PerfHandler22 : IConnectionHandler { } - public class PerfHandler23 : IConnectionHandler { } - public class PerfHandler24 : IConnectionHandler { } - public class PerfHandler25 : IConnectionHandler { } + public class PerfHandler1 : ConnectionHandler { } + public class PerfHandler2 : ConnectionHandler { } + public class PerfHandler3 : ConnectionHandler { } + public class PerfHandler4 : ConnectionHandler { } + public class PerfHandler5 : ConnectionHandler { } + public class PerfHandler6 : ConnectionHandler { } + public class PerfHandler7 : ConnectionHandler { } + public class PerfHandler8 : ConnectionHandler { } + public class PerfHandler9 : ConnectionHandler { } + public class PerfHandler10 : ConnectionHandler { } + public class PerfHandler11 : ConnectionHandler { } + public class PerfHandler12 : ConnectionHandler { } + public class PerfHandler13 : ConnectionHandler { } + public class PerfHandler14 : ConnectionHandler { } + public class PerfHandler15 : ConnectionHandler { } + public class PerfHandler16 : ConnectionHandler { } + public class PerfHandler17 : ConnectionHandler { } + public class PerfHandler18 : ConnectionHandler { } + public class PerfHandler19 : ConnectionHandler { } + public class PerfHandler20 : ConnectionHandler { } + public class PerfHandler21 : ConnectionHandler { } + public class PerfHandler22 : ConnectionHandler { } + public class PerfHandler23 : ConnectionHandler { } + public class PerfHandler24 : ConnectionHandler { } + public class PerfHandler25 : ConnectionHandler { } #endregion @@ -156,6 +157,19 @@ public void NoDefaultConstructorTest() domain.DisposeSafely(); } + [Test] + public void NoDefaultConstructorAsyncTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(NoDefaultConstructorHandler)); + + Domain domain = null; + _ = Assert.ThrowsAsync(async () => domain = await Domain.BuildAsync(domainConfig)); + domain.DisposeSafely(); + } + [Test] public void NonPublicDefaultConstructorTest() { @@ -167,6 +181,17 @@ public void NonPublicDefaultConstructorTest() using var domain = Domain.Build(domainConfig); } + [Test] + public async Task NonPublicDefaultConstructorAsyncTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(NonPublicDefaultConstructorHandler)); + + await using var domain = await Domain.BuildAsync(domainConfig); + } + [Test] public void SessionConnectionHandlersTest() { @@ -175,7 +200,7 @@ public void SessionConnectionHandlersTest() domainConfig.Types.Register(typeof(DummyEntity)); domainConfig.Types.Register(typeof(MyConnectionHandler)); - Guid? first = null; + Guid? first = null; using (var domain = Domain.Build(domainConfig)) using (var session = domain.OpenSession()) { var nativeHandler = (SqlSessionHandler) session.Handler; @@ -200,6 +225,39 @@ public void SessionConnectionHandlersTest() Assert.That(first != null && second != null && first != second, Is.True); } + [Test] + public async Task SessionConnectionHandlersAsyncTest() + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + domainConfig.Types.Register(typeof(DummyEntity)); + domainConfig.Types.Register(typeof(MyConnectionHandler)); + + Guid? first = null; + await using (var domain = await Domain.BuildAsync(domainConfig)) + await using (var session = await domain.OpenSessionAsync()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extension = nativeHandler.Connection.Extensions.Get(); + var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); + Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + first = handlerInstance.UniqueInstanceIdentifier; + } + + Guid? second = null; + await using (var domain = await Domain.BuildAsync(domainConfig)) + await using (var session = await domain.OpenSessionAsync()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extension = nativeHandler.Connection.Extensions.Get(); + var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); + Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + second = handlerInstance.UniqueInstanceIdentifier; + } + + Assert.That(first != null && second != null && first != second, Is.True); + } + [Test] [TestCase(0)] [TestCase(1)] @@ -229,6 +287,35 @@ public void ConnectionExtensionExistanceTest(int includeHandlersCount) } } + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public async Task ConnectionExtensionExistanceAsyncTest(int includeHandlersCount) + { + var domainConfig = DomainConfigurationFactory.Create(); + domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; + + foreach (var handler in GetHandlers(includeHandlersCount)) { + domainConfig.Types.Register(handler); + } + + await using (var domain = await Domain.BuildAsync(domainConfig)) + await using (var session = await domain.OpenSessionAsync()) { + var nativeHandler = (SqlSessionHandler) session.Handler; + var extensions = nativeHandler.Connection.Extensions; + if (includeHandlersCount > 0) { + Assert.That(extensions.Count, Is.EqualTo(1)); + var extension = extensions.Get(); + Assert.That(extension, Is.Not.Null); + Assert.That(extension.Handlers.Count, Is.EqualTo(includeHandlersCount)); + } + else { + Assert.That(extensions.Count, Is.EqualTo(0)); + } + } + } + [Explicit] [TestCase(0)] [TestCase(5)] diff --git a/Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs b/Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs new file mode 100644 index 0000000000..b63dcabd30 --- /dev/null +++ b/Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs @@ -0,0 +1,63 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +namespace Xtensive.Orm +{ + /// + /// Base type for connection handlers to be inherited from. + /// + public abstract class ConnectionHandler : IConnectionHandler + { + /// + public virtual void ConnectionOpening(ConnectionEventData eventData) + { + } + + /// + public virtual Task ConnectionOpeningAsync(ConnectionEventData eventData, CancellationToken cancellationToken) + { + ConnectionOpening(eventData); + return Task.CompletedTask; + } + + /// + public virtual void ConnectionInitialization(ConnectionInitEventData eventData) + { + } + + /// + public virtual Task ConnectionInitializationAsync(ConnectionInitEventData eventData, CancellationToken cancellationToken) + { + ConnectionInitialization(eventData); + return Task.CompletedTask; + } + + /// + public virtual void ConnectionOpened(ConnectionEventData eventData) + { + } + + /// + public virtual Task ConnectionOpenedAsync(ConnectionEventData eventData, CancellationToken cancellationToken) + { + ConnectionOpened(eventData); + return Task.CompletedTask; + } + + /// + public virtual void ConnectionOpeningFailed(ConnectionErrorEventData eventData) + { + } + + /// + public virtual Task ConnectionOpeningFailedAsync(ConnectionErrorEventData eventData, CancellationToken cancellationToken) + { + ConnectionOpeningFailed(eventData); + return Task.CompletedTask; + } + } +} diff --git a/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs b/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs index 39708d3d29..48b02edc9e 100644 --- a/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs +++ b/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs @@ -1,7 +1,14 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + namespace Xtensive.Orm { /// - /// Offers event-like methods to access native database connection on different stages + /// Offers event-like methods to access native database connection on different stages. /// public interface IConnectionHandler { @@ -9,25 +16,58 @@ public interface IConnectionHandler /// Executes before connection opening. /// /// Information connected with this event. - void ConnectionOpening(ConnectionEventData eventData) { } + void ConnectionOpening(ConnectionEventData eventData); + + /// + /// Executes before connection opening. + /// + /// Information connected with this event. + /// Cancellation token. + /// Task performing operation. + Task ConnectionOpeningAsync(ConnectionEventData eventData, CancellationToken cancellationToken); + + /// + /// Executes when connection is already opened but initialization script + /// hasn't been executed yet. + /// + /// Information connected with this event. + void ConnectionInitialization(ConnectionInitEventData eventData); /// /// Executes when connection is already opened but initialization script /// hasn't been executed yet. /// /// Information connected with this event. - void ConnectionInitialization(ConnectionInitEventData eventData) { } + /// Cancellation token. + /// Task performing operation. + Task ConnectionInitializationAsync(ConnectionInitEventData eventData, CancellationToken cancellationToken); + + /// + /// Executes when connection is successfully opened and initialized. + /// + /// Information connected with this event. + void ConnectionOpened(ConnectionEventData eventData); + + /// + /// Executes when connection is successfully opened and initialized. + /// + /// Information connected with this event. + /// Cancellation token. + /// Task performing operation. + Task ConnectionOpenedAsync(ConnectionEventData eventData, CancellationToken cancellationToken); /// - /// Executes when connection is successfully opened and initialized + /// Executes if an error appeared on either connection opening or connection initialization. /// - /// Information connected with this event - void ConnectionOpened(ConnectionEventData eventData) { } + /// Information connected with this event. + void ConnectionOpeningFailed(ConnectionErrorEventData eventData); /// /// Executes if an error appeared on either connection opening or connection initialization. /// - /// Information connected with this event - void ConnectionOpeningFailed(ConnectionErrorEventData eventData) { } + /// Information connected with this event. + /// Cancellation token. + /// Task performing operation. + Task ConnectionOpeningFailedAsync(ConnectionErrorEventData eventData, CancellationToken cancellationToken); } } From 3eaa7c1a06134ae732153aed7556d1bf7e283218 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 15 Jul 2021 17:14:09 +0500 Subject: [PATCH 08/16] Async notification of ConnectionHandlers --- Orm/Xtensive.Orm/Sql/SqlHelper.cs | 111 +++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/Orm/Xtensive.Orm/Sql/SqlHelper.cs b/Orm/Xtensive.Orm/Sql/SqlHelper.cs index 9bc6cef33c..d10ae88074 100644 --- a/Orm/Xtensive.Orm/Sql/SqlHelper.cs +++ b/Orm/Xtensive.Orm/Sql/SqlHelper.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -8,14 +8,9 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; -using System.Data.SqlClient; -using System.Linq; using System.Runtime.CompilerServices; -using System.Text; using System.Threading; using System.Threading.Tasks; -using JetBrains.Annotations; -using Xtensive.Collections; using Xtensive.Core; using Xtensive.Orm; using Xtensive.Sql.Dml; @@ -491,6 +486,8 @@ public static NotSupportedException NotSupported(ServerFeatures feature) return NotSupported(feature.ToString()); } + #region Notifications + /// /// Notifies all the that /// is about to be opened. @@ -502,8 +499,29 @@ public static NotSupportedException NotSupported(ServerFeatures feature) public static void NotifyConnectionOpening( IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) { - foreach (var handler in connectionHandlers) + foreach (var handler in connectionHandlers) { handler.ConnectionOpening(new ConnectionEventData(connection, reconnect)); + } + } + + /// + /// Notifies all the that + /// is about to be opened. + /// + /// The handlers that should be notified. + /// The connection that is opening. + /// if event happened on attemp to restore connection, otherwise . + /// Cancellation token. + /// Task performing operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static async Task NotifyConnectionOpeningAsync( + IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false, CancellationToken token = default) + { + foreach (var handler in connectionHandlers) { + await handler.ConnectionOpeningAsync( + new ConnectionEventData(connection, reconnect), token) + .ConfigureAwait(false); + } } /// @@ -518,8 +536,33 @@ public static void NotifyConnectionOpening( public static void NotifyConnectionInitializing( IEnumerable connectionHandlers, DbConnection connection, string initializationScript, bool reconnect = false) { - foreach (var handler in connectionHandlers) + foreach (var handler in connectionHandlers) { handler.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect)); + } + } + + /// + /// Notifies all the that + /// opened connection is about to be initialized with . + /// + /// The handlers that should be notified. + /// Opened but not initialized connection + /// The script that will run to initialize connection + /// if event happened on attemp to restore connection, otherwise . + /// Cancellation token. + /// Task performing operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static async Task NotifyConnectionInitializingAsync(IEnumerable connectionHandlers, + DbConnection connection, + string initializationScript, + bool reconnect = false, + CancellationToken token = default) + { + foreach (var handler in connectionHandlers) { + await handler.ConnectionInitializationAsync( + new ConnectionInitEventData(initializationScript, connection, reconnect), token) + .ConfigureAwait(false); + } } /// @@ -533,8 +576,29 @@ public static void NotifyConnectionInitializing( public static void NotifyConnectionOpened( IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) { - foreach (var handler in connectionHandlers) + foreach (var handler in connectionHandlers) { handler.ConnectionOpened(new ConnectionEventData(connection, reconnect)); + } + } + + /// + /// Notifies all the about + /// successful connection opening. + /// + /// The handlers that should be notified. + /// The connection that is completely opened and initialized. + /// if event happened on attemp to restore connection, otherwise . + /// Cancellation token. + /// Task performing operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static async Task NotifyConnectionOpenedAsync( + IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false, CancellationToken token = default) + { + foreach (var handler in connectionHandlers) { + await handler.ConnectionOpenedAsync( + new ConnectionEventData(connection, reconnect), token) + .ConfigureAwait(false); + } } /// @@ -549,8 +613,35 @@ public static void NotifyConnectionOpened( public static void NotifyConnectionOpeningFailed( IEnumerable connectionHandlers, DbConnection connection, Exception exception, bool reconnect = false) { - foreach (var handler in connectionHandlers) + foreach (var handler in connectionHandlers) { handler.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect)); + } } + + /// + /// Notifies all the about + /// connection opening failure. + /// + /// The handlers that should be notified. + /// Connection that failed to be opened or properly initialized. + /// The exception which appeared. + /// if event happened on attemp to restore connection, otherwise . + /// Cancellation token. + /// Task performing operation. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static async Task NotifyConnectionOpeningFailedAsync(IEnumerable connectionHandlers, + DbConnection connection, + Exception exception, + bool reconnect = false, + CancellationToken token = default) + { + foreach (var handler in connectionHandlers) { + await handler.ConnectionOpeningFailedAsync( + new ConnectionErrorEventData(exception, connection, reconnect), token) + .ConfigureAwait(false); + } + } + + #endregion } } From 3e35a07a858788f45b977335d7ee449c35db9b26 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 15 Jul 2021 17:16:24 +0500 Subject: [PATCH 09/16] Remove old connectionInterceptor name completely --- Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs index b6a469daea..3a20dcc59e 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs @@ -1,6 +1,6 @@ -// Copyright (C) 2003-2012 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2012-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2012.12.27 @@ -43,7 +43,7 @@ public sealed class SqlDriverConfiguration public SqlDriverConfiguration Clone() { // no deep cloning - var interceptors = (ConnectionHandlers.Count == 0) + var handlers = (ConnectionHandlers.Count == 0) ? Array.Empty() : ConnectionHandlers.ToArray(ConnectionHandlers.Count); @@ -51,7 +51,7 @@ public SqlDriverConfiguration Clone() ForcedServerVersion = ForcedServerVersion, ConnectionInitializationSql = ConnectionInitializationSql, EnsureConnectionIsAlive = EnsureConnectionIsAlive, - ConnectionHandlers = interceptors + ConnectionHandlers = handlers }; } @@ -63,9 +63,9 @@ public SqlDriverConfiguration() ConnectionHandlers = Array.Empty(); } - public SqlDriverConfiguration(IReadOnlyCollection connectionInterceptors) + public SqlDriverConfiguration(IReadOnlyCollection connectionHandlers) { - ConnectionHandlers = connectionInterceptors; + ConnectionHandlers = connectionHandlers; } } } \ No newline at end of file From 8d9e2ccb85a5df7822497ac347f24fae5d77e46a Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 15 Jul 2021 18:01:33 +0500 Subject: [PATCH 10/16] Add async connection notifications + fix for Sql server notification fix --- .../Sql.Drivers.Firebird/DriverFactory.cs | 21 +++-- .../Sql.Drivers.MySql/DriverFactory.cs | 21 +++-- .../Sql.Drivers.Oracle/DriverFactory.cs | 21 +++-- .../Sql.Drivers.PostgreSql/DriverFactory.cs | 25 +++-- .../Sql.Drivers.SqlServer/Connection.cs | 94 ++++++++++++++++--- .../Sql.Drivers.SqlServer/DriverFactory.cs | 69 +++++++++++--- .../Sql.Drivers.Sqlite/DriverFactory.cs | 25 +++-- 7 files changed, 208 insertions(+), 68 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs index b520cf48c0..50840f8f2a 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2020 Xtensive LLC. +// Copyright (C) 2011-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Csaba Beer @@ -152,16 +152,21 @@ private async ValueTask OpenConnectionWithNotifications(FbConnection connection, } } else { - SqlHelper.NotifyConnectionOpening(handlers, connection); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); try { - await connection.OpenAsync(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); - SqlHelper.NotifyConnectionOpened(handlers, connection); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, cancellationToken) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index 605dffaf67..72ae03589f 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2020 Xtensive LLC. +// Copyright (C) 2011-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube @@ -172,16 +172,21 @@ private async ValueTask OpenConnectionWithNotifications(MySqlConnection connecti } } else { - SqlHelper.NotifyConnectionOpening(handlers, connection); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); try { - await connection.OpenAsync(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); - SqlHelper.NotifyConnectionOpened(handlers, connection); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, cancellationToken) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs index 1d47092386..d2c75d7fee 100644 --- a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -165,16 +165,21 @@ private async ValueTask OpenConnectionWithNotifications(OracleConnection connect } } else { - SqlHelper.NotifyConnectionOpening(handlers, connection); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); try { - await connection.OpenAsync(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); - SqlHelper.NotifyConnectionOpened(handlers, connection); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, cancellationToken) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs index 0c9bc86e9d..3b5bece3a6 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -160,8 +160,10 @@ private async ValueTask OpenConnectionWithNotifications(NpgsqlConnection connect SqlHelper.NotifyConnectionOpening(handlers, connection); try { connection.Open(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + } + SqlHelper.ExecuteInitializationSql(connection, configuration); SqlHelper.NotifyConnectionOpened(handlers, connection); } @@ -171,16 +173,21 @@ private async ValueTask OpenConnectionWithNotifications(NpgsqlConnection connect } } else { - SqlHelper.NotifyConnectionOpening(handlers, connection); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); try { - await connection.OpenAsync(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); - SqlHelper.NotifyConnectionOpened(handlers, connection); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, cancellationToken) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs index fe9f497067..27f91d29e9 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -39,7 +39,13 @@ public override void Open() base.Open(); } else { - OpenWithCheckFast(DefaultCheckConnectionQuery); + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) { + OpenWithCheckFast(DefaultCheckConnectionQuery); + } + else { + OpenWithCheckAndNotifications(DefaultCheckConnectionQuery, connectionHandlers); + } } } @@ -51,7 +57,13 @@ public override Task OpenAsync(CancellationToken cancellationToken) return base.OpenAsync(cancellationToken); } - return OpenWithCheckAsync(DefaultCheckConnectionQuery, cancellationToken); + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) { + return OpenWithCheckFastAsync(DefaultCheckConnectionQuery, cancellationToken); + } + else { + return OpenWithCheckAndNotificationsAsync(DefaultCheckConnectionQuery, connectionHandlers, cancellationToken); + } } /// @@ -66,10 +78,12 @@ public override void OpenAndInitialize(string initializationScript) ? DefaultCheckConnectionQuery : initializationScript; var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) + if (connectionHandlers == null) { OpenWithCheckFast(script); - else - OpenWithChecksAndNotifications(script, connectionHandlers); + } + else { + OpenWithCheckAndNotifications(script, connectionHandlers); + } } /// @@ -82,7 +96,10 @@ public override Task OpenAndInitializeAsync(string initializationScript, Cancell var script = string.IsNullOrEmpty(initializationScript.Trim()) ? DefaultCheckConnectionQuery : initializationScript; - return OpenWithCheckAsync(script, token); + var connectionHandlers = Extensions.Get(); + return connectionHandlers == null + ? OpenWithCheckFastAsync(script, token) + : OpenWithCheckAndNotificationsAsync(script, connectionHandlers, token); } /// @@ -203,7 +220,7 @@ private void OpenWithCheckFast(string checkQueryString) var connectionChecked = false; var restoreTriggered = false; while (!connectionChecked) { - base.Open(); + underlyingConnection.Open(); try { using (var command = underlyingConnection.CreateCommand()) { command.CommandText = checkQueryString; @@ -234,7 +251,7 @@ private void OpenWithCheckFast(string checkQueryString) } } - private void OpenWithChecksAndNotifications(string checkQueryString, ConnectionHandlersExtension connectionHandlers) + private void OpenWithCheckAndNotifications(string checkQueryString, ConnectionHandlersExtension connectionHandlers) { var connectionChecked = false; var restoreTriggered = false; @@ -242,7 +259,6 @@ private void OpenWithChecksAndNotifications(string checkQueryString, ConnectionH while (!connectionChecked) { SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); underlyingConnection.Open(); - //base.Open(); try { SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered)); using (var command = underlyingConnection.CreateCommand()) { @@ -276,24 +292,78 @@ private void OpenWithChecksAndNotifications(string checkQueryString, ConnectionH } } + private async Task OpenWithCheckFastAsync(string checkQueryString, CancellationToken cancellationToken) + { + var connectionChecked = false; + var restoreTriggered = false; + + while (!connectionChecked) { + cancellationToken.ThrowIfCancellationRequested(); + await underlyingConnection.OpenAsync(cancellationToken).ConfigureAwait(false); + try { + var command = underlyingConnection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = checkQueryString; + _ = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); + } + connectionChecked = true; + } + catch (Exception exception) { + if (InternalHelpers.ShouldRetryOn(exception)) { + if (restoreTriggered) { + throw; + } + var newConnection = new SqlServerConnection(underlyingConnection.ConnectionString); + try { + underlyingConnection.Close(); + underlyingConnection.Dispose(); + } + catch { } + + underlyingConnection = newConnection; + restoreTriggered = true; + continue; + } + + throw; + } + } + } - private async Task OpenWithCheckAsync(string checkQueryString, CancellationToken cancellationToken) + private async Task OpenWithCheckAndNotificationsAsync(string checkQueryString, + ConnectionHandlersExtension connectionHandlers, CancellationToken cancellationToken) { var connectionChecked = false; var restoreTriggered = false; + var handlers = connectionHandlers.Handlers; while (!connectionChecked) { cancellationToken.ThrowIfCancellationRequested(); - await base.OpenAsync(cancellationToken).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionOpeningAsync(handlers, + UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) + .ConfigureAwait(false); + + await underlyingConnection.OpenAsync(cancellationToken).ConfigureAwait(false); try { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered), cancellationToken) + .ConfigureAwait(false); + var command = underlyingConnection.CreateCommand(); await using (command.ConfigureAwait(false)) { command.CommandText = checkQueryString; _ = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); } connectionChecked = true; + await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) + .ConfigureAwait(false); } catch (Exception exception) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, + UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered), cancellationToken) + .ConfigureAwait(false); + if (InternalHelpers.ShouldRetryOn(exception)) { if (restoreTriggered) { throw; diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs index e2a30e8fe4..a1cd8f50a9 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov @@ -235,8 +235,10 @@ private static SqlServerConnection CreateAndOpenConnection( try { connection.Open(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + } + SqlHelper.ExecuteInitializationSql(connection, configuration); SqlHelper.NotifyConnectionOpened(handlers, connection); } @@ -258,15 +260,33 @@ private static async Task CreateAndOpenConnectionAsync( { var connection = new SqlServerConnection(connectionString); if (!configuration.EnsureConnectionIsAlive) { - await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + var handlers = configuration.ConnectionHandlers; + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); + + try { + await connection.OpenAsync(token).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, token) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token); + } + catch (Exception ex) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, token); + throw; + } return connection; } var testQuery = string.IsNullOrEmpty(configuration.ConnectionInitializationSql) ? CheckConnectionQuery : configuration.ConnectionInitializationSql; - return await EnsureConnectionIsAliveAsync(connection, testQuery, token).ConfigureAwait(false); + return await EnsureConnectionIsAliveAsync(connection, configuration.ConnectionHandlers, testQuery, token).ConfigureAwait(false); } private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection connection, IReadOnlyCollection handlers, string query) @@ -297,7 +317,7 @@ private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection c // ignored } - if (InternalHelpers.ShouldRetryOn(exception)) { + if (retryToConnect) { var (isReconnected, newConnection) = TryReconnect(connectionString, query, handlers); if (isReconnected) { return newConnection; @@ -308,19 +328,31 @@ private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection c } private static async Task EnsureConnectionIsAliveAsync( - SqlServerConnection connection, string query, CancellationToken token) + SqlServerConnection connection, IReadOnlyCollection handlers, + string query, CancellationToken token) { try { + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); + await connection.OpenAsync(token).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, false, token).ConfigureAwait(false); + var command = connection.CreateCommand(); await using (command.ConfigureAwait(false)) { command.CommandText = query; - await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); } + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token).ConfigureAwait(false); return connection; } catch (Exception exception) { + var retryToConnect = InternalHelpers.ShouldRetryOn(exception); + if (!retryToConnect) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, false, token).ConfigureAwait(false); + } + var connectionString = connection.ConnectionString; try { await connection.CloseAsync().ConfigureAwait(false); @@ -330,9 +362,9 @@ private static async Task EnsureConnectionIsAliveAsync( // ignored } - if (InternalHelpers.ShouldRetryOn(exception)) { + if (retryToConnect) { var (isReconnected, newConnection) = - await TryReconnectAsync(connectionString, query, token).ConfigureAwait(false); + await TryReconnectAsync(connectionString, query, handlers, token).ConfigureAwait(false); if (isReconnected) { return newConnection; } @@ -364,19 +396,28 @@ private static (bool isReconnected, SqlServerConnection connection) TryReconnect } private static async Task<(bool isReconnected, SqlServerConnection connection)> TryReconnectAsync( - string connectionString, string query, CancellationToken token) + string connectionString, string query, IReadOnlyCollection handlers, CancellationToken token) { + var connection = new SqlServerConnection(connectionString); try { - var connection = new SqlServerConnection(connectionString); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, true, token).ConfigureAwait(false); + await connection.OpenAsync(token).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, true, token).ConfigureAwait(false); + var command = connection.CreateCommand(); await using (command.ConfigureAwait(false)) { command.CommandText = query; - await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); } + + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, true, token).ConfigureAwait(false); return (true, connection); } - catch { + catch(Exception exception) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, true, token).ConfigureAwait(false); + connection.Dispose(); return (false, null); } } diff --git a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs index 3d2718140f..6c78b0398e 100644 --- a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2011-2020 Xtensive LLC. +// Copyright (C) 2011-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Malisa Ncube @@ -133,8 +133,10 @@ private async ValueTask OpenConnectionWithNotifications(SQLiteConnection connect SqlHelper.NotifyConnectionOpening(handlers, connection); try { connection.Open(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + } + SqlHelper.ExecuteInitializationSql(connection, configuration); SqlHelper.NotifyConnectionOpened(handlers, connection); } @@ -144,16 +146,21 @@ private async ValueTask OpenConnectionWithNotifications(SQLiteConnection connect } } else { - SqlHelper.NotifyConnectionOpening(handlers, connection); + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); try { - await connection.OpenAsync(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken); - SqlHelper.NotifyConnectionOpened(handlers, connection); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, + connection, configuration.ConnectionInitializationSql, false, cancellationToken) + .ConfigureAwait(false); + } + + await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } From 430912d9614cdd973b0ad03eec97fbe431412e7b Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 15 Jul 2021 18:11:12 +0500 Subject: [PATCH 11/16] Copyright update --- Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs | 2 +- Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs | 2 +- Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs | 6 +++++- Orm/Xtensive.Orm/Orm/ConnectionEventData.cs | 6 +++++- Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs | 6 +++++- Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs | 2 +- Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs | 2 +- Orm/Xtensive.Orm/Sql/SqlConnection.cs | 2 +- Orm/Xtensive.Orm/Sql/SqlDriver.cs | 2 +- 9 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs index 7fb9ed1d66..e002490e34 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2010 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs index 8e1b3fb949..8d2c5394b1 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2010-2020 Xtensive LLC. +// Copyright (C) 2010-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Alex Yakunin diff --git a/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs index 83c295beaa..1e8ff71210 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionErrorEventData.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System; using System.Data.Common; using Xtensive.Core; diff --git a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs index 770212195d..39327b3a17 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs @@ -1,4 +1,8 @@ -using System.Data.Common; +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Data.Common; using Xtensive.Core; namespace Xtensive.Orm diff --git a/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs index b2c9e1cb76..6825bbaa38 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionInitEventData.cs @@ -1,4 +1,8 @@ -using System.Data.Common; +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Data.Common; using Xtensive.Core; namespace Xtensive.Orm diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs index 9c76a00aff..ede6db42c1 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs index 51c34a7e8a..7236f7502c 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov diff --git a/Orm/Xtensive.Orm/Sql/SqlConnection.cs b/Orm/Xtensive.Orm/Sql/SqlConnection.cs index bacbc36ad6..a13b86565b 100644 --- a/Orm/Xtensive.Orm/Sql/SqlConnection.cs +++ b/Orm/Xtensive.Orm/Sql/SqlConnection.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. diff --git a/Orm/Xtensive.Orm/Sql/SqlDriver.cs b/Orm/Xtensive.Orm/Sql/SqlDriver.cs index e1ce488783..566d9e3c33 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriver.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriver.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2020 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. From 4b354f2adc04afe1c6186315aa000c15120c4c58 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 16 Jul 2021 11:30:17 +0500 Subject: [PATCH 12/16] Async variant of SqlConnection opening --- Orm/Xtensive.Orm/Sql/SqlConnection.cs | 78 +++++++++++++++++++++------ 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/Orm/Xtensive.Orm/Sql/SqlConnection.cs b/Orm/Xtensive.Orm/Sql/SqlConnection.cs index a13b86565b..8a71f14677 100644 --- a/Orm/Xtensive.Orm/Sql/SqlConnection.cs +++ b/Orm/Xtensive.Orm/Sql/SqlConnection.cs @@ -167,8 +167,9 @@ public virtual void Open() { EnsureIsNotDisposed(); var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) + if (connectionHandlers == null) { UnderlyingConnection.Open(); + } else { var handlers = connectionHandlers.Handlers; SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection); @@ -230,11 +231,27 @@ public virtual void OpenAndInitialize(string initializationScript) /// to ensure that all asynchronous operations have completed. /// Token to control cancellation. /// Awaitable task. - public virtual Task OpenAsync(CancellationToken cancellationToken) + public virtual async Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); EnsureIsNotDisposed(); - return UnderlyingConnection.OpenAsync(cancellationToken); + var connectionHandlers = Extensions.Get(); + + if (connectionHandlers == null) { + await UnderlyingConnection.OpenAsync(cancellationToken).ConfigureAwait(false); + } + else { + var handlers = connectionHandlers.Handlers; + await SqlHelper.NotifyConnectionOpeningAsync(handlers, UnderlyingConnection, false, cancellationToken); + try { + await UnderlyingConnection.OpenAsync(cancellationToken); + await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, cancellationToken); + } + catch (Exception ex) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, cancellationToken); + throw; + } + } } /// @@ -249,21 +266,52 @@ public virtual async Task OpenAndInitializeAsync(string initializationScript, Ca { token.ThrowIfCancellationRequested(); EnsureIsNotDisposed(); - await UnderlyingConnection.OpenAsync(token).ConfigureAwait(false); - if (string.IsNullOrEmpty(initializationScript)) { - return; - } + var connectionHandlers = Extensions.Get(); + if (connectionHandlers == null) { + await UnderlyingConnection.OpenAsync(token).ConfigureAwait(false); + if (string.IsNullOrEmpty(initializationScript)) { + return; + } - try { - var command = UnderlyingConnection.CreateCommand(); - await using (command.ConfigureAwait(false)) { - command.CommandText = initializationScript; - await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + try { + var command = UnderlyingConnection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = initializationScript; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + } + catch (OperationCanceledException) { + await UnderlyingConnection.CloseAsync().ConfigureAwait(false); + throw; } } - catch (OperationCanceledException) { - await UnderlyingConnection.CloseAsync().ConfigureAwait(false); - throw; + else { + var handlers = connectionHandlers.Handlers; + await SqlHelper.NotifyConnectionOpeningAsync(handlers, UnderlyingConnection, false, token); + await UnderlyingConnection.OpenAsync(token).ConfigureAwait(false); + if (string.IsNullOrEmpty(initializationScript)) { + await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, token); + return; + } + + try { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, UnderlyingConnection, initializationScript, false, token); + var command = UnderlyingConnection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = initializationScript; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, token); + } + catch (OperationCanceledException ex) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, token); + await UnderlyingConnection.CloseAsync().ConfigureAwait(false); + throw; + } + catch (Exception ex) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, token); + throw; + } } } From 30e1819dc39430c820dc6d102c23b2a5099dd984 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Wed, 4 Aug 2021 19:36:56 +0500 Subject: [PATCH 13/16] Code improvements StorageDriver: ConcurrentDictionary replaced with regular Distionary, SqlDriver: Removed unused property SqlServer driver factory: reorganized connection opening w/ and w/o notification Other minor changes --- .../Sql.Drivers.Firebird/DriverFactory.cs | 10 +- .../Sql.Drivers.MySql/DriverFactory.cs | 6 +- .../Sql.Drivers.Oracle/DriverFactory.cs | 6 +- .../Sql.Drivers.PostgreSql/DriverFactory.cs | 6 +- .../Sql.Drivers.SqlServer/Connection.cs | 12 +- .../Sql.Drivers.SqlServer/DriverFactory.cs | 387 ++++++++++++------ .../Sql.Drivers.Sqlite/DriverFactory.cs | 6 +- .../Orm/Providers/StorageDriver.Operations.cs | 11 +- .../Orm/Providers/StorageDriver.cs | 50 ++- .../Sql/ConnectionHandlersExtension.cs | 2 +- Orm/Xtensive.Orm/Sql/SqlDriver.cs | 15 +- .../Sql/SqlDriverConfiguration.cs | 8 +- Orm/Xtensive.Orm/Sql/SqlExtensions.cs | 18 +- Orm/Xtensive.Orm/Sql/SqlHelper.cs | 37 ++ 14 files changed, 384 insertions(+), 190 deletions(-) diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs index 50840f8f2a..7a12c3b16b 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs @@ -34,7 +34,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf { using var connection = new FbConnection(connectionString); if (configuration.ConnectionHandlers.Count > 0) - OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var defaultSchema = GetDefaultSchema(connection); @@ -48,7 +48,7 @@ protected override async Task CreateDriverAsync( var connection = new FbConnection(connectionString); await using (connection.ConfigureAwait(false)) { if (configuration.ConnectionHandlers.Count > 0) - await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var defaultSchema = await GetDefaultSchemaAsync(connection, token: token).ConfigureAwait(false); @@ -122,7 +122,8 @@ protected override Task ReadDefaultSchemaAsync( DbConnection connection, DbTransaction transaction, CancellationToken token) => SqlHelper.ReadDatabaseAndSchemaAsync(DatabaseAndSchemaQuery, connection, transaction, token); - private async ValueTask OpenConnectionFast(FbConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) + private static async ValueTask OpenConnectionFast(FbConnection connection, + SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) { if (!isAsync) { connection.Open(); @@ -134,7 +135,8 @@ private async ValueTask OpenConnectionFast(FbConnection connection, SqlDriverCon } } - private async ValueTask OpenConnectionWithNotifications(FbConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) + private static async ValueTask OpenConnectionWithNotification(FbConnection connection, + SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) { var handlers = configuration.ConnectionHandlers; if (!isAsync) { diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index 72ae03589f..e08630b9dd 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -71,7 +71,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf { using (var connection = new MySqlConnection(connectionString)) { if (configuration.ConnectionHandlers.Count > 0) - OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var versionString = string.IsNullOrEmpty(configuration.ForcedServerVersion) @@ -91,7 +91,7 @@ protected override async Task CreateDriverAsync( var connection = new MySqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { if (configuration.ConnectionHandlers.Count > 0) - await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var versionString = string.IsNullOrEmpty(configuration.ForcedServerVersion) @@ -151,7 +151,7 @@ private async ValueTask OpenConnectionFast(MySqlConnection connection, } } - private async ValueTask OpenConnectionWithNotifications(MySqlConnection connection, + private async ValueTask OpenConnectionWithNotification(MySqlConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) diff --git a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs index d2c75d7fee..135d75c7c5 100644 --- a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs @@ -72,7 +72,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf { using var connection = new OracleConnection(connectionString); if (configuration.ConnectionHandlers.Count > 0) - OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var version = string.IsNullOrEmpty(configuration.ForcedServerVersion) @@ -89,7 +89,7 @@ protected override async Task CreateDriverAsync( var connection = new OracleConnection(connectionString); await using (connection.ConfigureAwait(false)) { if (configuration.ConnectionHandlers.Count > 0) - await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var version = string.IsNullOrEmpty(configuration.ForcedServerVersion) @@ -144,7 +144,7 @@ private async ValueTask OpenConnectionFast(OracleConnection connection, } } - private async ValueTask OpenConnectionWithNotifications(OracleConnection connection, + private async ValueTask OpenConnectionWithNotification(OracleConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs index 3b5bece3a6..0ee07de734 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs @@ -62,7 +62,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf { using var connection = new NpgsqlConnection(connectionString); if (configuration.ConnectionHandlers.Count > 0) - OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var version = GetVersion(configuration, connection); @@ -77,7 +77,7 @@ protected override async Task CreateDriverAsync( var connection = new NpgsqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { if (configuration.ConnectionHandlers.Count > 0) - await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var version = GetVersion(configuration, connection); @@ -150,7 +150,7 @@ private async ValueTask OpenConnectionFast(NpgsqlConnection connection, } } - private async ValueTask OpenConnectionWithNotifications(NpgsqlConnection connection, + private async ValueTask OpenConnectionWithNotification(NpgsqlConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs index 27f91d29e9..8e0e7e89a4 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs @@ -44,7 +44,7 @@ public override void Open() OpenWithCheckFast(DefaultCheckConnectionQuery); } else { - OpenWithCheckAndNotifications(DefaultCheckConnectionQuery, connectionHandlers); + OpenWithCheckAndNotification(DefaultCheckConnectionQuery, connectionHandlers); } } } @@ -62,7 +62,7 @@ public override Task OpenAsync(CancellationToken cancellationToken) return OpenWithCheckFastAsync(DefaultCheckConnectionQuery, cancellationToken); } else { - return OpenWithCheckAndNotificationsAsync(DefaultCheckConnectionQuery, connectionHandlers, cancellationToken); + return OpenWithCheckAndNotificationAsync(DefaultCheckConnectionQuery, connectionHandlers, cancellationToken); } } @@ -82,7 +82,7 @@ public override void OpenAndInitialize(string initializationScript) OpenWithCheckFast(script); } else { - OpenWithCheckAndNotifications(script, connectionHandlers); + OpenWithCheckAndNotification(script, connectionHandlers); } } @@ -99,7 +99,7 @@ public override Task OpenAndInitializeAsync(string initializationScript, Cancell var connectionHandlers = Extensions.Get(); return connectionHandlers == null ? OpenWithCheckFastAsync(script, token) - : OpenWithCheckAndNotificationsAsync(script, connectionHandlers, token); + : OpenWithCheckAndNotificationAsync(script, connectionHandlers, token); } /// @@ -251,7 +251,7 @@ private void OpenWithCheckFast(string checkQueryString) } } - private void OpenWithCheckAndNotifications(string checkQueryString, ConnectionHandlersExtension connectionHandlers) + private void OpenWithCheckAndNotification(string checkQueryString, ConnectionHandlersExtension connectionHandlers) { var connectionChecked = false; var restoreTriggered = false; @@ -330,7 +330,7 @@ private async Task OpenWithCheckFastAsync(string checkQueryString, CancellationT } } - private async Task OpenWithCheckAndNotificationsAsync(string checkQueryString, + private async Task OpenWithCheckAndNotificationAsync(string checkQueryString, ConnectionHandlersExtension connectionHandlers, CancellationToken cancellationToken) { var connectionChecked = false; diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs index a1cd8f50a9..7ab96ac498 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs @@ -229,196 +229,337 @@ private static SqlServerConnection CreateAndOpenConnection( string connectionString, SqlDriverConfiguration configuration) { var connection = new SqlServerConnection(connectionString); - if (!configuration.EnsureConnectionIsAlive) { - var handlers = configuration.ConnectionHandlers; - SqlHelper.NotifyConnectionOpening(handlers, connection); + var initScript = configuration.ConnectionInitializationSql; - try { - connection.Open(); - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); - } - - SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); - } - catch(Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); - throw; - } + if (!configuration.EnsureConnectionIsAlive) { + if (configuration.ConnectionHandlers.Count == 0) + OpenConnectionFast(connection, initScript, false).GetAwaiter().GetResult(); + else + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); return connection; } - var testQuery = string.IsNullOrEmpty(configuration.ConnectionInitializationSql) + var testQuery = string.IsNullOrEmpty(initScript) ? CheckConnectionQuery - : configuration.ConnectionInitializationSql; - return EnsureConnectionIsAlive(connection, configuration.ConnectionHandlers, testQuery); + : initScript; + if (configuration.ConnectionHandlers.Count == 0) + return EnsureConnectionIsAliveFast(connection, testQuery, false).GetAwaiter().GetResult(); + else + return EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.ConnectionHandlers, false) + .GetAwaiter().GetResult(); } private static async Task CreateAndOpenConnectionAsync( string connectionString, SqlDriverConfiguration configuration, CancellationToken token) { var connection = new SqlServerConnection(connectionString); + var initScript = configuration.ConnectionInitializationSql; + if (!configuration.EnsureConnectionIsAlive) { - var handlers = configuration.ConnectionHandlers; - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); + if (configuration.ConnectionHandlers.Count == 0) + await OpenConnectionFast(connection, initScript, true, token).ConfigureAwait(false); + else + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); + return connection; + } - try { - await connection.OpenAsync(token).ConfigureAwait(false); + var testQuery = string.IsNullOrEmpty(initScript) + ? CheckConnectionQuery + : initScript; + if (configuration.ConnectionHandlers.Count == 0) + return await EnsureConnectionIsAliveFast(connection, testQuery, true, token).ConfigureAwait(false); + else + return await EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.ConnectionHandlers, true, token) + .ConfigureAwait(false); + } - if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, - connection, configuration.ConnectionInitializationSql, false, token) - .ConfigureAwait(false); - } + private static async ValueTask OpenConnectionFast(SqlServerConnection connection, + string sqlScript, bool isAsync, CancellationToken token = default) + { + if (!isAsync) { + connection.Open(); + SqlHelper.ExecuteInitializationSql(connection, sqlScript); + } + else { + await connection.OpenAsync(token).ConfigureAwait(false); + await SqlHelper.ExecuteInitializationSqlAsync(connection, sqlScript, token).ConfigureAwait(false); + } + } - await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, token).ConfigureAwait(false); + private static async ValueTask OpenConnectionWithNotification(SqlServerConnection connection, + SqlDriverConfiguration configuration, bool isAsync, CancellationToken token = default) + { + var handlers = configuration.ConnectionHandlers; + var initSql = configuration.ConnectionInitializationSql; + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); + if (!string.IsNullOrEmpty(initSql)) { + SqlHelper.NotifyConnectionInitializing(handlers, connection, initSql); + SqlHelper.ExecuteInitializationSql(connection, initSql); + } + SqlHelper.NotifyConnectionOpened(handlers, connection); + } + catch (Exception ex) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + throw; + } + } + else { + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token); + try { + await connection.OpenAsync(token); + if (!string.IsNullOrEmpty(initSql)) { + await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, initSql, false, token); + await SqlHelper.ExecuteInitializationSqlAsync(connection, initSql, token); + } await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token); } catch (Exception ex) { await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, token); throw; } - return connection; } - - var testQuery = string.IsNullOrEmpty(configuration.ConnectionInitializationSql) - ? CheckConnectionQuery - : configuration.ConnectionInitializationSql; - return await EnsureConnectionIsAliveAsync(connection, configuration.ConnectionHandlers, testQuery, token).ConfigureAwait(false); } - private static SqlServerConnection EnsureConnectionIsAlive(SqlServerConnection connection, IReadOnlyCollection handlers, string query) + private static async ValueTask EnsureConnectionIsAliveFast(SqlServerConnection connection, + string query, bool isAsync, CancellationToken token = default) { - try { - SqlHelper.NotifyConnectionOpening(handlers, connection); - connection.Open(); - SqlHelper.NotifyConnectionInitializing(handlers, connection, query); + if (!isAsync) { + try { + connection.Open(); + + using (var command = connection.CreateCommand()) { + command.CommandText = query; + _ = command.ExecuteNonQuery(); + } - using var command = connection.CreateCommand(); - command.CommandText = query; - _ = command.ExecuteNonQuery(); + return connection; + } + catch (Exception exception) { + try { + connection.Close(); + connection.Dispose(); + } + catch { + // ignored + } - SqlHelper.NotifyConnectionOpened(handlers, connection); - return connection; + if (InternalHelpers.ShouldRetryOn(exception)) { + var (isReconnected, newConnection) = + TryReconnectFast(connection.ConnectionString, query, isAsync).GetAwaiter().GetResult(); + if (isReconnected) + return newConnection; + } + throw; + } } - catch (Exception exception) { - var retryToConnect = InternalHelpers.ShouldRetryOn(exception); - if(!retryToConnect) - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception); - - var connectionString = connection.ConnectionString; + else { try { - connection.Close(); - connection.Dispose(); - } - catch { - // ignored + await connection.OpenAsync(token).ConfigureAwait(false); + + var command = connection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = query; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + + return connection; } + catch (Exception exception) { + try { + await connection.CloseAsync().ConfigureAwait(false); + await connection.DisposeAsync().ConfigureAwait(false); + } + catch { + // ignored + } - if (retryToConnect) { - var (isReconnected, newConnection) = TryReconnect(connectionString, query, handlers); - if (isReconnected) { - return newConnection; + if (InternalHelpers.ShouldRetryOn(exception)) { + var (isReconnected, newConnection) = + await TryReconnectFast(connection.ConnectionString, query, isAsync, token).ConfigureAwait(false); + if (isReconnected) { + return newConnection; + } } + throw; } - throw; } } - private static async Task EnsureConnectionIsAliveAsync( - SqlServerConnection connection, IReadOnlyCollection handlers, - string query, CancellationToken token) + private static async ValueTask EnsureConnectionIsAliveWithNotification(SqlServerConnection connection, + string query, IReadOnlyCollection handlers, bool isAsync, CancellationToken token = default) { - try { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection); + try { + connection.Open(); - await connection.OpenAsync(token).ConfigureAwait(false); + SqlHelper.NotifyConnectionInitializing(handlers, connection, query); - await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, false, token).ConfigureAwait(false); + using (var command = connection.CreateCommand()) { + command.CommandText = query; + _ = command.ExecuteNonQuery(); + } - var command = connection.CreateCommand(); - await using (command.ConfigureAwait(false)) { - command.CommandText = query; - _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + SqlHelper.NotifyConnectionOpened(handlers, connection); + return connection; } + catch (Exception exception) { + var retryToConnect = InternalHelpers.ShouldRetryOn(exception); + if (!retryToConnect) + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception); + try { + connection.Close(); + connection.Dispose(); + } + catch { + // ignored + } - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token).ConfigureAwait(false); - return connection; - } - catch (Exception exception) { - var retryToConnect = InternalHelpers.ShouldRetryOn(exception); - if (!retryToConnect) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, false, token).ConfigureAwait(false); + if (retryToConnect) { + var (isReconnected, newConnection) = TryReconnectWithNotification(connection.ConnectionString, query, handlers, isAsync) + .GetAwaiter().GetResult(); + if (isReconnected) { + return newConnection; + } + } + throw; } + } + else { + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); - var connectionString = connection.ConnectionString; try { - await connection.CloseAsync().ConfigureAwait(false); - await connection.DisposeAsync().ConfigureAwait(false); - } - catch { - // ignored + await connection.OpenAsync(token).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, false, token).ConfigureAwait(false); + + var command = connection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = query; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token).ConfigureAwait(false); + return connection; } + catch (Exception exception) { + var retryToConnect = InternalHelpers.ShouldRetryOn(exception); + if (!retryToConnect) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, false, token).ConfigureAwait(false); + } - if (retryToConnect) { - var (isReconnected, newConnection) = - await TryReconnectAsync(connectionString, query, handlers, token).ConfigureAwait(false); - if (isReconnected) { - return newConnection; + var connectionString = connection.ConnectionString; + try { + await connection.CloseAsync().ConfigureAwait(false); + await connection.DisposeAsync().ConfigureAwait(false); + } + catch { + // ignored } + + if (retryToConnect) { + var (isReconnected, newConnection) = + await TryReconnectWithNotification(connectionString, query, handlers, isAsync, token).ConfigureAwait(false); + if (isReconnected) { + return newConnection; + } + } + throw; } - throw; } } - private static (bool isReconnected, SqlServerConnection connection) TryReconnect( - string connectionString, string query, IReadOnlyCollection handlers) + private static async Task<(bool isReconnected, SqlServerConnection connection)> TryReconnectFast( + string connectionString, string query, bool isAsync, CancellationToken token = default) { var connection = new SqlServerConnection(connectionString); - try { - SqlHelper.NotifyConnectionOpening(handlers, connection, true); - connection.Open(); - SqlHelper.NotifyConnectionInitializing(handlers, connection, query, true); - using (var command = connection.CreateCommand()) { - command.CommandText = query; - _ = command.ExecuteNonQuery(); + if (!isAsync) { + try { + connection.Open(); + + using (var command = connection.CreateCommand()) { + command.CommandText = query; + _ = command.ExecuteNonQuery(); + } + + return (true, connection); + } + catch { + connection.Dispose(); + return (false, null); } - SqlHelper.NotifyConnectionOpened(handlers, connection, true); - return (true, connection); } - catch(Exception exception) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception, true); - connection.Dispose(); - return (false, null); + else { + try { + await connection.OpenAsync(token).ConfigureAwait(false); + + var command = connection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = query; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + + return (true, connection); + } + catch { + await connection.DisposeAsync(); + return (false, null); + } } } - private static async Task<(bool isReconnected, SqlServerConnection connection)> TryReconnectAsync( - string connectionString, string query, IReadOnlyCollection handlers, CancellationToken token) + private static async Task<(bool isReconnected, SqlServerConnection connection)> TryReconnectWithNotification( + string connectionString, string query, IReadOnlyCollection handlers, + bool isAsync, CancellationToken token = default) { var connection = new SqlServerConnection(connectionString); - try { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, true, token).ConfigureAwait(false); + if (!isAsync) { + SqlHelper.NotifyConnectionOpening(handlers, connection, true); - await connection.OpenAsync(token).ConfigureAwait(false); + try { + connection.Open(); + SqlHelper.NotifyConnectionInitializing(handlers, connection, query, true); - await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, true, token).ConfigureAwait(false); + using (var command = connection.CreateCommand()) { + command.CommandText = query; + _ = command.ExecuteNonQuery(); + } - var command = connection.CreateCommand(); - await using (command.ConfigureAwait(false)) { - command.CommandText = query; - _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + SqlHelper.NotifyConnectionOpened(handlers, connection, true); + return (true, connection); + } + catch (Exception exception) { + SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception, true); + connection.Dispose(); + return (false, null); } - - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, true, token).ConfigureAwait(false); - return (true, connection); } - catch(Exception exception) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, true, token).ConfigureAwait(false); - connection.Dispose(); - return (false, null); + else { + await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, true, token).ConfigureAwait(false); + + try { + await connection.OpenAsync(token).ConfigureAwait(false); + + await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, true, token).ConfigureAwait(false); + + var command = connection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = query; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + + await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, true, token).ConfigureAwait(false); + return (true, connection); + } + catch (Exception exception) { + await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, true, token).ConfigureAwait(false); + await connection.DisposeAsync(); + return (false, null); + } } } diff --git a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs index 6c78b0398e..bfc01d35c3 100644 --- a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs @@ -44,7 +44,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf { using var connection = new SQLiteConnection(connectionString); if (configuration.ConnectionHandlers.Count > 0) - OpenConnectionWithNotifications(connection, configuration, false).GetAwaiter().GetResult(); + OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); var defaultSchema = GetDefaultSchema(connection); @@ -59,7 +59,7 @@ protected override async Task CreateDriverAsync( var connection = new SQLiteConnection(connectionString); await using (connection.ConfigureAwait(false)) { if (configuration.ConnectionHandlers.Count > 0) - await OpenConnectionWithNotifications(connection, configuration, true, token).ConfigureAwait(false); + await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); var defaultSchema = await GetDefaultSchemaAsync(connection, token: token).ConfigureAwait(false); @@ -123,7 +123,7 @@ private async ValueTask OpenConnectionFast(SQLiteConnection connection, } } - private async ValueTask OpenConnectionWithNotifications(SQLiteConnection connection, + private async ValueTask OpenConnectionWithNotification(SQLiteConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs index ede6db42c1..b138c6ccbb 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs @@ -50,9 +50,10 @@ public SqlConnection CreateConnection(Session session) catch (Exception exception) { throw ExceptionBuilder.BuildException(exception); } + if (handlerFactoriesCache != null) { - connection.Extensions.Set( - new ConnectionHandlersExtension(CreateHandlersForConnection(configuration.Types.ConnectionHandlers))); + connection.AssignConnectionHandlers( + CreateConnectionHandlersFast(configuration.Types.ConnectionHandlers)); } var sessionConfiguration = GetConfiguration(session); @@ -75,9 +76,8 @@ public void OpenConnection(Session session, SqlConnection connection) SqlLog.Info(Strings.LogSessionXOpeningConnectionY, session.ToStringSafely(), connection.ConnectionInfo); } - var extension = connection.Extensions.Get(); + var script = connection.Extensions.Get()?.Script; - var script = extension?.Script; try { if (!string.IsNullOrEmpty(script)) { connection.OpenAndInitialize(script); @@ -101,10 +101,9 @@ public async Task OpenConnectionAsync(Session session, SqlConnection connection, SqlLog.Info(Strings.LogSessionXOpeningConnectionY, session.ToStringSafely(), connection.ConnectionInfo); } - var extension = connection.Extensions.Get(); + var script = connection.Extensions.Get()?.Script; try { - var script = extension?.Script; if (!string.IsNullOrEmpty(script)) { await connection.OpenAndInitializeAsync(script, cancellationToken).ConfigureAwait(false); } diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs index 7236f7502c..0b2a1e1690 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs @@ -7,9 +7,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading; using System.Threading.Tasks; +using System.Reflection; using Xtensive.Core; +using Xtensive.Linq; using Xtensive.Orm.Logging; using Xtensive.Orm.Configuration; using Xtensive.Orm.Model; @@ -18,10 +21,6 @@ using Xtensive.Sql.Info; using Xtensive.Sql.Model; using Xtensive.Tuples; -using System.Collections.Concurrent; -using Xtensive.Linq; -using System.Linq.Expressions; -using System.Reflection; namespace Xtensive.Orm.Providers { @@ -30,7 +29,8 @@ namespace Xtensive.Orm.Providers /// public sealed partial class StorageDriver { - private static readonly MethodInfo FactoryCreatorMethod = typeof(StorageDriver).GetMethod(nameof(NewFactory), BindingFlags.Static | BindingFlags.NonPublic); + private static readonly MethodInfo FactoryCreatorMethod = typeof(StorageDriver) + .GetMethod(nameof(CreateNewHandler), BindingFlags.Static | BindingFlags.NonPublic); private readonly DomainConfiguration configuration; private readonly SqlDriver underlyingDriver; @@ -39,7 +39,7 @@ public sealed partial class StorageDriver private readonly bool isLoggingEnabled; private readonly bool hasSavepoints; - private readonly ConcurrentDictionary> handlerFactoriesCache; + private readonly IReadOnlyDictionary> handlerFactoriesCache; public ProviderInfo ProviderInfo { get; private set; } @@ -159,25 +159,40 @@ private void FixExtractionResultSqlServerFamily(SqlExtractionResult result) } } - private IReadOnlyCollection CreateHandlersForConnection(IEnumerable connectionHandlerTypes) + private IReadOnlyCollection CreateConnectionHandlersFast(IEnumerable connectionHandlerTypes) { if (handlerFactoriesCache == null) return Array.Empty(); var instances = new List(handlerFactoriesCache.Count); foreach (var type in connectionHandlerTypes) { - if (handlerFactoriesCache.TryGetValue(type, out var factory)) + if (handlerFactoriesCache.TryGetValue(type, out var factory)) { instances.Add(factory()); + } } return instances.ToArray(); } - // used on driver creation so it is very first time handlers are created. - // great place to create and cache factories for faster initialization on session opening later private static IReadOnlyCollection CreateConnectionHandlers(IEnumerable connectionHandlerTypes, - out ConcurrentDictionary> factories) + out IReadOnlyDictionary> factories) { - var instances = new List(); - factories = new ConcurrentDictionary>(); + factories = null; + + List instances; + Dictionary> factoriesLocal; + + if(connectionHandlerTypes is IReadOnlyCollection asCollection) { + if (asCollection.Count == 0) + return Array.Empty(); + instances = new List(asCollection.Count); + factoriesLocal = new Dictionary>(asCollection.Count); + } + else { + if (connectionHandlerTypes.Any()) + return Array.Empty(); + instances = new List(); + factoriesLocal = new Dictionary>(); + } + foreach (var type in connectionHandlerTypes) { var ctor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); if (ctor == null) { @@ -186,14 +201,13 @@ private static IReadOnlyCollection CreateConnectionHandlers( var handlerFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(type).Invoke(null, null); instances.Add(handlerFactory()); - factories[type] = handlerFactory; + factoriesLocal[type] = handlerFactory; } - if (factories.Count == 0) - factories = null; + factories = factoriesLocal; return instances.ToArray(); } - private static Func NewFactory() where T : IConnectionHandler + private static Func CreateNewHandler() where T : IConnectionHandler { return FastExpression.Lambda>( Expression.Convert(Expression.New(typeof(T)), typeof(IConnectionHandler))) @@ -244,7 +258,7 @@ private StorageDriver(SqlDriver driver, ProviderInfo providerInfo, DomainConfiguration configuration, Func modelProvider, - ConcurrentDictionary> factoryCache) + IReadOnlyDictionary> factoryCache) { underlyingDriver = driver; ProviderInfo = providerInfo; diff --git a/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs b/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs index 03e2abc199..abd0bdbf7c 100644 --- a/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs +++ b/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs @@ -8,7 +8,7 @@ namespace Xtensive.Sql { /// - /// Wrapper to pass handlers to connection. + /// Wrapper to pass s to connection. /// public sealed class ConnectionHandlersExtension { diff --git a/Orm/Xtensive.Orm/Sql/SqlDriver.cs b/Orm/Xtensive.Orm/Sql/SqlDriver.cs index 566d9e3c33..107319c921 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriver.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriver.cs @@ -45,11 +45,6 @@ public abstract class SqlDriver /// public SqlTranslator Translator { get; private set; } - /// - /// Gets s collection. - /// - public IReadOnlyCollection ConnectionHandlers { get; private set; } - /// /// Gets connection string for the specified . /// @@ -302,8 +297,6 @@ public SqlConnection CreateConnection() { var result = DoCreateConnection(); result.ConnectionInfo = originConnectionInfo; - if (ConnectionHandlers.Count != 0) - result.Extensions.Set(new ConnectionHandlersExtension(ConnectionHandlers)); return result; } @@ -316,8 +309,6 @@ public SqlConnection CreateConnection(ConnectionInfo connectionInfo) { var result = DoCreateConnection(); result.ConnectionInfo = connectionInfo; - if (ConnectionHandlers.Count != 0) - result.Extensions.Set(new ConnectionHandlersExtension(ConnectionHandlers)); return result; } @@ -382,14 +373,10 @@ protected virtual void RegisterCustomReverseMappings(TypeMappingRegistryBuilder #region Private / internal methods - internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo) => - Initialize(creator, creatorConnectionInfo, Array.Empty()); - - internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo, IReadOnlyCollection connectionHandlers) + internal void Initialize(SqlDriverFactory creator, ConnectionInfo creatorConnectionInfo) { origin = creator; originConnectionInfo = creatorConnectionInfo; - ConnectionHandlers = connectionHandlers; var serverInfoProvider = CreateServerInfoProvider(); ServerInfo = ServerInfo.Build(serverInfoProvider); diff --git a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs index 3a20dcc59e..e295a2a67b 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs @@ -47,11 +47,10 @@ public SqlDriverConfiguration Clone() ? Array.Empty() : ConnectionHandlers.ToArray(ConnectionHandlers.Count); - return new SqlDriverConfiguration { + return new SqlDriverConfiguration(handlers) { ForcedServerVersion = ForcedServerVersion, ConnectionInitializationSql = ConnectionInitializationSql, - EnsureConnectionIsAlive = EnsureConnectionIsAlive, - ConnectionHandlers = handlers + EnsureConnectionIsAlive = EnsureConnectionIsAlive }; } @@ -63,6 +62,9 @@ public SqlDriverConfiguration() ConnectionHandlers = Array.Empty(); } + /// + /// Creates new instance of this type. + /// public SqlDriverConfiguration(IReadOnlyCollection connectionHandlers) { ConnectionHandlers = connectionHandlers; diff --git a/Orm/Xtensive.Orm/Sql/SqlExtensions.cs b/Orm/Xtensive.Orm/Sql/SqlExtensions.cs index 5d656e584f..80615e39ce 100644 --- a/Orm/Xtensive.Orm/Sql/SqlExtensions.cs +++ b/Orm/Xtensive.Orm/Sql/SqlExtensions.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2003-2010 Xtensive LLC. -// All rights reserved. -// For conditions of distribution and use, see license. +// Copyright (C) 2009-2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. // Created by: Denis Krjuchkov // Created: 2009.07.30 using System; +using System.Collections.Generic; using Xtensive.Core; using Xtensive.Orm; using Xtensive.Sql.Dml; @@ -49,5 +50,16 @@ public static string GetSchema(this UrlInfo url, string defaultValue) var result = resource.Substring(position + 1).TryCutSuffix(SchemaSeparatorString); return string.IsNullOrEmpty(result) ? defaultValue : result; } + + /// + /// Adds handlers to connection so they will take effect on connection operations. + /// + /// The connection to assign handlers. + /// The handlers. + public static void AssignConnectionHandlers(this SqlConnection connection, + IReadOnlyCollection connectionHandlers) + { + connection.Extensions.Set(new ConnectionHandlersExtension(connectionHandlers)); + } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/SqlHelper.cs b/Orm/Xtensive.Orm/Sql/SqlHelper.cs index d10ae88074..57e64c7720 100644 --- a/Orm/Xtensive.Orm/Sql/SqlHelper.cs +++ b/Orm/Xtensive.Orm/Sql/SqlHelper.cs @@ -401,6 +401,21 @@ public static void ExecuteInitializationSql(DbConnection connection, SqlDriverCo command.ExecuteNonQuery(); } + /// + /// Executes (if any). + /// + /// Connection to initialize. + /// Sql expression. + public static void ExecuteInitializationSql(DbConnection connection, string initializationSql) + { + if (string.IsNullOrEmpty(initializationSql)) { + return; + } + using var command = connection.CreateCommand(); + command.CommandText = initializationSql; + _ = command.ExecuteNonQuery(); + } + /// /// Executes (if any). /// @@ -423,6 +438,28 @@ public static async Task ExecuteInitializationSqlAsync( } } + /// + /// Executes (if any). + /// + /// Multiple active operations are not supported. Use + /// to ensure that all asynchronous operations have completed. + /// Connection to initialize. + /// Sql expression. + /// The token to cancel async operation if needed. + public static async Task ExecuteInitializationSqlAsync( + DbConnection connection, string initializationSql, CancellationToken token) + { + if (string.IsNullOrEmpty(initializationSql)) { + return; + } + + var command = connection.CreateCommand(); + await using (command.ConfigureAwait(false)) { + command.CommandText = initializationSql; + _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); + } + } + /// /// Reduces the isolation level to the most commonly supported ones. /// From 31b15a3b8db3e7af61ffc3ef17682d4cf5567fac Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 5 Aug 2021 15:45:49 +0500 Subject: [PATCH 14/16] Off topic: Forced Azure Version updated and moved to constant --- .../Sql.Drivers.SqlServer/DriverFactory.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs index 7ab96ac498..7e7bd2adf5 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs @@ -37,6 +37,8 @@ FROM [master].[sys].[sysmessages] msg private const string VersionQuery = "SELECT @@VERSION"; + private const string ForcedAzureVersion = "12.0.0.0"; + private static ErrorMessageParser CreateMessageParser(SqlServerConnection connection) { bool isEnglish; @@ -151,7 +153,7 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf var parser = isAzure ? new ErrorMessageParser() : CreateMessageParser(connection); var versionString = isForcedVersion - ? isForcedAzure ? "10.0.0.0" : forcedServerVersion + ? isForcedAzure ? ForcedAzureVersion : forcedServerVersion : connection.ServerVersion ?? string.Empty; var version = new Version(versionString); var defaultSchema = GetDefaultSchema(connection); From 85abac961d93b9f2fa35998bb2cf8c401e752a18 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Tue, 10 Aug 2021 09:18:27 +0500 Subject: [PATCH 15/16] Mistake in comment fixed --- Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs index 97601645ff..c678ab999f 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs @@ -92,7 +92,7 @@ public IEnumerable ConnectionHandlers } return connectionHandlers; } - // if instacne is not locked then there is a chance of new handlers appeared + // if instance is not locked then there is a chance of new handlers appeared return this.Where(IsConnectionHandler); } } From 03fdc5ab68597a71dcb6d5a691103d70324b4ec0 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 26 Aug 2021 16:15:38 +0500 Subject: [PATCH 16/16] Rename connection handlers -> connection accessors --- .../Sql.Drivers.Firebird/DriverFactory.cs | 22 +- .../Sql.Drivers.MySql/DriverFactory.cs | 22 +- .../Sql.Drivers.Oracle/DriverFactory.cs | 22 +- .../Sql.Drivers.PostgreSql/DriverFactory.cs | 22 +- .../Sql.Drivers.SqlServer/Connection.cs | 48 ++-- .../Sql.Drivers.SqlServer/DriverFactory.cs | 70 +++--- .../Sql.Drivers.Sqlite/DriverFactory.cs | 22 +- .../DriverFactoryTest.cs | 218 +++++++++--------- ...ndlerTest.cs => ConnectionAccessorTest.cs} | 175 +++++++------- .../Orm/Configuration/DomainTypeRegistry.cs | 30 +-- Orm/Xtensive.Orm/Orm/ConnectionEventData.cs | 2 +- ...tionHandler.cs => DbConnectionAccessor.cs} | 4 +- ...ionHandler.cs => IDbConnectionAccessor.cs} | 2 +- .../Orm/Providers/StorageDriver.Operations.cs | 6 +- .../Orm/Providers/StorageDriver.cs | 70 +++--- .../Sql/ConnectionHandlersExtension.cs | 25 -- .../Sql/DbConnectionAccessorExtension.cs | 25 ++ Orm/Xtensive.Orm/Sql/SqlConnection.cs | 57 +++-- .../Sql/SqlDriverConfiguration.cs | 18 +- Orm/Xtensive.Orm/Sql/SqlExtensions.cs | 12 +- Orm/Xtensive.Orm/Sql/SqlHelper.cs | 96 ++++---- Orm/Xtensive.Orm/Strings.Designer.cs | 6 +- Orm/Xtensive.Orm/Strings.resx | 4 +- 23 files changed, 487 insertions(+), 491 deletions(-) rename Orm/Xtensive.Orm.Tests/Storage/{ConnectionHandlerTest.cs => ConnectionAccessorTest.cs} (60%) rename Orm/Xtensive.Orm/Orm/Interfaces/{ConnectionHandler.cs => DbConnectionAccessor.cs} (91%) rename Orm/Xtensive.Orm/Orm/Interfaces/{IConnectionHandler.cs => IDbConnectionAccessor.cs} (98%) delete mode 100644 Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs create mode 100644 Orm/Xtensive.Orm/Sql/DbConnectionAccessorExtension.cs diff --git a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs index 7a12c3b16b..6a272eb8e0 100644 --- a/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Firebird/Sql.Drivers.Firebird/DriverFactory.cs @@ -33,7 +33,7 @@ public class DriverFactory : SqlDriverFactory protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new FbConnection(connectionString); - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); @@ -47,7 +47,7 @@ protected override async Task CreateDriverAsync( { var connection = new FbConnection(connectionString); await using (connection.ConfigureAwait(false)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); @@ -138,37 +138,37 @@ private static async ValueTask OpenConnectionFast(FbConnection connection, private static async ValueTask OpenConnectionWithNotification(FbConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken cancellationToken = default) { - var handlers = configuration.ConnectionHandlers; + var accessors = configuration.DbConnectionAccessors; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(accessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.NotifyConnectionInitializing(accessors, connection, configuration.ConnectionInitializationSql); SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(accessors, connection); } catch(Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(accessors, connection, configuration.ConnectionInitializationSql, false, cancellationToken) .ConfigureAwait(false); } await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs index e08630b9dd..ab35623afc 100644 --- a/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.MySql/Sql.Drivers.MySql/DriverFactory.cs @@ -70,7 +70,7 @@ private static Version ParseVersion(string version) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using (var connection = new MySqlConnection(connectionString)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); @@ -90,7 +90,7 @@ protected override async Task CreateDriverAsync( { var connection = new MySqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); @@ -156,37 +156,37 @@ private async ValueTask OpenConnectionWithNotification(MySqlConnection connectio bool isAsync, CancellationToken cancellationToken = default) { - var handlers = configuration.ConnectionHandlers; + var acessors = configuration.DbConnectionAccessors; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(acessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.NotifyConnectionInitializing(acessors, connection, configuration.ConnectionInitializationSql); SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(acessors, connection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(acessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(acessors, connection, false, cancellationToken).ConfigureAwait(false); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(acessors, connection, configuration.ConnectionInitializationSql, false, cancellationToken) .ConfigureAwait(false); } await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(acessors, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(acessors, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs index 135d75c7c5..18ed9dc7f9 100644 --- a/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Oracle/Sql.Drivers.Oracle/DriverFactory.cs @@ -71,7 +71,7 @@ protected override string BuildConnectionString(UrlInfo url) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new OracleConnection(connectionString); - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); @@ -88,7 +88,7 @@ protected override async Task CreateDriverAsync( { var connection = new OracleConnection(connectionString); await using (connection.ConfigureAwait(false)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); @@ -149,37 +149,37 @@ private async ValueTask OpenConnectionWithNotification(OracleConnection connecti bool isAsync, CancellationToken cancellationToken = default) { - var handlers = configuration.ConnectionHandlers; + var accessors = configuration.DbConnectionAccessors; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(accessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.NotifyConnectionInitializing(accessors, connection, configuration.ConnectionInitializationSql); SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(accessors, connection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(accessors, connection, configuration.ConnectionInitializationSql, false, cancellationToken) .ConfigureAwait(false); } await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs index 0ee07de734..bf4db22e50 100644 --- a/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs +++ b/Orm/Xtensive.Orm.PostgreSql/Sql.Drivers.PostgreSql/DriverFactory.cs @@ -61,7 +61,7 @@ protected override string BuildConnectionString(UrlInfo url) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new NpgsqlConnection(connectionString); - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); @@ -76,7 +76,7 @@ protected override async Task CreateDriverAsync( { var connection = new NpgsqlConnection(connectionString); await using (connection.ConfigureAwait(false)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); @@ -155,39 +155,39 @@ private async ValueTask OpenConnectionWithNotification(NpgsqlConnection connecti bool isAsync, CancellationToken cancellationToken = default) { - var handlers = configuration.ConnectionHandlers; + var accessors = configuration.DbConnectionAccessors; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(accessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.NotifyConnectionInitializing(accessors, connection, configuration.ConnectionInitializationSql); } SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(accessors, connection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(accessors, connection, configuration.ConnectionInitializationSql, false, cancellationToken) .ConfigureAwait(false); } await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs index 75d9d44887..1bbc6f39ad 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/Connection.cs @@ -39,12 +39,12 @@ public override void Open() base.Open(); } else { - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { OpenWithCheckFast(DefaultCheckConnectionQuery); } else { - OpenWithCheckAndNotification(DefaultCheckConnectionQuery, connectionHandlers); + OpenWithCheckAndNotification(DefaultCheckConnectionQuery, connectionAccessorEx); } } } @@ -57,12 +57,12 @@ public override Task OpenAsync(CancellationToken cancellationToken) return base.OpenAsync(cancellationToken); } - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { return OpenWithCheckFastAsync(DefaultCheckConnectionQuery, cancellationToken); } else { - return OpenWithCheckAndNotificationAsync(DefaultCheckConnectionQuery, connectionHandlers, cancellationToken); + return OpenWithCheckAndNotificationAsync(DefaultCheckConnectionQuery, connectionAccessorEx, cancellationToken); } } @@ -77,12 +77,12 @@ public override void OpenAndInitialize(string initializationScript) var script = string.IsNullOrEmpty(initializationScript.Trim()) ? DefaultCheckConnectionQuery : initializationScript; - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { OpenWithCheckFast(script); } else { - OpenWithCheckAndNotification(script, connectionHandlers); + OpenWithCheckAndNotification(script, connectionAccessorEx); } } @@ -96,10 +96,10 @@ public override Task OpenAndInitializeAsync(string initializationScript, Cancell var script = string.IsNullOrEmpty(initializationScript.Trim()) ? DefaultCheckConnectionQuery : initializationScript; - var connectionHandlers = Extensions.Get(); - return connectionHandlers == null + var connectionAccessorEx = Extensions.Get(); + return connectionAccessorEx == null ? OpenWithCheckFastAsync(script, token) - : OpenWithCheckAndNotificationAsync(script, connectionHandlers, token); + : OpenWithCheckAndNotificationAsync(script, connectionAccessorEx, token); } /// @@ -217,25 +217,25 @@ private void OpenWithCheckFast(string checkQueryString) } } - private void OpenWithCheckAndNotification(string checkQueryString, ConnectionHandlersExtension connectionHandlers) + private void OpenWithCheckAndNotification(string checkQueryString, DbConnectionAccessorExtension connectionAccessorEx) { var connectionChecked = false; var restoreTriggered = false; - var handlers = connectionHandlers.Handlers; + var accessors = connectionAccessorEx.Accessors; while (!connectionChecked) { - SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); underlyingConnection.Open(); try { - SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionInitializing(accessors, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered)); using (var command = underlyingConnection.CreateCommand()) { command.CommandText = checkQueryString; _ = command.ExecuteNonQuery(); } connectionChecked = true; - SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered)); } catch (Exception exception) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered)); + SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered)); if (InternalHelpers.ShouldRetryOn(exception)) { if (restoreTriggered) { throw; @@ -297,22 +297,22 @@ private async Task OpenWithCheckFastAsync(string checkQueryString, CancellationT } private async Task OpenWithCheckAndNotificationAsync(string checkQueryString, - ConnectionHandlersExtension connectionHandlers, CancellationToken cancellationToken) + DbConnectionAccessorExtension connectionAccessorEx, CancellationToken cancellationToken) { var connectionChecked = false; var restoreTriggered = false; - var handlers = connectionHandlers.Handlers; + var accessors = connectionAccessorEx.Accessors; while (!connectionChecked) { cancellationToken.ThrowIfCancellationRequested(); - await SqlHelper.NotifyConnectionOpeningAsync(handlers, + await SqlHelper.NotifyConnectionOpeningAsync(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) .ConfigureAwait(false); await underlyingConnection.OpenAsync(cancellationToken).ConfigureAwait(false); try { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(accessors, UnderlyingConnection, checkQueryString, (!connectionChecked && !restoreTriggered), cancellationToken) .ConfigureAwait(false); @@ -322,11 +322,11 @@ await SqlHelper.NotifyConnectionInitializingAsync(handlers, _ = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false); } connectionChecked = true; - await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) + await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, (!connectionChecked && !restoreTriggered), cancellationToken) .ConfigureAwait(false); } catch (Exception exception) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, exception, (!connectionChecked && !restoreTriggered), cancellationToken) .ConfigureAwait(false); diff --git a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs index 7e7bd2adf5..042f1c20ed 100644 --- a/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs +++ b/Orm/Xtensive.Orm.SqlServer/Sql.Drivers.SqlServer/DriverFactory.cs @@ -234,7 +234,7 @@ private static SqlServerConnection CreateAndOpenConnection( var initScript = configuration.ConnectionInitializationSql; if (!configuration.EnsureConnectionIsAlive) { - if (configuration.ConnectionHandlers.Count == 0) + if (configuration.DbConnectionAccessors.Count == 0) OpenConnectionFast(connection, initScript, false).GetAwaiter().GetResult(); else OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); @@ -244,10 +244,10 @@ private static SqlServerConnection CreateAndOpenConnection( var testQuery = string.IsNullOrEmpty(initScript) ? CheckConnectionQuery : initScript; - if (configuration.ConnectionHandlers.Count == 0) + if (configuration.DbConnectionAccessors.Count == 0) return EnsureConnectionIsAliveFast(connection, testQuery, false).GetAwaiter().GetResult(); else - return EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.ConnectionHandlers, false) + return EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.DbConnectionAccessors, false) .GetAwaiter().GetResult(); } @@ -258,7 +258,7 @@ private static async Task CreateAndOpenConnectionAsync( var initScript = configuration.ConnectionInitializationSql; if (!configuration.EnsureConnectionIsAlive) { - if (configuration.ConnectionHandlers.Count == 0) + if (configuration.DbConnectionAccessors.Count == 0) await OpenConnectionFast(connection, initScript, true, token).ConfigureAwait(false); else await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); @@ -268,10 +268,10 @@ private static async Task CreateAndOpenConnectionAsync( var testQuery = string.IsNullOrEmpty(initScript) ? CheckConnectionQuery : initScript; - if (configuration.ConnectionHandlers.Count == 0) + if (configuration.DbConnectionAccessors.Count == 0) return await EnsureConnectionIsAliveFast(connection, testQuery, true, token).ConfigureAwait(false); else - return await EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.ConnectionHandlers, true, token) + return await EnsureConnectionIsAliveWithNotification(connection, testQuery, configuration.DbConnectionAccessors, true, token) .ConfigureAwait(false); } @@ -291,36 +291,36 @@ private static async ValueTask OpenConnectionFast(SqlServerConnection connection private static async ValueTask OpenConnectionWithNotification(SqlServerConnection connection, SqlDriverConfiguration configuration, bool isAsync, CancellationToken token = default) { - var handlers = configuration.ConnectionHandlers; + var accessors = configuration.DbConnectionAccessors; var initSql = configuration.ConnectionInitializationSql; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(accessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(initSql)) { - SqlHelper.NotifyConnectionInitializing(handlers, connection, initSql); + SqlHelper.NotifyConnectionInitializing(accessors, connection, initSql); SqlHelper.ExecuteInitializationSql(connection, initSql); } - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(accessors, connection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token); + await SqlHelper.NotifyConnectionOpeningAsync(accessors, connection, false, token); try { await connection.OpenAsync(token); if (!string.IsNullOrEmpty(initSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, initSql, false, token); + await SqlHelper.NotifyConnectionInitializingAsync(accessors, connection, initSql, false, token); await SqlHelper.ExecuteInitializationSqlAsync(connection, initSql, token); } - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, connection, false, token); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, token); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, connection, ex, false, token); throw; } } @@ -392,27 +392,27 @@ private static async ValueTask EnsureConnectionIsAliveFast( } private static async ValueTask EnsureConnectionIsAliveWithNotification(SqlServerConnection connection, - string query, IReadOnlyCollection handlers, bool isAsync, CancellationToken token = default) + string query, IReadOnlyCollection connectionAccessos, bool isAsync, CancellationToken token = default) { if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(connectionAccessos, connection); try { connection.Open(); - SqlHelper.NotifyConnectionInitializing(handlers, connection, query); + SqlHelper.NotifyConnectionInitializing(connectionAccessos, connection, query); using (var command = connection.CreateCommand()) { command.CommandText = query; _ = command.ExecuteNonQuery(); } - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(connectionAccessos, connection); return connection; } catch (Exception exception) { var retryToConnect = InternalHelpers.ShouldRetryOn(exception); if (!retryToConnect) - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception); + SqlHelper.NotifyConnectionOpeningFailed(connectionAccessos, connection, exception); try { connection.Close(); connection.Dispose(); @@ -422,7 +422,7 @@ private static async ValueTask EnsureConnectionIsAliveWithN } if (retryToConnect) { - var (isReconnected, newConnection) = TryReconnectWithNotification(connection.ConnectionString, query, handlers, isAsync) + var (isReconnected, newConnection) = TryReconnectWithNotification(connection.ConnectionString, query, connectionAccessos, isAsync) .GetAwaiter().GetResult(); if (isReconnected) { return newConnection; @@ -432,12 +432,12 @@ private static async ValueTask EnsureConnectionIsAliveWithN } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(connectionAccessos, connection, false, token).ConfigureAwait(false); try { await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, false, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionInitializingAsync(connectionAccessos, connection, query, false, token).ConfigureAwait(false); var command = connection.CreateCommand(); await using (command.ConfigureAwait(false)) { @@ -445,13 +445,13 @@ private static async ValueTask EnsureConnectionIsAliveWithN _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); } - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(connectionAccessos, connection, false, token).ConfigureAwait(false); return connection; } catch (Exception exception) { var retryToConnect = InternalHelpers.ShouldRetryOn(exception); if (!retryToConnect) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, false, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(connectionAccessos, connection, exception, false, token).ConfigureAwait(false); } var connectionString = connection.ConnectionString; @@ -465,7 +465,7 @@ private static async ValueTask EnsureConnectionIsAliveWithN if (retryToConnect) { var (isReconnected, newConnection) = - await TryReconnectWithNotification(connectionString, query, handlers, isAsync, token).ConfigureAwait(false); + await TryReconnectWithNotification(connectionString, query, connectionAccessos, isAsync, token).ConfigureAwait(false); if (isReconnected) { return newConnection; } @@ -515,38 +515,38 @@ private static async ValueTask EnsureConnectionIsAliveWithN } private static async Task<(bool isReconnected, SqlServerConnection connection)> TryReconnectWithNotification( - string connectionString, string query, IReadOnlyCollection handlers, + string connectionString, string query, IReadOnlyCollection connectionAccessors, bool isAsync, CancellationToken token = default) { var connection = new SqlServerConnection(connectionString); if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection, true); + SqlHelper.NotifyConnectionOpening(connectionAccessors, connection, true); try { connection.Open(); - SqlHelper.NotifyConnectionInitializing(handlers, connection, query, true); + SqlHelper.NotifyConnectionInitializing(connectionAccessors, connection, query, true); using (var command = connection.CreateCommand()) { command.CommandText = query; _ = command.ExecuteNonQuery(); } - SqlHelper.NotifyConnectionOpened(handlers, connection, true); + SqlHelper.NotifyConnectionOpened(connectionAccessors, connection, true); return (true, connection); } catch (Exception exception) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, exception, true); + SqlHelper.NotifyConnectionOpeningFailed(connectionAccessors, connection, exception, true); connection.Dispose(); return (false, null); } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, true, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(connectionAccessors, connection, true, token).ConfigureAwait(false); try { await connection.OpenAsync(token).ConfigureAwait(false); - await SqlHelper.NotifyConnectionInitializingAsync(handlers, connection, query, true, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionInitializingAsync(connectionAccessors, connection, query, true, token).ConfigureAwait(false); var command = connection.CreateCommand(); await using (command.ConfigureAwait(false)) { @@ -554,11 +554,11 @@ private static async ValueTask EnsureConnectionIsAliveWithN _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); } - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, true, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(connectionAccessors, connection, true, token).ConfigureAwait(false); return (true, connection); } catch (Exception exception) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, exception, true, token).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(connectionAccessors, connection, exception, true, token).ConfigureAwait(false); await connection.DisposeAsync(); return (false, null); } diff --git a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs index bfc01d35c3..a97e12838c 100644 --- a/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs +++ b/Orm/Xtensive.Orm.Sqlite/Sql.Drivers.Sqlite/DriverFactory.cs @@ -43,7 +43,7 @@ private static string GetDataSource(string connectionString) protected override SqlDriver CreateDriver(string connectionString, SqlDriverConfiguration configuration) { using var connection = new SQLiteConnection(connectionString); - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) OpenConnectionWithNotification(connection, configuration, false).GetAwaiter().GetResult(); else OpenConnectionFast(connection, configuration, false).GetAwaiter().GetResult(); @@ -58,7 +58,7 @@ protected override async Task CreateDriverAsync( { var connection = new SQLiteConnection(connectionString); await using (connection.ConfigureAwait(false)) { - if (configuration.ConnectionHandlers.Count > 0) + if (configuration.DbConnectionAccessors.Count > 0) await OpenConnectionWithNotification(connection, configuration, true, token).ConfigureAwait(false); else await OpenConnectionFast(connection, configuration, true, token).ConfigureAwait(false); @@ -128,39 +128,39 @@ private async ValueTask OpenConnectionWithNotification(SQLiteConnection connecti bool isAsync, CancellationToken cancellationToken = default) { - var handlers = configuration.ConnectionHandlers; + var accessors = configuration.DbConnectionAccessors; if (!isAsync) { - SqlHelper.NotifyConnectionOpening(handlers, connection); + SqlHelper.NotifyConnectionOpening(accessors, connection); try { connection.Open(); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - SqlHelper.NotifyConnectionInitializing(handlers, connection, configuration.ConnectionInitializationSql); + SqlHelper.NotifyConnectionInitializing(accessors, connection, configuration.ConnectionInitializationSql); } SqlHelper.ExecuteInitializationSql(connection, configuration); - SqlHelper.NotifyConnectionOpened(handlers, connection); + SqlHelper.NotifyConnectionOpened(accessors, connection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, connection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, connection, ex); throw; } } else { - await SqlHelper.NotifyConnectionOpeningAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); try { await connection.OpenAsync(cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(configuration.ConnectionInitializationSql)) { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, + await SqlHelper.NotifyConnectionInitializingAsync(accessors, connection, configuration.ConnectionInitializationSql, false, cancellationToken) .ConfigureAwait(false); } await SqlHelper.ExecuteInitializationSqlAsync(connection, configuration, cancellationToken).ConfigureAwait(false); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, connection, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, connection, false, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, connection, ex, false, cancellationToken).ConfigureAwait(false); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, connection, ex, false, cancellationToken).ConfigureAwait(false); throw; } } diff --git a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs index e002490e34..75b32fbabb 100644 --- a/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs +++ b/Orm/Xtensive.Orm.Tests.Sql/DriverFactoryTest.cs @@ -14,7 +14,7 @@ namespace Xtensive.Orm.Tests.Sql.DriverFactoryTestTypes { - public class TestConnectionHandler : ConnectionHandler + public class TestConnectionAccessor : DbConnectionAccessor { public int OpeningCounter = 0; public int OpeningAsyncCounter = 0; @@ -167,162 +167,162 @@ public void SqlServerConnectionCheckTest() } [Test] - public void ConnectionHandlerTest() + public void ConnectionAccessorTest() { - var handlerInstance = new TestConnectionHandler(); - var handlersArray = new[] { handlerInstance }; + var accessorInstance = new TestConnectionAccessor(); + var accessorsArray = new[] { accessorInstance }; var descriptor = ProviderDescriptor.Get(provider); var factory = (SqlDriverFactory) Activator.CreateInstance(descriptor.DriverFactory); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - var configuration = new SqlDriverConfiguration(handlersArray); + var configuration = new SqlDriverConfiguration(accessorsArray); _ = factory.GetDriver(new ConnectionInfo(Url), configuration); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - - configuration = new SqlDriverConfiguration(handlersArray) { EnsureConnectionIsAlive = true }; + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(accessorsArray) { EnsureConnectionIsAlive = true }; _ = factory.GetDriver(new ConnectionInfo(Url), configuration); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; + configuration = new SqlDriverConfiguration(accessorsArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; _ = factory.GetDriver(new ConnectionInfo(Url), configuration); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = "dummy string to trigger error" }; + configuration = new SqlDriverConfiguration(accessorsArray) { ConnectionInitializationSql = "dummy string to trigger error" }; try { _ = factory.GetDriver(new ConnectionInfo(Url), configuration); } catch { //skip it } - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(4)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(4)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); } [Test] - public async Task ConnectionHandlerAsyncTest() + public async Task ConnectionAccessorAsyncTest() { - var handlerInstance = new TestConnectionHandler(); - var handlersArray = new[] { handlerInstance }; + var accessorInstance = new TestConnectionAccessor(); + var accessorsArray = new[] { accessorInstance }; var descriptor = ProviderDescriptor.Get(provider); var factory = (SqlDriverFactory) Activator.CreateInstance(descriptor.DriverFactory); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - var configuration = new SqlDriverConfiguration(handlersArray); + var configuration = new SqlDriverConfiguration(accessorsArray); _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - - configuration = new SqlDriverConfiguration(handlersArray) { EnsureConnectionIsAlive = true }; + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + + configuration = new SqlDriverConfiguration(accessorsArray) { EnsureConnectionIsAlive = true }; _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(2)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(0)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; + configuration = new SqlDriverConfiguration(accessorsArray) { ConnectionInitializationSql = InitQueryPerProvider(provider) }; _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(3)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(1)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(0)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(0)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(0)); - configuration = new SqlDriverConfiguration(handlersArray) { ConnectionInitializationSql = "dummy string to trigger error" }; + configuration = new SqlDriverConfiguration(accessorsArray) { ConnectionInitializationSql = "dummy string to trigger error" }; try { _ = await factory.GetDriverAsync(new ConnectionInfo(Url), configuration, CancellationToken.None); } @@ -330,22 +330,22 @@ public async Task ConnectionHandlerAsyncTest() //skip it } - Assert.That(handlerInstance.OpeningCounter, Is.EqualTo(4)); - Assert.That(handlerInstance.OpeningAsyncCounter, Is.EqualTo(4)); + Assert.That(accessorInstance.OpeningCounter, Is.EqualTo(4)); + Assert.That(accessorInstance.OpeningAsyncCounter, Is.EqualTo(4)); if (provider == WellKnown.Provider.SqlServer) { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(3)); } else { - Assert.That(handlerInstance.OpeningInitCounter, Is.EqualTo(2)); - Assert.That(handlerInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitCounter, Is.EqualTo(2)); + Assert.That(accessorInstance.OpeningInitAsyncCounter, Is.EqualTo(2)); } - Assert.That(handlerInstance.OpenedCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpenedAsyncCounter, Is.EqualTo(3)); - Assert.That(handlerInstance.OpeningFailedCounter, Is.EqualTo(1)); - Assert.That(handlerInstance.OpeningFailedAsyncCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpenedCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpenedAsyncCounter, Is.EqualTo(3)); + Assert.That(accessorInstance.OpeningFailedCounter, Is.EqualTo(1)); + Assert.That(accessorInstance.OpeningFailedAsyncCounter, Is.EqualTo(1)); } private static void TestProvider(string providerName, string connectionString, string connectionUrl) diff --git a/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs b/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs similarity index 60% rename from Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs rename to Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs index 0aa5edf81e..e2f7cd34db 100644 --- a/Orm/Xtensive.Orm.Tests/Storage/ConnectionHandlerTest.cs +++ b/Orm/Xtensive.Orm.Tests/Storage/ConnectionAccessorTest.cs @@ -11,12 +11,12 @@ using Xtensive.Core; using Xtensive.Orm.Providers; using Xtensive.Sql; -using Xtensive.Orm.Tests.Storage.ConnectionHandlersModel; +using Xtensive.Orm.Tests.Storage.ConnectionAccessorsModel; using System.Threading.Tasks; -namespace Xtensive.Orm.Tests.Storage.ConnectionHandlersModel +namespace Xtensive.Orm.Tests.Storage.ConnectionAccessorsModel { - public class MyConnectionHandler : ConnectionHandler + public class MyConnectionAccessor : DbConnectionAccessor { private Guid instanceMarker; @@ -57,55 +57,55 @@ public override void ConnectionOpeningFailed(ConnectionErrorEventData eventData) } } - public MyConnectionHandler() + public MyConnectionAccessor() { UniqueInstanceIdentifier = Guid.NewGuid(); } } - public class NoDefaultConstructorHandler : ConnectionHandler + public class NoDefaultConstructorAccessor : DbConnectionAccessor { #pragma warning disable IDE0060 // Remove unused parameter - public NoDefaultConstructorHandler(int dummyParameter) + public NoDefaultConstructorAccessor(int dummyParameter) #pragma warning restore IDE0060 // Remove unused parameter { } } - public class NonPublicDefaultConstructorHandler : ConnectionHandler + public class NonPublicDefaultConstructorAccessor : DbConnectionAccessor { - private NonPublicDefaultConstructorHandler() + private NonPublicDefaultConstructorAccessor() { } } - #region Performance Test handlers - - public class PerfHandler1 : ConnectionHandler { } - public class PerfHandler2 : ConnectionHandler { } - public class PerfHandler3 : ConnectionHandler { } - public class PerfHandler4 : ConnectionHandler { } - public class PerfHandler5 : ConnectionHandler { } - public class PerfHandler6 : ConnectionHandler { } - public class PerfHandler7 : ConnectionHandler { } - public class PerfHandler8 : ConnectionHandler { } - public class PerfHandler9 : ConnectionHandler { } - public class PerfHandler10 : ConnectionHandler { } - public class PerfHandler11 : ConnectionHandler { } - public class PerfHandler12 : ConnectionHandler { } - public class PerfHandler13 : ConnectionHandler { } - public class PerfHandler14 : ConnectionHandler { } - public class PerfHandler15 : ConnectionHandler { } - public class PerfHandler16 : ConnectionHandler { } - public class PerfHandler17 : ConnectionHandler { } - public class PerfHandler18 : ConnectionHandler { } - public class PerfHandler19 : ConnectionHandler { } - public class PerfHandler20 : ConnectionHandler { } - public class PerfHandler21 : ConnectionHandler { } - public class PerfHandler22 : ConnectionHandler { } - public class PerfHandler23 : ConnectionHandler { } - public class PerfHandler24 : ConnectionHandler { } - public class PerfHandler25 : ConnectionHandler { } + #region Performance Test accessors + + public class PerfAccessor1 : DbConnectionAccessor { } + public class PerfAccessor2 : DbConnectionAccessor { } + public class PerfAccessor3 : DbConnectionAccessor { } + public class PerfAccessor4 : DbConnectionAccessor { } + public class PerfAccessor5 : DbConnectionAccessor { } + public class PerfAccessor6 : DbConnectionAccessor { } + public class PerfAccessor7 : DbConnectionAccessor { } + public class PerfAccessor8 : DbConnectionAccessor { } + public class PerfAccessor9 : DbConnectionAccessor { } + public class PerfAccessor10 : DbConnectionAccessor { } + public class PerfAccessor11 : DbConnectionAccessor { } + public class PerfAccessor12 : DbConnectionAccessor { } + public class PerfAccessor13 : DbConnectionAccessor { } + public class PerfAccessor14 : DbConnectionAccessor { } + public class PerfAccessor15 : DbConnectionAccessor { } + public class PerfAccessor16 : DbConnectionAccessor { } + public class PerfAccessor17 : DbConnectionAccessor { } + public class PerfAccessor18 : DbConnectionAccessor { } + public class PerfAccessor19 : DbConnectionAccessor { } + public class PerfAccessor20 : DbConnectionAccessor { } + public class PerfAccessor21 : DbConnectionAccessor { } + public class PerfAccessor22 : DbConnectionAccessor { } + public class PerfAccessor23 : DbConnectionAccessor { } + public class PerfAccessor24 : DbConnectionAccessor { } + public class PerfAccessor25 : DbConnectionAccessor { } #endregion @@ -132,16 +132,17 @@ public DummyEntity(Session session) namespace Xtensive.Orm.Tests.Storage { - public class ConnectionHandlerTest + [TestFixture] + public class ConnectionAccessorTest { [Test] public void DomainRegistryTest() { var domainConfig = DomainConfigurationFactory.Create(); domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(MyConnectionHandler)); + domainConfig.Types.Register(typeof(MyConnectionAccessor)); - Assert.That(domainConfig.Types.ConnectionHandlers.Count(), Is.EqualTo(1)); + Assert.That(domainConfig.Types.DbConnectionAccessors.Count(), Is.EqualTo(1)); } [Test] @@ -150,7 +151,7 @@ public void NoDefaultConstructorTest() var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(NoDefaultConstructorHandler)); + domainConfig.Types.Register(typeof(NoDefaultConstructorAccessor)); Domain domain = null; _ = Assert.Throws(() => domain = Domain.Build(domainConfig)); @@ -163,7 +164,7 @@ public void NoDefaultConstructorAsyncTest() var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(NoDefaultConstructorHandler)); + domainConfig.Types.Register(typeof(NoDefaultConstructorAccessor)); Domain domain = null; _ = Assert.ThrowsAsync(async () => domain = await Domain.BuildAsync(domainConfig)); @@ -176,7 +177,7 @@ public void NonPublicDefaultConstructorTest() var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(NonPublicDefaultConstructorHandler)); + domainConfig.Types.Register(typeof(NonPublicDefaultConstructorAccessor)); using var domain = Domain.Build(domainConfig); } @@ -187,72 +188,72 @@ public async Task NonPublicDefaultConstructorAsyncTest() var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(NonPublicDefaultConstructorHandler)); + domainConfig.Types.Register(typeof(NonPublicDefaultConstructorAccessor)); await using var domain = await Domain.BuildAsync(domainConfig); } [Test] - public void SessionConnectionHandlersTest() + public void SessionConnectionAccessorsTest() { var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(MyConnectionHandler)); + domainConfig.Types.Register(typeof(MyConnectionAccessor)); Guid? first = null; using (var domain = Domain.Build(domainConfig)) using (var session = domain.OpenSession()) { var nativeHandler = (SqlSessionHandler) session.Handler; - var extension = nativeHandler.Connection.Extensions.Get(); - var handlerInstance = (MyConnectionHandler)extension.Handlers.First(); - Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); - Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); - first = handlerInstance.UniqueInstanceIdentifier; + var extension = nativeHandler.Connection.Extensions.Get(); + var accessorInstance = (MyConnectionAccessor)extension.Accessors.First(); + Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + first = accessorInstance.UniqueInstanceIdentifier; } Guid? second = null; using (var domain = Domain.Build(domainConfig)) using (var session = domain.OpenSession()) { var nativeHandler = (SqlSessionHandler) session.Handler; - var extension = nativeHandler.Connection.Extensions.Get(); - var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); - Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); - Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); - second = handlerInstance.UniqueInstanceIdentifier; + var extension = nativeHandler.Connection.Extensions.Get(); + var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); + Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + second = accessorInstance.UniqueInstanceIdentifier; } Assert.That(first != null && second != null && first != second, Is.True); } [Test] - public async Task SessionConnectionHandlersAsyncTest() + public async Task SessionConnectionAccessorsAsyncTest() { var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; domainConfig.Types.Register(typeof(DummyEntity)); - domainConfig.Types.Register(typeof(MyConnectionHandler)); + domainConfig.Types.Register(typeof(MyConnectionAccessor)); Guid? first = null; await using (var domain = await Domain.BuildAsync(domainConfig)) await using (var session = await domain.OpenSessionAsync()) { var nativeHandler = (SqlSessionHandler) session.Handler; - var extension = nativeHandler.Connection.Extensions.Get(); - var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); - Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); - Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); - first = handlerInstance.UniqueInstanceIdentifier; + var extension = nativeHandler.Connection.Extensions.Get(); + var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); + Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + first = accessorInstance.UniqueInstanceIdentifier; } Guid? second = null; await using (var domain = await Domain.BuildAsync(domainConfig)) await using (var session = await domain.OpenSessionAsync()) { var nativeHandler = (SqlSessionHandler) session.Handler; - var extension = nativeHandler.Connection.Extensions.Get(); - var handlerInstance = (MyConnectionHandler) extension.Handlers.First(); - Assert.That(handlerInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); - Assert.That(handlerInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); - second = handlerInstance.UniqueInstanceIdentifier; + var extension = nativeHandler.Connection.Extensions.Get(); + var accessorInstance = (MyConnectionAccessor) extension.Accessors.First(); + Assert.That(accessorInstance.ConnectionOpeningCounter, Is.Not.EqualTo(0)); + Assert.That(accessorInstance.ConnectionOpenedCounter, Is.Not.EqualTo(0)); + second = accessorInstance.UniqueInstanceIdentifier; } Assert.That(first != null && second != null && first != second, Is.True); @@ -267,8 +268,8 @@ public void ConnectionExtensionExistanceTest(int includeHandlersCount) var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; - foreach (var handler in GetHandlers(includeHandlersCount)) { - domainConfig.Types.Register(handler); + foreach (var accessor in GetAccessors(includeHandlersCount)) { + domainConfig.Types.Register(accessor); } using (var domain = Domain.Build(domainConfig)) @@ -277,9 +278,9 @@ public void ConnectionExtensionExistanceTest(int includeHandlersCount) var extensions = nativeHandler.Connection.Extensions; if (includeHandlersCount > 0) { Assert.That(extensions.Count, Is.EqualTo(1)); - var extension = extensions.Get(); + var extension = extensions.Get(); Assert.That(extension, Is.Not.Null); - Assert.That(extension.Handlers.Count, Is.EqualTo(includeHandlersCount)); + Assert.That(extension.Accessors.Count, Is.EqualTo(includeHandlersCount)); } else { Assert.That(extensions.Count, Is.EqualTo(0)); @@ -291,24 +292,24 @@ public void ConnectionExtensionExistanceTest(int includeHandlersCount) [TestCase(0)] [TestCase(1)] [TestCase(2)] - public async Task ConnectionExtensionExistanceAsyncTest(int includeHandlersCount) + public async Task ConnectionExtensionExistanceAsyncTest(int amoundOtAccessors) { var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; - foreach (var handler in GetHandlers(includeHandlersCount)) { - domainConfig.Types.Register(handler); + foreach (var accessor in GetAccessors(amoundOtAccessors)) { + domainConfig.Types.Register(accessor); } await using (var domain = await Domain.BuildAsync(domainConfig)) await using (var session = await domain.OpenSessionAsync()) { var nativeHandler = (SqlSessionHandler) session.Handler; var extensions = nativeHandler.Connection.Extensions; - if (includeHandlersCount > 0) { + if (amoundOtAccessors > 0) { Assert.That(extensions.Count, Is.EqualTo(1)); - var extension = extensions.Get(); + var extension = extensions.Get(); Assert.That(extension, Is.Not.Null); - Assert.That(extension.Handlers.Count, Is.EqualTo(includeHandlersCount)); + Assert.That(extension.Accessors.Count, Is.EqualTo(amoundOtAccessors)); } else { Assert.That(extensions.Count, Is.EqualTo(0)); @@ -323,13 +324,13 @@ public async Task ConnectionExtensionExistanceAsyncTest(int includeHandlersCount [TestCase(15)] [TestCase(20)] [TestCase(25)] - public void SessionOpeningPerformanceTest(int includeHandlersCount) + public void SessionOpeningPerformanceTest(int amountOfAccessors) { var domainConfig = DomainConfigurationFactory.Create(); domainConfig.UpgradeMode = DomainUpgradeMode.Recreate; - foreach (var handler in GetHandlers(includeHandlersCount)) { - domainConfig.Types.Register(handler); + foreach (var accessor in GetAccessors(amountOfAccessors)) { + domainConfig.Types.Register(accessor); } var watch = new Stopwatch(); @@ -343,20 +344,20 @@ public void SessionOpeningPerformanceTest(int includeHandlersCount) Console.WriteLine(watch.ElapsedTicks / 1000000); } - private IEnumerable GetHandlers(int neededCount) + private IEnumerable GetAccessors(int neededCount) { if (neededCount > 25) { throw new Exception(); } var all = new Type[] { - typeof(PerfHandler1), typeof(PerfHandler2), typeof(PerfHandler3), typeof(PerfHandler4), - typeof(PerfHandler5), typeof(PerfHandler6), typeof(PerfHandler7), typeof(PerfHandler8), - typeof(PerfHandler9), typeof(PerfHandler10), typeof(PerfHandler11), typeof(PerfHandler12), - typeof(PerfHandler13), typeof(PerfHandler14), typeof(PerfHandler15), typeof(PerfHandler16), - typeof(PerfHandler17), typeof(PerfHandler18), typeof(PerfHandler19), typeof(PerfHandler20), - typeof(PerfHandler21), typeof(PerfHandler22), typeof(PerfHandler23), typeof(PerfHandler24), - typeof(PerfHandler25) + typeof(PerfAccessor1), typeof(PerfAccessor2), typeof(PerfAccessor3), typeof(PerfAccessor4), + typeof(PerfAccessor5), typeof(PerfAccessor6), typeof(PerfAccessor7), typeof(PerfAccessor8), + typeof(PerfAccessor9), typeof(PerfAccessor10), typeof(PerfAccessor11), typeof(PerfAccessor12), + typeof(PerfAccessor13), typeof(PerfAccessor14), typeof(PerfAccessor15), typeof(PerfAccessor16), + typeof(PerfAccessor17), typeof(PerfAccessor18), typeof(PerfAccessor19), typeof(PerfAccessor20), + typeof(PerfAccessor21), typeof(PerfAccessor22), typeof(PerfAccessor23), typeof(PerfAccessor24), + typeof(PerfAccessor25) }; for (var i = 0; i < neededCount; i++) { yield return all[i]; diff --git a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs index c678ab999f..2287ae88db 100644 --- a/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs +++ b/Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs @@ -27,9 +27,9 @@ public class DomainTypeRegistry : TypeRegistry private readonly static Type iUpgradeHandlerType = typeof(IUpgradeHandler); private readonly static Type keyGeneratorType = typeof(KeyGenerator); private readonly static Type ifulltextCatalogNameBuilder = typeof(IFullTextCatalogNameBuilder); - private readonly static Type iConnectionHandlerType = typeof(IConnectionHandler); + private readonly static Type iDbConnectionAccessorType = typeof(IDbConnectionAccessor); - private Type[] connectionHandlers; + private Type[] connectionAccessors; /// @@ -77,23 +77,23 @@ public class DomainTypeRegistry : TypeRegistry public IEnumerable FullTextCatalogResolvers => this.Where(IsFullTextCatalogNameBuilder); /// - /// Gets all the registered implementations. + /// Gets all the registered implementations. /// - public IEnumerable ConnectionHandlers + public IEnumerable DbConnectionAccessors { get { // a lot of access to this property. better to have items cached; if (IsLocked) { - if(connectionHandlers == null) { - var container = new List(10);// not so many handlers expected - foreach (var type in this.Where(IsConnectionHandler)) + if(connectionAccessors == null) { + var container = new List(10);// not so many accessors expected + foreach (var type in this.Where(IsConnectionAccessor)) container.Add(type); - connectionHandlers = container.Count == 0 ? Array.Empty() : container.ToArray(); + connectionAccessors = container.Count == 0 ? Array.Empty() : container.ToArray(); } - return connectionHandlers; + return connectionAccessors; } - // if instance is not locked then there is a chance of new handlers appeared - return this.Where(IsConnectionHandler); + // if instance is not locked then there is a chance of new accessors appeared + return this.Where(IsConnectionAccessor); } } @@ -115,7 +115,7 @@ public static bool IsInterestingType(Type type) => IsKeyGenerator(type) || IsCompilerContainer(type) || IsFullTextCatalogNameBuilder(type) || - IsConnectionHandler(type); + IsConnectionAccessor(type); /// /// Determines whether a @@ -233,17 +233,17 @@ public static bool IsFullTextCatalogNameBuilder(Type type) /// /// Determines whether the is - /// a connection handler. + /// a connection accessor. /// /// The type to check. /// Check result. - public static bool IsConnectionHandler(Type type) + public static bool IsConnectionAccessor(Type type) { if (type.IsAbstract) { return false; } - return iConnectionHandlerType.IsAssignableFrom(type) && iConnectionHandlerType != type; + return iDbConnectionAccessorType.IsAssignableFrom(type) && iDbConnectionAccessorType != type; } #endregion diff --git a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs index 39327b3a17..3230ca6867 100644 --- a/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs +++ b/Orm/Xtensive.Orm/Orm/ConnectionEventData.cs @@ -8,7 +8,7 @@ namespace Xtensive.Orm { /// - /// Contains general data for methods. + /// Contains general data for methods. /// public class ConnectionEventData { diff --git a/Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs b/Orm/Xtensive.Orm/Orm/Interfaces/DbConnectionAccessor.cs similarity index 91% rename from Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs rename to Orm/Xtensive.Orm/Orm/Interfaces/DbConnectionAccessor.cs index b63dcabd30..9c306daf49 100644 --- a/Orm/Xtensive.Orm/Orm/Interfaces/ConnectionHandler.cs +++ b/Orm/Xtensive.Orm/Orm/Interfaces/DbConnectionAccessor.cs @@ -8,9 +8,9 @@ namespace Xtensive.Orm { /// - /// Base type for connection handlers to be inherited from. + /// Base type for native database connection accessors to be inherited from. /// - public abstract class ConnectionHandler : IConnectionHandler + public abstract class DbConnectionAccessor : IDbConnectionAccessor { /// public virtual void ConnectionOpening(ConnectionEventData eventData) diff --git a/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs b/Orm/Xtensive.Orm/Orm/Interfaces/IDbConnectionAccessor.cs similarity index 98% rename from Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs rename to Orm/Xtensive.Orm/Orm/Interfaces/IDbConnectionAccessor.cs index 48b02edc9e..6a7231aa87 100644 --- a/Orm/Xtensive.Orm/Orm/Interfaces/IConnectionHandler.cs +++ b/Orm/Xtensive.Orm/Orm/Interfaces/IDbConnectionAccessor.cs @@ -10,7 +10,7 @@ namespace Xtensive.Orm /// /// Offers event-like methods to access native database connection on different stages. /// - public interface IConnectionHandler + public interface IDbConnectionAccessor { /// /// Executes before connection opening. diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs index b138c6ccbb..f57b21d3fa 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs @@ -51,9 +51,9 @@ public SqlConnection CreateConnection(Session session) throw ExceptionBuilder.BuildException(exception); } - if (handlerFactoriesCache != null) { - connection.AssignConnectionHandlers( - CreateConnectionHandlersFast(configuration.Types.ConnectionHandlers)); + if (connectionAccessorFactories != null) { + connection.AssignConnectionAccessors( + CreateConnectionAccessorsFast(configuration.Types.DbConnectionAccessors)); } var sessionConfiguration = GetConfiguration(session); diff --git a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs index 0b2a1e1690..31591b4983 100644 --- a/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs +++ b/Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs @@ -30,7 +30,7 @@ namespace Xtensive.Orm.Providers public sealed partial class StorageDriver { private static readonly MethodInfo FactoryCreatorMethod = typeof(StorageDriver) - .GetMethod(nameof(CreateNewHandler), BindingFlags.Static | BindingFlags.NonPublic); + .GetMethod(nameof(CreateNewAccessor), BindingFlags.Static | BindingFlags.NonPublic); private readonly DomainConfiguration configuration; private readonly SqlDriver underlyingDriver; @@ -39,7 +39,7 @@ public sealed partial class StorageDriver private readonly bool isLoggingEnabled; private readonly bool hasSavepoints; - private readonly IReadOnlyDictionary> handlerFactoriesCache; + private readonly IReadOnlyDictionary> connectionAccessorFactories; public ProviderInfo ProviderInfo { get; private set; } @@ -105,7 +105,7 @@ public DbDataReaderAccessor GetDataReaderAccessor(TupleDescriptor descriptor) public StorageDriver CreateNew(Domain domain) { ArgumentValidator.EnsureArgumentNotNull(domain, "domain"); - return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain), handlerFactoriesCache); + return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain), connectionAccessorFactories); } private static DomainModel GetNullModel() @@ -159,58 +159,58 @@ private void FixExtractionResultSqlServerFamily(SqlExtractionResult result) } } - private IReadOnlyCollection CreateConnectionHandlersFast(IEnumerable connectionHandlerTypes) + private IReadOnlyCollection CreateConnectionAccessorsFast(IEnumerable connectionAccessorTypes) { - if (handlerFactoriesCache == null) - return Array.Empty(); - var instances = new List(handlerFactoriesCache.Count); - foreach (var type in connectionHandlerTypes) { - if (handlerFactoriesCache.TryGetValue(type, out var factory)) { + if (connectionAccessorFactories == null) + return Array.Empty(); + var instances = new List(connectionAccessorFactories.Count); + foreach (var type in connectionAccessorTypes) { + if (connectionAccessorFactories.TryGetValue(type, out var factory)) { instances.Add(factory()); } } return instances.ToArray(); } - private static IReadOnlyCollection CreateConnectionHandlers(IEnumerable connectionHandlerTypes, - out IReadOnlyDictionary> factories) + private static IReadOnlyCollection CreateConnectionAccessors(IEnumerable connectionAccessorTypes, + out IReadOnlyDictionary> factories) { factories = null; - List instances; - Dictionary> factoriesLocal; + List instances; + Dictionary> factoriesLocal; - if(connectionHandlerTypes is IReadOnlyCollection asCollection) { + if(connectionAccessorTypes is IReadOnlyCollection asCollection) { if (asCollection.Count == 0) - return Array.Empty(); - instances = new List(asCollection.Count); - factoriesLocal = new Dictionary>(asCollection.Count); + return Array.Empty(); + instances = new List(asCollection.Count); + factoriesLocal = new Dictionary>(asCollection.Count); } else { - if (connectionHandlerTypes.Any()) - return Array.Empty(); - instances = new List(); - factoriesLocal = new Dictionary>(); + if (connectionAccessorTypes.Any()) + return Array.Empty(); + instances = new List(); + factoriesLocal = new Dictionary>(); } - foreach (var type in connectionHandlerTypes) { + foreach (var type in connectionAccessorTypes) { var ctor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); if (ctor == null) { - throw new NotSupportedException(string.Format(Strings.ExConnectionHandlerXHasNoParameterlessConstructor, type)); + throw new NotSupportedException(string.Format(Strings.ExConnectionAccessorXHasNoParameterlessConstructor, type)); } - var handlerFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(type).Invoke(null, null); - instances.Add(handlerFactory()); - factoriesLocal[type] = handlerFactory; + var accessorFactory = (Func) FactoryCreatorMethod.MakeGenericMethod(type).Invoke(null, null); + instances.Add(accessorFactory()); + factoriesLocal[type] = accessorFactory; } factories = factoriesLocal; return instances.ToArray(); } - private static Func CreateNewHandler() where T : IConnectionHandler + private static Func CreateNewAccessor() where T : IDbConnectionAccessor { - return FastExpression.Lambda>( - Expression.Convert(Expression.New(typeof(T)), typeof(IConnectionHandler))) + return FastExpression.Lambda>( + Expression.Convert(Expression.New(typeof(T)), typeof(IDbConnectionAccessor))) .Compile(); } @@ -221,8 +221,8 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu ArgumentValidator.EnsureArgumentNotNull(driverFactory, nameof(driverFactory)); ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories); - var driverConfiguration = new SqlDriverConfiguration(handlers) { + var accessors = CreateConnectionAccessors(configuration.Types.DbConnectionAccessors, out var factories); + var driverConfiguration = new SqlDriverConfiguration(accessors) { ForcedServerVersion = configuration.ForcedServerVersion, ConnectionInitializationSql = configuration.ConnectionInitializationSql, EnsureConnectionIsAlive = configuration.EnsureConnectionIsAlive, @@ -240,8 +240,8 @@ public static async Task CreateAsync( ArgumentValidator.EnsureArgumentNotNull(driverFactory, nameof(driverFactory)); ArgumentValidator.EnsureArgumentNotNull(configuration, nameof(configuration)); - var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories); - var driverConfiguration = new SqlDriverConfiguration(handlers) { + var accessors = CreateConnectionAccessors(configuration.Types.DbConnectionAccessors, out var factories); + var driverConfiguration = new SqlDriverConfiguration(accessors) { ForcedServerVersion = configuration.ForcedServerVersion, ConnectionInitializationSql = configuration.ConnectionInitializationSql, EnsureConnectionIsAlive = configuration.EnsureConnectionIsAlive, @@ -258,7 +258,7 @@ private StorageDriver(SqlDriver driver, ProviderInfo providerInfo, DomainConfiguration configuration, Func modelProvider, - IReadOnlyDictionary> factoryCache) + IReadOnlyDictionary> factoryCache) { underlyingDriver = driver; ProviderInfo = providerInfo; @@ -269,7 +269,7 @@ private StorageDriver(SqlDriver driver, hasSavepoints = underlyingDriver.ServerInfo.ServerFeatures.Supports(ServerFeatures.Savepoints); isLoggingEnabled = SqlLog.IsLogged(LogLevel.Info); // Just to cache this value ServerInfo = underlyingDriver.ServerInfo; - handlerFactoriesCache = factoryCache; + connectionAccessorFactories = factoryCache; } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs b/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs deleted file mode 100644 index abd0bdbf7c..0000000000 --- a/Orm/Xtensive.Orm/Sql/ConnectionHandlersExtension.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2021 Xtensive LLC. -// This code is distributed under MIT license terms. -// See the License.txt file in the project root for more information. - -using System.Collections.Generic; -using Xtensive.Orm; - -namespace Xtensive.Sql -{ - /// - /// Wrapper to pass s to connection. - /// - public sealed class ConnectionHandlersExtension - { - /// - /// Collection of instances. - /// - public IReadOnlyCollection Handlers { get; } - - internal ConnectionHandlersExtension(IReadOnlyCollection handlers) - { - Handlers = handlers; - } - } -} diff --git a/Orm/Xtensive.Orm/Sql/DbConnectionAccessorExtension.cs b/Orm/Xtensive.Orm/Sql/DbConnectionAccessorExtension.cs new file mode 100644 index 0000000000..1cc9e25a91 --- /dev/null +++ b/Orm/Xtensive.Orm/Sql/DbConnectionAccessorExtension.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + +using System.Collections.Generic; +using Xtensive.Orm; + +namespace Xtensive.Sql +{ + /// + /// Wrapper to pass s to connection. + /// + public sealed class DbConnectionAccessorExtension + { + /// + /// Collection of instances. + /// + public IReadOnlyCollection Accessors { get; } + + internal DbConnectionAccessorExtension(IReadOnlyCollection connectionAccessors) + { + Accessors = connectionAccessors; + } + } +} diff --git a/Orm/Xtensive.Orm/Sql/SqlConnection.cs b/Orm/Xtensive.Orm/Sql/SqlConnection.cs index 8a71f14677..b1f0c9b3b8 100644 --- a/Orm/Xtensive.Orm/Sql/SqlConnection.cs +++ b/Orm/Xtensive.Orm/Sql/SqlConnection.cs @@ -166,19 +166,19 @@ public virtual IBinaryLargeObject CreateBinaryLargeObject() => public virtual void Open() { EnsureIsNotDisposed(); - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { UnderlyingConnection.Open(); } else { - var handlers = connectionHandlers.Handlers; - SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection); + var accessors = connectionAccessorEx.Accessors; + SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection); try { UnderlyingConnection.Open(); - SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex); throw; } } @@ -191,8 +191,8 @@ public virtual void Open() public virtual void OpenAndInitialize(string initializationScript) { EnsureIsNotDisposed(); - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { UnderlyingConnection.Open(); if (string.IsNullOrEmpty(initializationScript)) { return; @@ -203,22 +203,22 @@ public virtual void OpenAndInitialize(string initializationScript) _ = command.ExecuteNonQuery(); } else { - var handlers = connectionHandlers.Handlers; - SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection); + var accessors = connectionAccessorEx.Accessors; + SqlHelper.NotifyConnectionOpening(accessors, UnderlyingConnection); try { UnderlyingConnection.Open(); if (string.IsNullOrEmpty(initializationScript)) { - SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection); + SqlHelper.NotifyConnectionOpened(accessors, UnderlyingConnection); return; } - SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, initializationScript); + SqlHelper.NotifyConnectionInitializing(accessors, UnderlyingConnection, initializationScript); using var command = UnderlyingConnection.CreateCommand(); command.CommandText = initializationScript; _ = command.ExecuteNonQuery(); } catch (Exception ex) { - SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex); + SqlHelper.NotifyConnectionOpeningFailed(accessors, UnderlyingConnection, ex); throw; } } @@ -235,20 +235,19 @@ public virtual async Task OpenAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); EnsureIsNotDisposed(); - var connectionHandlers = Extensions.Get(); - - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { await UnderlyingConnection.OpenAsync(cancellationToken).ConfigureAwait(false); } else { - var handlers = connectionHandlers.Handlers; - await SqlHelper.NotifyConnectionOpeningAsync(handlers, UnderlyingConnection, false, cancellationToken); + var accessors = connectionAccessorEx.Accessors; + await SqlHelper.NotifyConnectionOpeningAsync(accessors, UnderlyingConnection, false, cancellationToken); try { await UnderlyingConnection.OpenAsync(cancellationToken); - await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, cancellationToken); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, cancellationToken); } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, cancellationToken); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, cancellationToken); throw; } } @@ -266,8 +265,8 @@ public virtual async Task OpenAndInitializeAsync(string initializationScript, Ca { token.ThrowIfCancellationRequested(); EnsureIsNotDisposed(); - var connectionHandlers = Extensions.Get(); - if (connectionHandlers == null) { + var connectionAccessorEx = Extensions.Get(); + if (connectionAccessorEx == null) { await UnderlyingConnection.OpenAsync(token).ConfigureAwait(false); if (string.IsNullOrEmpty(initializationScript)) { return; @@ -286,30 +285,30 @@ public virtual async Task OpenAndInitializeAsync(string initializationScript, Ca } } else { - var handlers = connectionHandlers.Handlers; - await SqlHelper.NotifyConnectionOpeningAsync(handlers, UnderlyingConnection, false, token); + var accessors = connectionAccessorEx.Accessors; + await SqlHelper.NotifyConnectionOpeningAsync(accessors, UnderlyingConnection, false, token); await UnderlyingConnection.OpenAsync(token).ConfigureAwait(false); if (string.IsNullOrEmpty(initializationScript)) { - await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, token); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, token); return; } try { - await SqlHelper.NotifyConnectionInitializingAsync(handlers, UnderlyingConnection, initializationScript, false, token); + await SqlHelper.NotifyConnectionInitializingAsync(accessors, UnderlyingConnection, initializationScript, false, token); var command = UnderlyingConnection.CreateCommand(); await using (command.ConfigureAwait(false)) { command.CommandText = initializationScript; _ = await command.ExecuteNonQueryAsync(token).ConfigureAwait(false); } - await SqlHelper.NotifyConnectionOpenedAsync(handlers, UnderlyingConnection, false, token); + await SqlHelper.NotifyConnectionOpenedAsync(accessors, UnderlyingConnection, false, token); } catch (OperationCanceledException ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, token); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, token); await UnderlyingConnection.CloseAsync().ConfigureAwait(false); throw; } catch (Exception ex) { - await SqlHelper.NotifyConnectionOpeningFailedAsync(handlers, UnderlyingConnection, ex, false, token); + await SqlHelper.NotifyConnectionOpeningFailedAsync(accessors, UnderlyingConnection, ex, false, token); throw; } } diff --git a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs index e295a2a67b..7a7f0b5a9b 100644 --- a/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs +++ b/Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs @@ -32,9 +32,9 @@ public sealed class SqlDriverConfiguration public bool EnsureConnectionIsAlive { get; set; } /// - /// Gets connection handlers that should be notified about connection events. + /// Gets connection accessors that should be notified about connection events. /// - public IReadOnlyCollection ConnectionHandlers { get; private set; } + public IReadOnlyCollection DbConnectionAccessors { get; private set; } /// /// Clones this instance. @@ -43,11 +43,11 @@ public sealed class SqlDriverConfiguration public SqlDriverConfiguration Clone() { // no deep cloning - var handlers = (ConnectionHandlers.Count == 0) - ? Array.Empty() - : ConnectionHandlers.ToArray(ConnectionHandlers.Count); + var accessors = (DbConnectionAccessors.Count == 0) + ? Array.Empty() + : DbConnectionAccessors.ToArray(DbConnectionAccessors.Count); - return new SqlDriverConfiguration(handlers) { + return new SqlDriverConfiguration(accessors) { ForcedServerVersion = ForcedServerVersion, ConnectionInitializationSql = ConnectionInitializationSql, EnsureConnectionIsAlive = EnsureConnectionIsAlive @@ -59,15 +59,15 @@ public SqlDriverConfiguration Clone() /// public SqlDriverConfiguration() { - ConnectionHandlers = Array.Empty(); + DbConnectionAccessors = Array.Empty(); } /// /// Creates new instance of this type. /// - public SqlDriverConfiguration(IReadOnlyCollection connectionHandlers) + public SqlDriverConfiguration(IReadOnlyCollection connectionAccessors) { - ConnectionHandlers = connectionHandlers; + DbConnectionAccessors = connectionAccessors; } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/SqlExtensions.cs b/Orm/Xtensive.Orm/Sql/SqlExtensions.cs index 80615e39ce..bcf5516b96 100644 --- a/Orm/Xtensive.Orm/Sql/SqlExtensions.cs +++ b/Orm/Xtensive.Orm/Sql/SqlExtensions.cs @@ -52,14 +52,14 @@ public static string GetSchema(this UrlInfo url, string defaultValue) } /// - /// Adds handlers to connection so they will take effect on connection operations. + /// Assigns connection accessors to so they will have access. /// - /// The connection to assign handlers. - /// The handlers. - public static void AssignConnectionHandlers(this SqlConnection connection, - IReadOnlyCollection connectionHandlers) + /// The connection to assign accessors. + /// The accessors. + public static void AssignConnectionAccessors(this SqlConnection connection, + IReadOnlyCollection connectionAccessors) { - connection.Extensions.Set(new ConnectionHandlersExtension(connectionHandlers)); + connection.Extensions.Set(new DbConnectionAccessorExtension(connectionAccessors)); } } } \ No newline at end of file diff --git a/Orm/Xtensive.Orm/Sql/SqlHelper.cs b/Orm/Xtensive.Orm/Sql/SqlHelper.cs index 57e64c7720..b3ce61a215 100644 --- a/Orm/Xtensive.Orm/Sql/SqlHelper.cs +++ b/Orm/Xtensive.Orm/Sql/SqlHelper.cs @@ -526,154 +526,150 @@ public static NotSupportedException NotSupported(ServerFeatures feature) #region Notifications /// - /// Notifies all the that + /// Notifies all the that /// is about to be opened. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// The connection that is opening. /// if event happened on attemp to restore connection, otherwise . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpening( - IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) + IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false) { - foreach (var handler in connectionHandlers) { - handler.ConnectionOpening(new ConnectionEventData(connection, reconnect)); + foreach (var accessor in connectionAccessors) { + accessor.ConnectionOpening(new ConnectionEventData(connection, reconnect)); } } /// - /// Notifies all the that + /// Notifies all the that /// is about to be opened. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// The connection that is opening. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionOpeningAsync( - IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false, CancellationToken token = default) { - foreach (var handler in connectionHandlers) { - await handler.ConnectionOpeningAsync( + foreach (var accessor in connectionAccessors) { + await accessor.ConnectionOpeningAsync( new ConnectionEventData(connection, reconnect), token) .ConfigureAwait(false); } } /// - /// Notifies all the that + /// Notifies all the that /// opened connection is about to be initialized with . /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// Opened but not initialized connection /// The script that will run to initialize connection /// if event happened on attemp to restore connection, otherwise . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionInitializing( - IEnumerable connectionHandlers, DbConnection connection, string initializationScript, bool reconnect = false) + IEnumerable connectionAccessors, DbConnection connection, string initializationScript, bool reconnect = false) { - foreach (var handler in connectionHandlers) { - handler.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect)); + foreach (var accessor in connectionAccessors) { + accessor.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect)); } } /// - /// Notifies all the that + /// Notifies all the that /// opened connection is about to be initialized with . /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// Opened but not initialized connection /// The script that will run to initialize connection /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static async Task NotifyConnectionInitializingAsync(IEnumerable connectionHandlers, - DbConnection connection, - string initializationScript, - bool reconnect = false, - CancellationToken token = default) - { - foreach (var handler in connectionHandlers) { - await handler.ConnectionInitializationAsync( + public static async Task NotifyConnectionInitializingAsync( + IEnumerable connectionAccessors, DbConnection connection, string initializationScript, + bool reconnect = false, CancellationToken token = default) + { + foreach (var accessor in connectionAccessors) { + await accessor.ConnectionInitializationAsync( new ConnectionInitEventData(initializationScript, connection, reconnect), token) .ConfigureAwait(false); } } /// - /// Notifies all the about + /// Notifies all the about /// successful connection opening. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// The connection that is completely opened and initialized. /// if event happened on attemp to restore connection, otherwise . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpened( - IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false) + IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false) { - foreach (var handler in connectionHandlers) { - handler.ConnectionOpened(new ConnectionEventData(connection, reconnect)); + foreach (var accessor in connectionAccessors) { + accessor.ConnectionOpened(new ConnectionEventData(connection, reconnect)); } } /// - /// Notifies all the about + /// Notifies all the about /// successful connection opening. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// The connection that is completely opened and initialized. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static async Task NotifyConnectionOpenedAsync( - IEnumerable connectionHandlers, DbConnection connection, bool reconnect = false, CancellationToken token = default) + IEnumerable connectionAccessors, DbConnection connection, bool reconnect = false, CancellationToken token = default) { - foreach (var handler in connectionHandlers) { - await handler.ConnectionOpenedAsync( + foreach (var accessor in connectionAccessors) { + await accessor.ConnectionOpenedAsync( new ConnectionEventData(connection, reconnect), token) .ConfigureAwait(false); } } /// - /// Notifies all the about + /// Notifies all the about /// connection opening failure. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// Connection that failed to be opened or properly initialized. /// The exception which appeared. /// if event happened on attemp to restore connection, otherwise . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void NotifyConnectionOpeningFailed( - IEnumerable connectionHandlers, DbConnection connection, Exception exception, bool reconnect = false) + IEnumerable connectionAccessors, DbConnection connection, Exception exception, bool reconnect = false) { - foreach (var handler in connectionHandlers) { - handler.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect)); + foreach (var accessor in connectionAccessors) { + accessor.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect)); } } /// - /// Notifies all the about + /// Notifies all the about /// connection opening failure. /// - /// The handlers that should be notified. + /// The accessors that should be notified. /// Connection that failed to be opened or properly initialized. /// The exception which appeared. /// if event happened on attemp to restore connection, otherwise . /// Cancellation token. /// Task performing operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static async Task NotifyConnectionOpeningFailedAsync(IEnumerable connectionHandlers, - DbConnection connection, - Exception exception, - bool reconnect = false, - CancellationToken token = default) - { - foreach (var handler in connectionHandlers) { - await handler.ConnectionOpeningFailedAsync( + public static async Task NotifyConnectionOpeningFailedAsync( + IEnumerable connectionAccessors, DbConnection connection, Exception exception, + bool reconnect = false, CancellationToken token = default) + { + foreach (var accessor in connectionAccessors) { + await accessor.ConnectionOpeningFailedAsync( new ConnectionErrorEventData(exception, connection, reconnect), token) .ConfigureAwait(false); } diff --git a/Orm/Xtensive.Orm/Strings.Designer.cs b/Orm/Xtensive.Orm/Strings.Designer.cs index 0956e187d7..2644a4da82 100644 --- a/Orm/Xtensive.Orm/Strings.Designer.cs +++ b/Orm/Xtensive.Orm/Strings.Designer.cs @@ -1525,11 +1525,11 @@ internal static string ExConfigurationWithXNameAlreadyRegistered { } /// - /// Looks up a localized string similar to Connection handler '{0}' has no parameterless constructor.. + /// Looks up a localized string similar to Connection accessor '{0}' has no parameterless constructor.. /// - internal static string ExConnectionHandlerXHasNoParameterlessConstructor { + internal static string ExConnectionAccessorXHasNoParameterlessConstructor { get { - return ResourceManager.GetString("ExConnectionHandlerXHasNoParameterlessConstructor", resourceCulture); + return ResourceManager.GetString("ExConnectionAccessorXHasNoParameterlessConstructor", resourceCulture); } } diff --git a/Orm/Xtensive.Orm/Strings.resx b/Orm/Xtensive.Orm/Strings.resx index a2983a39e0..e001aecdff 100644 --- a/Orm/Xtensive.Orm/Strings.resx +++ b/Orm/Xtensive.Orm/Strings.resx @@ -3470,7 +3470,7 @@ Error: {1} Can't modify Active or Disposed scope. - - Connection handler '{0}' has no parameterless constructor. + + Connection accessor '{0}' has no parameterless constructor. \ No newline at end of file