public static void RemoveDriverInTransaction(Transaction transaction) { lock (driversInUse.SyncRoot) { driversInUse.Remove(transaction.GetHashCode()); } }
private TransactionException CreateVolatileEnlistment(System.Transactions.Transaction transactionToEnlist) { TransactionException exception = null; PersistenceContextEnlistment enlistment = null; int hashCode = transactionToEnlist.GetHashCode(); lock (System.ServiceModel.Activities.Dispatcher.PersistenceContext.Enlistments) { try { if (!System.ServiceModel.Activities.Dispatcher.PersistenceContext.Enlistments.TryGetValue(hashCode, out enlistment)) { enlistment = new PersistenceContextEnlistment(this.PersistenceContext, transactionToEnlist); transactionToEnlist.EnlistVolatile(enlistment, EnlistmentOptions.None); System.ServiceModel.Activities.Dispatcher.PersistenceContext.Enlistments.Add(hashCode, enlistment); return(exception); } enlistment.AddToEnlistment(this.PersistenceContext); return(exception); } catch (TransactionException exception2) { exception = exception2; this.PersistenceContext.ScheduleNextTransactionWaiter(); } } return(exception); }
public static Driver GetDriverInTransaction(Transaction transaction) { lock (driversInUse.SyncRoot) { return (Driver) driversInUse[transaction.GetHashCode()]; } }
private void AddToConnectionInfoTable(Transaction transaction, SharedConnectionInfo connectionInfo) { lock (this.tableSyncObject) { this.transactionConnectionTable.Add(transaction, connectionInfo); WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, string.Concat(new object[] { "AddToConnectionInfoTable ", transaction.GetHashCode(), " in table of count ", this.transactionConnectionTable.Count })); } }
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); } }
private void AddToConnectionInfoTable(Transaction transaction, SharedConnectionInfo connectionInfo) { lock (this.tableSyncObject) { this.transactionConnectionTable.Add(transaction, connectionInfo); WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "AddToConnectionInfoTable " + transaction.GetHashCode() + " in table of count " + this.transactionConnectionTable.Count); } }
private void RemoveConnectionFromInfoTable(Transaction transaction) { lock (this.tableSyncObject) { SharedConnectionInfo connectionInfo; WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode()); if (transactionConnectionTable.TryGetValue(transaction, out connectionInfo)) { connectionInfo.Dispose(); this.transactionConnectionTable.Remove(transaction); } else { WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode() + " not found in table of count " + this.transactionConnectionTable.Count); } } }
private void EnlistNonNull(SysTx.Transaction tx) { Debug.Assert(null != tx, "null transaction?"); SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, transaction {1}.", ObjectID, tx.GetHashCode()); bool hasDelegatedTransaction = false; if (Is2005OrNewer) { SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, attempting to delegate", ObjectID); // Promotable transactions are only supported on 2005 // servers or newer. SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx); try { // NOTE: System.Transactions claims to resolve all // potential race conditions between multiple delegate // requests of the same transaction to different // connections in their code, such that only one // attempt to delegate will succeed. // NOTE: PromotableSinglePhaseEnlist will eventually // make a round trip to the server; doing this inside // a lock is not the best choice. We presume that you // aren't trying to enlist concurrently on two threads // and leave it at that -- We don't claim any thread // safety with regard to multiple concurrent requests // to enlist the same connection in different // transactions, which is good, because we don't have // it anyway. // PromotableSinglePhaseEnlist may not actually promote // the transaction when it is already delegated (this is // the way they resolve the race condition when two // threads attempt to delegate the same Lightweight // Transaction) In that case, we can safely ignore // our delegated transaction, and proceed to enlist // in the promoted one. // NOTE: Global Transactions is an Azure SQL DB only // feature where the Transaction Manager (TM) is not // MS-DTC. Sys.Tx added APIs to support Non MS-DTC // promoter types/TM in .NET 4.6.1. Following directions // from .NETFX shiproom, to avoid a "hard-dependency" // (compile time) on Sys.Tx, we use reflection to invoke // the new APIs. Further, the _isGlobalTransaction flag // indicates that this is an Azure SQL DB Transaction // that could be promoted to a Global Transaction (it's // always false for on-prem Sql Server). The Promote() // call in SqlDelegatedTransaction makes sure that the // right Sys.Tx.dll is loaded and that Global Transactions // are actually allowed for this Azure SQL DB. if (_isGlobalTransaction) { if (SysTxForGlobalTransactions.EnlistPromotableSinglePhase == null) { // This could be a local Azure SQL DB transaction. hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); } else { hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID }); } } else { // This is an MS-DTC distributed transaction hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); } if (hasDelegatedTransaction) { this.DelegatedTransaction = delegatedTransaction; SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, delegated to transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId); } } catch (SqlException e) { // we do not want to eat the error if it is a fatal one if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { throw; } // if the parser is null or its state is not openloggedin, the connection is no longer good. SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds; if (tdsConnection != null) { TdsParser parser = tdsConnection.Parser; if (parser == null || parser.State != TdsParserState.OpenLoggedIn) { throw; } } ADP.TraceExceptionWithoutRethrow(e); // In this case, SqlDelegatedTransaction.Initialize // failed and we don't necessarily want to reject // things -- there may have been a legitimate reason // for the failure. } } if (!hasDelegatedTransaction) { SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, delegation not possible, enlisting.", ObjectID); byte[] cookie = null; if (_isGlobalTransaction) { if (SysTxForGlobalTransactions.GetPromotedToken == null) { throw SQL.UnsupportedSysTxForGlobalTransactions(); } cookie = (byte[])SysTxForGlobalTransactions.GetPromotedToken.Invoke(tx, null); } else { if (null == _whereAbouts) { byte[] dtcAddress = GetDTCAddress(); if (null == dtcAddress) { throw SQL.CannotGetDTCAddress(); } _whereAbouts = dtcAddress; } cookie = GetTransactionCookie(tx, _whereAbouts); } // send cookie to server to finish enlistment PropagateTransactionCookie(cookie); _isEnlistedInTransaction = true; SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnection.EnlistNonNull|ADV> {0}, enlisted with transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId); } EnlistedTransaction = tx; // Tell the base class about our enlistment // If we're on a 2005 or newer server, and we we delegate the // transaction successfully, we will have done a begin transaction, // which produces a transaction id that we should execute all requests // on. The TdsParser or SmiEventSink will store this information as // the current transaction. // // Likewise, propagating a transaction to a 2005 or newer server will // produce a transaction id that The TdsParser or SmiEventSink will // store as the current transaction. // // In either case, when we're working with a 2005 or newer server // we better have a current transaction by now. Debug.Assert(!Is2005OrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?"); }
private void EnlistNonNull(SysTx.Transaction tx) { Debug.Assert(null != tx, "null transaction?"); if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode()); } bool hasDelegatedTransaction = false; if (IsYukonOrNewer) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID); } // Promotable transactions are only supported on Yukon // servers or newer. SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx); try { // NOTE: System.Transactions claims to resolve all // potential race conditions between multiple delegate // requests of the same transaction to different // connections in their code, such that only one // attempt to delegate will succeed. // NOTE: PromotableSinglePhaseEnlist will eventually // make a round trip to the server; doing this inside // a lock is not the best choice. We presume that you // aren't trying to enlist concurrently on two threads // and leave it at that -- We don't claim any thread // safety with regard to multiple concurrent requests // to enlist the same connection in different // transactions, which is good, because we don't have // it anyway. // PromotableSinglePhaseEnlist may not actually promote // the transaction when it is already delegated (this is // the way they resolve the race condition when two // threads attempt to delegate the same Lightweight // Transaction) In that case, we can safely ignore // our delegated transaction, and proceed to enlist // in the promoted one. if (tx.EnlistPromotableSinglePhase(delegatedTransaction)) { hasDelegatedTransaction = true; this.DelegatedTransaction = delegatedTransaction; if (Bid.AdvancedOn) { long transactionId = SqlInternalTransaction.NullTransactionId; int transactionObjectID = 0; if (null != CurrentTransaction) { transactionId = CurrentTransaction.TransactionId; transactionObjectID = CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId); } } } catch (SqlException e) { // we do not want to eat the error if it is a fatal one if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) { throw; } // if the parser is null or its state is not openloggedin, the connection is no longer good. SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds; if (tdsConnection != null) { TdsParser parser = tdsConnection.Parser; if (parser == null || parser.State != TdsParserState.OpenLoggedIn) { throw; } } ADP.TraceExceptionWithoutRethrow(e); // In this case, SqlDelegatedTransaction.Initialize // failed and we don't necessarily want to reject // things -- there may have been a legitimate reason // for the failure. } } if (!hasDelegatedTransaction) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID); } byte[] cookie = null; if (null == _whereAbouts) { byte[] dtcAddress = GetDTCAddress(); if (null == dtcAddress) { throw SQL.CannotGetDTCAddress(); } _whereAbouts = dtcAddress; } cookie = GetTransactionCookie(tx, _whereAbouts); // send cookie to server to finish enlistment PropagateTransactionCookie(cookie); _isEnlistedInTransaction = true; if (Bid.AdvancedOn) { long transactionId = SqlInternalTransaction.NullTransactionId; int transactionObjectID = 0; if (null != CurrentTransaction) { transactionId = CurrentTransaction.TransactionId; transactionObjectID = CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, transactionObjectID, transactionId); } } EnlistedTransaction = tx; // Tell the base class about our enlistment // If we're on a Yukon or newer server, and we we delegate the // transaction successfully, we will have done a begin transaction, // which produces a transaction id that we should execute all requests // on. The TdsParser or SmiEventSink will store this information as // the current transaction. // // Likewise, propagating a transaction to a Yukon or newer server will // produce a transaction id that The TdsParser or SmiEventSink will // store as the current transaction. // // In either case, when we're working with a Yukon or newer server // we better have a current transaction by now. Debug.Assert(!IsYukonOrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?"); }
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; SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> {0}, contextTransactionId=0x{1}, contextTransaction={2}, currentSystemTransaction={3}.", 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. } SqlClientEventSource.Log.TryTraceEvent("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> {0}, using context transaction with transactionId=0x{1}", ObjectID, contextTransactionId); _currentTransaction = new SqlInternalTransaction(this, TransactionType.Context, null, contextTransactionId); ContextTransaction = contextTransaction; } else if (null == currentSystemTransaction) { _currentTransaction = null; // there really isn't a transaction. SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> {0}, no transaction.", ObjectID); } else { SqlClientEventSource.Log.TryAdvancedTraceEvent("<sc.SqlInternalConnectionSmi.AutomaticEnlistment|ADV> {0}, using current System.Transaction.", ObjectID); base.Enlist(currentSystemTransaction); } }
private void EnlistNonNull(Transaction tx) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, transaction %d#.\n", base.ObjectID, tx.GetHashCode()); } bool flag = false; if (this.IsYukonOrNewer) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, attempting to delegate\n", base.ObjectID); } SqlDelegatedTransaction promotableSinglePhaseNotification = new SqlDelegatedTransaction(this, tx); try { if (tx.EnlistPromotableSinglePhase(promotableSinglePhaseNotification)) { flag = true; this.DelegatedTransaction = promotableSinglePhaseNotification; if (Bid.AdvancedOn) { long transactionId = 0L; int objectID = 0; if (this.CurrentTransaction != null) { transactionId = this.CurrentTransaction.TransactionId; objectID = this.CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegated to transaction %d# with transactionId=0x%I64x\n", base.ObjectID, objectID, transactionId); } } } catch (SqlException exception) { if (exception.Class >= 20) { throw; } SqlInternalConnectionTds tds = this as SqlInternalConnectionTds; if (tds != null) { TdsParser parser = tds.Parser; if ((parser == null) || (parser.State != TdsParserState.OpenLoggedIn)) { throw; } } ADP.TraceExceptionWithoutRethrow(exception); } } if (!flag) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, delegation not possible, enlisting.\n", base.ObjectID); } byte[] transactionCookie = null; if (this._whereAbouts == null) { byte[] dTCAddress = this.GetDTCAddress(); if (dTCAddress == null) { throw SQL.CannotGetDTCAddress(); } this._whereAbouts = dTCAddress; } transactionCookie = GetTransactionCookie(tx, this._whereAbouts); this.PropagateTransactionCookie(transactionCookie); this._isEnlistedInTransaction = true; if (Bid.AdvancedOn) { long num2 = 0L; int num = 0; if (this.CurrentTransaction != null) { num2 = this.CurrentTransaction.TransactionId; num = this.CurrentTransaction.ObjectID; } Bid.Trace("<sc.SqlInternalConnection.EnlistNonNull|ADV> %d#, enlisted with transaction %d# with transactionId=0x%I64x\n", base.ObjectID, num, num2); } } base.EnlistedTransaction = tx; }
TransactionException CreateVolatileEnlistment(Transaction transactionToEnlist) { TransactionException result = null; PersistenceContextEnlistment enlistment = null; int key = transactionToEnlist.GetHashCode(); lock (PersistenceContext.Enlistments) { try { if (!PersistenceContext.Enlistments.TryGetValue(key, out enlistment)) { enlistment = new PersistenceContextEnlistment(this.PersistenceContext, transactionToEnlist); transactionToEnlist.EnlistVolatile(enlistment, EnlistmentOptions.None); // We don't save of the Enlistment object returned from EnlistVolatile. We don't need // it here. When our PersistenceContextEnlistment object gets notified on Prepare, // Commit, Rollback, or InDoubt, it is provided with the Enlistment object. PersistenceContext.Enlistments.Add(key, enlistment); } else { enlistment.AddToEnlistment(this.PersistenceContext); } } catch (TransactionException txException) { result = txException; // We own the lock but failed to create enlistment. Manually wake up the next waiter. // We only handle TransactionException, in case of other exception that failed to create enlistment, // It will fallback to Timeout. This is safe to avoid multiple waiters owning same lock. this.PersistenceContext.ScheduleNextTransactionWaiter(); } } return result; }