Skip to content

Commit 57ca535

Browse files
committed
Support for connection that storage driver opens
1 parent 21d49b2 commit 57ca535

File tree

7 files changed

+201
-25
lines changed

7 files changed

+201
-25
lines changed

Orm/Xtensive.Orm/Orm/Providers/StorageDriver.Operations.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2020 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
@@ -14,7 +14,7 @@
1414

1515
namespace Xtensive.Orm.Providers
1616
{
17-
partial class StorageDriver
17+
public partial class StorageDriver
1818
{
1919
private sealed class InitializationSqlExtension
2020
{
@@ -50,6 +50,11 @@ public SqlConnection CreateConnection(Session session)
5050
throw ExceptionBuilder.BuildException(exception);
5151
}
5252

53+
if (handlerFactoriesCache != null) {
54+
connection.AssignConnectionHandlers(
55+
CreateConnectionHandlersFast(configuration.Types.ConnectionHandlers));
56+
}
57+
5358
var sessionConfiguration = GetConfiguration(session);
5459
connection.CommandTimeout = sessionConfiguration.DefaultCommandTimeout;
5560
var connectionInfo = GetConnectionInfo(session) ?? sessionConfiguration.ConnectionInfo;
@@ -69,14 +74,14 @@ public void OpenConnection(Session session, SqlConnection connection)
6974
if (isLoggingEnabled)
7075
SqlLog.Info(Strings.LogSessionXOpeningConnectionY, session.ToStringSafely(), connection.ConnectionInfo);
7176

72-
var extension = connection.Extensions.Get<InitializationSqlExtension>();
77+
var script = connection.Extensions.Get<InitializationSqlExtension>()?.Script;
7378

7479
try {
75-
if (extension == null || string.IsNullOrEmpty(extension.Script)) {
76-
connection.Open();
80+
if (!string.IsNullOrEmpty(script)) {
81+
connection.OpenAndInitialize(script);
7782
}
7883
else {
79-
connection.OpenAndInitialize(extension.Script);
84+
connection.Open();
8085
}
8186
}
8287
catch (Exception exception) {
@@ -94,13 +99,15 @@ public async Task OpenConnectionAsync(Session session, SqlConnection connection,
9499
if (isLoggingEnabled)
95100
SqlLog.Info(Strings.LogSessionXOpeningConnectionY, session.ToStringSafely(), connection.ConnectionInfo);
96101

97-
var extension = connection.Extensions.Get<InitializationSqlExtension>();
102+
var script = connection.Extensions.Get<InitializationSqlExtension>()?.Script;
98103

99104
try {
100-
if (!string.IsNullOrEmpty(extension?.Script))
101-
await connection.OpenAndInitializeAsync(extension.Script, cancellationToken).ConfigureAwait(false);
102-
else
105+
if (!string.IsNullOrEmpty(script)) {
106+
await connection.OpenAndInitializeAsync(script, cancellationToken).ConfigureAwait(false);
107+
}
108+
else {
103109
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
110+
}
104111
}
105112
catch (OperationCanceledException) {
106113
throw;

Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu
211211
ArgumentValidator.EnsureArgumentNotNull(configuration, "configuration");
212212

213213
var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories);
214-
var driverConfiguration = new SqlDriverConfiguration {
214+
var driverConfiguration = new SqlDriverConfiguration(handlers) {
215215
ForcedServerVersion = configuration.ForcedServerVersion,
216216
ConnectionInitializationSql = configuration.ConnectionInitializationSql,
217217
EnsureConnectionIsAlive = configuration.EnsureConnectionIsAlive,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (C) 2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System.Collections.Generic;
6+
using Xtensive.Orm;
7+
8+
namespace Xtensive.Sql
9+
{
10+
/// <summary>
11+
/// Wrapper to pass <see cref="IConnectionHandler"/>s to connection.
12+
/// </summary>
13+
public sealed class ConnectionHandlersExtension
14+
{
15+
/// <summary>
16+
/// Collection of <see cref="IConnectionHandler"/> instances.
17+
/// </summary>
18+
public IReadOnlyCollection<IConnectionHandler> Handlers { get; }
19+
20+
internal ConnectionHandlersExtension(IReadOnlyCollection<IConnectionHandler> handlers)
21+
{
22+
Handlers = handlers;
23+
}
24+
}
25+
}

Orm/Xtensive.Orm/Sql/SqlConnection.cs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

@@ -166,7 +166,22 @@ public virtual IBinaryLargeObject CreateBinaryLargeObject() =>
166166
public virtual void Open()
167167
{
168168
EnsureIsNotDisposed();
169-
UnderlyingConnection.Open();
169+
var connectionHandlers = Extensions.Get<ConnectionHandlersExtension>();
170+
if (connectionHandlers == null) {
171+
UnderlyingConnection.Open();
172+
}
173+
else {
174+
var handlers = connectionHandlers.Handlers;
175+
SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection);
176+
try {
177+
UnderlyingConnection.Open();
178+
SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection);
179+
}
180+
catch (Exception ex) {
181+
SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex);
182+
throw;
183+
}
184+
}
170185
}
171186

172187
/// <summary>
@@ -176,14 +191,37 @@ public virtual void Open()
176191
public virtual void OpenAndInitialize(string initializationScript)
177192
{
178193
UnderlyingConnection.Open();
179-
if (string.IsNullOrEmpty(initializationScript)) {
180-
return;
181-
}
194+
var connectionHandlers = Extensions.Get<ConnectionHandlersExtension>();
195+
if (connectionHandlers == null) {
196+
UnderlyingConnection.Open();
197+
if (string.IsNullOrEmpty(initializationScript)) {
198+
return;
199+
}
182200

183-
using (var command = UnderlyingConnection.CreateCommand()) {
201+
using var command = UnderlyingConnection.CreateCommand();
184202
command.CommandText = initializationScript;
185203
_ = command.ExecuteNonQuery();
186204
}
205+
else {
206+
var handlers = connectionHandlers.Handlers;
207+
SqlHelper.NotifyConnectionOpening(handlers, UnderlyingConnection);
208+
try {
209+
UnderlyingConnection.Open();
210+
if (string.IsNullOrEmpty(initializationScript)) {
211+
SqlHelper.NotifyConnectionOpened(handlers, UnderlyingConnection);
212+
return;
213+
}
214+
215+
SqlHelper.NotifyConnectionInitializing(handlers, UnderlyingConnection, initializationScript);
216+
using var command = UnderlyingConnection.CreateCommand();
217+
command.CommandText = initializationScript;
218+
_ = command.ExecuteNonQuery();
219+
}
220+
catch (Exception ex) {
221+
SqlHelper.NotifyConnectionOpeningFailed(handlers, UnderlyingConnection, ex);
222+
throw;
223+
}
224+
}
187225
}
188226

189227
/// <summary>

Orm/Xtensive.Orm/Sql/SqlDriverConfiguration.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
// Copyright (C) 2003-2012 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2012-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2012.12.27
66

7+
using System;
8+
using System.Collections.Generic;
9+
using Xtensive.Core;
10+
using Xtensive.Orm;
11+
712
namespace Xtensive.Sql
813
{
914
/// <summary>
@@ -26,13 +31,23 @@ public sealed class SqlDriverConfiguration
2631
/// </summary>
2732
public bool EnsureConnectionIsAlive { get; set; }
2833

34+
/// <summary>
35+
/// Gets connection handlers that should be notified about connection events.
36+
/// </summary>
37+
public IReadOnlyCollection<IConnectionHandler> ConnectionHandlers { get; private set; }
38+
2939
/// <summary>
3040
/// Clones this instance.
3141
/// </summary>
3242
/// <returns>Clone of this instance.</returns>
3343
public SqlDriverConfiguration Clone()
3444
{
35-
return new SqlDriverConfiguration {
45+
// no deep cloning
46+
var handlers = (ConnectionHandlers.Count == 0)
47+
? Array.Empty<IConnectionHandler>()
48+
: ConnectionHandlers.ToArray(ConnectionHandlers.Count);
49+
50+
return new SqlDriverConfiguration(handlers) {
3651
ForcedServerVersion = ForcedServerVersion,
3752
ConnectionInitializationSql = ConnectionInitializationSql,
3853
EnsureConnectionIsAlive = EnsureConnectionIsAlive
@@ -44,6 +59,15 @@ public SqlDriverConfiguration Clone()
4459
/// </summary>
4560
public SqlDriverConfiguration()
4661
{
62+
ConnectionHandlers = Array.Empty<IConnectionHandler>();
63+
}
64+
65+
/// <summary>
66+
/// Creates new instance of this type.
67+
/// </summary>
68+
public SqlDriverConfiguration(IReadOnlyCollection<IConnectionHandler> connectionHandlers)
69+
{
70+
ConnectionHandlers = connectionHandlers;
4771
}
4872
}
4973
}

Orm/Xtensive.Orm/Sql/SqlExtensions.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
55
// Created: 2009.07.30
66

77
using System;
8+
using System.Collections.Generic;
89
using Xtensive.Core;
910
using Xtensive.Orm;
1011
using Xtensive.Sql.Dml;
@@ -49,5 +50,16 @@ public static string GetSchema(this UrlInfo url, string defaultValue)
4950
var result = resource.Substring(position + 1).TryCutSuffix(SchemaSeparatorString);
5051
return string.IsNullOrEmpty(result) ? defaultValue : result;
5152
}
53+
54+
/// <summary>
55+
/// Adds handlers to connection so they will take effect on connection operations.
56+
/// </summary>
57+
/// <param name="connection">The connection to assign handlers.</param>
58+
/// <param name="connectionHandlers">The handlers.</param>
59+
public static void AssignConnectionHandlers(this SqlConnection connection,
60+
IReadOnlyCollection<IConnectionHandler> connectionHandlers)
61+
{
62+
connection.Extensions.Set(new ConnectionHandlersExtension(connectionHandlers));
63+
}
5264
}
5365
}

Orm/Xtensive.Orm/Sql/SqlHelper.cs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// All rights reserved.
33
// For conditions of distribution and use, see license.
44
// Created by: Denis Krjuchkov
@@ -433,5 +433,75 @@ public static NotSupportedException NotSupported(ServerFeatures feature)
433433
{
434434
return NotSupported(feature.ToString());
435435
}
436+
437+
#region Notifications
438+
439+
/// <summary>
440+
/// Notifies all the <paramref name="connectionHandlers"/> that
441+
/// <paramref name="connection"/> is about to be opened.
442+
/// </summary>
443+
/// <param name="connectionHandlers">The handlers that should be notified.</param>
444+
/// <param name="connection">The connection that is opening.</param>
445+
/// <param name="reconnect"><see langword="true"/> if event happened on attemp to restore connection, otherwise <see langword="false"/>.</param>
446+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
447+
public static void NotifyConnectionOpening(
448+
IEnumerable<IConnectionHandler> connectionHandlers, DbConnection connection, bool reconnect = false)
449+
{
450+
foreach (var handler in connectionHandlers) {
451+
handler.ConnectionOpening(new ConnectionEventData(connection, reconnect));
452+
}
453+
}
454+
455+
/// <summary>
456+
/// Notifies all the <paramref name="connectionHandlers"/> that
457+
/// opened connection is about to be initialized with <paramref name="initializationScript"/>.
458+
/// </summary>
459+
/// <param name="connectionHandlers">The handlers that should be notified.</param>
460+
/// <param name="connection">Opened but not initialized connection</param>
461+
/// <param name="initializationScript">The script that will run to initialize connection</param>
462+
/// <param name="reconnect"><see langword="true"/> if event happened on attemp to restore connection, otherwise <see langword="false"/>.</param>
463+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
464+
public static void NotifyConnectionInitializing(
465+
IEnumerable<IConnectionHandler> connectionHandlers, DbConnection connection, string initializationScript, bool reconnect = false)
466+
{
467+
foreach (var handler in connectionHandlers) {
468+
handler.ConnectionInitialization(new ConnectionInitEventData(initializationScript, connection, reconnect));
469+
}
470+
}
471+
472+
/// <summary>
473+
/// Notifies all the <paramref name="connectionHandlers"/> about
474+
/// successful connection opening.
475+
/// </summary>
476+
/// <param name="connectionHandlers">The handlers that should be notified.</param>
477+
/// <param name="connection">The connection that is completely opened and initialized.</param>
478+
/// <param name="reconnect"><see langword="true"/> if event happened on attemp to restore connection, otherwise <see langword="false"/>.</param>
479+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
480+
public static void NotifyConnectionOpened(
481+
IEnumerable<IConnectionHandler> connectionHandlers, DbConnection connection, bool reconnect = false)
482+
{
483+
foreach (var handler in connectionHandlers) {
484+
handler.ConnectionOpened(new ConnectionEventData(connection, reconnect));
485+
}
486+
}
487+
488+
/// <summary>
489+
/// Notifies all the <paramref name="connectionHandlers"/> about
490+
/// connection opening failure.
491+
/// </summary>
492+
/// <param name="connectionHandlers">The handlers that should be notified.</param>
493+
/// <param name="connection">Connection that failed to be opened or properly initialized.</param>
494+
/// <param name="exception">The exception which appeared.</param>
495+
/// <param name="reconnect"><see langword="true"/> if event happened on attemp to restore connection, otherwise <see langword="false"/>.</param>
496+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
497+
public static void NotifyConnectionOpeningFailed(
498+
IEnumerable<IConnectionHandler> connectionHandlers, DbConnection connection, Exception exception, bool reconnect = false)
499+
{
500+
foreach (var handler in connectionHandlers) {
501+
handler.ConnectionOpeningFailed(new ConnectionErrorEventData(exception, connection, reconnect));
502+
}
503+
}
504+
505+
#endregion
436506
}
437507
}

0 commit comments

Comments
 (0)