[ResourceExposure(ResourceScope.Machine)] //Exposes the file names which are a Machine resource as part of the connection string private void ChangeConnectionString(string newConnectionString) { DbConnectionOptions userConnectionOptions = s_emptyConnectionOptions; if (!String.IsNullOrEmpty(newConnectionString)) { userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.Synonyms); } DbProviderFactory factory = null; DbConnection storeConnection = null; DbConnectionOptions effectiveConnectionOptions = userConnectionOptions; if (!userConnectionOptions.IsEmpty) { // Check if we have the named connection, if yes, then use the connection string from the configuration manager settings string namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName]; if (!string.IsNullOrEmpty(namedConnection)) { // There cannot be other parameters when the named connection is specified if (1 < userConnectionOptions.Parsetable.Count) { throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ExtraParametersWithNamedConnection); } // Find the named connection from the configuration, then extract the settings ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[namedConnection]; if (setting == null || setting.ProviderName != EntityConnection.s_entityClientProviderName) { throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidNamedConnection); } effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms); // Check for a nested Name keyword string nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName]; if (!string.IsNullOrEmpty(nestedNamedConnection)) { throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_NestedNamedConnection(namedConnection)); } } //Validate the connection string has the required Keywords( Provider and Metadata) //We trim the values for both the Keywords, so a string value with only spaces will throw an exception //reporting back to the user that the Keyword was missing. ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName); string providerName = ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName); // Get the correct provider factory factory = GetFactory(providerName); // Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object storeConnection = GetStoreConnection(factory); try { // When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all. // Providers should still be able handle empty connection strings since those may be explicitly passed by clients. string providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName]; if (providerConnectionString != null) { storeConnection.ConnectionString = providerConnectionString; } } catch (Exception e) { if (EntityUtil.IsCatchableExceptionType(e)) { throw EntityUtil.Provider(@"ConnectionString", e); } throw; } } // This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being // managed by this EntityConnection, so states in this connection object are not messed up. // It's not for security, but just to help reduce user error. lock (_connectionStringLock) { // Now we have sufficient information and verified the configuration string is good, use them for this connection object // Failure should not occur from this point to the end of this method this._providerFactory = factory; this._metadataWorkspace = null; ClearTransactions(); ResetStoreConnection(storeConnection, null, false); // Remembers the connection options objects with the connection string set by the user this._userConnectionOptions = userConnectionOptions; this._effectiveConnectionOptions = effectiveConnectionOptions; } }
internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions) { Debug.Assert(null != pool, "null pool?"); DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo; DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions); if (null != newConnection) { PerformanceCounters.HardConnectsPerSecond.Increment(); newConnection.MakePooledConnection(pool); } return(newConnection); }
internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions) { throw ADP.MethodNotImplemented("TryReplaceConnection"); }
protected abstract DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection);
protected abstract DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
internal virtual DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions) { return(null); }
internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions) { if (ADP.IsEmpty(key.ConnectionString)) { return((DbConnectionPoolGroup)null); } DbConnectionPoolGroup connectionPoolGroup; Dictionary <DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups; if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup) || (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions))) { // If we can't find an entry for the connection string in // our collection of pool entries, then we need to create a // new pool entry and add it to our collection. DbConnectionOptions connectionOptions = CreateConnectionOptions(key.ConnectionString, userConnectionOptions); if (null == connectionOptions) { throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing); } string expandedConnectionString = key.ConnectionString; if (null == userConnectionOptions) { // we only allow one expansion on the connection string userConnectionOptions = connectionOptions; expandedConnectionString = connectionOptions.Expand(); // if the expanded string is same instance (default implementation), the use the already created options if ((object)expandedConnectionString != (object)key.ConnectionString) { // CONSIDER: caching the original string to reduce future parsing DbConnectionPoolKey newKey = (DbConnectionPoolKey)((ICloneable)key).Clone(); newKey.ConnectionString = expandedConnectionString; return(GetConnectionPoolGroup(newKey, null, ref userConnectionOptions)); } } // We don't support connection pooling on Win9x; it lacks too many of the APIs we require. if ((null == poolOptions) && ADP.IsWindowsNT) { if (null != connectionPoolGroup) { // reusing existing pool option in case user originally used SetConnectionPoolOptions poolOptions = connectionPoolGroup.PoolGroupOptions; } else { // Note: may return null for non-pooled connections poolOptions = CreateConnectionPoolGroupOptions(connectionOptions); } } lock (this) { connectionPoolGroups = _connectionPoolGroups; if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup)) { DbConnectionPoolGroup newConnectionPoolGroup = new DbConnectionPoolGroup(connectionOptions, key, poolOptions); newConnectionPoolGroup.ProviderInfo = CreateConnectionPoolGroupProviderInfo(connectionOptions); // build new dictionary with space for new connection string Dictionary <DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary <DbConnectionPoolKey, DbConnectionPoolGroup>(1 + connectionPoolGroups.Count); foreach (KeyValuePair <DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups) { newConnectionPoolGroups.Add(entry.Key, entry.Value); } // lock prevents race condition with PruneConnectionPoolGroups newConnectionPoolGroups.Add(key, newConnectionPoolGroup); PerformanceCounters.NumberOfActiveConnectionPoolGroups.Increment(); connectionPoolGroup = newConnectionPoolGroup; _connectionPoolGroups = newConnectionPoolGroups; } else { Debug.Assert(!connectionPoolGroup.IsDisabled, "Disabled pool entry discovered"); } } Debug.Assert(null != connectionPoolGroup, "how did we not create a pool entry?"); Debug.Assert(null != userConnectionOptions, "how did we not have user connection options?"); } else if (null == userConnectionOptions) { userConnectionOptions = connectionPoolGroup.ConnectionOptions; } return(connectionPoolGroup); }
public IUnitOfWork GetUnitOfWork(Type dbContextType, string dbName = null) { Check.NotNull(dbContextType, nameof(dbContextType)); // 若替换之前的UnitOfWork则有可能造成数据库连接释放不及时 // 若使用锁,可以确保UnitOrWork在当前Scope生命周期的唯一性,但会影响性能 var key = string.Format("{0}${1}$", dbName, dbContextType.FullName); if (_works.ContainsKey(key)) { return(_works[key]); } else { foreach (var k in _works.Keys) { if (k.StartsWith(key)) { return(_works[k]); } } IDbContext dbContext; key += DateTime.Now.Ticks.ToString(); var dbConnectionOptionsMap = _serviceProvider.GetRequiredService <IOptions <AlasFx.Options.AlasFxOptions> >().Value.DbConnections; if (dbConnectionOptionsMap == null || dbConnectionOptionsMap.Count <= 0) { throw new AlasFxException("无法获取数据库配置"); } DbConnectionOptions dbConnectionOptions = dbName == null?dbConnectionOptionsMap.First().Value : dbConnectionOptionsMap[dbName]; var builderOptions = _serviceProvider.GetServices <DbContextOptionsBuilderOptions>() ?.Where(d => (d.DbName == null || d.DbName == dbName) && (d.DbContextType == null || d.DbContextType == dbContextType)) ?.OrderByDescending(d => d.DbName) ?.OrderByDescending(d => d.DbContextType); if (builderOptions == null || !builderOptions.Any()) { throw new AlasFxException("无法获取匹配的DbContextOptionsBuilder"); } var dbUser = _serviceProvider.GetServices <IDbContextOptionsBuilderUser>()?.FirstOrDefault(u => u.Type == dbConnectionOptions.DatabaseType); if (dbUser == null) { throw new AlasFxException($"无法解析类型为“{dbConnectionOptions.DatabaseType}”的 {typeof(IDbContextOptionsBuilderUser).FullName} 实例"); } var dbContextOptions = dbUser.Use(builderOptions.First().Builder, dbConnectionOptions.ConnectionString).Options; if (_expressionFactoryDict.TryGetValue(dbContextType, out Func <IServiceProvider, DbContextOptions, IDbContext> factory)) { dbContext = factory(_serviceProvider, dbContextOptions); } else { // 使用Expression创建DbContext var constructorMethod = dbContextType.GetConstructors() .Where(c => c.IsPublic && !c.IsAbstract && !c.IsStatic) .OrderByDescending(c => c.GetParameters().Length) .FirstOrDefault(); if (constructorMethod == null) { throw new AlasFxException("无法获取有效的上下文构造器"); } var dbContextOptionsBuilderType = typeof(DbContextOptionsBuilder <>); var dbContextOptionsType = typeof(DbContextOptions); var dbContextOptionsGenericType = typeof(DbContextOptions <>); var serviceProviderType = typeof(IServiceProvider); var getServiceMethod = serviceProviderType.GetMethod("GetService"); var lambdaParameterExpressions = new ParameterExpression[2]; lambdaParameterExpressions[0] = (Expression.Parameter(serviceProviderType, "serviceProvider")); lambdaParameterExpressions[1] = (Expression.Parameter(dbContextOptionsType, "dbContextOptions")); var paramTypes = constructorMethod.GetParameters(); var argumentExpressions = new Expression[paramTypes.Length]; for (int i = 0; i < paramTypes.Length; i++) { var pType = paramTypes[i]; if (pType.ParameterType == dbContextOptionsType || (pType.ParameterType.IsGenericType && pType.ParameterType.GetGenericTypeDefinition() == dbContextOptionsGenericType)) { argumentExpressions[i] = Expression.Convert(lambdaParameterExpressions[1], pType.ParameterType); } else if (pType.ParameterType == serviceProviderType) { argumentExpressions[i] = lambdaParameterExpressions[0]; } else { argumentExpressions[i] = Expression.Call(lambdaParameterExpressions[0], getServiceMethod); } } factory = Expression .Lambda <Func <IServiceProvider, DbContextOptions, IDbContext> >( Expression.Convert(Expression.New(constructorMethod, argumentExpressions), typeof(IDbContext)), lambdaParameterExpressions.AsEnumerable()) .Compile(); _expressionFactoryDict.TryAdd(dbContextType, factory); dbContext = factory(_serviceProvider, dbContextOptions); } var unitOfWorkFactory = _serviceProvider.GetRequiredService <IUnitOfWorkFactory>(); var unitOfWork = unitOfWorkFactory.GetUnitOfWork(_serviceProvider, dbContext); _works.Add(key, unitOfWork); return(unitOfWork); } }
protected override DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous) { Debug.Assert(!string.IsNullOrEmpty(connectionString), "empty connectionString"); SqlConnectionString result = new SqlConnectionString(connectionString); return(result); }
/// <summary> /// Initializes a new instance of the class. /// </summary> public OleDbDataSource(DbConnectionOptions connectionOptions) : base(connectionOptions) { }
/// <summary> /// Builds a connection string based on the specified connection settings. /// </summary> public override string BuildConnectionString(DbConnectionOptions connectionOptions) { return(""); }
internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions) { if (retry == null || !retry.Task.IsCompleted) { // retry is null if this is a synchronous call // if someone calls Open or OpenAsync while in this state, // then the retry task will not be completed throw ADP.ConnectionAlreadyOpen(State); } // we are completing an asynchronous open Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully"); DbConnectionInternal openConnection = retry.Task.Result; if (null == openConnection) { connectionFactory.SetInnerConnectionTo(outerConnection, this); throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull); } connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection); return(true); }
internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions) => TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
/// <summary> /// Builds a connection string based on the specified connection settings. /// </summary> public override string BuildConnectionString(DbConnectionOptions connectionOptions) { return(BuildSqlConnectionString(connectionOptions)); }
[ResourceExposure(ResourceScope.Machine)] //Exposes the file names which are a Machine resource as part of the connection string private void ChangeConnectionString(string newConnectionString) { var userConnectionOptions = _emptyConnectionOptions; if (!String.IsNullOrEmpty(newConnectionString)) { userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.ValidKeywords); } DbProviderFactory factory = null; DbConnection storeConnection = null; var effectiveConnectionOptions = userConnectionOptions; if (!userConnectionOptions.IsEmpty) { // Check if we have the named connection, if yes, then use the connection string from the configuration manager settings var namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName]; if (!string.IsNullOrEmpty(namedConnection)) { // There cannot be other parameters when the named connection is specified if (1 < userConnectionOptions.Parsetable.Count) { throw new ArgumentException(Strings.EntityClient_ExtraParametersWithNamedConnection); } // Find the named connection from the configuration, then extract the settings var setting = ConfigurationManager.ConnectionStrings[namedConnection]; if (setting == null || setting.ProviderName != EntityClientProviderName) { throw new ArgumentException(Strings.EntityClient_InvalidNamedConnection); } effectiveConnectionOptions = new DbConnectionOptions( setting.ConnectionString, EntityConnectionStringBuilder.ValidKeywords); // Check for a nested Name keyword var nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName]; if (!string.IsNullOrEmpty(nestedNamedConnection)) { throw new ArgumentException(Strings.EntityClient_NestedNamedConnection(namedConnection)); } } //Validate the connection string has the required Keywords( Provider and Metadata) //We trim the values for both the Keywords, so a string value with only spaces will throw an exception //reporting back to the user that the Keyword was missing. ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName); var providerName = ValidateValueForTheKeyword( effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName); // Get the correct provider factory factory = DbConfiguration.DependencyResolver.GetService<DbProviderFactory>(providerName); // Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object storeConnection = GetStoreConnection(factory); try { // When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all. // Providers should still be able handle empty connection strings since those may be explicitly passed by clients. var providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName]; if (providerConnectionString != null) { DbInterception.Dispatch.Connection.SetConnectionString( storeConnection, new DbConnectionPropertyInterceptionContext<string>(InterceptionContext).WithValue(providerConnectionString)); } } catch (Exception e) { if (e.IsCatchableExceptionType()) { throw new EntityException(Strings.EntityClient_ProviderSpecificError(@"ConnectionString"), e); } throw; } } // This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being // managed by this EntityConnection, so states in this connection object are not messed up. // It's not for security, but just to help reduce user error. lock (_connectionStringLock) { // Now we have sufficient information and verified the configuration string is good, use them for this connection object // Failure should not occur from this point to the end of this method _providerFactory = factory; _metadataWorkspace = null; ClearTransactions(); UnsubscribeFromStoreConnectionStateChangeEvents(); _storeConnection = storeConnection; SubscribeToStoreConnectionStateChangeEvents(); // Remembers the connection options objects with the connection string set by the user _userConnectionOptions = userConnectionOptions; _effectiveConnectionOptions = effectiveConnectionOptions; } }
override internal DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions) { DbConnectionPoolProviderInfo providerInfo = null; if (((SqlConnectionString)connectionOptions).UserInstance) { providerInfo = new SqlConnectionPoolProviderInfo(); } return(providerInfo); }
/// <summary> /// Initializes a new instance of the class. /// </summary> public SqlDataSource(DbConnectionOptions connectionOptions) : base(connectionOptions) { }
override protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions connectionOptions) { SqlConnectionString opt = (SqlConnectionString)connectionOptions; DbConnectionPoolGroupOptions poolingOptions = null; if (opt.Pooling) { // never pool context connections. int connectionTimeout = opt.ConnectTimeout; if ((0 < connectionTimeout) && (connectionTimeout < int.MaxValue / 1000)) { connectionTimeout *= 1000; } else if (connectionTimeout >= int.MaxValue / 1000) { connectionTimeout = int.MaxValue; } if (opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryInteractive || opt.Authentication == SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow) { // interactive/device code flow mode will always have pool's CreateTimeout = 10 x ConnectTimeout. if (connectionTimeout >= Int32.MaxValue / 10) { connectionTimeout = Int32.MaxValue; } else { connectionTimeout *= 10; } SqlClientEventSource.Log.TraceEvent("<sc.SqlConnectionFactory.CreateConnectionPoolGroupOptions>Set connection pool CreateTimeout={0} when {1} is in use.", connectionTimeout, opt.Authentication); } poolingOptions = new DbConnectionPoolGroupOptions( opt.IntegratedSecurity, opt.MinPoolSize, opt.MaxPoolSize, connectionTimeout, opt.LoadBalanceTimeout, opt.Enlist); } return(poolingOptions); }
internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, out DbConnectionInternal connection) { Debug.Assert(null != owningConnection, "null owningConnection?"); DbConnectionPoolGroup poolGroup; DbConnectionPool connectionPool; connection = null; // Work around race condition with clearing the pool between GetConnectionPool obtaining pool // and GetConnection on the pool checking the pool state. Clearing the pool in this window // will switch the pool into the ShuttingDown state, and GetConnection will return null. // There is probably a better solution involving locking the pool/group, but that entails a major // re-design of the connection pooling synchronization, so is post-poned for now. // use retriesLeft to prevent CPU spikes with incremental sleep // start with one msec, double the time every retry // max time is: 1 + 2 + 4 + ... + 2^(retries-1) == 2^retries -1 == 1023ms (for 10 retries) int retriesLeft = 10; int timeBetweenRetriesMilliseconds = 1; do { poolGroup = GetConnectionPoolGroup(owningConnection); // Doing this on the callers thread is important because it looks up the WindowsIdentity from the thread. connectionPool = GetConnectionPool(owningConnection, poolGroup); if (null == connectionPool) { // If GetConnectionPool returns null, we can be certain that // this connection should not be pooled via DbConnectionPool // or have a disabled pool entry. poolGroup = GetConnectionPoolGroup(owningConnection); // previous entry have been disabled if (retry != null) { Task <DbConnectionInternal> newTask; CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); lock (s_pendingOpenNonPooled) { // look for an available task slot (completed or empty) int idx; for (idx = 0; idx < s_pendingOpenNonPooled.Length; idx++) { Task task = s_pendingOpenNonPooled[idx]; if (task == null) { s_pendingOpenNonPooled[idx] = GetCompletedTask(); break; } else if (task.IsCompleted) { break; } } // if didn't find one, pick the next one in round-robbin fashion if (idx == s_pendingOpenNonPooled.Length) { idx = s_pendingOpenNonPooledNext++ % s_pendingOpenNonPooled.Length; } // now that we have an antecedent task, schedule our work when it is completed. // If it is a new slot or a compelted task, this continuation will start right away. // BUG? : If we have timed out task on top of running task, then new task could be started // on top of that, since we are only checking the top task. This will lead to starting more threads // than intended. newTask = s_pendingOpenNonPooled[idx].ContinueWith((_) => { Transactions.Transaction originalTransaction = ADP.GetCurrentTransaction(); try { ADP.SetCurrentTransaction(retry.Task.AsyncState as Transactions.Transaction); var newConnection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); if ((oldConnection != null) && (oldConnection.State == ConnectionState.Open)) { oldConnection.PrepareForReplaceConnection(); oldConnection.Dispose(); } return(newConnection); } finally { ADP.SetCurrentTransaction(originalTransaction); } }, cancellationTokenSource.Token, TaskContinuationOptions.LongRunning, TaskScheduler.Default); // Place this new task in the slot so any future work will be queued behind it s_pendingOpenNonPooled[idx] = newTask; } // Set up the timeout (if needed) if (owningConnection.ConnectionTimeout > 0) { int connectionTimeoutMilliseconds = owningConnection.ConnectionTimeout * 1000; cancellationTokenSource.CancelAfter(connectionTimeoutMilliseconds); } // once the task is done, propagate the final results to the original caller newTask.ContinueWith((task) => { cancellationTokenSource.Dispose(); if (task.IsCanceled) { retry.TrySetException(ADP.ExceptionWithStackTrace(ADP.NonPooledOpenTimeout())); } else if (task.IsFaulted) { retry.TrySetException(task.Exception.InnerException); } else { if (retry.TrySetResult(task.Result)) { PerformanceCounters.NumberOfNonPooledConnections.Increment(); } else { // The outer TaskCompletionSource was already completed // Which means that we don't know if someone has messed with the outer connection in the middle of creation // So the best thing to do now is to destroy the newly created connection task.Result.DoomThisConnection(); task.Result.Dispose(); } } }, TaskScheduler.Default); return(false); } connection = CreateNonPooledConnection(owningConnection, poolGroup, userOptions); PerformanceCounters.NumberOfNonPooledConnections.Increment(); } else { if (((System.Data.OleDb.OleDbConnection)owningConnection).ForceNewConnection) { Debug.Assert(!(oldConnection is DbConnectionClosed), "Force new connection, but there is no old connection"); connection = connectionPool.ReplaceConnection(owningConnection, userOptions, oldConnection); } else { if (!connectionPool.TryGetConnection(owningConnection, retry, userOptions, out connection)) { return(false); } } if (connection == null) { // connection creation failed on semaphore waiting or if max pool reached if (connectionPool.IsRunning) { // If GetConnection failed while the pool is running, the pool timeout occurred. throw ADP.PooledOpenTimeout(); } else { // We've hit the race condition, where the pool was shut down after we got it from the group. // Yield time slice to allow shut down activities to complete and a new, running pool to be instantiated // before retrying. Threading.Thread.Sleep(timeBetweenRetriesMilliseconds); timeBetweenRetriesMilliseconds *= 2; // double the wait time for next iteration } } } } while (connection == null && retriesLeft-- > 0); if (connection == null) { // exhausted all retries or timed out - give up throw ADP.PooledOpenTimeout(); } return(true); }
override internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions) { return(new SqlConnectionPoolGroupProviderInfo((SqlConnectionString)connectionOptions)); }
protected virtual DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) { return(CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection)); }
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) { return(CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection, userOptions: null)); }
protected abstract DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
override protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions) { SqlConnectionString opt = (SqlConnectionString)options; SqlConnectionPoolKey key = (SqlConnectionPoolKey)poolKey; SessionData recoverySessionData = null; SqlConnection sqlOwningConnection = (SqlConnection)owningConnection; bool applyTransientFaultHandling = sqlOwningConnection != null ? sqlOwningConnection._applyTransientFaultHandling : false; SqlConnectionString userOpt = null; if (userOptions != null) { userOpt = (SqlConnectionString)userOptions; } else if (sqlOwningConnection != null) { userOpt = (SqlConnectionString)(sqlOwningConnection.UserConnectionOptions); } if (sqlOwningConnection != null) { recoverySessionData = sqlOwningConnection._recoverySessionData; } bool redirectedUserInstance = false; DbConnectionPoolIdentity identity = null; // Pass DbConnectionPoolIdentity to SqlInternalConnectionTds if using integrated security. // Used by notifications. if (opt.IntegratedSecurity) { if (pool != null) { identity = pool.Identity; } else { identity = DbConnectionPoolIdentity.GetCurrent(); } } // FOLLOWING IF BLOCK IS ENTIRELY FOR SSE USER INSTANCES // If "user instance=true" is in the connection string, we're using SSE user instances if (opt.UserInstance) { // opt.DataSource is used to create the SSE connection redirectedUserInstance = true; string instanceName; if ((null == pool) || (null != pool && pool.Count <= 0)) { // Non-pooled or pooled and no connections in the pool. SqlInternalConnectionTds sseConnection = null; try { // We throw an exception in case of a failure // NOTE: Cloning connection option opt to set 'UserInstance=True' and 'Enlist=False' // This first connection is established to SqlExpress to get the instance name // of the UserInstance. SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, userInstance: true, setEnlistValue: false); sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false, applyTransientFaultHandling: applyTransientFaultHandling); // NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance. instanceName = sseConnection.InstanceName; if (!instanceName.StartsWith("\\\\.\\", StringComparison.Ordinal)) { throw SQL.NonLocalSSEInstance(); } if (null != pool) { // Pooled connection - cache result SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex providerInfo.InstanceName = instanceName; } } finally { if (null != sseConnection) { sseConnection.Dispose(); } } } else { // Cached info from pool. SqlConnectionPoolProviderInfo providerInfo = (SqlConnectionPoolProviderInfo)pool.ProviderInfo; // No lock since we are already in creation mutex instanceName = providerInfo.InstanceName; } // NOTE: Here connection option opt is cloned to set 'instanceName=<UserInstanceName>' that was // retrieved from the previous SSE connection. For this UserInstance connection 'Enlist=True'. // options immutable - stored in global hash - don't modify opt = new SqlConnectionString(opt, instanceName, userInstance: false, setEnlistValue: null); poolGroupProviderInfo = null; // null so we do not pass to constructor below... } return(new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData, applyTransientFaultHandling: applyTransientFaultHandling, key.AccessToken, pool)); }
internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions) { Debug.Assert(null != owningConnection, "null owningConnection?"); Debug.Assert(null != poolGroup, "null poolGroup?"); DbConnectionOptions connectionOptions = poolGroup.ConnectionOptions; DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = poolGroup.ProviderInfo; DbConnectionPoolKey poolKey = poolGroup.PoolKey; DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions); if (null != newConnection) { PerformanceCounters.HardConnectsPerSecond.Increment(); newConnection.MakeNonPooledObject(owningConnection, PerformanceCounters); } return(newConnection); }
public PendingGetConnection(long dueTime, DbConnection owner, TaskCompletionSource <DbConnectionInternal> completion, DbConnectionOptions userOptions) { DueTime = dueTime; Owner = owner; Completion = completion; }
/// <devdoc>The default implementation is for the open connection objects, and /// it simply throws. Our private closed-state connection objects /// override this and do the correct thing.</devdoc> // User code should either override DbConnectionInternal.Activate when it comes out of the pool // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions) { throw ADP.ConnectionAlreadyOpen(State); }
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) { DbConnectionInternal newObj = null; try { newObj = _connectionFactory.CreatePooledConnection(this, owningObject, _connectionPoolGroup.ConnectionOptions, _connectionPoolGroup.PoolKey, userOptions); if (null == newObj) { throw ADP.InternalError(ADP.InternalErrorCode.CreateObjectReturnedNull); // CreateObject succeeded, but null object } if (!newObj.CanBePooled) { throw ADP.InternalError(ADP.InternalErrorCode.NewObjectCannotBePooled); // CreateObject succeeded, but non-poolable object } newObj.PrePush(null); lock (_objectList) { if ((oldConnection != null) && (oldConnection.Pool == this)) { _objectList.Remove(oldConnection); } _objectList.Add(newObj); _totalObjects = _objectList.Count; } // If the old connection belonged to another pool, we need to remove it from that if (oldConnection != null) { var oldConnectionPool = oldConnection.Pool; if (oldConnectionPool != null && oldConnectionPool != this) { Debug.Assert(oldConnectionPool._state == State.ShuttingDown, "Old connections pool should be shutting down"); lock (oldConnectionPool._objectList) { oldConnectionPool._objectList.Remove(oldConnection); oldConnectionPool._totalObjects = oldConnectionPool._objectList.Count; } } } // Reset the error wait: _errorWait = ERROR_WAIT_DEFAULT; } catch (Exception e) { if (!ADP.IsCatchableExceptionType(e)) { throw; } newObj = null; // set to null, so we do not return bad new object // Failed to create instance _resError = e; // Make sure the timer starts even if ThreadAbort occurs after setting the ErrorEvent. // timer allocation has to be done out of CER block Timer t = new Timer(new TimerCallback(this.ErrorCallback), null, Timeout.Infinite, Timeout.Infinite); bool timerIsNotDisposed; try { } finally { _waitHandles.ErrorEvent.Set(); _errorOccurred = true; // Enable the timer. // Note that the timer is created to allow periodic invocation. If ThreadAbort occurs in the middle of ErrorCallback, // the timer will restart. Otherwise, the timer callback (ErrorCallback) destroys the timer after resetting the error to avoid second callback. _errorTimer = t; timerIsNotDisposed = t.Change(_errorWait, _errorWait); } Debug.Assert(timerIsNotDisposed, "ErrorCallback timer has been disposed"); if (30000 < _errorWait) { _errorWait = 60000; } else { _errorWait *= 2; } throw; } return(newObj); }
protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions) { // ?->Connecting: prevent set_ConnectionString during Open if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this)) { DbConnectionInternal openConnection = null; try { connectionFactory.PermissionDemand(outerConnection); if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection)) { return(false); } } catch { // This should occure for all exceptions, even ADP.UnCatchableExceptions. connectionFactory.SetInnerConnectionTo(outerConnection, this); throw; } if (null == openConnection) { connectionFactory.SetInnerConnectionTo(outerConnection, this); throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull); } connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection); } return(true); }
internal bool TryGetConnection(DbConnection owningObject, TaskCompletionSource <DbConnectionInternal> retry, DbConnectionOptions userOptions, out DbConnectionInternal connection) { uint waitForMultipleObjectsTimeout = 0; bool allowCreate = false; if (retry == null) { waitForMultipleObjectsTimeout = (uint)CreationTimeout; // Set the wait timeout to INFINITE (-1) if the SQL connection timeout is 0 (== infinite) if (waitForMultipleObjectsTimeout == 0) { waitForMultipleObjectsTimeout = unchecked ((uint)Timeout.Infinite); } allowCreate = true; } if (_state != State.Running) { connection = null; return(true); } bool onlyOneCheckConnection = true; if (TryGetConnection(owningObject, waitForMultipleObjectsTimeout, allowCreate, onlyOneCheckConnection, userOptions, out connection)) { return(true); } else if (retry == null) { // timed out on a sync call return(true); } var pendingGetConnection = new PendingGetConnection( CreationTimeout == 0 ? Timeout.Infinite : ADP.TimerCurrent() + ADP.TimerFromSeconds(CreationTimeout / 1000), owningObject, retry, userOptions); _pendingOpens.Enqueue(pendingGetConnection); // it is better to StartNew too many times than not enough if (_pendingOpensWaiting == 0) { Thread waitOpenThread = new Thread(WaitForPendingOpen); waitOpenThread.IsBackground = true; waitOpenThread.Start(); } connection = null; return(false); }
private static void LoadStoreItemCollections(MetadataWorkspace workspace, DbConnection storeConnection, DbProviderFactory factory, DbConnectionOptions connectionOptions, EdmItemCollection edmItemCollection, MetadataArtifactLoader artifactLoader) { Debug.Assert(workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space"); // The provider connection string is optional; if it has not been specified, // we pick up the store's connection string. // string providerConnectionString = connectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName]; if (string.IsNullOrEmpty(providerConnectionString) && (storeConnection != null)) { providerConnectionString = storeConnection.ConnectionString; } // Build a string as the key and look up the MetadataCache for a match string storeCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(), connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], providerConnectionString); // Load store metadata. object entryToken; StorageMappingItemCollection mappingCollection = MetadataCache.GetOrCreateStoreAndMappingItemCollections(storeCacheKey, artifactLoader, edmItemCollection, out entryToken); workspace.RegisterItemCollection(mappingCollection.StoreItemCollection); workspace.RegisterItemCollection(mappingCollection); // Adding the store metadata entry token to the workspace workspace.AddMetadataEntryToken(entryToken); }
private bool TryGetConnection(DbConnection owningObject, uint waitForMultipleObjectsTimeout, bool allowCreate, bool onlyOneCheckConnection, DbConnectionOptions userOptions, out DbConnectionInternal connection) { DbConnectionInternal obj = null; if (null == obj) { Interlocked.Increment(ref _waitCount); do { int waitResult = BOGUS_HANDLE; try { try { } finally { waitResult = WaitHandle.WaitAny(_waitHandles.GetHandles(allowCreate), unchecked ((int)waitForMultipleObjectsTimeout)); } // From the WaitAny docs: "If more than one object became signaled during // the call, this is the array index of the signaled object with the // smallest index value of all the signaled objects." This is important // so that the free object signal will be returned before a creation // signal. switch (waitResult) { case WaitHandle.WaitTimeout: Interlocked.Decrement(ref _waitCount); connection = null; return(false); case ERROR_HANDLE: // Throw the error that PoolCreateRequest stashed. Interlocked.Decrement(ref _waitCount); throw TryCloneCachedException(); case CREATION_HANDLE: try { obj = UserCreateRequest(owningObject, userOptions); } catch { if (null == obj) { Interlocked.Decrement(ref _waitCount); } throw; } finally { // Ensure that we release this waiter, regardless // of any exceptions that may be thrown. if (null != obj) { Interlocked.Decrement(ref _waitCount); } } if (null == obj) { // If we were not able to create an object, check to see if // we reached MaxPoolSize. If so, we will no longer wait on // the CreationHandle, but instead wait for a free object or // the timeout. if (Count >= MaxPoolSize && 0 != MaxPoolSize) { if (!ReclaimEmancipatedObjects()) { // modify handle array not to wait on creation mutex anymore Debug.Assert(2 == CREATION_HANDLE, "creation handle changed value"); allowCreate = false; } } } break; case SEMAPHORE_HANDLE: // // guaranteed available inventory // Interlocked.Decrement(ref _waitCount); obj = GetFromGeneralPool(); if ((obj != null) && (!obj.IsConnectionAlive())) { DestroyObject(obj); obj = null; // Setting to null in case creating a new object fails if (onlyOneCheckConnection) { if (_waitHandles.CreationSemaphore.WaitOne(unchecked ((int)waitForMultipleObjectsTimeout))) { try { obj = UserCreateRequest(owningObject, userOptions); } finally { _waitHandles.CreationSemaphore.Release(1); } } else { // Timeout waiting for creation semaphore - return null connection = null; return(false); } } } break; default: Interlocked.Decrement(ref _waitCount); throw ADP.InternalError(ADP.InternalErrorCode.UnexpectedWaitAnyResult); } } finally { if (CREATION_HANDLE == waitResult) { _waitHandles.CreationSemaphore.Release(1); } } } while (null == obj); } if (null != obj) { PrepareConnection(owningObject, obj); } connection = obj; return(true); }
private static string ValidateValueForTheKeyword( DbConnectionOptions effectiveConnectionOptions, string keywordName) { var keywordValue = effectiveConnectionOptions[keywordName]; if (!string.IsNullOrEmpty(keywordValue)) { keywordValue = keywordValue.Trim(); // be nice to user, always trim the value } // Check that we have a non-null and non-empty value for the keyword if (string.IsNullOrEmpty(keywordValue)) { throw new ArgumentException(Strings.EntityClient_ConnectionStringMissingInfo(keywordName)); } return keywordValue; }
internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions) { Debug.Assert(null != pool, "null pool?"); DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo; DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions); if (null != newConnection) { PerformanceCounters.HardConnectsPerSecond.Increment(); newConnection.MakePooledConnection(pool); } SqlClientEventSource.Log.TryTraceEvent("<prov.DbConnectionFactory.CreatePooledConnection|RES|CPOOL> {0}, Pooled database connection created.", ObjectID); return(newConnection); }