internal void AutomaticEnlistment() { SysTx.Transaction currentSystemTransaction = ADP.GetCurrentTransaction(); // NOTE: Must be first to ensure _smiContext.ContextTransaction is set! SysTx.Transaction contextTransaction = _smiContext.ContextTransaction; // returns the transaction that was handed to SysTx that wraps the ContextTransactionId. long contextTransactionId = _smiContext.ContextTransactionId; if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, contextTransactionId=0x%I64x, contextTransaction=%d#, currentSystemTransaction=%d#.\n", base.ObjectID, contextTransactionId, (null != contextTransaction) ? contextTransaction.GetHashCode() : 0, (null != currentSystemTransaction) ? currentSystemTransaction.GetHashCode() : 0); } if (SqlInternalTransaction.NullTransactionId != contextTransactionId) { if (null != currentSystemTransaction && contextTransaction != currentSystemTransaction) { throw SQL.NestedTransactionScopesNotSupported(); // can't use TransactionScope(RequiresNew) inside a Sql Transaction. } if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using context transaction with transactionId=0x%I64x\n", base.ObjectID, contextTransactionId); } _currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId); ContextTransaction = contextTransaction; } else if (null == currentSystemTransaction) { _currentTransaction = null; // there really isn't a transaction. if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, no transaction.\n", base.ObjectID); } } else { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> %d#, using current System.Transaction.\n", base.ObjectID); } base.Enlist(currentSystemTransaction); } }
internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, IsolationLevel iso, SqlInternalTransaction internalTransaction) { _isolationLevel = iso; _connection = con; if (internalTransaction == null) { _internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this); } else { Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!"); _internalTransaction = internalTransaction; _internalTransaction.InitParent(this); } }
//////////////////////////////////////////////////////////////////////////////////////// // INTERNAL METHODS //////////////////////////////////////////////////////////////////////////////////////// internal void Zombie() { // SQLBUDT #402544 For Yukon, we have to defer "zombification" until // we get past the users' next rollback, else we'll // throw an exception there that is a breaking change. // Of course, if the connection is aready closed, // then we're free to zombify... SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection); if (null != internalConnection && internalConnection.IsYukonOrNewer && !_isFromAPI) { SqlClientEventSource.Log.AdvanceTrace("<sc.SqlTransaction.Zombie|ADV> {0}# yukon deferred zombie", ObjectID); } else { _internalTransaction = null; // pre-yukon zombification } }
//////////////////////////////////////////////////////////////////////////////////////// // INTERNAL METHODS //////////////////////////////////////////////////////////////////////////////////////// internal void Zombie() { // For 2005, we have to defer "zombification" until // we get past the users' next rollback, else we'll // throw an exception there that is a breaking change. // Of course, if the connection is already closed, // then we're free to zombify... SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection); if (null != internalConnection && !_isFromAPI) { SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlTransaction.Zombie | ADV | Object Id {0} 2005 deferred zombie", ObjectID); } else { _internalTransaction = null; // pre-2005 zombification } }
private void TransactionEnded(long transactionId, TransactionState transactionState) { // When we get notification of a completed transaction // we null out the current transaction. if (null != _currentTransaction) { #if DEBUG // Check null for case where Begin and Rollback obtained in the same message. if (0 != _currentTransaction.TransactionId) { Debug.Assert(_currentTransaction.TransactionId == transactionId, "transaction id's are not equal!"); } #endif _currentTransaction.Completed(transactionState); _currentTransaction = null; } }
public void Initialize() { // if we get here, then we know for certain that we're the delegated // transaction. SqlInternalConnection connection = _connection; SqlConnection usersConnection = connection.Connection; RuntimeHelpers.PrepareConstrainedRegions(); try { if (connection.IsEnlistedInTransaction) { // defect first connection.EnlistNull(); } _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null); connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true); // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw. if (null == connection.CurrentTransaction) { connection.DoomThisConnection(); throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure); } _active = true; } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } }
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { Exception e = null; Guid operationId = s_diagnosticListener.WriteTransactionRollbackBefore(_isolationLevel, _connection, null); if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; try { statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Rollback(); } catch (Exception ex) { e = ex; throw; } finally { if (e != null) { s_diagnosticListener.WriteTransactionRollbackError(operationId, _isolationLevel, _connection, null, e); } else { s_diagnosticListener.WriteTransactionRollbackAfter(operationId, _isolationLevel, _connection, null); } _isFromAPI = false; SqlStatistics.StopTimer(statistics); } } }
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { using (DiagnosticTransactionScope diagnosticScope = s_diagnosticListener.CreateTransactionRollbackScope(_isolationLevel, _connection, InternalTransaction, null)) { if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlTransaction.Rollback | ADV | Object Id {0}, partial zombie no rollback required", ObjectID); _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; using (TryEventScope.Create("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 { statistics = SqlStatistics.StartTimer(Statistics); _isFromAPI = true; _internalTransaction.Rollback(); } catch (Exception ex) { diagnosticScope.SetException(ex); throw; } finally { SqlStatistics.StopTimer(statistics); _isFromAPI = false; } } } } }
private void TransactionStarted(long transactionId, bool isDistributed) { // When we get notification from the server of a new // transaction, we move any pending transaction over to // the current transaction, then we store the token in it. // if there isn't a pending transaction, then it's either // a TSQL transaction or a distributed transaction. Debug.Assert(null == _currentTransaction, "non-null current transaction with an env change"); _currentTransaction = _pendingTransaction; _pendingTransaction = null; if (null != _currentTransaction) { _currentTransaction.TransactionId = transactionId; // this is defined as a ULongLong in the server and in the TDS Spec. } else { TransactionType transactionType = (isDistributed) ? TransactionType.Distributed : TransactionType.LocalFromTSQL; _currentTransaction = new SqlInternalTransaction(this, transactionType, null, transactionId); } _currentTransaction.Activate(); // SQLBUDT #376531 -- ensure this is activated to prevent asserts later. }
public static DiagnosticTransactionScope CreateTransactionRollbackScope(SqlDiagnosticListener diagnostics, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, string transactionName, [CallerMemberName] string operationName = "") { Guid operationId = diagnostics.WriteTransactionRollbackBefore(isolationLevel, connection, transaction, transactionName, operationName); return(new DiagnosticTransactionScope(diagnostics, TransactionCommit, operationId, operationName, isolationLevel, connection, transaction, transactionName)); }
public static DiagnosticTransactionScope CreateTransactionRollbackScope(this SqlDiagnosticListener @this, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, string transactionName, [CallerMemberName] string operationName = "") { return(DiagnosticTransactionScope.CreateTransactionRollbackScope(@this, isolationLevel, connection, transaction, transactionName, operationName)); }
public static void WriteTransactionCommitAfter(this SqlDiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, [CallerMemberName] string operation = "") { if (@this.IsEnabled(SqlAfterCommitTransaction)) { @this.Write( SqlAfterCommitTransaction, new { OperationId = operationId, Operation = operation, IsolationLevel = isolationLevel, Connection = connection, transaction?.TransactionId, Timestamp = Stopwatch.GetTimestamp() }); } }
override internal void DelegatedTransactionEnded() { base.DelegatedTransactionEnded(); SqlClientEventSource.Log.AdvanceTrace("<sc.SqlInternalConnectionSmi.DelegatedTransactionEnded|ADV> {0}#, cleaning up after Delegated Transaction Completion", ObjectID); _currentTransaction = null; // clean up our current transaction too }
public void Initialize() { // if we get here, then we know for certain that we're the delegated // transaction. SqlInternalConnection connection = _connection; SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, delegating transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG if (connection.IsEnlistedInTransaction) { // defect first Bid.Trace("<sc.SqlDelegatedTransaction.Initialize|RES|CPOOL> %d#, Connection %d#, was enlisted, now defecting.\n", ObjectID, connection.ObjectID); connection.EnlistNull(); } _internalTransaction = new SqlInternalTransaction(connection, TransactionType.Delegated, null); connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Begin, null, _isolationLevel, _internalTransaction, true); // Handle case where ExecuteTran didn't produce a new transaction, but also didn't throw. if (null == connection.CurrentTransaction) { connection.DoomThisConnection(); throw ADP.InternalError(ADP.InternalErrorCode.UnknownTransactionFailure); } _active = true; } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException e) { usersConnection.Abort(e); throw; } catch (System.StackOverflowException e) { usersConnection.Abort(e); throw; } catch (System.Threading.ThreadAbortException e) { usersConnection.Abort(e); throw; } }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue SqlClientEventSource.Log.AdvanceTrace("<sc.SqlTransaction.Rollback|ADV> {0}# partial zombie no rollback required", ObjectID); _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; long scopeID = SqlClientEventSource.Log.ScopeEnterEvent("<sc.SqlTransaction.Rollback|API> {0}#", ObjectID); SqlClientEventSource.Log.CorrelationTraceEvent("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID {0}#, ActivityID {1}", ObjectID, ActivityCorrelator.Current.ToString()); 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); SqlClientEventSource.Log.ScopeLeaveEvent(scopeID); } } }
abstract internal void DisconnectTransaction(SqlInternalTransaction internalTransaction);
abstract internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest);
public static Guid WriteTransactionRollbackBefore(this SqlDiagnosticListener @this, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, string transactionName = null, [CallerMemberName] string operation = "") { if (@this.IsEnabled(SqlBeforeRollbackTransaction)) { Guid operationId = Guid.NewGuid(); @this.Write( SqlBeforeRollbackTransaction, new { OperationId = operationId, Operation = operation, IsolationLevel = isolationLevel, Connection = connection, transaction?.TransactionId, TransactionName = transactionName, Timestamp = Stopwatch.GetTimestamp() }); return(operationId); } else { return(Guid.Empty); } }
public static void WriteTransactionRollbackError(this SqlDiagnosticListener @this, Guid operationId, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, Exception ex, string transactionName = null, [CallerMemberName] string operation = "") { if (@this.IsEnabled(SqlErrorRollbackTransaction)) { @this.Write( SqlErrorRollbackTransaction, new { OperationId = operationId, Operation = operation, IsolationLevel = isolationLevel, Connection = connection, transaction?.TransactionId, TransactionName = transactionName, Exception = ex, Timestamp = Stopwatch.GetTimestamp() }); } }
public DiagnosticTransactionScope(SqlDiagnosticListener diagnostics, int operation, Guid operationId, string operationName, IsolationLevel isolationLevel, SqlConnection connection, SqlInternalTransaction transaction, string transactionName) { _diagnostics = diagnostics; _operation = operation; _operationId = operationId; _operationName = operationName; _isolationLevel = isolationLevel; _connection = connection; _transaction = transaction; _transactionName = transactionName; _exception = null; }
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' /> override public void Rollback() { if (IsYukonPartialZombie) { // Put something in the trace in case a customer has an issue if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", ObjectID); } _internalTransaction = null; // yukon zombification } else { ZombieCheck(); SqlStatistics statistics = null; IntPtr hscp; Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d#", ObjectID); Bid.CorrelationTrace("<sc.SqlTransaction.Rollback|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID); 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); Bid.ScopeLeave(ref hscp); } } }
override internal void ExecuteTransaction( TransactionRequest transactionRequest, string transactionName, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionSmi.ExecuteTransaction|ADV> %d#, transactionRequest=%ls, transactionName='%ls', isolationLevel=%ls, internalTransaction=#%d transactionId=0x%I64x.\n", base.ObjectID, transactionRequest.ToString(), (null != transactionName) ? transactionName : "null", iso.ToString(), (null != internalTransaction) ? internalTransaction.ObjectID : 0, (null != internalTransaction) ? internalTransaction.TransactionId : SqlInternalTransaction.NullTransactionId ); } switch (transactionRequest) { case TransactionRequest.Begin: try { _pendingTransaction = internalTransaction; // store this for the time being. _smiConnection.BeginTransaction(transactionName, iso, _smiEventSink); } finally { _pendingTransaction = null; } Debug.Assert(_smiEventSink.HasMessages || null != _currentTransaction, "begin transaction without TransactionStarted event?"); break; case TransactionRequest.Commit: Debug.Assert(null != _currentTransaction, "commit transaction without TransactionStarted event?"); _smiConnection.CommitTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Promote: Debug.Assert(null != _currentTransaction, "promote transaction without TransactionStarted event?"); PromotedDTCToken = _smiConnection.PromoteTransaction(_currentTransaction.TransactionId, _smiEventSink); break; case TransactionRequest.Rollback: case TransactionRequest.IfRollback: Debug.Assert(null != _currentTransaction, "rollback/ifrollback transaction without TransactionStarted event?"); _smiConnection.RollbackTransaction(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; case TransactionRequest.Save: Debug.Assert(null != _currentTransaction, "save transaction without TransactionStarted event?"); _smiConnection.CreateTransactionSavePoint(_currentTransaction.TransactionId, transactionName, _smiEventSink); break; default: Debug.Assert(false, "unhandled case for TransactionRequest"); break; } _smiEventSink.ProcessMessagesAndThrow(); }