public async Task <DbCommandProxy> CreateCommandAsync(ConnectionFactoryParameters parameters, ICommandMetricsReportable?metricsReporter, CancellationToken cancellationToken)
        {
            var(connection, index, payOutNumber) = await this._pool.GetConnectionAsync(
                parameters,
                _maxExecutionTime,
                nameof(GlobalConnectionPoolStrategy),
                cancellationToken)
                                                   .ConfigureAwait(false);

            //ChangeDatabase はあまり対応したくない感じだけど、一応指定されてたらここで反映しよう。
            if (!string.IsNullOrWhiteSpace(this._overriddenDatabaseName) && connection.Connection.Database != this._overriddenDatabaseName)
            {
                await connection.Connection.ChangeDatabaseAsync(this._overriddenDatabaseName, cancellationToken).ConfigureAwait(false);
            }

            var sourceCommand = connection.Connection.CreateCommand();

            var command = new DbCommandProxy(
                connection.Id,
                sourceCommand,
                metricsReporter,
                x =>
            {
                this._workingCommands.TryRemove(x, out _);
                this._pool.ReleaseConnection(index, payOutNumber);
            });

            this._workingCommands.TryAdd(command, true);

            return(command);
        }
예제 #2
0
        public async Task <DbCommandProxy> CreateCommandAsync(ConnectionFactoryParameters parameters,
                                                              ICommandMetricsReportable?metricsReporter,
                                                              CancellationToken cancellationToken)
        {
            var connection = this.TryReuse();

            if (connection == null)
            {
                connection = this._factory.CreateConnection(parameters);
                await connection.Connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                if (!string.IsNullOrWhiteSpace(this._overriddenDatabaseName))
                {
                    connection.Connection.ChangeDatabase(this._overriddenDatabaseName !);
                }
            }

            var command = new DbCommandProxy(
                connection.Id,
                connection.Connection.CreateCommand(),
                metricsReporter,
                this.OnCommandCompleted);

            this._workingCommands.TryAdd(command, connection);

            return(command);
        }
예제 #3
0
        private async Task <IConnectionWithId <MySqlConnection> > GetConnectionAsync(ConnectionFactoryParameters parameters, CancellationToken cancellationToken)
        {
            //取得済ならそのまま使う
            if (this._connection != null)
            {
                return(this._connection.ConnectionWithId);
            }

            await this._connectionLock.WaitAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                if (this._connection != null)
                {
                    return(this._connection.ConnectionWithId);
                }

                //未取得の場合は Pool から払い出してもらう
                //Strategy が破棄されるまで返さないぞ!
                var connection = await this._pool.GetConnectionAsync(
                    parameters,
                    _maxExecutionTime,
                    nameof(GlobalConnectionPoolTransactionStrategy),
                    cancellationToken)
                                 .ConfigureAwait(false);

                this._connection = connection;

                if (!string.IsNullOrWhiteSpace(this._overriddenDatabaseName) && connection.ConnectionWithId.Connection.Database != this._overriddenDatabaseName)
                {
                    await connection.ConnectionWithId.Connection.ChangeDatabaseAsync(this._overriddenDatabaseName, cancellationToken).ConfigureAwait(false);
                }

                return((this._connection = connection).ConnectionWithId);
            }
            finally
            {
                this._connectionLock.Release();
            }
        }
예제 #4
0
        public async Task <DbCommandProxy> CreateCommandAsync(ConnectionFactoryParameters parameters,
                                                              ICommandMetricsReportable metricsReporter,
                                                              CancellationToken cancellationToken)
        {
            var preparer = new TaskCompletionSource <bool>();

            lock (this._commandQueueLock)
            {
                if (!this._isCommandExecuting)
                {
                    this._isCommandExecuting = true;
                    preparer.SetResult(true);
                }
                else
                {
                    this._commandPreparerQueue.Enqueue(preparer);
                }
            }

            await preparer.Task.ConfigureAwait(false);

            var connection = await this.GetConnectionAsync(parameters, cancellationToken).ConfigureAwait(false);

            var sourceCommand = connection.Connection.CreateCommand();

            if (this._transaction != null)
            {
                sourceCommand.Transaction = this._transaction;
            }

            var command = new DbCommandProxy(
                connection.Id,
                sourceCommand,
                metricsReporter,
                this.OnCommandCompleted);

            return(command);
        }
예제 #5
0
        public async Task BeginTransactionAsync(IsolationLevel isolationLevel, ConnectionFactoryParameters parameters, CancellationToken cancellationToken)
        {
            var connection = await this.GetConnectionAsync(parameters, cancellationToken).ConfigureAwait(false);

            this._transaction = await connection.Connection.BeginTransactionAsync(isolationLevel, cancellationToken).ConfigureAwait(false);
        }
 public ConnectionStrategyPair CreateStrategyPair(IConnectionFactory <MySqlConnection> connectionFactory, ConnectionFactoryParameters parameters)
 {
     return(new ConnectionStrategyPair(
                new GlobalConnectionPoolStrategy(this._pool),
                new GlobalConnectionPoolTransactionStrategy(this._pool)));
 }
예제 #7
0
        /// <summary>
        /// 利用可能な Connection と、その Connection の <see cref="_connectionPool"/> 内での Index を取得する。
        /// 利用可能な Connection が無い場合は、利用可能になるまで待機する。
        /// </summary>
        public async ValueTask <PooledConnection> GetConnectionAsync(ConnectionFactoryParameters parameters,
                                                                     TimeSpan expiry,
                                                                     string callerName,
                                                                     CancellationToken cancellationToken)
        {
            var    usablePayOut = this.GetUsableConnection();
            PayOut payOut;

            if (usablePayOut.HasValue)
            {
                payOut = usablePayOut.Value;
            }
            else
            {
                //利用可能なコネクションが無かったら待機列へどうぞ。

                var preparer = new TaskCompletionSource <PayOut>(TaskCreationOptions.RunContinuationsAsynchronously);
                lock (this._waitQueueLock)
                {
                    this._waitQueue.Enqueue(preparer);
                }

                //利用可能なコネクションの Index を受け取って待機列を抜けるのだ。
                payOut = await preparer.Task.ConfigureAwait(false);
            }

            var pooledConnection = this._connectionPool[payOut.Index];

            lock (this._connectionPoolLock)
            {
                //準備が間に合わず再利用されてしまった場合はしょうがないので例外
                if (pooledConnection.Status != PoolStatus.Preparing ||
                    pooledConnection.PayOutNumber.HasValue == false ||
                    pooledConnection.PayOutNumber.Value != payOut.PayOutNumber)
                {
                    throw new InvalidOperationException("時間切れのため他の処理にコネクションが再利用されました。");
                }

                pooledConnection.Status          = PoolStatus.Using;
                pooledConnection.StatusChangedAt = DateTime.Now;
                pooledConnection.CallerName      = callerName;
                pooledConnection.ExpiredAt       = pooledConnection.StatusChangedAt.Add(expiry);
            }

            try
            {
                //実際のコネクションが無かったら作る。
                if (pooledConnection.ConnectionWithId == null)
                {
                    pooledConnection.ConnectionWithId = this._factory.CreateConnection(parameters);
                }

                //作ったやつは当然開いてないから開く必要がある。
                //あるいは時間経過で勝手に閉じられることもあるかもね。
                if (pooledConnection.ConnectionWithId.Connection.State != ConnectionState.Open)
                {
                    await pooledConnection.ConnectionWithId.Connection.OpenAsync(cancellationToken).ConfigureAwait(false);
                }
            }
            catch (Exception)
            {
                lock (this._connectionPoolLock)
                {
                    pooledConnection.Status          = PoolStatus.Assignable;
                    pooledConnection.StatusChangedAt = DateTime.Now;
                    pooledConnection.PayOutNumber    = null;
                    pooledConnection.CallerName      = null;
                    pooledConnection.ExpiredAt       = pooledConnection.StatusChangedAt;
                    pooledConnection.ConnectionWithId?.Dispose();
                    pooledConnection.ConnectionWithId = null;
                }
                throw;
            }

            return(new PooledConnection(pooledConnection.ConnectionWithId, payOut.Index, payOut.PayOutNumber));
        }
        private async Task <IConnectionWithId <DbConnection> > GetOrCreateConnectionAsync(ConnectionFactoryParameters parameters, CancellationToken cancellationToken)
        {
            if (this._connection != null)
            {
                return(this._connection);
            }

            await this._connectionLock.WaitAsync(cancellationToken).ConfigureAwait(false);

            try
            {
                if (this._connection != null)
                {
                    return(this._connection);
                }
                var connection = this._factory.CreateConnection(parameters);
                await connection.Connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                if (!string.IsNullOrWhiteSpace(this._overriddenDatabaseName))
                {
                    connection.Connection.ChangeDatabase(this._overriddenDatabaseName);
                }

                return(this._connection = connection);
            }
            finally
            {
                this._connectionLock.Release();
            }
        }
예제 #9
0
            public ConnectionStrategyPair CreateStrategyPair(IConnectionFactory <MySqlConnection> connectionFactory, ConnectionFactoryParameters parameters)
            {
                var strategy = new QueuedSingleConnectionStrategy(connectionFactory);

                return(new ConnectionStrategyPair(strategy, strategy));
            }
예제 #10
0
 public IConnectionWithId <MySqlConnection> CreateConnection(ConnectionFactoryParameters parameters)
 {
     return(new ConnectionWithId <MySqlConnection>(new MySqlConnection(parameters.ConnectionString)));
 }
 public ConnectionStrategyPair CreateStrategyPair(IConnectionFactory <DbConnection> connectionFactory, ConnectionFactoryParameters parameters)
 {
     return(new ConnectionStrategyPair(
                new TermBasedReuseStrategy(connectionFactory, this._reusableTime),
                new QueuedSingleConnectionStrategy(connectionFactory)));
 }