Beispiel #1
0
        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);
        }
Beispiel #2
0
        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)
            {
                newConnection.MakeNonPooledObject(owningConnection);
            }
            return(newConnection);
        }
Beispiel #3
0
 protected abstract DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions?previous);
Beispiel #4
0
        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)
            {
                newConnection.MakePooledConnection(pool);
            }
            return(newConnection);
        }
Beispiel #5
0
        internal DbConnectionPoolGroup?GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions?poolOptions, ref DbConnectionOptions?userConnectionOptions)
        {
            if (string.IsNullOrEmpty(key.ConnectionString))
            {
                return(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);
                }

                if (null == userConnectionOptions)
                { // we only allow one expansion on the connection string
                    userConnectionOptions = connectionOptions;
                }

                // We don't support connection pooling on Win9x
                if (null == poolOptions)
                {
                    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);
                        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);
        }
Beispiel #6
0
        internal DbConnectionPoolGroup?GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions?poolOptions, ref DbConnectionOptions?userConnectionOptions)
        {
            if (ADP.IsEmpty(key.ConnectionString))
            {
                return(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);
                }

                if (null == userConnectionOptions)
                { // we only allow one expansion on the connection string
                    userConnectionOptions = connectionOptions;
                    string 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);
        }
 internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource <DbConnectionInternal>?retry, DbConnectionOptions?userOptions)
 {
     return(base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions));
 }
Beispiel #8
0
        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);
        }
 /// <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);
 }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
 public PendingGetConnection(long dueTime, DbConnection owner, TaskCompletionSource <DbConnectionInternal> completion, DbConnectionOptions?userOptions)
 {
     DueTime    = dueTime;
     Owner      = owner;
     Completion = completion;
 }
Beispiel #13
0
        protected override DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions?previous)
        {
            Debug.Assert(!string.IsNullOrEmpty(connectionString), "empty connectionString");
            OdbcConnectionString result = new OdbcConnectionString(connectionString, (null != previous));

            return(result);
        }
        protected override DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions?previous)
        {
            Debug.Assert(!ADP.IsEmpty(connectionString), "null connectionString");
            OleDbConnectionString result = new OleDbConnectionString(connectionString, (null != previous));

            return(result);
        }
Beispiel #15
0
        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();
 }
Beispiel #17
0
        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);
        }
        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 occur 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);
        }
Beispiel #19
0
 protected virtual DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool?pool, DbConnection?owningConnection, DbConnectionOptions?userOptions)
 {
     return(CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection));
 }
        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);
        }