diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index a41eeb8b02..df16ee4d23 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -49,8 +49,7 @@ abstract public DbProviderFactory ProviderFactory public void ClearAllPools() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" connectionPoolGroups = _connectionPoolGroups; foreach (KeyValuePair entry in connectionPoolGroups) @@ -62,17 +61,12 @@ public void ClearAllPools() } } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } public void ClearPool(DbConnection connection) { ADP.CheckArgumentNull(connection, nameof(connection)); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", GetObjectId(connection)); - try + using (TryEventScope.Create(" {0}", GetObjectId(connection))) { DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection); if (null != poolGroup) @@ -80,30 +74,20 @@ public void ClearPool(DbConnection connection) poolGroup.Clear(); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } public void ClearPool(DbConnectionPoolKey key) { Debug.Assert(key != null, "key cannot be null"); ADP.CheckArgumentNull(key.ConnectionString, nameof(key) + "." + nameof(key.ConnectionString)); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" connectionString"); - try + using (TryEventScope.Create(" connectionString")) { - DbConnectionPoolGroup poolGroup; Dictionary connectionPoolGroups = _connectionPoolGroups; - if (connectionPoolGroups.TryGetValue(key, out poolGroup)) + if (connectionPoolGroups.TryGetValue(key, out DbConnectionPoolGroup poolGroup)) { poolGroup.Clear(); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 7c07ed3c99..3975c5d3ca 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -795,67 +795,68 @@ public override void Prepare() _pendingCancel = false; SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.Prepare | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.Prepare | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); - try + using (TryEventScope.Create("SqlCommand.Prepare | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - - // only prepare if batch with parameters - if (this.IsPrepared && !this.IsDirty - || (this.CommandType == CommandType.StoredProcedure) - || ((System.Data.CommandType.Text == this.CommandType) - && (0 == GetParameterCount(_parameters)))) + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.Prepare | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); + try { - if (null != Statistics) + statistics = SqlStatistics.StartTimer(Statistics); + + // only prepare if batch with parameters + if (this.IsPrepared && !this.IsDirty + || (this.CommandType == CommandType.StoredProcedure) + || ((System.Data.CommandType.Text == this.CommandType) + && (0 == GetParameterCount(_parameters)))) { - Statistics.SafeIncrement(ref Statistics._prepares); + if (null != Statistics) + { + Statistics.SafeIncrement(ref Statistics._prepares); + } + _hiddenPrepare = false; } - _hiddenPrepare = false; - } - else - { - // Validate the command outside of the try/catch to avoid putting the _stateObj on error - ValidateCommand(isAsync: false); - - bool processFinallyBlock = true; - try + else { - // NOTE: The state object isn't actually needed for this, but it is still here for back-compat (since it does a bunch of checks) - GetStateObject(); + // Validate the command outside of the try/catch to avoid putting the _stateObj on error + ValidateCommand(isAsync: false); - // Loop through parameters ensuring that we do not have unspecified types, sizes, scales, or precisions - if (null != _parameters) + bool processFinallyBlock = true; + try { - int count = _parameters.Count; - for (int i = 0; i < count; ++i) + // NOTE: The state object isn't actually needed for this, but it is still here for back-compat (since it does a bunch of checks) + GetStateObject(); + + // Loop through parameters ensuring that we do not have unspecified types, sizes, scales, or precisions + if (null != _parameters) { - _parameters[i].Prepare(this); + int count = _parameters.Count; + for (int i = 0; i < count; ++i) + { + _parameters[i].Prepare(this); + } } - } - InternalPrepare(); - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (processFinallyBlock) + InternalPrepare(); + } + catch (Exception e) + { + processFinallyBlock = ADP.IsCatchableExceptionType(e); + throw; + } + finally { - _hiddenPrepare = false; // The command is now officially prepared + if (processFinallyBlock) + { + _hiddenPrepare = false; // The command is now officially prepared - ReliablePutStateObject(); + ReliablePutStateObject(); + } } } } - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -918,86 +919,87 @@ internal void Unprepare() /// public override void Cancel() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.Cancel | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.Cancel | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); - - SqlStatistics statistics = null; - try + using (TryEventScope.Create("SqlCommand.Cancel | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.Cancel | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); - // If we are in reconnect phase simply cancel the waiting task - var reconnectCompletionSource = _reconnectionCompletionSource; - if (reconnectCompletionSource != null) + SqlStatistics statistics = null; + try { - if (reconnectCompletionSource.TrySetCanceled()) + statistics = SqlStatistics.StartTimer(Statistics); + + // If we are in reconnect phase simply cancel the waiting task + var reconnectCompletionSource = _reconnectionCompletionSource; + if (reconnectCompletionSource != null) { - return; + if (reconnectCompletionSource.TrySetCanceled()) + { + return; + } } - } - // the pending data flag means that we are awaiting a response or are in the middle of processing a response - // if we have no pending data, then there is nothing to cancel - // if we have pending data, but it is not a result of this command, then we don't cancel either. Note that - // this model is implementable because we only allow one active command at any one time. This code - // will have to change we allow multiple outstanding batches - if (null == _activeConnection) - { - return; - } - SqlInternalConnectionTds connection = (_activeConnection.InnerConnection as SqlInternalConnectionTds); - if (null == connection) - { // Fail with out locking - return; - } - - // The lock here is to protect against the command.cancel / connection.close race condition - // The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and - // the command will no longer be cancelable. It might be desirable to be able to cancel the close operation, but this is - // outside of the scope of Whidbey RTM. See (SqlConnection::Close) for other lock. - lock (connection) - { - if (connection != (_activeConnection.InnerConnection as SqlInternalConnectionTds)) - { // make sure the connection held on the active connection is what we have stored in our temp connection variable, if not between getting "connection" and taking the lock, the connection has been closed + // the pending data flag means that we are awaiting a response or are in the middle of processing a response + // if we have no pending data, then there is nothing to cancel + // if we have pending data, but it is not a result of this command, then we don't cancel either. Note that + // this model is implementable because we only allow one active command at any one time. This code + // will have to change we allow multiple outstanding batches + if (null == _activeConnection) + { return; } - - TdsParser parser = connection.Parser; - if (null == parser) - { + SqlInternalConnectionTds connection = (_activeConnection.InnerConnection as SqlInternalConnectionTds); + if (null == connection) + { // Fail with out locking return; } + // The lock here is to protect against the command.cancel / connection.close race condition + // The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and + // the command will no longer be cancelable. It might be desirable to be able to cancel the close operation, but this is + // outside of the scope of Whidbey RTM. See (SqlConnection::Close) for other lock. + lock (connection) + { + if (connection != (_activeConnection.InnerConnection as SqlInternalConnectionTds)) + { // make sure the connection held on the active connection is what we have stored in our temp connection variable, if not between getting "connection" and taking the lock, the connection has been closed + return; + } - if (!_pendingCancel) - { // Do nothing if already pending. - // Before attempting actual cancel, set the _pendingCancel flag to false. - // This denotes to other thread before obtaining stateObject from the - // session pool that there is another thread wishing to cancel. - // The period in question is between entering the ExecuteAPI and obtaining - // a stateObject. - _pendingCancel = true; - - TdsParserStateObject stateObj = _stateObj; - if (null != stateObj) + TdsParser parser = connection.Parser; + if (null == parser) { - stateObj.Cancel(this); + return; } - else - { - SqlDataReader reader = connection.FindLiveReader(this); - if (reader != null) + + + if (!_pendingCancel) + { // Do nothing if already pending. + // Before attempting actual cancel, set the _pendingCancel flag to false. + // This denotes to other thread before obtaining stateObject from the + // session pool that there is another thread wishing to cancel. + // The period in question is between entering the ExecuteAPI and obtaining + // a stateObject. + _pendingCancel = true; + + TdsParserStateObject stateObj = _stateObj; + if (null != stateObj) { - reader.Cancel(this); + stateObj.Cancel(this); + } + else + { + SqlDataReader reader = connection.FindLiveReader(this); + if (reader != null) + { + reader.Cancel(this); + } } } } } - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -1038,52 +1040,51 @@ public override object ExecuteScalar() // between entry into Execute* API and the thread obtaining the stateObject. _pendingCancel = false; - Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); - SqlStatistics statistics = null; - - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.ExecuteScalar | API | ObjectId {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteScalar | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); - Exception e = null; bool success = false; int? sqlExceptionNumber = null; + Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); - try + using (TryEventScope.Create("SqlCommand.ExecuteScalar | API | ObjectId {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - SqlDataReader ds; - ds = IsRetryEnabled ? - RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, returnStream: true) : - RunExecuteReader(0, RunBehavior.ReturnImmediately, returnStream: true, method: nameof(ExecuteScalar)); - success = true; + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteScalar | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); - return CompleteExecuteScalar(ds, false); - } - catch (Exception ex) - { - if (ex is SqlException) + try { - SqlException exception = (SqlException)ex; - sqlExceptionNumber = exception.Number; - } + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + SqlDataReader ds; + ds = IsRetryEnabled ? + RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, returnStream: true) : + RunExecuteReader(0, RunBehavior.ReturnImmediately, returnStream: true, method: nameof(ExecuteScalar)); + success = true; - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); - if (e != null) + return CompleteExecuteScalar(ds, false); + } + catch (Exception ex) { - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + if (ex is SqlException) + { + SqlException exception = (SqlException)ex; + sqlExceptionNumber = exception.Number; + } + + e = ex; + throw; } - else + finally { - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + if (e != null) + { + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + } + else + { + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + } } } } @@ -1133,43 +1134,44 @@ public override int ExecuteNonQuery() // between entry into Execute* API and the thread obtaining the stateObject. _pendingCancel = false; - Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); - SqlStatistics statistics = null; - - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.ExecuteNonQuery | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteNonQuery | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}, Command Text {3}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); Exception e = null; - try + Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); + + using (TryEventScope.Create("SqlCommand.ExecuteNonQuery | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - if (IsRetryEnabled) - { - InternalExecuteNonQueryWithRetry(sendToPipe: false, timeout: CommandTimeout, out _, asyncWrite: false, inRetry: false); - } - else + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteNonQuery | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}, Command Text {3}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); + + try { - InternalExecuteNonQuery(completion: null, sendToPipe: false, timeout: CommandTimeout, out _); + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + if (IsRetryEnabled) + { + InternalExecuteNonQueryWithRetry(sendToPipe: false, timeout: CommandTimeout, out _, asyncWrite: false, inRetry: false); + } + else + { + InternalExecuteNonQuery(completion: null, sendToPipe: false, timeout: CommandTimeout, out _); + } + return _rowsAffected; } - return _rowsAffected; - } - catch (Exception ex) - { - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - if (e != null) + catch (Exception ex) { - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + e = ex; + throw; } - else + finally { - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + SqlStatistics.StopTimer(statistics); + if (e != null) + { + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + } + else + { + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + } } } } @@ -1641,51 +1643,52 @@ public XmlReader ExecuteXmlReader() // Reset _pendingCancel upon entry into any Execute - used to synchronize state // between entry into Execute* API and the thread obtaining the stateObject. _pendingCancel = false; - bool success = false; - - Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.ExecuteXmlReader | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteXmlReader | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); + bool success = false; int? sqlExceptionNumber = null; - Exception e = null; - try - { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - // use the reader to consume metadata - SqlDataReader ds; - ds = IsRetryEnabled ? - RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true) : - RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true); - success = true; - return CompleteXmlReader(ds); - } - catch (Exception ex) + Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); + + using (TryEventScope.Create("SqlCommand.ExecuteXmlReader | API | Object Id {0}", ObjectID)) { - e = ex; - if (ex is SqlException) + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlCommand.ExecuteXmlReader | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}, Command Text '{3}'", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId, CommandText); + + try { - SqlException exception = (SqlException)ex; - sqlExceptionNumber = exception.Number; + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + // use the reader to consume metadata + SqlDataReader ds; + ds = IsRetryEnabled ? + RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true) : + RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true); + success = true; + return CompleteXmlReader(ds); } - - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); - if (e != null) + catch (Exception ex) { - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + e = ex; + if (ex is SqlException) + { + SqlException exception = (SqlException)ex; + sqlExceptionNumber = exception.Number; + } + + throw; } - else + finally { - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + if (e != null) + { + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + } + else + { + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + } } } } @@ -1978,50 +1981,50 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) /// new public SqlDataReader ExecuteReader(CommandBehavior behavior) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommand.ExecuteReader | API | Object Id {0}", ObjectID); // Reset _pendingCancel upon entry into any Execute - used to synchronize state // between entry into Execute* API and the thread obtaining the stateObject. _pendingCancel = false; - Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); - SqlStatistics statistics = null; bool success = false; int? sqlExceptionNumber = null; Exception e = null; - try - { - WriteBeginExecuteEvent(); - statistics = SqlStatistics.StartTimer(Statistics); - return IsRetryEnabled ? - RunExecuteReaderWithRetry(behavior, RunBehavior.ReturnImmediately, returnStream: true) : - RunExecuteReader(behavior, RunBehavior.ReturnImmediately, returnStream: true); - } - catch (Exception ex) + Guid operationId = _diagnosticListener.WriteCommandBefore(this, _transaction); + + using (TryEventScope.Create("SqlCommand.ExecuteReader | API | Object Id {0}", ObjectID)) { - if (ex is SqlException) + try { - SqlException exception = (SqlException)ex; - sqlExceptionNumber = exception.Number; + WriteBeginExecuteEvent(); + statistics = SqlStatistics.StartTimer(Statistics); + return IsRetryEnabled ? + RunExecuteReaderWithRetry(behavior, RunBehavior.ReturnImmediately, returnStream: true) : + RunExecuteReader(behavior, RunBehavior.ReturnImmediately, returnStream: true); } - - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); - - if (e != null) + catch (Exception ex) { - _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + if (ex is SqlException) + { + SqlException exception = (SqlException)ex; + sqlExceptionNumber = exception.Number; + } + + e = ex; + throw; } - else + finally { - _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + if (e != null) + { + _diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + } + else + { + _diagnosticListener.WriteCommandAfter(operationId, this, _transaction); + } } - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommandSet.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommandSet.cs index 2129ecaf8b..f474877d41 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommandSet.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommandSet.cs @@ -278,9 +278,7 @@ internal void Dispose() internal int ExecuteNonQuery() { ValidateCommandBehavior(nameof(ExecuteNonQuery), CommandBehavior.Default); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlCommandSet.ExecuteNonQuery | API | Object Id {0}, Commands executed in Batch RPC mode", ObjectID); - - try + using (TryEventScope.Create("SqlCommandSet.ExecuteNonQuery | API | Object Id {0}, Commands executed in Batch RPC mode", ObjectID)) { BatchCommand.BatchRPCMode = true; BatchCommand.ClearBatchCommand(); @@ -293,10 +291,6 @@ internal int ExecuteNonQuery() return BatchCommand.ExecuteBatchRPCCommand(); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal SqlParameter GetParameter(int commandIndex, int parameterIndex) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs index 4879a3111c..00c90bb2b9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -1034,8 +1034,7 @@ public SqlTransaction BeginTransaction(string transactionName) [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive")] override protected DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.BeginDbTransaction | API | Object Id {0}, Isolation Level {1}", ObjectID, (int)isolationLevel); - try + using (TryEventScope.Create("SqlConnection.BeginDbTransaction | API | Object Id {0}, Isolation Level {1}", ObjectID, (int)isolationLevel)) { DbTransaction transaction = BeginTransaction(isolationLevel); @@ -1047,10 +1046,6 @@ override protected DbTransaction BeginDbTransaction(System.Data.IsolationLevel i return transaction; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// @@ -1058,32 +1053,33 @@ public SqlTransaction BeginTransaction(System.Data.IsolationLevel iso, string tr { WaitForPendingReconnection(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.BeginTransaction | API | Object Id {0}, Iso {1}, Transaction Name '{2}'", ObjectID, (int)iso, transactionName); - try + using (TryEventScope.Create(SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.BeginTransaction | API | Object Id {0}, Iso {1}, Transaction Name '{2}'", ObjectID, (int)iso, transactionName))) { - statistics = SqlStatistics.StartTimer(Statistics); - - SqlTransaction transaction; - bool isFirstAttempt = true; - do + try { - transaction = GetOpenTdsConnection().BeginSqlTransaction(iso, transactionName, isFirstAttempt); // do not reconnect twice - Debug.Assert(isFirstAttempt || !transaction.InternalTransaction.ConnectionHasBeenRestored, "Restored connection on non-first attempt"); - isFirstAttempt = false; - } while (transaction.InternalTransaction.ConnectionHasBeenRestored); + statistics = SqlStatistics.StartTimer(Statistics); + SqlTransaction transaction; + bool isFirstAttempt = true; + do + { + transaction = GetOpenTdsConnection().BeginSqlTransaction(iso, transactionName, isFirstAttempt); // do not reconnect twice + Debug.Assert(isFirstAttempt || !transaction.InternalTransaction.ConnectionHasBeenRestored, "Restored connection on non-first attempt"); + isFirstAttempt = false; + } while (transaction.InternalTransaction.ConnectionHasBeenRestored); - // The GetOpenConnection line above doesn't keep a ref on the outer connection (this), - // and it could be collected before the inner connection can hook it to the transaction, resulting in - // a transaction with a null connection property. Use GC.KeepAlive to ensure this doesn't happen. - GC.KeepAlive(this); - return transaction; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + // The GetOpenConnection line above doesn't keep a ref on the outer connection (this), + // and it could be collected before the inner connection can hook it to the transaction, resulting in + // a transaction with a null connection property. Use GC.KeepAlive to ensure this doesn't happen. + GC.KeepAlive(this); + + return transaction; + } + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -1137,10 +1133,10 @@ private void CloseInnerConnection() /// public override void Close() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.Close | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.Close | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, ClientConnectionId); - try + using (TryEventScope.Create("SqlConnection.Close | API | Object Id {0}", ObjectID)) { + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.Close | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, ClientConnectionId); + ConnectionState previousState = State; Guid operationId = default(Guid); Guid clientConnectionId = default(Guid); @@ -1214,10 +1210,6 @@ public override void Close() } } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// @@ -1260,10 +1252,10 @@ private bool TryOpenWithRetry(TaskCompletionSource retry, /// public void Open(SqlConnectionOverrides overrides) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.Open | API | Correlation | Object Id {0}, Activity Id {1}", ObjectID, ActivityCorrelator.Current); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.Open | API | Correlation | Object Id {0}, Activity Id {1}", ObjectID, ActivityCorrelator.Current); - try + using (TryEventScope.Create("SqlConnection.Open | API | Correlation | Object Id {0}, Activity Id {1}", ObjectID, ActivityCorrelator.Current)) { + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.Open | API | Correlation | Object Id {0}, Activity Id {1}", ObjectID, ActivityCorrelator.Current); + Guid operationId = s_diagnosticListener.WriteConnectionOpenBefore(this); PrepareStatisticsForNewConnection(); @@ -1298,10 +1290,6 @@ public void Open(SqlConnectionOverrides overrides) } } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void RegisterWaitingForReconnect(Task waitingTask) @@ -2023,10 +2011,10 @@ internal void OnInfoMessage(SqlInfoMessageEventArgs imevent, out bool notified) /// public static void ChangePassword(string connectionString, string newPassword) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.ChangePassword | API | Password change requested."); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.ChangePassword | API | Correlation | ActivityID {0}", ActivityCorrelator.Current); - try + using (TryEventScope.Create("SqlConnection.ChangePassword | API | Password change requested.")) { + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.ChangePassword | API | Correlation | ActivityID {0}", ActivityCorrelator.Current); + if (string.IsNullOrEmpty(connectionString)) { throw SQL.ChangePasswordArgumentMissing(nameof(newPassword)); @@ -2054,19 +2042,15 @@ public static void ChangePassword(string connectionString, string newPassword) ChangePassword(connectionString, connectionOptions, null, newPassword, null); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// public static void ChangePassword(string connectionString, SqlCredential credential, SecureString newSecurePassword) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlConnection.ChangePassword | API | Password change requested."); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.ChangePassword | API | Correlation | ActivityID {0}", ActivityCorrelator.Current); - try + using (TryEventScope.Create("SqlConnection.ChangePassword | API | Password change requested.")) { + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.ChangePassword | API | Correlation | ActivityID {0}", ActivityCorrelator.Current); + if (string.IsNullOrEmpty(connectionString)) { throw SQL.ChangePasswordArgumentMissing(nameof(connectionString)); @@ -2115,10 +2099,6 @@ public static void ChangePassword(string connectionString, SqlCredential credent ChangePassword(connectionString, connectionOptions, credential, null, newSecurePassword); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } private static void ChangePassword(string connectionString, SqlConnectionString connectionOptions, SqlCredential credential, string newPassword, SecureString newSecurePassword) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs index cf9ab34507..a34be614cd 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs @@ -153,8 +153,7 @@ internal void AddWeakReference(object value, int tag) /// override protected DbCommand CreateDbCommand() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - try + using (TryEventScope.Create(" {0}", ObjectID)) { DbCommand command = null; DbProviderFactory providerFactory = ConnectionFactory.ProviderFactory; @@ -162,10 +161,6 @@ override protected DbCommand CreateDbCommand() command.Connection = this; return command; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 275fdde457..4dc0eec82d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -851,90 +851,91 @@ protected override void Dispose(bool disposing) /// public override void Close() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.Close | API | Object Id {0}, Command Object Id {1}", ObjectID, Command?.ObjectID); - SqlStatistics statistics = null; - try + using (TryEventScope.Create("SqlDataReader.Close | API | Object Id {0}, Command Object Id {1}", ObjectID, Command?.ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - TdsParserStateObject stateObj = _stateObj; - - // Request that the current task is stopped - _cancelAsyncOnCloseTokenSource.Cancel(); - var currentTask = _currentTask; - if ((currentTask != null) && (!currentTask.IsCompleted)) + SqlStatistics statistics = null; + try { - try - { - // Wait for the task to complete - ((IAsyncResult)currentTask).AsyncWaitHandle.WaitOne(); + statistics = SqlStatistics.StartTimer(Statistics); + TdsParserStateObject stateObj = _stateObj; - // Ensure that we've finished reading any pending data - var networkPacketTaskSource = stateObj._networkPacketTaskSource; - if (networkPacketTaskSource != null) - { - ((IAsyncResult)networkPacketTaskSource.Task).AsyncWaitHandle.WaitOne(); - } - } - catch (Exception) + // Request that the current task is stopped + _cancelAsyncOnCloseTokenSource.Cancel(); + var currentTask = _currentTask; + if ((currentTask != null) && (!currentTask.IsCompleted)) { - // If we receive any exceptions while waiting, something has gone horribly wrong and we need to doom the connection and fast-fail the reader - _connection.InnerConnection.DoomThisConnection(); - _isClosed = true; - - if (stateObj != null) + try { - lock (stateObj) + // Wait for the task to complete + ((IAsyncResult)currentTask).AsyncWaitHandle.WaitOne(); + + // Ensure that we've finished reading any pending data + var networkPacketTaskSource = stateObj._networkPacketTaskSource; + if (networkPacketTaskSource != null) { - _stateObj = null; - _command = null; - _connection = null; + ((IAsyncResult)networkPacketTaskSource.Task).AsyncWaitHandle.WaitOne(); } } + catch (Exception) + { + // If we receive any exceptions while waiting, something has gone horribly wrong and we need to doom the connection and fast-fail the reader + _connection.InnerConnection.DoomThisConnection(); + _isClosed = true; - throw; + if (stateObj != null) + { + lock (stateObj) + { + _stateObj = null; + _command = null; + _connection = null; + } + } + + throw; + } } - } - // Close down any active Streams and TextReaders (this will also wait for them to finish their async tasks) - // NOTE: This must be done outside of the lock on the stateObj otherwise it will deadlock with CleanupAfterAsyncInvocation - CloseActiveSequentialStreamAndTextReader(); + // Close down any active Streams and TextReaders (this will also wait for them to finish their async tasks) + // NOTE: This must be done outside of the lock on the stateObj otherwise it will deadlock with CleanupAfterAsyncInvocation + CloseActiveSequentialStreamAndTextReader(); - if (stateObj != null) - { - // protect against concurrent close and cancel - lock (stateObj) + if (stateObj != null) { - if (_stateObj != null) - { // reader not closed while we waited for the lock - // TryCloseInternal will clear out the snapshot when it is done - if (_snapshot != null) - { + // protect against concurrent close and cancel + lock (stateObj) + { + if (_stateObj != null) + { // reader not closed while we waited for the lock + // TryCloseInternal will clear out the snapshot when it is done + if (_snapshot != null) + { #if DEBUG - // The stack trace for replays will differ since they weren't captured during close - stateObj._permitReplayStackTraceToDiffer = true; + // The stack trace for replays will differ since they weren't captured during close + stateObj._permitReplayStackTraceToDiffer = true; #endif - PrepareForAsyncContinuation(); - } + PrepareForAsyncContinuation(); + } - SetTimeout(_defaultTimeoutMilliseconds); + SetTimeout(_defaultTimeoutMilliseconds); - // Close can be called from async methods in error cases, - // in which case we need to switch to syncOverAsync - stateObj._syncOverAsync = true; + // Close can be called from async methods in error cases, + // in which case we need to switch to syncOverAsync + stateObj._syncOverAsync = true; - if (!TryCloseInternal(true /*closeReader*/)) - { - throw SQL.SynchronousCallMayNotPend(); + if (!TryCloseInternal(true /*closeReader*/)) + { + throw SQL.SynchronousCallMayNotPend(); + } + // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread } - // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread } } } - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -1449,24 +1450,25 @@ override public int GetProviderSpecificValues(object[] values) public override DataTable GetSchemaTable() { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.GetSchemaTable | API | Object Id {0}, Command Object Id {1}", ObjectID, Command?.ObjectID); - try + using (TryEventScope.Create("SqlDataReader.GetSchemaTable | API | Object Id {0}, Command Object Id {1}", ObjectID, Command?.ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - if (null == _metaData || null == _metaData.schemaTable) + try { - if (null != this.MetaData) + statistics = SqlStatistics.StartTimer(Statistics); + if (null == _metaData || null == _metaData.schemaTable) { - _metaData.schemaTable = BuildSchemaTable(); - Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); + if (null != this.MetaData) + { + _metaData.schemaTable = BuildSchemaTable(); + Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); + } } + return _metaData?.schemaTable; + } + finally + { + SqlStatistics.StopTimer(statistics); } - return _metaData?.schemaTable; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -3250,138 +3252,139 @@ override public bool NextResult() private bool TryNextResult(out bool more) { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.NextResult | API | Object Id {0}", ObjectID); - try + using (TryEventScope.Create("SqlDataReader.NextResult | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - - SetTimeout(_defaultTimeoutMilliseconds); - - if (IsClosed) + try { - throw ADP.DataReaderClosed(nameof(NextResult)); - } - _fieldNameLookup = null; + statistics = SqlStatistics.StartTimer(Statistics); - bool success = false; // WebData 100390 - _hasRows = false; // reset HasRows + SetTimeout(_defaultTimeoutMilliseconds); - // if we are specifically only processing a single result, then read all the results off the wire and detach - if (IsCommandBehavior(CommandBehavior.SingleResult)) - { - if (!TryCloseInternal(false /*closeReader*/)) + if (IsClosed) { - more = false; - return false; + throw ADP.DataReaderClosed(nameof(NextResult)); } + _fieldNameLookup = null; - // In the case of not closing the reader, null out the metadata AFTER - // CloseInternal finishes - since CloseInternal may go to the wire - // and use the metadata. - ClearMetaData(); - more = success; - return true; - } + bool success = false; // WebData 100390 + _hasRows = false; // reset HasRows - if (null != _parser) - { - // if there are more rows, then skip them, the user wants the next result - bool moreRows = true; - while (moreRows) + // if we are specifically only processing a single result, then read all the results off the wire and detach + if (IsCommandBehavior(CommandBehavior.SingleResult)) { - if (!TryReadInternal(false, out moreRows)) - { // don't reset set the timeout value + if (!TryCloseInternal(false /*closeReader*/)) + { more = false; return false; } - } - } - // we may be done, so continue only if we have not detached ourselves from the parser - if (null != _parser) - { - bool moreResults; - if (!TryHasMoreResults(out moreResults)) - { - more = false; - return false; + // In the case of not closing the reader, null out the metadata AFTER + // CloseInternal finishes - since CloseInternal may go to the wire + // and use the metadata. + ClearMetaData(); + more = success; + return true; } - if (moreResults) - { - _metaDataConsumed = false; - _browseModeInfoConsumed = false; - switch (_altRowStatus) + if (null != _parser) + { + // if there are more rows, then skip them, the user wants the next result + bool moreRows = true; + while (moreRows) { - case ALTROWSTATUS.AltRow: - int altRowId; - if (!_parser.TryGetAltRowId(_stateObj, out altRowId)) - { - more = false; - return false; - } - _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId); - if (altMetaDataSet != null) - { - _metaData = altMetaDataSet; - } - Debug.Assert((_metaData != null), "Can't match up altrowmetadata"); - break; - case ALTROWSTATUS.Done: - // restore the row-metaData - _metaData = _altMetaDataSetCollection.metaDataSet; - Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus"); - _altRowStatus = ALTROWSTATUS.Null; - break; - default: - if (!TryConsumeMetaData()) - { - more = false; - return false; - } - if (_metaData == null) - { - more = false; - return true; - } - break; + if (!TryReadInternal(false, out moreRows)) + { // don't reset set the timeout value + more = false; + return false; + } } - - success = true; } - else + + // we may be done, so continue only if we have not detached ourselves from the parser + if (null != _parser) { - // detach the parser from this reader now - if (!TryCloseInternal(false /*closeReader*/)) + bool moreResults; + if (!TryHasMoreResults(out moreResults)) { more = false; return false; } + if (moreResults) + { + _metaDataConsumed = false; + _browseModeInfoConsumed = false; - // In the case of not closing the reader, null out the metadata AFTER - // CloseInternal finishes - since CloseInternal may go to the wire - // and use the metadata. - if (!TrySetMetaData(null, false)) + switch (_altRowStatus) + { + case ALTROWSTATUS.AltRow: + int altRowId; + if (!_parser.TryGetAltRowId(_stateObj, out altRowId)) + { + more = false; + return false; + } + _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId); + if (altMetaDataSet != null) + { + _metaData = altMetaDataSet; + } + Debug.Assert((_metaData != null), "Can't match up altrowmetadata"); + break; + case ALTROWSTATUS.Done: + // restore the row-metaData + _metaData = _altMetaDataSetCollection.metaDataSet; + Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Null; + break; + default: + if (!TryConsumeMetaData()) + { + more = false; + return false; + } + if (_metaData == null) + { + more = false; + return true; + } + break; + } + + success = true; + } + else { - more = false; - return false; + // detach the parser from this reader now + if (!TryCloseInternal(false /*closeReader*/)) + { + more = false; + return false; + } + + // In the case of not closing the reader, null out the metadata AFTER + // CloseInternal finishes - since CloseInternal may go to the wire + // and use the metadata. + if (!TrySetMetaData(null, false)) + { + more = false; + return false; + } } } + else + { + // Clear state in case of Read calling CloseInternal() then user calls NextResult() + // and the case where the Read() above will do essentially the same thing. + ClearMetaData(); + } + + more = success; + return true; } - else + finally { - // Clear state in case of Read calling CloseInternal() then user calls NextResult() - // and the case where the Read() above will do essentially the same thing. - ClearMetaData(); + SqlStatistics.StopTimer(statistics); } - - more = success; - return true; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -3411,195 +3414,196 @@ override public bool Read() private bool TryReadInternal(bool setTimeout, out bool more) { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID); - RuntimeHelpers.PrepareConstrainedRegions(); - - try + using (TryEventScope.Create("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); + RuntimeHelpers.PrepareConstrainedRegions(); - if (null != _parser) + try { - if (setTimeout) - { - SetTimeout(_defaultTimeoutMilliseconds); - } - if (_sharedState._dataReady) + statistics = SqlStatistics.StartTimer(Statistics); + + if (null != _parser) { - if (!TryCleanPartialRead()) + if (setTimeout) { - more = false; - return false; + SetTimeout(_defaultTimeoutMilliseconds); + } + if (_sharedState._dataReady) + { + if (!TryCleanPartialRead()) + { + more = false; + return false; + } } - } - // clear out our buffers - SqlBuffer.Clear(_data); + // clear out our buffers + SqlBuffer.Clear(_data); - _sharedState._nextColumnHeaderToRead = 0; - _sharedState._nextColumnDataToRead = 0; - _sharedState._columnDataBytesRemaining = -1; // unknown - _lastColumnWithDataChunkRead = -1; + _sharedState._nextColumnHeaderToRead = 0; + _sharedState._nextColumnDataToRead = 0; + _sharedState._columnDataBytesRemaining = -1; // unknown + _lastColumnWithDataChunkRead = -1; - if (!_haltRead) - { - bool moreRows; - if (!TryHasMoreRows(out moreRows)) + if (!_haltRead) { - more = false; - return false; - } - if (moreRows) - { - // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) - while (_stateObj.HasPendingData) + bool moreRows; + if (!TryHasMoreRows(out moreRows)) + { + more = false; + return false; + } + if (moreRows) { - if (_altRowStatus != ALTROWSTATUS.AltRow) + // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) + while (_stateObj.HasPendingData) { - // if this is an ordinary row we let the run method consume the ROW token - if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + if (_altRowStatus != ALTROWSTATUS.AltRow) { - more = false; - return false; + // if this is an ordinary row we let the run method consume the ROW token + if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + { + more = false; + return false; + } + if (_sharedState._dataReady) + { + break; + } } - if (_sharedState._dataReady) + else { + // ALTROW token and AltrowId are already consumed ... + Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Done; + _sharedState._dataReady = true; break; } } - else + if (_sharedState._dataReady) { - // ALTROW token and AltrowId are already consumed ... - Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); - _altRowStatus = ALTROWSTATUS.Done; - _sharedState._dataReady = true; - break; + _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); + more = true; + return true; } } - if (_sharedState._dataReady) + + if (!_stateObj.HasPendingData) { - _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); - more = true; - return true; + if (!TryCloseInternal(false /*closeReader*/)) + { + more = false; + return false; + } } } - - if (!_stateObj.HasPendingData) + else { - if (!TryCloseInternal(false /*closeReader*/)) + // if we did not get a row and halt is true, clean off rows of result + // success must be false - or else we could have just read off row and set + // halt to true + bool moreRows; + if (!TryHasMoreRows(out moreRows)) { more = false; return false; } - } - } - else - { - // if we did not get a row and halt is true, clean off rows of result - // success must be false - or else we could have just read off row and set - // halt to true - bool moreRows; - if (!TryHasMoreRows(out moreRows)) - { - more = false; - return false; - } - while (moreRows) - { - // if we are in SingleRow mode, and we've read the first row, - // read the rest of the rows, if any - while (_stateObj.HasPendingData && !_sharedState._dataReady) + while (moreRows) { - if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + // if we are in SingleRow mode, and we've read the first row, + // read the rest of the rows, if any + while (_stateObj.HasPendingData && !_sharedState._dataReady) { - more = false; - return false; + if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + { + more = false; + return false; + } } - } - if (_sharedState._dataReady) - { - if (!TryCleanPartialRead()) + if (_sharedState._dataReady) + { + if (!TryCleanPartialRead()) + { + more = false; + return false; + } + } + + // clear out our buffers + SqlBuffer.Clear(_data); + + _sharedState._nextColumnHeaderToRead = 0; + + if (!TryHasMoreRows(out moreRows)) { more = false; return false; } } - // clear out our buffers - SqlBuffer.Clear(_data); - - _sharedState._nextColumnHeaderToRead = 0; + // reset haltRead + _haltRead = false; + } + } + else if (IsClosed) + { + throw ADP.DataReaderClosed(nameof(Read)); + } + more = false; - if (!TryHasMoreRows(out moreRows)) - { - more = false; - return false; - } +#if DEBUG + if ((!_sharedState._dataReady) && (_stateObj.HasPendingData)) + { + byte token; + if (!_stateObj.TryPeekByte(out token)) + { + return false; } - // reset haltRead - _haltRead = false; + Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); } - } - else if (IsClosed) - { - throw ADP.DataReaderClosed(nameof(Read)); - } - more = false; +#endif -#if DEBUG - if ((!_sharedState._dataReady) && (_stateObj.HasPendingData)) + return true; + } + catch (OutOfMemoryException e) { - byte token; - if (!_stateObj.TryPeekByte(out token)) + _isClosed = true; + SqlConnection con = _connection; + if (con != null) { - return false; + con.Abort(e); } - - Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); + throw; } -#endif - - return true; - } - catch (OutOfMemoryException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + catch (StackOverflowException e) { - con.Abort(e); + _isClosed = true; + SqlConnection con = _connection; + if (con != null) + { + con.Abort(e); + } + throw; } - throw; - } - catch (StackOverflowException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + /* Even though ThreadAbortException exists in .NET Core, + * since Abort is not supported, the common language runtime won't ever throw ThreadAbortException. + * just to keep a common codebase!*/ + catch (System.Threading.ThreadAbortException e) { - con.Abort(e); + _isClosed = true; + SqlConnection con = _connection; + if (con != null) + { + con.Abort(e); + } + throw; } - throw; - } - /* Even though ThreadAbortException exists in .NET Core, - * since Abort is not supported, the common language runtime won't ever throw ThreadAbortException. - * just to keep a common codebase!*/ - catch (System.Threading.ThreadAbortException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + finally { - con.Abort(e); + SqlStatistics.StopTimer(statistics); } - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -4292,8 +4296,7 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn /// public override Task NextResultAsync(CancellationToken cancellationToken) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.NextResultAsync | API | Object Id {0}", ObjectID); - try + using (TryEventScope.Create("SqlDataReader.NextResultAsync | API | Object Id {0}", ObjectID)) { TaskCompletionSource source = new TaskCompletionSource(); @@ -4331,10 +4334,6 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registration)); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } private static Task NextResultAsyncExecute(Task task, object state) @@ -4627,8 +4626,7 @@ out bytesRead /// public override Task ReadAsync(CancellationToken cancellationToken) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlDataReader.ReadAsync | API | Object Id {0}", ObjectID); - try + using (TryEventScope.Create("SqlDataReader.ReadAsync | API | Object Id {0}", ObjectID)) { if (IsClosed) { @@ -4759,10 +4757,6 @@ public override Task ReadAsync(CancellationToken cancellationToken) return InvokeAsyncCall(context); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } private static Task ReadAsyncExecute(Task task, object state) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs index aeb37cda27..408dba0645 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalTransaction.cs @@ -280,37 +280,34 @@ internal void CloseFromConnection() internal void Commit() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlInternalTransaction.Commit | API | Object Id {0}", ObjectID); - - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create("SqlInternalTransaction.Commit | API | Object Id {0}", ObjectID)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - // If this transaction has been completed, throw exception since it is unusable. - try - { - // COMMIT ignores transaction names, and so there is no reason to pass it anything. COMMIT - // simply commits the transaction from the most recent BEGIN, nested or otherwise. - _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, IsolationLevel.Unspecified, null, false); + // If this transaction has been completed, throw exception since it is unusable. + try { - ZombieParent(); + // COMMIT ignores transaction names, and so there is no reason to pass it anything. COMMIT + // simply commits the transaction from the most recent BEGIN, nested or otherwise. + _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, IsolationLevel.Unspecified, null, false); + { + ZombieParent(); + } } - } - catch (Exception e) - { - if (ADP.IsCatchableExceptionType(e)) + catch (Exception e) { - CheckTransactionLevelAndZombie(); - } + if (ADP.IsCatchableExceptionType(e)) + { + CheckTransactionLevelAndZombie(); + } - throw; - } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + throw; + } } } @@ -390,112 +387,106 @@ internal void InitParent(SqlTransaction transaction) internal void Rollback() { - var scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlInternalTransaction.Rollback | API | Object Id {0}", ObjectID); - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create("SqlInternalTransaction.Rollback | API | Object Id {0}", ObjectID)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - try - { - // If no arg is given to ROLLBACK it will rollback to the outermost begin - rolling back - // all nested transactions as well as the outermost transaction. - _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.IfRollback, null, IsolationLevel.Unspecified, null, false); + try + { + // If no arg is given to ROLLBACK it will rollback to the outermost begin - rolling back + // all nested transactions as well as the outermost transaction. + _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.IfRollback, null, IsolationLevel.Unspecified, null, false); - // Since Rollback will rollback to outermost begin, no need to check - // server transaction level. This transaction has been completed. - Zombie(); - } - catch (Exception e) - { - if (ADP.IsCatchableExceptionType(e)) + // Since Rollback will rollback to outermost begin, no need to check + // server transaction level. This transaction has been completed. + Zombie(); + } + catch (Exception e) { - CheckTransactionLevelAndZombie(); + if (ADP.IsCatchableExceptionType(e)) + { + CheckTransactionLevelAndZombie(); - if (!_disposing) + if (!_disposing) + { + throw; + } + } + else { throw; } } - else - { - throw; - } - } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } internal void Rollback(string transactionName) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlInternalTransaction.Rollback | API | Object Id {0}, Transaction Name {1}", ObjectID, transactionName); - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create("SqlInternalTransaction.Rollback | API | Object Id {0}, Transaction Name {1}", ObjectID, transactionName)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - // ROLLBACK takes either a save point name or a transaction name. It will rollback the - // transaction to either the save point with the save point name or begin with the - // transaction name. NOTE: for simplicity it is possible to give all save point names - // the same name, and ROLLBACK will simply rollback to the most recent save point with the - // save point name. - if (string.IsNullOrEmpty(transactionName)) - throw SQL.NullEmptyTransactionName(); + // ROLLBACK takes either a save point name or a transaction name. It will rollback the + // transaction to either the save point with the save point name or begin with the + // transaction name. NOTE: for simplicity it is possible to give all save point names + // the same name, and ROLLBACK will simply rollback to the most recent save point with the + // save point name. + if (string.IsNullOrEmpty(transactionName)) + throw SQL.NullEmptyTransactionName(); - try - { - _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Rollback, transactionName, IsolationLevel.Unspecified, null, false); - } - catch (Exception e) - { - if (ADP.IsCatchableExceptionType(e)) + try { - CheckTransactionLevelAndZombie(); + _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Rollback, transactionName, IsolationLevel.Unspecified, null, false); + } + catch (Exception e) + { + if (ADP.IsCatchableExceptionType(e)) + { + CheckTransactionLevelAndZombie(); + } + throw; } - throw; - } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } internal void Save(string savePointName) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlInternalTransaction.Save | API | Object Id {0}, Save Point Name {1}", ObjectID, savePointName); - _innerConnection.ValidateConnectionForExecute(null); + using (TryEventScope.Create("SqlInternalTransaction.Save | API | Object Id {0}, Save Point Name {1}", ObjectID, savePointName)) + { + _innerConnection.ValidateConnectionForExecute(null); - // ROLLBACK takes either a save point name or a transaction name. It will rollback the - // transaction to either the save point with the save point name or begin with the - // transaction name. So, to rollback a nested transaction you must have a save point. - // SAVE TRANSACTION MUST HAVE AN ARGUMENT!!! Save Transaction without an arg throws an - // exception from the server. So, an overload for SaveTransaction without an arg doesn't make - // sense to have. Save Transaction does not affect the transaction level. - if (string.IsNullOrEmpty(savePointName)) - throw SQL.NullEmptyTransactionName(); + // ROLLBACK takes either a save point name or a transaction name. It will rollback the + // transaction to either the save point with the save point name or begin with the + // transaction name. So, to rollback a nested transaction you must have a save point. + // SAVE TRANSACTION MUST HAVE AN ARGUMENT!!! Save Transaction without an arg throws an + // exception from the server. So, an overload for SaveTransaction without an arg doesn't make + // sense to have. Save Transaction does not affect the transaction level. + if (string.IsNullOrEmpty(savePointName)) + throw SQL.NullEmptyTransactionName(); - try - { - _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Save, savePointName, IsolationLevel.Unspecified, null, false); - } - catch (Exception e) - { - if (ADP.IsCatchableExceptionType(e)) + try { - CheckTransactionLevelAndZombie(); + _innerConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Save, savePointName, IsolationLevel.Unspecified, null, false); } + catch (Exception e) + { + if (ADP.IsCatchableExceptionType(e)) + { + CheckTransactionLevelAndZombie(); + } - throw; - } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + throw; + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs index d80a7c22a0..63e0e0d10e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs @@ -141,48 +141,49 @@ override public void Commit() ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlTransaction.Commit | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlTransaction.Commit | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); - try + using (TryEventScope.Create("SqlTransaction.Commit | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlTransaction.Commit | API | Correlation | Object Id {0}, Activity Id {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); + try + { + statistics = SqlStatistics.StartTimer(Statistics); - _isFromAPI = true; + _isFromAPI = true; - _internalTransaction.Commit(); - } - catch (SqlException ex) - { - // GitHub Issue #130 - When a timeout exception has occurred on transaction completion request, - // this connection may not be in reusable state. - // We will abort this connection and make sure it does not go back to the pool. - var innerException = ex.InnerException as Win32Exception; - if (innerException != null && innerException.NativeErrorCode == TdsEnums.SNI_WAIT_TIMEOUT) - { - _connection.Abort(ex); + _internalTransaction.Commit(); } - e = ex; - throw; - } - catch (Exception ex) - { - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - if (e != null) + catch (SqlException ex) { - s_diagnosticListener.WriteTransactionCommitError(operationId, _isolationLevel, _connection, InternalTransaction, e); + // GitHub Issue #130 - When a timeout exception has occurred on transaction completion request, + // this connection may not be in reusable state. + // We will abort this connection and make sure it does not go back to the pool. + var innerException = ex.InnerException as Win32Exception; + if (innerException != null && innerException.NativeErrorCode == TdsEnums.SNI_WAIT_TIMEOUT) + { + _connection.Abort(ex); + } + e = ex; + throw; } - else + catch (Exception ex) { - s_diagnosticListener.WriteTransactionCommitAfter(operationId, _isolationLevel, _connection, InternalTransaction); + e = ex; + throw; } + finally + { + SqlStatistics.StopTimer(statistics); + if (e != null) + { + s_diagnosticListener.WriteTransactionCommitError(operationId, _isolationLevel, _connection, InternalTransaction, e); + } + else + { + s_diagnosticListener.WriteTransactionCommitAfter(operationId, _isolationLevel, _connection, InternalTransaction); + } - _isFromAPI = false; + _isFromAPI = false; + } } } @@ -216,34 +217,35 @@ override public void Rollback() ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlTransaction.Rollback | API | Object Id {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlTransaction.Rollback | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); - try + using (TryEventScope.Create("SqlTransaction.Rollback | API | Object Id {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); + SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlTransaction.Rollback | API | Correlation | Object Id {0}, ActivityID {1}, Client Connection Id {2}", ObjectID, ActivityCorrelator.Current, Connection?.ClientConnectionId); + try + { + statistics = SqlStatistics.StartTimer(Statistics); - _isFromAPI = true; + _isFromAPI = true; - _internalTransaction.Rollback(); - } - catch (Exception ex) - { - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - if (e != null) + _internalTransaction.Rollback(); + } + catch (Exception ex) { - s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, InternalTransaction, e); + e = ex; + throw; } - else + finally { - s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, InternalTransaction); + SqlStatistics.StopTimer(statistics); + if (e != null) + { + s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, InternalTransaction, e); + } + else + { + s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, InternalTransaction); + } + _isFromAPI = false; } - _isFromAPI = false; } } } @@ -255,36 +257,36 @@ public void Rollback(string transactionName) Guid operationId = s_diagnosticListener.WriteTransactionRollbackBefore(_isolationLevel, _connection, InternalTransaction, transactionName); ZombieCheck(); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlTransaction.Rollback | API | Object Id {0}, Transaction Name='{1}', ActivityID {2}, Client Connection Id {3}", ObjectID, transactionName, ActivityCorrelator.Current, Connection?.ClientConnectionId); - SqlStatistics statistics = null; - try + using (TryEventScope.Create(SqlClientEventSource.Log.TryScopeEnterEvent("SqlTransaction.Rollback | API | Object Id {0}, Transaction Name='{1}', ActivityID {2}, Client Connection Id {3}", ObjectID, transactionName, ActivityCorrelator.Current, Connection?.ClientConnectionId))) { - statistics = SqlStatistics.StartTimer(Statistics); + SqlStatistics statistics = null; + try + { + statistics = SqlStatistics.StartTimer(Statistics); - _isFromAPI = true; + _isFromAPI = true; - _internalTransaction.Rollback(transactionName); - } - catch (Exception ex) - { - e = ex; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - if (e != null) - { - s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, InternalTransaction, e, transactionName); + _internalTransaction.Rollback(transactionName); } - else + catch (Exception ex) { - s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, InternalTransaction, transactionName); + e = ex; + throw; } + finally + { + SqlStatistics.StopTimer(statistics); + if (e != null) + { + s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, InternalTransaction, e, transactionName); + } + else + { + s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, InternalTransaction, transactionName); + } - _isFromAPI = false; - + _isFromAPI = false; + } } } @@ -294,17 +296,18 @@ public void Save(string savePointName) ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlTransaction.Save | API | Object Id {0} | Save Point Name '{1}'", ObjectID, savePointName); - try + using (TryEventScope.Create("SqlTransaction.Save | API | Object Id {0} | Save Point Name '{1}'", ObjectID, savePointName)) { - statistics = SqlStatistics.StartTimer(Statistics); + try + { + statistics = SqlStatistics.StartTimer(Statistics); - _internalTransaction.Save(savePointName); - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + _internalTransaction.Save(savePointName); + } + finally + { + SqlStatistics.StopTimer(statistics); + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 99d7d72f76..c84a8e3230 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -1301,8 +1301,7 @@ internal void ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool calle internal SqlError ProcessSNIError(TdsParserStateObject stateObj) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(""); - try + using (TryEventScope.Create("")) { #if DEBUG // There is an exception here for MARS as its possible that another thread has closed the connection just as we see an error @@ -1435,10 +1434,6 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj) return new SqlError(infoNumber: (int)details.nativeError, errorState: 0x00, TdsEnums.FATAL_ERROR_CLASS, _server, errorMessage, details.function, (int)details.lineNumber, win32ErrorCode: details.nativeError, details.exception); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void CheckResetConnection(TdsParserStateObject stateObj) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs index f89086384b..be3cd1404d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs @@ -60,8 +60,7 @@ internal void Deactivate() // When being deactivated, we check all the sessions in the // cache to make sure they're cleaned up and then we dispose of // sessions that are past what we want to keep around. - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0} deactivating cachedCount={1}", ObjectID, _cachedCount); - try + using (TryEventScope.Create(" {0} deactivating cachedCount={1}", ObjectID, _cachedCount)) { lock (_cache) { @@ -88,10 +87,6 @@ internal void Deactivate() //Debug.Assert (_cachedCount < MaxInactiveCount, "non-orphaned connection past initial allocation?"); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void Dispose() diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs index 195f8341fc..d52bfadf30 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs @@ -61,8 +61,7 @@ public SqlFileStream(string path, byte[] transactionContext, FileAccess access) /// public SqlFileStream(string path, byte[] transactionContext, FileAccess access, FileOptions options, long allocationSize) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent("SqlFileStream.ctor | API | Object Id {0} | Access {1} | Options {2} | Path '{3}'", ObjectID, (int)access, (int)options, path); - try + using (TryEventScope.Create(SqlClientEventSource.Log.TryScopeEnterEvent("SqlFileStream.ctor | API | Object Id {0} | Access {1} | Options {2} | Path '{3}'", ObjectID, (int)access, (int)options, path))) { //----------------------------------------------------------------- // precondition validation @@ -84,10 +83,6 @@ public SqlFileStream(string path, byte[] transactionContext, FileAccess access, Name = path; TransactionContext = transactionContext; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } #region destructor/dispose code diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs index 50383d27a7..28d2a9679f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbConnectionFactory.cs @@ -65,8 +65,7 @@ internal int ObjectID public void ClearAllPools() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(""); - try + using (TryEventScope.Create("")) { Dictionary connectionPoolGroups = _connectionPoolGroups; foreach (KeyValuePair entry in connectionPoolGroups) @@ -78,17 +77,13 @@ public void ClearAllPools() } } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } + } public void ClearPool(DbConnection connection) { ADP.CheckArgumentNull(connection, "connection"); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", GetObjectId(connection)); - try + using (TryEventScope.Create(" {0}", GetObjectId(connection))) { DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection); if (null != poolGroup) @@ -96,19 +91,13 @@ public void ClearPool(DbConnection connection) poolGroup.Clear(); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } public void ClearPool(DbConnectionPoolKey key) { Debug.Assert(key != null, "key cannot be null"); ADP.CheckArgumentNull(key.ConnectionString, "key.ConnectionString"); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" connectionString"); - - try + using (TryEventScope.Create(" connectionString")) { DbConnectionPoolGroup poolGroup; Dictionary connectionPoolGroups = _connectionPoolGroups; @@ -117,10 +106,6 @@ public void ClearPool(DbConnectionPoolKey key) poolGroup.Clear(); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index dfcbf50bdc..76bfed9986 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -1023,110 +1023,111 @@ public override void Prepare() } SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + using (TryEventScope.Create(" {0}", ObjectID)) + { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - statistics = SqlStatistics.StartTimer(Statistics); + statistics = SqlStatistics.StartTimer(Statistics); - // only prepare if batch with parameters - // MDAC BUG #'s 73776 & 72101 - if ( - this.IsPrepared && !this.IsDirty - || (this.CommandType == CommandType.StoredProcedure) - || ( - (System.Data.CommandType.Text == this.CommandType) - && (0 == GetParameterCount(_parameters)) - ) + // only prepare if batch with parameters + // MDAC BUG #'s 73776 & 72101 + if ( + this.IsPrepared && !this.IsDirty + || (this.CommandType == CommandType.StoredProcedure) + || ( + (System.Data.CommandType.Text == this.CommandType) + && (0 == GetParameterCount(_parameters)) + ) - ) - { - if (null != Statistics) + ) { - Statistics.SafeIncrement(ref Statistics._prepares); + if (null != Statistics) + { + Statistics.SafeIncrement(ref Statistics._prepares); + } + _hiddenPrepare = false; } - _hiddenPrepare = false; - } - else - { - // Validate the command outside of the try\catch to avoid putting the _stateObj on error - ValidateCommand(ADP.Prepare, false /*not async*/); - - bool processFinallyBlock = true; - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try + else { - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + // Validate the command outside of the try\catch to avoid putting the _stateObj on error + ValidateCommand(ADP.Prepare, false /*not async*/); - // NOTE: The state object isn't actually needed for this, but it is still here for back-compat (since it does a bunch of checks) - GetStateObject(); - - // Loop through parameters ensuring that we do not have unspecified types, sizes, scales, or precisions - if (null != _parameters) + bool processFinallyBlock = true; + TdsParser bestEffortCleanupTarget = null; + RuntimeHelpers.PrepareConstrainedRegions(); + try { - int count = _parameters.Count; - for (int i = 0; i < count; ++i) + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + + // NOTE: The state object isn't actually needed for this, but it is still here for back-compat (since it does a bunch of checks) + GetStateObject(); + + // Loop through parameters ensuring that we do not have unspecified types, sizes, scales, or precisions + if (null != _parameters) { - _parameters[i].Prepare(this); // MDAC 67063 + int count = _parameters.Count; + for (int i = 0; i < count; ++i) + { + _parameters[i].Prepare(this); // MDAC 67063 + } } - } #if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - InternalPrepare(); - } + InternalPrepare(); + } #if DEBUG - finally + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + processFinallyBlock = false; + _activeConnection.Abort(e); + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - processFinallyBlock = false; - _activeConnection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - processFinallyBlock = false; - _activeConnection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - processFinallyBlock = false; - _activeConnection.Abort(e); + catch (System.StackOverflowException e) + { + processFinallyBlock = false; + _activeConnection.Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + processFinallyBlock = false; + _activeConnection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (processFinallyBlock) + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; + } + catch (Exception e) + { + processFinallyBlock = ADP.IsCatchableExceptionType(e); + throw; + } + finally { - _hiddenPrepare = false; // The command is now officially prepared + if (processFinallyBlock) + { + _hiddenPrepare = false; // The command is now officially prepared - ReliablePutStateObject(); + ReliablePutStateObject(); + } } } - } - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + SqlStatistics.StopTimer(statistics); + } } private void InternalPrepare() @@ -1200,125 +1201,126 @@ internal void Unprepare() /// public override void Cancel() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - SqlStatistics statistics = null; - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - // If we are in reconnect phase simply cancel the waiting task - var reconnectCompletionSource = _reconnectionCompletionSource; - if (reconnectCompletionSource != null) + SqlStatistics statistics = null; + try { - if (reconnectCompletionSource.TrySetCanceled()) + statistics = SqlStatistics.StartTimer(Statistics); + + // If we are in reconnect phase simply cancel the waiting task + var reconnectCompletionSource = _reconnectionCompletionSource; + if (reconnectCompletionSource != null) { - return; + if (reconnectCompletionSource.TrySetCanceled()) + { + return; + } } - } - - // the pending data flag means that we are awaiting a response or are in the middle of processing a response - // if we have no pending data, then there is nothing to cancel - // if we have pending data, but it is not a result of this command, then we don't cancel either. Note that - // this model is implementable because we only allow one active command at any one time. This code - // will have to change we allow multiple outstanding batches - if (null == _activeConnection) - { - return; - } - SqlInternalConnectionTds connection = (_activeConnection.InnerConnection as SqlInternalConnectionTds); - if (null == connection) - { // Fail with out locking - return; - } - // The lock here is to protect against the command.cancel / connection.close race condition - // The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and - // the command will no longer be cancelable. It might be desirable to be able to cancel the close operation, but this is - // outside of the scope of Whidbey RTM. See (SqlConnection::Close) for other lock. - lock (connection) - { - if (connection != (_activeConnection.InnerConnection as SqlInternalConnectionTds)) - { // make sure the connection held on the active connection is what we have stored in our temp connection variable, if not between getting "connection" and taking the lock, the connection has been closed + // the pending data flag means that we are awaiting a response or are in the middle of processing a response + // if we have no pending data, then there is nothing to cancel + // if we have pending data, but it is not a result of this command, then we don't cancel either. Note that + // this model is implementable because we only allow one active command at any one time. This code + // will have to change we allow multiple outstanding batches + if (null == _activeConnection) + { return; } - - TdsParser parser = connection.Parser; - if (null == parser) - { + SqlInternalConnectionTds connection = (_activeConnection.InnerConnection as SqlInternalConnectionTds); + if (null == connection) + { // Fail with out locking return; } - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try + // The lock here is to protect against the command.cancel / connection.close race condition + // The SqlInternalConnectionTds is set to OpenBusy during close, once this happens the cast below will fail and + // the command will no longer be cancelable. It might be desirable to be able to cancel the close operation, but this is + // outside of the scope of Whidbey RTM. See (SqlConnection::Close) for other lock. + lock (connection) { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + if (connection != (_activeConnection.InnerConnection as SqlInternalConnectionTds)) + { // make sure the connection held on the active connection is what we have stored in our temp connection variable, if not between getting "connection" and taking the lock, the connection has been closed + return; + } + + TdsParser parser = connection.Parser; + if (null == parser) + { + return; + } + TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - - if (!_pendingCancel) - { // Do nothing if aleady pending. - // Before attempting actual cancel, set the _pendingCancel flag to false. - // This denotes to other thread before obtaining stateObject from the - // session pool that there is another thread wishing to cancel. - // The period in question is between entering the ExecuteAPI and obtaining - // a stateObject. - _pendingCancel = true; - - TdsParserStateObject stateObj = _stateObj; - if (null != stateObj) - { - stateObj.Cancel(ObjectID); - } - else - { - SqlDataReader reader = connection.FindLiveReader(this); - if (reader != null) + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); + + if (!_pendingCancel) + { // Do nothing if aleady pending. + // Before attempting actual cancel, set the _pendingCancel flag to false. + // This denotes to other thread before obtaining stateObject from the + // session pool that there is another thread wishing to cancel. + // The period in question is between entering the ExecuteAPI and obtaining + // a stateObject. + _pendingCancel = true; + + TdsParserStateObject stateObj = _stateObj; + if (null != stateObj) + { + stateObj.Cancel(ObjectID); + } + else { - reader.Cancel(ObjectID); + SqlDataReader reader = connection.FindLiveReader(this); + if (reader != null) + { + reader.Cancel(ObjectID); + } } } } - } #if DEBUG - finally + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + _activeConnection.Abort(e); + throw; + } + catch (System.StackOverflowException e) + { + _activeConnection.Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + _activeConnection.Abort(e); + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _activeConnection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - _activeConnection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _activeConnection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; } } - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -1361,34 +1363,35 @@ public override object ExecuteScalar() _pendingCancel = false; SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID{0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + using (TryEventScope.Create(" {0}", ObjectID)) + { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID{0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - bool success = false; - int? sqlExceptionNumber = null; + bool success = false; + int? sqlExceptionNumber = null; - try - { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - SqlDataReader ds; - ds = IsRetryEnabled ? - RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar) : - RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar); - object result = CompleteExecuteScalar(ds, false); - success = true; - return result; - } - catch (SqlException ex) - { - sqlExceptionNumber = ex.Number; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + try + { + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + SqlDataReader ds; + ds = IsRetryEnabled ? + RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar) : + RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar); + object result = CompleteExecuteScalar(ds, false); + success = true; + return result; + } + catch (SqlException ex) + { + sqlExceptionNumber = ex.Number; + throw; + } + finally + { + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + } } } @@ -1441,37 +1444,38 @@ public override int ExecuteNonQuery() SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - bool success = false; - int? sqlExceptionNumber = null; - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - bool usedCache; - if (IsRetryEnabled) + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + + bool success = false; + int? sqlExceptionNumber = null; + try { - InternalExecuteNonQueryWithRetry(ADP.ExecuteNonQuery, sendToPipe: false, CommandTimeout, out usedCache, asyncWrite: false, inRetry: false); + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + bool usedCache; + if (IsRetryEnabled) + { + InternalExecuteNonQueryWithRetry(ADP.ExecuteNonQuery, sendToPipe: false, CommandTimeout, out usedCache, asyncWrite: false, inRetry: false); + } + else + { + InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, sendToPipe: false, CommandTimeout, out usedCache); + } + success = true; + return _rowsAffected; } - else + catch (SqlException ex) { - InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, sendToPipe: false, CommandTimeout, out usedCache); + sqlExceptionNumber = ex.Number; + throw; + } + finally + { + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); } - success = true; - return _rowsAffected; - } - catch (SqlException ex) - { - sqlExceptionNumber = ex.Number; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); } } @@ -1486,17 +1490,19 @@ internal void ExecuteToPipe(SmiContext pipeContext) _pendingCancel = false; SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - try - { - statistics = SqlStatistics.StartTimer(Statistics); - bool usedCache; - InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout, out usedCache); - } - finally + + using (TryEventScope.Create(" {0}", ObjectID)) { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + try + { + statistics = SqlStatistics.StartTimer(Statistics); + bool usedCache; + InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout, out usedCache); + } + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -2072,35 +2078,36 @@ public XmlReader ExecuteXmlReader() SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - bool success = false; - int? sqlExceptionNumber = null; - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - // use the reader to consume metadata - SqlDataReader ds; - ds = IsRetryEnabled ? - RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader) : - RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader); - XmlReader result = CompleteXmlReader(ds); - success = true; - return result; - } - catch (SqlException ex) - { - sqlExceptionNumber = ex.Number; - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + bool success = false; + int? sqlExceptionNumber = null; + try + { + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + + // use the reader to consume metadata + SqlDataReader ds; + ds = IsRetryEnabled ? + RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader) : + RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader); + XmlReader result = CompleteXmlReader(ds); + success = true; + return result; + } + catch (SqlException ex) + { + sqlExceptionNumber = ex.Number; + throw; + } + finally + { + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true); + } } } @@ -2406,38 +2413,34 @@ private SqlDataReader ExecuteReaderWithRetry(CommandBehavior behavior, string me new public SqlDataReader ExecuteReader() { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - return IsRetryEnabled ? - ExecuteReaderWithRetry(CommandBehavior.Default, ADP.ExecuteReader) : - ExecuteReader(CommandBehavior.Default, ADP.ExecuteReader); - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + try + { + statistics = SqlStatistics.StartTimer(Statistics); + return IsRetryEnabled ? + ExecuteReaderWithRetry(CommandBehavior.Default, ADP.ExecuteReader) : + ExecuteReader(CommandBehavior.Default, ADP.ExecuteReader); + } + finally + { + SqlStatistics.StopTimer(statistics); + } } } /// new public SqlDataReader ExecuteReader(CommandBehavior behavior) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}, behavior={1}", ObjectID, (int)behavior); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, behavior={1}, ActivityID {2}", ObjectID, (int)behavior, ActivityCorrelator.Current); - - try + using (TryEventScope.Create(" {0}, behavior={1}", ObjectID, (int)behavior)) { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, behavior={1}, ActivityID {2}", ObjectID, (int)behavior, ActivityCorrelator.Current); + return IsRetryEnabled ? ExecuteReaderWithRetry(behavior, ADP.ExecuteReader) : ExecuteReader(behavior, ADP.ExecuteReader); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommandSet.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommandSet.cs index 6c5c3a306a..19004a02ee 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommandSet.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommandSet.cs @@ -294,9 +294,7 @@ internal void Dispose() internal int ExecuteNonQuery() { SqlConnection.ExecutePermission.Demand(); - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { if (Connection.IsContextConnection) { @@ -313,10 +311,6 @@ internal int ExecuteNonQuery() } return BatchCommand.ExecuteBatchRPCCommand(); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal SqlParameter GetParameter(int commandIndex, int parameterIndex) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs index cf77f152d6..a22071b5ca 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -1327,8 +1327,7 @@ public SqlTransaction BeginTransaction(string transactionName) [SuppressMessage("Microsoft.Reliability", "CA2004:RemoveCallsToGCKeepAlive")] override protected DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}, isolationLevel={1}", ObjectID, (int)isolationLevel); - try + using (TryEventScope.Create(" {0}, isolationLevel={1}", ObjectID, (int)isolationLevel)) { DbTransaction transaction = BeginTransaction(isolationLevel); @@ -1341,10 +1340,6 @@ override protected DbTransaction BeginDbTransaction(IsolationLevel isolationLeve return transaction; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// @@ -1484,98 +1479,97 @@ void CloseInnerConnection() /// override public void Close() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { - SqlStatistics statistics = null; + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + SqlStatistics statistics = null; + TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); - statistics = SqlStatistics.StartTimer(Statistics); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this); + statistics = SqlStatistics.StartTimer(Statistics); - Task reconnectTask = _currentReconnectionTask; - if (reconnectTask != null && !reconnectTask.IsCompleted) - { - CancellationTokenSource cts = _reconnectionCancellationSource; - if (cts != null) + Task reconnectTask = _currentReconnectionTask; + if (reconnectTask != null && !reconnectTask.IsCompleted) { - cts.Cancel(); + CancellationTokenSource cts = _reconnectionCancellationSource; + if (cts != null) + { + cts.Cancel(); + } + AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection + if (State != ConnectionState.Open) + {// if we cancelled before the connection was opened + OnStateChange(DbConnectionInternal.StateChangeClosed); + } } - AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection - if (State != ConnectionState.Open) - {// if we cancelled before the connection was opened - OnStateChange(DbConnectionInternal.StateChangeClosed); + CancelOpenAndWait(); + CloseInnerConnection(); + GC.SuppressFinalize(this); + + if (null != Statistics) + { + _statistics._closeTimestamp = ADP.TimerCurrent(); } } - CancelOpenAndWait(); - CloseInnerConnection(); - GC.SuppressFinalize(this); - - if (null != Statistics) +#if DEBUG + finally { - _statistics._closeTimestamp = ADP.TimerCurrent(); + tdsReliabilitySection.Stop(); } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) + { + Abort(e); + throw; + } + catch (System.StackOverflowException e) + { + Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + Abort(e); + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; } -#if DEBUG finally { - tdsReliabilitySection.Stop(); + SqlStatistics.StopTimer(statistics); + //dispose windows identity once connection is closed. + if (_lastIdentity != null) + { + _lastIdentity.Dispose(); + } } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; } finally { - SqlStatistics.StopTimer(statistics); - //dispose windows identity once connection is closed. - if (_lastIdentity != null) + SqlDebugContext sdc = _sdc; + _sdc = null; + if (sdc != null) { - _lastIdentity.Dispose(); + sdc.Dispose(); } } } - finally - { - SqlDebugContext sdc = _sdc; - _sdc = null; - - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - - if (sdc != null) - { - sdc.Dispose(); - } - } } /// @@ -1632,11 +1626,10 @@ private bool TryOpenWithRetry(TaskCompletionSource retry, /// public void Open(SqlConnectionOverrides overrides) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - try + using (TryEventScope.Create(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current)) { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + if (StatisticsEnabled) { if (null == _statistics) @@ -1665,10 +1658,6 @@ public void Open(SqlConnectionOverrides overrides) SqlStatistics.StopTimer(statistics); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void RegisterWaitingForReconnect(Task waitingTask) @@ -2686,11 +2675,10 @@ private void IssueSQLDebug(uint option, string machineName, uint pid, uint id, s /// public static void ChangePassword(string connectionString, string newPassword) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(""); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ActivityID {0}", ActivityCorrelator.Current); - - try + using (TryEventScope.Create("")) { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ActivityID {0}", ActivityCorrelator.Current); + if (ADP.IsEmpty(connectionString)) { throw SQL.ChangePasswordArgumentMissing("connectionString"); @@ -2725,20 +2713,15 @@ public static void ChangePassword(string connectionString, string newPassword) ChangePassword(connectionString, connectionOptions, null, newPassword, null); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// public static void ChangePassword(string connectionString, SqlCredential credential, SecureString newSecurePassword) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(""); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ActivityID {0}", ActivityCorrelator.Current); - - try + using (TryEventScope.Create("")) { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ActivityID {0}", ActivityCorrelator.Current); + if (ADP.IsEmpty(connectionString)) { throw SQL.ChangePasswordArgumentMissing("connectionString"); @@ -2795,10 +2778,6 @@ public static void ChangePassword(string connectionString, SqlCredential credent ChangePassword(connectionString, connectionOptions, credential, null, newSecurePassword); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } private static void ChangePassword(string connectionString, SqlConnectionString connectionOptions, SqlCredential credential, string newPassword, SecureString newSecurePassword) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs index ad0e88a1d2..ace3935643 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnectionHelper.cs @@ -200,19 +200,13 @@ internal void AddWeakReference(object value, int tag) /// override protected DbCommand CreateDbCommand() { - DbCommand command = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - try + using (TryEventScope.Create(" {0}", ObjectID)) { DbProviderFactory providerFactory = ConnectionFactory.ProviderFactory; - command = providerFactory.CreateCommand(); + DbCommand command = providerFactory.CreateCommand(); command.Connection = this; + return command; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } - return command; } private static System.Security.CodeAccessPermission CreateExecutePermission() diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 76a992becc..d129b30033 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -956,94 +956,94 @@ protected override void Dispose(bool disposing) override public void Close() { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - TdsParserStateObject stateObj = _stateObj; - - // Request that the current task is stopped - _cancelAsyncOnCloseTokenSource.Cancel(); - var currentTask = _currentTask; - if ((currentTask != null) && (!currentTask.IsCompleted)) + try { - try - { - // Wait for the task to complete - ((IAsyncResult)currentTask).AsyncWaitHandle.WaitOne(); + statistics = SqlStatistics.StartTimer(Statistics); + TdsParserStateObject stateObj = _stateObj; - // Ensure that we've finished reading any pending data - var networkPacketTaskSource = stateObj._networkPacketTaskSource; - if (networkPacketTaskSource != null) - { - ((IAsyncResult)networkPacketTaskSource.Task).AsyncWaitHandle.WaitOne(); - } - } - catch (Exception) + // Request that the current task is stopped + _cancelAsyncOnCloseTokenSource.Cancel(); + var currentTask = _currentTask; + if ((currentTask != null) && (!currentTask.IsCompleted)) { - // If we receive any exceptions while waiting, something has gone horribly wrong and we need to doom the connection and fast-fail the reader - _connection.InnerConnection.DoomThisConnection(); - _isClosed = true; - - if (stateObj != null) + try { - lock (stateObj) + // Wait for the task to complete + ((IAsyncResult)currentTask).AsyncWaitHandle.WaitOne(); + + // Ensure that we've finished reading any pending data + var networkPacketTaskSource = stateObj._networkPacketTaskSource; + if (networkPacketTaskSource != null) { - _stateObj = null; - _command = null; - _connection = null; + ((IAsyncResult)networkPacketTaskSource.Task).AsyncWaitHandle.WaitOne(); } } + catch (Exception) + { + // If we receive any exceptions while waiting, something has gone horribly wrong and we need to doom the connection and fast-fail the reader + _connection.InnerConnection.DoomThisConnection(); + _isClosed = true; - throw; - } - } + if (stateObj != null) + { + lock (stateObj) + { + _stateObj = null; + _command = null; + _connection = null; + } + } - // Close down any active Streams and TextReaders (this will also wait for them to finish their async tasks) - // NOTE: This must be done outside of the lock on the stateObj otherwise it will deadlock with CleanupAfterAsyncInvocation - CloseActiveSequentialStreamAndTextReader(); + throw; + } + } - if (stateObj != null) - { + // Close down any active Streams and TextReaders (this will also wait for them to finish their async tasks) + // NOTE: This must be done outside of the lock on the stateObj otherwise it will deadlock with CleanupAfterAsyncInvocation + CloseActiveSequentialStreamAndTextReader(); - // protect against concurrent close and cancel - lock (stateObj) + if (stateObj != null) { - if (_stateObj != null) - { // reader not closed while we waited for the lock + // protect against concurrent close and cancel + lock (stateObj) + { - // TryCloseInternal will clear out the snapshot when it is done - if (_snapshot != null) - { + if (_stateObj != null) + { // reader not closed while we waited for the lock + + // TryCloseInternal will clear out the snapshot when it is done + if (_snapshot != null) + { #if DEBUG - // The stack trace for replays will differ since they weren't captured during close - stateObj._permitReplayStackTraceToDiffer = true; + // The stack trace for replays will differ since they weren't captured during close + stateObj._permitReplayStackTraceToDiffer = true; #endif - PrepareForAsyncContinuation(); - } + PrepareForAsyncContinuation(); + } - SetTimeout(_defaultTimeoutMilliseconds); + SetTimeout(_defaultTimeoutMilliseconds); - // Close can be called from async methods in error cases, - // in which case we need to switch to syncOverAsync - stateObj._syncOverAsync = true; + // Close can be called from async methods in error cases, + // in which case we need to switch to syncOverAsync + stateObj._syncOverAsync = true; - if (!TryCloseInternal(true /*closeReader*/)) - { - throw SQL.SynchronousCallMayNotPend(); - } + if (!TryCloseInternal(true /*closeReader*/)) + { + throw SQL.SynchronousCallMayNotPend(); + } - // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread + // DO NOT USE stateObj after this point - it has been returned to the TdsParser's session pool and potentially handed out to another thread + } } } } - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + finally + { + SqlStatistics.StopTimer(statistics); + } } } @@ -1687,25 +1687,25 @@ override public int GetProviderSpecificValues(object[] values) override public DataTable GetSchemaTable() { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { - statistics = SqlStatistics.StartTimer(Statistics); - if (null == _metaData || null == _metaData.schemaTable) + try { - if (null != this.MetaData) + statistics = SqlStatistics.StartTimer(Statistics); + if (null == _metaData || null == _metaData.schemaTable) { - _metaData.schemaTable = BuildSchemaTable(); - Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); + if (null != this.MetaData) + { + _metaData.schemaTable = BuildSchemaTable(); + Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); + } } + return _metaData?.schemaTable; + } + finally + { + SqlStatistics.StopTimer(statistics); } - return _metaData?.schemaTable; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -3613,185 +3613,186 @@ override public bool NextResult() private bool TryNextResult(out bool more) { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - RuntimeHelpers.PrepareConstrainedRegions(); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); + try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - statistics = SqlStatistics.StartTimer(Statistics); + statistics = SqlStatistics.StartTimer(Statistics); - SetTimeout(_defaultTimeoutMilliseconds); - - if (IsClosed) - { - throw ADP.DataReaderClosed("NextResult"); - } - _fieldNameLookup = null; - - bool success = false; // WebData 100390 - _hasRows = false; // reset HasRows + SetTimeout(_defaultTimeoutMilliseconds); - // if we are specifically only processing a single result, then read all the results off the wire and detach - if (IsCommandBehavior(CommandBehavior.SingleResult)) - { - if (!TryCloseInternal(false /*closeReader*/)) + if (IsClosed) { - more = false; - return false; + throw ADP.DataReaderClosed("NextResult"); } + _fieldNameLookup = null; - // In the case of not closing the reader, null out the metadata AFTER - // CloseInternal finishes - since CloseInternal may go to the wire - // and use the metadata. - ClearMetaData(); - more = success; - return true; - } + bool success = false; // WebData 100390 + _hasRows = false; // reset HasRows - if (null != _parser) - { - // if there are more rows, then skip them, the user wants the next result - bool moreRows = true; - while (moreRows) + // if we are specifically only processing a single result, then read all the results off the wire and detach + if (IsCommandBehavior(CommandBehavior.SingleResult)) { - if (!TryReadInternal(false, out moreRows)) - { // don't reset set the timeout value + if (!TryCloseInternal(false /*closeReader*/)) + { more = false; return false; } - } - } - // we may be done, so continue only if we have not detached ourselves from the parser - if (null != _parser) - { - bool moreResults; - if (!TryHasMoreResults(out moreResults)) - { - more = false; - return false; + // In the case of not closing the reader, null out the metadata AFTER + // CloseInternal finishes - since CloseInternal may go to the wire + // and use the metadata. + ClearMetaData(); + more = success; + return true; } - if (moreResults) - { - _metaDataConsumed = false; - _browseModeInfoConsumed = false; - switch (_altRowStatus) + if (null != _parser) + { + // if there are more rows, then skip them, the user wants the next result + bool moreRows = true; + while (moreRows) { - case ALTROWSTATUS.AltRow: - int altRowId; - if (!_parser.TryGetAltRowId(_stateObj, out altRowId)) - { - more = false; - return false; - } - _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId); - if (altMetaDataSet != null) - { - _metaData = altMetaDataSet; - } - Debug.Assert((_metaData != null), "Can't match up altrowmetadata"); - break; - case ALTROWSTATUS.Done: - // restore the row-metaData - _metaData = _altMetaDataSetCollection.metaDataSet; - Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus"); - _altRowStatus = ALTROWSTATUS.Null; - break; - default: - if (!TryConsumeMetaData()) - { - more = false; - return false; - } - if (_metaData == null) - { - more = false; - return true; - } - break; + if (!TryReadInternal(false, out moreRows)) + { // don't reset set the timeout value + more = false; + return false; + } } - - success = true; } - else + + // we may be done, so continue only if we have not detached ourselves from the parser + if (null != _parser) { - // detach the parser from this reader now - if (!TryCloseInternal(false /*closeReader*/)) + bool moreResults; + if (!TryHasMoreResults(out moreResults)) { more = false; return false; } + if (moreResults) + { + _metaDataConsumed = false; + _browseModeInfoConsumed = false; - // In the case of not closing the reader, null out the metadata AFTER - // CloseInternal finishes - since CloseInternal may go to the wire - // and use the metadata. - if (!TrySetMetaData(null, false)) + switch (_altRowStatus) + { + case ALTROWSTATUS.AltRow: + int altRowId; + if (!_parser.TryGetAltRowId(_stateObj, out altRowId)) + { + more = false; + return false; + } + _SqlMetaDataSet altMetaDataSet = _altMetaDataSetCollection.GetAltMetaData(altRowId); + if (altMetaDataSet != null) + { + _metaData = altMetaDataSet; + } + Debug.Assert((_metaData != null), "Can't match up altrowmetadata"); + break; + case ALTROWSTATUS.Done: + // restore the row-metaData + _metaData = _altMetaDataSetCollection.metaDataSet; + Debug.Assert(_altRowStatus == ALTROWSTATUS.Done, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Null; + break; + default: + if (!TryConsumeMetaData()) + { + more = false; + return false; + } + if (_metaData == null) + { + more = false; + return true; + } + break; + } + + success = true; + } + else { - more = false; - return false; + // detach the parser from this reader now + if (!TryCloseInternal(false /*closeReader*/)) + { + more = false; + return false; + } + + // In the case of not closing the reader, null out the metadata AFTER + // CloseInternal finishes - since CloseInternal may go to the wire + // and use the metadata. + if (!TrySetMetaData(null, false)) + { + more = false; + return false; + } } } + else + { + // Clear state in case of Read calling CloseInternal() then user calls NextResult() + // MDAC 81986. Or, also the case where the Read() above will do essentially the same + // thing. + ClearMetaData(); + } + + more = success; + return true; } - else +#if DEBUG + finally { - // Clear state in case of Read calling CloseInternal() then user calls NextResult() - // MDAC 81986. Or, also the case where the Read() above will do essentially the same - // thing. - ClearMetaData(); + tdsReliabilitySection.Stop(); } - - more = success; - return true; +#endif //DEBUG } -#if DEBUG - finally + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + _isClosed = true; + if (null != _connection) + { + _connection.Abort(e); + } + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _isClosed = true; - if (null != _connection) + catch (System.StackOverflowException e) { - _connection.Abort(e); + _isClosed = true; + if (null != _connection) + { + _connection.Abort(e); + } + throw; } - throw; - } - catch (System.StackOverflowException e) - { - _isClosed = true; - if (null != _connection) + catch (System.Threading.ThreadAbortException e) { - _connection.Abort(e); + _isClosed = true; + if (null != _connection) + { + _connection.Abort(e); + } + throw; } - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _isClosed = true; - if (null != _connection) + finally { - _connection.Abort(e); + SqlStatistics.StopTimer(statistics); } - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -3819,209 +3820,210 @@ override public bool Read() private bool TryReadInternal(bool setTimeout, out bool more) { SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - RuntimeHelpers.PrepareConstrainedRegions(); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - RuntimeHelpers.PrepareConstrainedRegions(); + try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - statistics = SqlStatistics.StartTimer(Statistics); + statistics = SqlStatistics.StartTimer(Statistics); - if (null != _parser) - { - if (setTimeout) - { - SetTimeout(_defaultTimeoutMilliseconds); - } - if (_sharedState._dataReady) + if (null != _parser) { - if (!TryCleanPartialRead()) + if (setTimeout) { - more = false; - return false; + SetTimeout(_defaultTimeoutMilliseconds); + } + if (_sharedState._dataReady) + { + if (!TryCleanPartialRead()) + { + more = false; + return false; + } } - } - // clear out our buffers - SqlBuffer.Clear(_data); + // clear out our buffers + SqlBuffer.Clear(_data); - _sharedState._nextColumnHeaderToRead = 0; - _sharedState._nextColumnDataToRead = 0; - _sharedState._columnDataBytesRemaining = -1; // unknown - _lastColumnWithDataChunkRead = -1; + _sharedState._nextColumnHeaderToRead = 0; + _sharedState._nextColumnDataToRead = 0; + _sharedState._columnDataBytesRemaining = -1; // unknown + _lastColumnWithDataChunkRead = -1; - if (!_haltRead) - { - bool moreRows; - if (!TryHasMoreRows(out moreRows)) + if (!_haltRead) { - more = false; - return false; - } - if (moreRows) - { - // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) - while (_stateObj._pendingData) + bool moreRows; + if (!TryHasMoreRows(out moreRows)) + { + more = false; + return false; + } + if (moreRows) { - if (_altRowStatus != ALTROWSTATUS.AltRow) + // read the row from the backend (unless it's an altrow were the marker is already inside the altrow ...) + while (_stateObj._pendingData) { - // if this is an ordinary row we let the run method consume the ROW token - if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + if (_altRowStatus != ALTROWSTATUS.AltRow) { - more = false; - return false; + // if this is an ordinary row we let the run method consume the ROW token + if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + { + more = false; + return false; + } + if (_sharedState._dataReady) + { + break; + } } - if (_sharedState._dataReady) + else { + // ALTROW token and AltrowId are already consumed ... + Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); + _altRowStatus = ALTROWSTATUS.Done; + _sharedState._dataReady = true; break; } } - else + if (_sharedState._dataReady) { - // ALTROW token and AltrowId are already consumed ... - Debug.Assert(_altRowStatus == ALTROWSTATUS.AltRow, "invalid AltRowStatus"); - _altRowStatus = ALTROWSTATUS.Done; - _sharedState._dataReady = true; - break; + _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); + more = true; + return true; } } - if (_sharedState._dataReady) + + if (!_stateObj._pendingData) { - _haltRead = IsCommandBehavior(CommandBehavior.SingleRow); - more = true; - return true; + if (!TryCloseInternal(false /*closeReader*/)) + { + more = false; + return false; + } } } - - if (!_stateObj._pendingData) + else { - if (!TryCloseInternal(false /*closeReader*/)) + // if we did not get a row and halt is true, clean off rows of result + // success must be false - or else we could have just read off row and set + // halt to true + bool moreRows; + if (!TryHasMoreRows(out moreRows)) { more = false; return false; } - } - } - else - { - // if we did not get a row and halt is true, clean off rows of result - // success must be false - or else we could have just read off row and set - // halt to true - bool moreRows; - if (!TryHasMoreRows(out moreRows)) - { - more = false; - return false; - } - while (moreRows) - { - // if we are in SingleRow mode, and we've read the first row, - // read the rest of the rows, if any - while (_stateObj._pendingData && !_sharedState._dataReady) + while (moreRows) { - if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + // if we are in SingleRow mode, and we've read the first row, + // read the rest of the rows, if any + while (_stateObj._pendingData && !_sharedState._dataReady) { - more = false; - return false; + if (!_parser.TryRun(RunBehavior.ReturnImmediately, _command, this, null, _stateObj, out _sharedState._dataReady)) + { + more = false; + return false; + } } - } - if (_sharedState._dataReady) - { - if (!TryCleanPartialRead()) + if (_sharedState._dataReady) { - more = false; - return false; + if (!TryCleanPartialRead()) + { + more = false; + return false; + } } - } - // clear out our buffers - SqlBuffer.Clear(_data); + // clear out our buffers + SqlBuffer.Clear(_data); - _sharedState._nextColumnHeaderToRead = 0; + _sharedState._nextColumnHeaderToRead = 0; - if (!TryHasMoreRows(out moreRows)) - { - more = false; - return false; + if (!TryHasMoreRows(out moreRows)) + { + more = false; + return false; + } } - } - // reset haltRead - _haltRead = false; + // reset haltRead + _haltRead = false; + } } - } - else if (IsClosed) - { - throw ADP.DataReaderClosed("Read"); - } - more = false; + else if (IsClosed) + { + throw ADP.DataReaderClosed("Read"); + } + more = false; #if DEBUG - if ((!_sharedState._dataReady) && (_stateObj._pendingData)) - { - byte token; - if (!_stateObj.TryPeekByte(out token)) + if ((!_sharedState._dataReady) && (_stateObj._pendingData)) { - return false; - } + byte token; + if (!_stateObj.TryPeekByte(out token)) + { + return false; + } - Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); - } + Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}"); + } #endif - return true; - } + return true; + } #if DEBUG - finally + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + _isClosed = true; + SqlConnection con = _connection; + if (con != null) + { + con.Abort(e); + } + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + catch (System.StackOverflowException e) { - con.Abort(e); + _isClosed = true; + SqlConnection con = _connection; + if (con != null) + { + con.Abort(e); + } + throw; } - throw; - } - catch (System.StackOverflowException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + catch (System.Threading.ThreadAbortException e) { - con.Abort(e); + _isClosed = true; + SqlConnection con = _connection; + if (con != null) + { + con.Abort(e); + } + throw; } - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _isClosed = true; - SqlConnection con = _connection; - if (con != null) + finally { - con.Abort(e); + SqlStatistics.StopTimer(statistics); } - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } @@ -4808,10 +4810,9 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn /// public override Task NextResultAsync(CancellationToken cancellationToken) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - - try + using (TryEventScope.Create(" {0}", ObjectID)) { + TaskCompletionSource source = new TaskCompletionSource(); if (IsClosed) @@ -4870,10 +4871,6 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return InvokeRetryable(moreFunc, source, registration); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } // NOTE: This will return null if it completed sequentially @@ -5107,8 +5104,7 @@ private Task GetBytesAsyncReadDataStage(int i, byte[] buffer, int index, in /// public override Task ReadAsync(CancellationToken cancellationToken) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - try + using (TryEventScope.Create(" {0}", ObjectID)) { if (IsClosed) { @@ -5264,10 +5260,6 @@ public override Task ReadAsync(CancellationToken cancellationToken) return InvokeRetryable(moreFunc, source, registration); } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs index 50fd5e0746..1207285e5b 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReaderSmi.cs @@ -374,43 +374,43 @@ public override void Close() private void CloseInternal(bool closeConnection) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - bool processFinallyBlock = true; - try + using (TryEventScope.Create(" {0}", ObjectID)) { - if (!IsClosed) + bool processFinallyBlock = true; + try { - _hasRows = false; - - // Process the remaining events. This makes sure that environment changes are applied and any errors are picked up. - while (_eventStream.HasEvents) + if (!IsClosed) { - _eventStream.ProcessEvent(_readerEventSink); + _hasRows = false; + + // Process the remaining events. This makes sure that environment changes are applied and any errors are picked up. + while (_eventStream.HasEvents) + { + _eventStream.ProcessEvent(_readerEventSink); + _readerEventSink.ProcessMessagesAndThrow(true); + } + + // Close the request executor + _requestExecutor.Close(_readerEventSink); _readerEventSink.ProcessMessagesAndThrow(true); } - - // Close the request executor - _requestExecutor.Close(_readerEventSink); - _readerEventSink.ProcessMessagesAndThrow(true); } - } - catch (Exception e) - { - processFinallyBlock = ADP.IsCatchableExceptionType(e); - throw; - } - finally - { - if (processFinallyBlock) + catch (Exception e) { - _isOpen = false; - - if ((closeConnection) && (Connection != null)) + processFinallyBlock = ADP.IsCatchableExceptionType(e); + throw; + } + finally + { + if (processFinallyBlock) { - Connection.Close(); - } + _isOpen = false; - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + if ((closeConnection) && (Connection != null)) + { + Connection.Close(); + } + } } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs index 1017c8b789..e9116df172 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlTransaction.cs @@ -142,71 +142,72 @@ override public void Commit() ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); - - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try + using (TryEventScope.Create(" {0}", ObjectID)) { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - _isFromAPI = true; + _isFromAPI = true; - _internalTransaction.Commit(); - } + _internalTransaction.Commit(); + } #if DEBUG - finally + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + _connection.Abort(e); + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _connection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - _connection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _connection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - catch (SqlException e) - { - // GitHub Issue #130 - When a timeout exception has occurred on transaction completion request, - // this connection may not be in reusable state. - // We will abort this connection and make sure it does not go back to the pool. - var innerException = e.InnerException as Win32Exception; - if (innerException != null && innerException.NativeErrorCode == TdsEnums.SNI_WAIT_TIMEOUT) + catch (System.StackOverflowException e) { _connection.Abort(e); + throw; } - throw; - } - finally - { - _isFromAPI = false; + catch (System.Threading.ThreadAbortException e) + { + _connection.Abort(e); + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; + } + catch (SqlException e) + { + // GitHub Issue #130 - When a timeout exception has occurred on transaction completion request, + // this connection may not be in reusable state. + // We will abort this connection and make sure it does not go back to the pool. + var innerException = e.InnerException as Win32Exception; + if (innerException != null && innerException.NativeErrorCode == TdsEnums.SNI_WAIT_TIMEOUT) + { + _connection.Abort(e); + } + throw; + } + finally + { + _isFromAPI = false; - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); + SqlStatistics.StopTimer(statistics); + } } } @@ -277,9 +278,74 @@ override public void Rollback() ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + using (TryEventScope.Create(" {0}", ObjectID)) + { + SqlClientEventSource.Log.TryCorrelationTraceEvent(" ObjectID {0}, ActivityID {1}", ObjectID, ActivityCorrelator.Current); + + TdsParser bestEffortCleanupTarget = null; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif //DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); + + _isFromAPI = true; + + _internalTransaction.Rollback(); + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) + { + _connection.Abort(e); + throw; + } + catch (System.StackOverflowException e) + { + _connection.Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + _connection.Abort(e); + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; + } + finally + { + _isFromAPI = false; + + SqlStatistics.StopTimer(statistics); + } + } + } + } + + /// + public void Rollback(string transactionName) + { + SqlConnection.ExecutePermission.Demand(); // MDAC 81476 + + ZombieCheck(); + SqlStatistics statistics = null; + using (TryEventScope.Create(" {0} transactionName='{1}'", ObjectID, transactionName)) + { TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try @@ -292,14 +358,14 @@ override public void Rollback() { tdsReliabilitySection.Start(); #else - { + { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; - _internalTransaction.Rollback(); + _internalTransaction.Rollback(transactionName); } #if DEBUG finally @@ -329,129 +395,67 @@ override public void Rollback() _isFromAPI = false; SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } } - /// - public void Rollback(string transactionName) + /// + public void Save(string savePointName) { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0} transactionName='{1}'", ObjectID, transactionName); - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try + using (TryEventScope.Create(" {0} savePointName='{1}'", ObjectID, savePointName)) { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { - tdsReliabilitySection.Start(); +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); #else { #endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); - - _isFromAPI = true; + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); + statistics = SqlStatistics.StartTimer(Statistics); - _internalTransaction.Rollback(transactionName); - } + _internalTransaction.Save(savePointName); + } #if DEBUG - finally + finally + { + tdsReliabilitySection.Stop(); + } +#endif //DEBUG + } + catch (System.OutOfMemoryException e) { - tdsReliabilitySection.Stop(); + _connection.Abort(e); + throw; } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _connection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - _connection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _connection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - finally - { - _isFromAPI = false; - - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } - } - - /// - public void Save(string savePointName) - { - SqlConnection.ExecutePermission.Demand(); // MDAC 81476 - - ZombieCheck(); - - SqlStatistics statistics = null; - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0} savePointName='{1}'", ObjectID, savePointName); - - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try + catch (System.StackOverflowException e) { - tdsReliabilitySection.Start(); -#else + _connection.Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection); - statistics = SqlStatistics.StartTimer(Statistics); - - _internalTransaction.Save(savePointName); + _connection.Abort(e); + SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); + throw; } -#if DEBUG finally { - tdsReliabilitySection.Stop(); + SqlStatistics.StopTimer(statistics); } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - _connection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - _connection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - _connection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs index 16754b0b7c..5c1f64aa09 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs @@ -60,8 +60,7 @@ internal void Deactivate() // When being deactivated, we check all the sessions in the // cache to make sure they're cleaned up and then we dispose of // sessions that are past what we want to keep around. - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0} deactivating cachedCount={1}", ObjectID, _cachedCount); - try + using (TryEventScope.Create(" {0} deactivating cachedCount={1}", ObjectID, _cachedCount)) { lock (_cache) { @@ -88,10 +87,6 @@ internal void Deactivate() //Debug.Assert (_cachedCount < MaxInactiveCount, "non-orphaned connection past initial allocation?"); } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } // This is called from a ThreadAbort - ensure that it can be run from a CER Catch diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/sqlinternaltransaction.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/sqlinternaltransaction.cs index 7438dab671..c0d4b9c6f7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/sqlinternaltransaction.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/sqlinternaltransaction.cs @@ -295,16 +295,15 @@ internal void CloseFromConnection() internal void Commit() { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create(" {0}", ObjectID)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - try - { // If this transaction has been completed, throw exception since it is unusable. try { @@ -337,10 +336,6 @@ internal void Commit() throw; } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void Completed(TransactionState transactionState) @@ -424,17 +419,15 @@ internal void InitParent(SqlTransaction transaction) internal void Rollback() { - var scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}", ObjectID); - - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create(" {0}", ObjectID)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - try - { try { // If no arg is given to ROLLBACK it will rollback to the outermost begin - rolling back @@ -463,32 +456,28 @@ internal void Rollback() } } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void Rollback(string transactionName) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}, transactionName='{1}'", ObjectID, transactionName); - - if (_innerConnection.IsLockedForBulkCopy) + using (TryEventScope.Create(" {0}, transactionName='{1}'", ObjectID, transactionName)) { - throw SQL.ConnectionLockedForBcpEvent(); - } + if (_innerConnection.IsLockedForBulkCopy) + { + throw SQL.ConnectionLockedForBcpEvent(); + } - _innerConnection.ValidateConnectionForExecute(null); + _innerConnection.ValidateConnectionForExecute(null); - try - { // ROLLBACK takes either a save point name or a transaction name. It will rollback the // transaction to either the save point with the save point name or begin with the // transaction name. NOTE: for simplicity it is possible to give all save point names // the same name, and ROLLBACK will simply rollback to the most recent save point with the // save point name. if (ADP.IsEmpty(transactionName)) + { throw SQL.NullEmptyTransactionName(); + } try { @@ -512,19 +501,14 @@ internal void Rollback(string transactionName) throw; } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void Save(string savePointName) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0}, savePointName='{1}'", ObjectID, savePointName); - _innerConnection.ValidateConnectionForExecute(null); - - try + using (TryEventScope.Create(" {0}, savePointName='{1}'", ObjectID, savePointName)) { + _innerConnection.ValidateConnectionForExecute(null); + // ROLLBACK takes either a save point name or a transaction name. It will rollback the // transaction to either the save point with the save point name or begin with the // transaction name. So, to rollback a nested transaction you must have a save point. @@ -532,7 +516,9 @@ internal void Save(string savePointName) // exception from the server. So, an overload for SaveTransaction without an arg doesn't make // sense to have. Save Transaction does not affect the transaction level. if (ADP.IsEmpty(savePointName)) + { throw SQL.NullEmptyTransactionName(); + } try { @@ -549,10 +535,6 @@ internal void Save(string savePointName) throw; } } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } internal void Zombie() diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlTypes/SqlFileStream.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlTypes/SqlFileStream.cs index f459f32a25..40103edee5 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlTypes/SqlFileStream.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlTypes/SqlFileStream.cs @@ -65,17 +65,21 @@ public SqlFileStream Int64 allocationSize ) { - long scopeID = SqlClientEventSource.Log.TryScopeEnterEvent(" {0} access={1} options={2} path='{3}'", ObjectID, (int)access, (int)options, path); - try + using (TryEventScope.Create(SqlClientEventSource.Log.TryScopeEnterEvent(" {0} access={1} options={2} path='{3}'", ObjectID, (int)access, (int)options, path))) + { //----------------------------------------------------------------- // precondition validation if (transactionContext == null) + { throw ADP.ArgumentNull("transactionContext"); + } if (path == null) + { throw ADP.ArgumentNull("path"); + } //----------------------------------------------------------------- @@ -88,10 +92,6 @@ Int64 allocationSize this.Name = path; this.TransactionContext = transactionContext; } - finally - { - SqlClientEventSource.Log.TryScopeLeaveEvent(scopeID); - } } #region destructor/dispose code diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs index 0d7f4ad368..efa619ff5e 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientEventSource.cs @@ -1127,4 +1127,27 @@ public static TrySNIEventScope Create(string message, [System.Runtime.CompilerSe return new TrySNIEventScope(SqlClientEventSource.Log.TrySNIScopeEnterEvent(message, memberName)); } } + + internal readonly ref struct TryEventScope //: IDisposable + { + private readonly long _scopeId; + + public TryEventScope(long scopeID) => _scopeId = scopeID; + + public void Dispose() + { + if (_scopeId != 0) + { + SqlClientEventSource.Log.TryScopeLeaveEvent(_scopeId); + } + } + + public static TryEventScope Create(string message, T0 args0) => new TryEventScope(SqlClientEventSource.Log.TryScopeEnterEvent(message, args0)); + + public static TryEventScope Create(string message, T0 args0, T1 args1) => new TryEventScope(SqlClientEventSource.Log.TryScopeEnterEvent(message, args0, args1)); + + public static TryEventScope Create(string className, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "") => new TryEventScope(SqlClientEventSource.Log.TryScopeEnterEvent(className, memberName)); + + public static TryEventScope Create(long scopeId) => new TryEventScope(scopeId); + } }