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
77using System ;
88using System . Collections . Generic ;
99using System . Linq ;
10+ using System . Linq . Expressions ;
11+ using System . Reflection ;
1012using Xtensive . Core ;
13+ using Xtensive . Linq ;
1114using Xtensive . Orm . Logging ;
1215using Xtensive . Orm . Configuration ;
1316using Xtensive . Orm . Model ;
@@ -24,13 +27,18 @@ namespace Xtensive.Orm.Providers
2427 /// </summary>
2528 public sealed partial class StorageDriver
2629 {
30+ private static readonly MethodInfo FactoryCreatorMethod = typeof ( StorageDriver )
31+ . GetMethod ( nameof ( CreateNewHandler ) , BindingFlags . Static | BindingFlags . NonPublic ) ;
32+
2733 private readonly DomainConfiguration configuration ;
2834 private readonly SqlDriver underlyingDriver ;
2935 private readonly SqlTranslator translator ;
3036 private readonly TypeMappingRegistry allMappings ;
3137 private readonly bool isLoggingEnabled ;
3238 private readonly bool hasSavepoints ;
3339
40+ private readonly IReadOnlyDictionary < Type , Func < IConnectionHandler > > handlerFactoriesCache ;
41+
3442 public ProviderInfo ProviderInfo { get ; private set ; }
3543
3644 public StorageExceptionBuilder ExceptionBuilder { get ; private set ; }
@@ -86,7 +94,7 @@ public DbDataReaderAccessor GetDataReaderAccessor(TupleDescriptor descriptor)
8694 public StorageDriver CreateNew ( Domain domain )
8795 {
8896 ArgumentValidator . EnsureArgumentNotNull ( domain , "domain" ) ;
89- return new StorageDriver ( underlyingDriver , ProviderInfo , domain . Configuration , GetModelProvider ( domain ) ) ;
97+ return new StorageDriver ( underlyingDriver , ProviderInfo , domain . Configuration , GetModelProvider ( domain ) , handlerFactoriesCache ) ;
9098 }
9199
92100 private static DomainModel GetNullModel ( )
@@ -140,13 +148,69 @@ private void FixExtractionResultSqlServerFamily(SqlExtractionResult result)
140148 }
141149 }
142150
151+ private IReadOnlyCollection < IConnectionHandler > CreateConnectionHandlersFast ( IEnumerable < Type > connectionHandlerTypes )
152+ {
153+ if ( handlerFactoriesCache == null )
154+ return Array . Empty < IConnectionHandler > ( ) ;
155+ var instances = new List < IConnectionHandler > ( handlerFactoriesCache . Count ) ;
156+ foreach ( var type in connectionHandlerTypes ) {
157+ if ( handlerFactoriesCache . TryGetValue ( type , out var factory ) ) {
158+ instances . Add ( factory ( ) ) ;
159+ }
160+ }
161+ return instances . ToArray ( ) ;
162+ }
163+
164+ private static IReadOnlyCollection < IConnectionHandler > CreateConnectionHandlers ( IEnumerable < Type > connectionHandlerTypes ,
165+ out IReadOnlyDictionary < Type , Func < IConnectionHandler > > factories )
166+ {
167+ factories = null ;
168+
169+ List < IConnectionHandler > instances ;
170+ Dictionary < Type , Func < IConnectionHandler > > factoriesLocal ;
171+
172+ if ( connectionHandlerTypes is IReadOnlyCollection < Type > asCollection ) {
173+ if ( asCollection . Count == 0 )
174+ return Array . Empty < IConnectionHandler > ( ) ;
175+ instances = new List < IConnectionHandler > ( asCollection . Count ) ;
176+ factoriesLocal = new Dictionary < Type , Func < IConnectionHandler > > ( asCollection . Count ) ;
177+ }
178+ else {
179+ if ( connectionHandlerTypes . Any ( ) )
180+ return Array . Empty < IConnectionHandler > ( ) ;
181+ instances = new List < IConnectionHandler > ( ) ;
182+ factoriesLocal = new Dictionary < Type , Func < IConnectionHandler > > ( ) ;
183+ }
184+
185+ foreach ( var type in connectionHandlerTypes ) {
186+ var ctor = type . GetConstructor ( BindingFlags . NonPublic | BindingFlags . Public | BindingFlags . Instance , null , Type . EmptyTypes , null ) ;
187+ if ( ctor == null ) {
188+ throw new NotSupportedException ( string . Format ( Strings . ExConnectionHandlerXHasNoParameterlessConstructor , type ) ) ;
189+ }
190+
191+ var handlerFactory = ( Func < IConnectionHandler > ) FactoryCreatorMethod . MakeGenericMethod ( type ) . Invoke ( null , null ) ;
192+ instances . Add ( handlerFactory ( ) ) ;
193+ factoriesLocal [ type ] = handlerFactory ;
194+ }
195+ factories = factoriesLocal ;
196+ return instances . ToArray ( ) ;
197+ }
198+
199+ private static Func < IConnectionHandler > CreateNewHandler < T > ( ) where T : IConnectionHandler
200+ {
201+ return FastExpression . Lambda < Func < IConnectionHandler > > (
202+ Expression . Convert ( Expression . New ( typeof ( T ) ) , typeof ( IConnectionHandler ) ) )
203+ . Compile ( ) ;
204+ }
205+
143206 // Constructors
144207
145208 public static StorageDriver Create ( SqlDriverFactory driverFactory , DomainConfiguration configuration )
146209 {
147210 ArgumentValidator . EnsureArgumentNotNull ( driverFactory , "driverFactory" ) ;
148211 ArgumentValidator . EnsureArgumentNotNull ( configuration , "configuration" ) ;
149212
213+ var handlers = CreateConnectionHandlers ( configuration . Types . ConnectionHandlers , out var factories ) ;
150214 var driverConfiguration = new SqlDriverConfiguration {
151215 ForcedServerVersion = configuration . ForcedServerVersion ,
152216 ConnectionInitializationSql = configuration . ConnectionInitializationSql ,
@@ -156,11 +220,14 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu
156220 var driver = driverFactory . GetDriver ( configuration . ConnectionInfo , driverConfiguration ) ;
157221 var providerInfo = ProviderInfoBuilder . Build ( configuration . ConnectionInfo . Provider , driver ) ;
158222
159- return new StorageDriver ( driver , providerInfo , configuration , GetNullModel ) ;
223+ return new StorageDriver ( driver , providerInfo , configuration , GetNullModel , factories ) ;
160224 }
161225
162- private StorageDriver (
163- SqlDriver driver , ProviderInfo providerInfo , DomainConfiguration configuration , Func < DomainModel > modelProvider )
226+ private StorageDriver ( SqlDriver driver ,
227+ ProviderInfo providerInfo ,
228+ DomainConfiguration configuration ,
229+ Func < DomainModel > modelProvider ,
230+ IReadOnlyDictionary < Type , Func < IConnectionHandler > > factoryCache )
164231 {
165232 underlyingDriver = driver ;
166233 ProviderInfo = providerInfo ;
@@ -171,6 +238,7 @@ private StorageDriver(
171238 hasSavepoints = underlyingDriver . ServerInfo . ServerFeatures . Supports ( ServerFeatures . Savepoints ) ;
172239 isLoggingEnabled = SqlLog . IsLogged ( LogLevel . Info ) ; // Just to cache this value
173240 ServerInfo = underlyingDriver . ServerInfo ;
241+ handlerFactoriesCache = factoryCache ;
174242 }
175243 }
176244}
0 commit comments