internal SqlDelegatedTransaction(SqlInternalConnection connection, System.Transactions.Transaction tx) { this._connection = connection; this._atomicTransaction = tx; this._active = false; System.Transactions.IsolationLevel isolationLevel = tx.IsolationLevel; switch (isolationLevel) { case System.Transactions.IsolationLevel.Serializable: this._isolationLevel = System.Data.IsolationLevel.Serializable; return; case System.Transactions.IsolationLevel.RepeatableRead: this._isolationLevel = System.Data.IsolationLevel.RepeatableRead; return; case System.Transactions.IsolationLevel.ReadCommitted: this._isolationLevel = System.Data.IsolationLevel.ReadCommitted; return; case System.Transactions.IsolationLevel.ReadUncommitted: this._isolationLevel = System.Data.IsolationLevel.ReadUncommitted; return; case System.Transactions.IsolationLevel.Snapshot: this._isolationLevel = System.Data.IsolationLevel.Snapshot; return; } throw SQL.UnknownSysTxIsolationLevel(isolationLevel); }
public void Rollback(string transactionName) { SqlConnection.ExecutePermission.Demand(); // MDAC 81476 ZombieCheck(); SqlStatistics statistics = null; IntPtr hscp; Bid.ScopeEnter(out hscp, "<sc.SqlTransaction.Rollback|API> %d# transactionName='%ls'", ObjectID, transactionName); 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(transactionName); } #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); } }
public byte[] Promote() { Exception exception; SqlInternalConnection validConnection = this.GetValidConnection(); byte[] promotedDTCToken = null; SqlConnection connection = validConnection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Promote|RES|CPOOL> %d#, Connection %d#, promoting transaction.\n", this.ObjectID, validConnection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { lock (validConnection) { try { this.ValidateActiveOnConnection(validConnection); validConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Promote, null, System.Data.IsolationLevel.Unspecified, this._internalTransaction, true); promotedDTCToken = this._connection.PromotedDTCToken; exception = null; } catch (SqlException exception3) { exception = exception3; ADP.TraceExceptionWithoutRethrow(exception3); validConnection.DoomThisConnection(); } catch (InvalidOperationException exception2) { exception = exception2; ADP.TraceExceptionWithoutRethrow(exception2); validConnection.DoomThisConnection(); } } } catch (OutOfMemoryException exception6) { connection.Abort(exception6); throw; } catch (StackOverflowException exception5) { connection.Abort(exception5); throw; } catch (ThreadAbortException exception4) { connection.Abort(exception4); throw; } if (exception != null) { throw SQL.PromotionFailed(exception); } return(promotedDTCToken); }
private SqlInternalConnection GetValidConnection() { SqlInternalConnection connection = this._connection; if (connection == null) { throw ADP.ObjectDisposed(this); } return(connection); }
internal SqlInternalConnection GetOpenConnection(string method) { DbConnectionInternal innerConnection = this.InnerConnection; SqlInternalConnection connection = innerConnection as SqlInternalConnection; if (connection == null) { throw ADP.OpenConnectionRequired(method, innerConnection.State); } return connection; }
internal void Zombie() { this.ZombieParent(); SqlInternalConnection connection = this._innerConnection; this._innerConnection = null; if (connection != null) { connection.DisconnectTransaction(this); } }
// Check for connection validity private SqlInternalConnection GetValidConnection() { SqlInternalConnection connection = _connection; if (null == connection && Transaction.TransactionInformation.Status != TransactionStatus.Aborted) { throw ADP.ObjectDisposed(this); } return(connection); }
public override void Close() { IntPtr ptr; Bid.ScopeEnter(out ptr, "<sc.SqlConnection.Close|API> %d#", this.ObjectID); try { SqlStatistics statistics = null; SNIHandle target = null; RuntimeHelpers.PrepareConstrainedRegions(); try { target = SqlInternalConnection.GetBestEffortCleanupTarget(this); statistics = SqlStatistics.StartTimer(this.Statistics); lock (this.InnerConnection) { this.InnerConnection.CloseConnection(this, this.ConnectionFactory); } if (this.Statistics != null) { ADP.TimerCurrent(out this._statistics._closeTimestamp); } } catch (OutOfMemoryException exception3) { this.Abort(exception3); throw; } catch (StackOverflowException exception2) { this.Abort(exception2); throw; } catch (ThreadAbortException exception) { this.Abort(exception); SqlInternalConnection.BestEffortCleanup(target); throw; } finally { SqlStatistics.StopTimer(statistics); } } finally { SqlDebugContext context = this._sdc; this._sdc = null; Bid.ScopeLeave(ref ptr); if (context != null) { context.Dispose(); } } }
static public void DeriveParameters(SqlCommand command) // MDAC 65927\ { SqlConnection.ExecutePermission.Demand(); if (null == command) { throw ADP.ArgumentNull("command"); } TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(command.Connection); command.DeriveParameters(); } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif } catch (System.OutOfMemoryException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } throw; } catch (System.StackOverflowException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } throw; } catch (System.Threading.ThreadAbortException e) { if (null != command && null != command.Connection) { command.Connection.Abort(e); } SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { this._objectID = Interlocked.Increment(ref _objectTypeCount); Bid.PoolerTrace("<sc.SqlInternalTransaction.ctor|RES|CPOOL> %d#, Created for connection %d#, outer transaction %d#, Type %d\n", this.ObjectID, innerConnection.ObjectID, (outerTransaction != null) ? outerTransaction.ObjectID : -1, (int) type); this._innerConnection = innerConnection; this._transactionType = type; if (outerTransaction != null) { this._parent = new WeakReference(outerTransaction); } this._transactionId = transactionId; }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { this._objectID = Interlocked.Increment(ref _objectTypeCount); Bid.PoolerTrace("<sc.SqlInternalTransaction.ctor|RES|CPOOL> %d#, Created for connection %d#, outer transaction %d#, Type %d\n", this.ObjectID, innerConnection.ObjectID, (outerTransaction != null) ? outerTransaction.ObjectID : -1, (int)type); this._innerConnection = innerConnection; this._transactionType = type; if (outerTransaction != null) { this._parent = new WeakReference(outerTransaction); } this._transactionId = transactionId; }
private void DestroyConnection(SqlInternalConnection con) { try { lock (_connections.SyncRoot) { _connections.Remove(con); } } catch { // MDAC 80973 throw; } _poolCounter.Modify(-cAddTotal); _ctrl.DestroyConnection(this, con); }
//////////////////////////////////////////////////////////////////////////////////////// // INTERNAL METHODS //////////////////////////////////////////////////////////////////////////////////////// internal void Zombie() { // 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 already closed, // then we're free to zombify... SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection); if (internalConnection == null || _isFromAPI) { _internalTransaction = null; // pre-yukon zombification } }
internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction) { this._isolationLevel = iso; this._connection = con; if (internalTransaction == null) { this._internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this); } else { this._internalTransaction = internalTransaction; this._internalTransaction.InitParent(this); } }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { _innerConnection = innerConnection; _transactionType = type; if (null != outerTransaction) { _parent = new WeakReference(outerTransaction); } _transactionId = transactionId; RestoreBrokenConnection = false; ConnectionHasBeenRestored = false; }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { _innerConnection = innerConnection; _transactionType = type; if (null != outerTransaction) { _parent = new WeakReference(outerTransaction); } _transactionId = transactionId; RestoreBrokenConnection = false; ConnectionHasBeenRestored = false; }
internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction) { this._isolationLevel = iso; this._connection = con; if (internalTransaction == null) { this._internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this); } else { this._internalTransaction = internalTransaction; this._internalTransaction.InitParent(this); } }
public override void Rollback() { if (this.IsYukonPartialZombie) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlTransaction.Rollback|ADV> %d# partial zombie no rollback required\n", this.ObjectID); } this._internalTransaction = null; } else { IntPtr ptr; this.ZombieCheck(); SqlStatistics statistics = null; Bid.ScopeEnter(out ptr, "<sc.SqlTransaction.Rollback|API> %d#", this.ObjectID); SNIHandle target = null; RuntimeHelpers.PrepareConstrainedRegions(); try { target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection); statistics = SqlStatistics.StartTimer(this.Statistics); this._isFromAPI = true; this._internalTransaction.Rollback(); } catch (OutOfMemoryException exception3) { this._connection.Abort(exception3); throw; } catch (StackOverflowException exception2) { this._connection.Abort(exception2); throw; } catch (ThreadAbortException exception) { this._connection.Abort(exception); SqlInternalConnection.BestEffortCleanup(target); throw; } finally { this._isFromAPI = false; SqlStatistics.StopTimer(statistics); Bid.ScopeLeave(ref ptr); } } }
private void ValidateActiveOnConnection(SqlInternalConnection connection) { if ((!this._active || (connection != this._connection)) || (connection.DelegatedTransaction != this)) { if (connection != null) { connection.DoomThisConnection(); } if ((connection != this._connection) && (this._connection != null)) { this._connection.DoomThisConnection(); } throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); } }
private SqlInternalConnection GetFromPool() { SqlInternalConnection res = null; res = (SqlInternalConnection)_stackNew.Pop(); if (res == null) { res = (SqlInternalConnection)_stackOld.Pop(); } // Shouldn't be null, we could assert here. Debug.Assert(res != null, "GetFromPool called with nothing in the pool!"); return(res); }
public void Rollback(SinglePhaseEnlistment enlistment) { SqlInternalConnection validConnection = this.GetValidConnection(); SqlConnection connection = validConnection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Rollback|RES|CPOOL> %d#, Connection %d#, aborting transaction.\n", this.ObjectID, validConnection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { lock (validConnection) { try { this.ValidateActiveOnConnection(validConnection); this._active = false; this._connection = null; validConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Rollback, null, System.Data.IsolationLevel.Unspecified, this._internalTransaction, true); } catch (SqlException exception5) { ADP.TraceExceptionWithoutRethrow(exception5); validConnection.DoomThisConnection(); } catch (InvalidOperationException exception4) { ADP.TraceExceptionWithoutRethrow(exception4); validConnection.DoomThisConnection(); } } validConnection.CleanupConnectionOnTransactionCompletion(this._atomicTransaction); enlistment.Aborted(); } catch (OutOfMemoryException exception3) { connection.Abort(exception3); throw; } catch (StackOverflowException exception2) { connection.Abort(exception2); throw; } catch (ThreadAbortException exception) { connection.Abort(exception); throw; } }
internal void Zombie() { SqlInternalConnection innerConnection = this._connection.InnerConnection as SqlInternalConnection; if (((innerConnection != null) && innerConnection.IsYukonOrNewer) && !this._isFromAPI) { if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlTransaction.Zombie|ADV> %d# yukon deferred zombie\n", this.ObjectID); } } else { this._internalTransaction = null; } }
internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con, IsolationLevel iso, SqlInternalTransaction internalTransaction) { SqlConnection.VerifyExecutePermission(); _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 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 void TransactionEnded(System.Transactions.Transaction transaction) { SqlInternalConnection connection = this._connection; if (connection != null) { Bid.Trace("<sc.SqlDelegatedTransaction.TransactionEnded|RES|CPOOL> %d#, Connection %d#, transaction completed externally.\n", this.ObjectID, connection.ObjectID); lock (connection) { if (this._atomicTransaction.Equals(transaction)) { this._active = false; this._connection = null; } } } }
// Event notification that transaction ended. This comes from the subscription to the Transaction's // ended event via the internal connection. If it occurs without a prior Rollback or SinglePhaseCommit call, // it indicates the transaction was ended externally (generally that one of the DTC participants aborted // the transaction). internal void TransactionEnded(Transaction transaction) { SqlInternalConnection connection = _connection; if (connection != null) { lock (connection) { if (_atomicTransaction.Equals(transaction)) { // No need to validate active on connection, this operation can be called on completed transactions _active = false; _connection = null; } } } }
// Event notification that transaction ended. This comes from the subscription to the Transaction's // ended event via the internal connection. If it occurs without a prior Rollback or SinglePhaseCommit call, // it indicates the transaction was ended externally (generally that one the the DTC participants aborted // the transaction). internal void TransactionEnded(SysTx.Transaction transaction) { SqlInternalConnection connection = _connection; if (connection != null) { Bid.Trace("<sc.SqlDelegatedTransaction.TransactionEnded|RES|CPOOL> %d#, Connection %d#, transaction completed externally.\n", ObjectID, connection.ObjectID); lock (connection) { if (_atomicTransaction.Equals(transaction)) { // No need to validate active on connection, this operation can be called on completed transactions _active = false; _connection = null; } } } }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { Bid.PoolerTrace("<sc.SqlInternalTransaction.ctor|RES|CPOOL> %d#, Created for connection %d#, outer transaction %d#, Type %d\n", ObjectID, innerConnection.ObjectID, (null != outerTransaction) ? outerTransaction.ObjectID : -1, (int)type); _innerConnection = innerConnection; _transactionType = type; if (null != outerTransaction) { _parent = new WeakReference(outerTransaction); } _transactionId = transactionId; RestoreBrokenConnection = false; ConnectionHasBeenRestored = false; }
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; } }
protected override void Dispose(bool disposing) { if (disposing) { 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); if (!IsZombied && !IsYukonPartialZombie) { _internalTransaction.Dispose(); } } #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; } } base.Dispose(disposing); }
private void ReturnToPool() { if (_signaled) { if (null != _connection && null != _pool) { _pool.PutNewConnection(_connection); _pool = null; _connection = null; } if (0 != _cookie && null != _point) { _point.Unadvise(_cookie); _point = null; _cookie = 0; } } }
private bool TryPutResourceInContext(SqlInternalConnection con) { try { if (_ctrl.TransactionAffinity && ContextUtil.IsInTransaction) { if (null != _txPool) { if (_txPool.PutResource(con)) { return(true); } } } } catch (Exception e) { ADP.TraceException(e); } return(false); }
// Method called when the connection is put back into the pool while it is manually // enlisted in a distributed transaction. We must create an outcome event and let the // connection wait until the distributed transaction has finished. Once it does, we then // put it back into the general population of the pool. private void PutConnectionManualEnlisted(SqlInternalConnection con) { ITransaction transaction = con.ManualEnlistedTransaction; con.ResetCachedTransaction(); // Null out con internal transaction reference con.InPool = true; // Mark as in pool so it will not be reclaimed by CheckForDeadConnections // Create IConnectionPoint object - from ITransaction UCOMIConnectionPoint point = (UCOMIConnectionPoint)transaction; // Create outcome event - passing pool, connection, and the IConnectionPoint object TransactionOutcomeEvents outcomeEvent = new TransactionOutcomeEvents(this, con, point); Int32 cookie = 0; point.Advise(outcomeEvent, out cookie); // Register for callbacks, obtain cookie outcomeEvent.SetCookie(cookie); // Set the cookie on the event }
public override void Commit() { IntPtr ptr; SqlConnection.ExecutePermission.Demand(); this.ZombieCheck(); SqlStatistics statistics = null; Bid.ScopeEnter(out ptr, "<sc.SqlTransaction.Commit|API> %d#", this.ObjectID); SNIHandle target = null; RuntimeHelpers.PrepareConstrainedRegions(); try { target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection); statistics = SqlStatistics.StartTimer(this.Statistics); this._isFromAPI = true; this._internalTransaction.Commit(); } catch (OutOfMemoryException exception3) { this._connection.Abort(exception3); throw; } catch (StackOverflowException exception2) { this._connection.Abort(exception2); throw; } catch (ThreadAbortException exception) { this._connection.Abort(exception); SqlInternalConnection.BestEffortCleanup(target); throw; } finally { this._isFromAPI = false; SqlStatistics.StopTimer(statistics); Bid.ScopeLeave(ref ptr); } }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction, long transactionId) { Bid.PoolerTrace("<sc.SqlInternalTransaction.ctor|RES|CPOOL> %d#, Created for connection %d#, outer transaction %d#, Type %d\n", ObjectID, innerConnection.ObjectID, (null != outerTransaction) ? outerTransaction.ObjectID : -1, (int)type); _innerConnection = innerConnection; _transactionType = type; if (null != outerTransaction) { _parent = new WeakReference(outerTransaction); } _transactionId = transactionId; RestoreBrokenConnection = false; ConnectionHasBeenRestored = false; }
// Dooms connection and throws and error if not a valid, active, delegated transaction for the given // connection. Designed to be called AFTER a lock is placed on the connection, otherwise a normal return // may not be trusted. private void ValidateActiveOnConnection(SqlInternalConnection connection) { bool valid = _active && (connection == _connection) && (connection.DelegatedTransaction == this); if (!valid) { // Invalid indicates something BAAAD happened (Commit after TransactionEnded, for instance) // Doom anything remotely involved. if (null != connection) { connection.DoomThisConnection(); } if (connection != _connection && null != _connection) { _connection.DoomThisConnection(); } throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); //TODO: Create a new code } }
internal void FailoverCheck(SqlInternalConnection connection, bool actualUseFailoverPartner, SqlConnectionString userConnectionOptions, string actualFailoverPartner) { if (this.UseFailoverPartner != actualUseFailoverPartner) { Bid.Trace("<sc.SqlConnectionPoolGroupProviderInfo|INFO> Failover detected. failover partner='%ls'. Clearing PoolGroup\n", actualFailoverPartner); base.PoolGroup.Clear(); this._useFailoverPartner = actualUseFailoverPartner; } if (!this._useFailoverPartner && (this._failoverPartner != actualFailoverPartner)) { PermissionSet set = this.CreateFailoverPermission(userConnectionOptions, actualFailoverPartner); lock (this) { if (this._failoverPartner != actualFailoverPartner) { this._failoverPartner = actualFailoverPartner; this._failoverPermissionSet = set; } } } }
private bool _active; // Is the transaction active? internal SqlDelegatedTransaction(SqlInternalConnection connection, SysTx.Transaction tx) { Debug.Assert(null != connection, "null connection?"); _connection = connection; _atomicTransaction = tx; _active = false; SysTx.IsolationLevel systxIsolationLevel = tx.IsolationLevel; // We need to map the System.Transactions IsolationLevel to the one // that System.Data uses and communicates to SqlServer. We could // arguably do that in Initialize when the transaction is delegated, // however it is better to do this before we actually begin the process // of delegation, in case System.Transactions adds another isolation // level we don't know about -- we can throw the exception at a better // place. switch (systxIsolationLevel) { case SysTx.IsolationLevel.ReadCommitted: _isolationLevel = IsolationLevel.ReadCommitted; break; case SysTx.IsolationLevel.ReadUncommitted: _isolationLevel = IsolationLevel.ReadUncommitted; break; case SysTx.IsolationLevel.RepeatableRead: _isolationLevel = IsolationLevel.RepeatableRead; break; case SysTx.IsolationLevel.Serializable: _isolationLevel = IsolationLevel.Serializable; break; case SysTx.IsolationLevel.Snapshot: _isolationLevel = IsolationLevel.Snapshot; break; default: throw SQL.UnknownSysTxIsolationLevel(systxIsolationLevel); } }
internal void FailoverCheck(SqlInternalConnection connection, bool actualUseFailoverPartner, SqlConnectionString userConnectionOptions, string actualFailoverPartner) { if (UseFailoverPartner != actualUseFailoverPartner) { base.PoolGroup.Clear(); _useFailoverPartner = actualUseFailoverPartner; } // Only construct a new permission set when we're connecting to the // primary data source, not the failover partner. if (!_useFailoverPartner && _failoverPartner != actualFailoverPartner) { // NOTE: we optimisitically generate the permission set to keep // lock short, but we only do this when we get a new // failover partner. lock (this) { if (_failoverPartner != actualFailoverPartner) { _failoverPartner = actualFailoverPartner; } } } }
private void ValidateActiveOnConnection(SqlInternalConnection connection) { if ((!this._active || (connection != this._connection)) || (connection.DelegatedTransaction != this)) { if (connection != null) { connection.DoomThisConnection(); } if ((connection != this._connection) && (this._connection != null)) { this._connection.DoomThisConnection(); } throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); } }
internal void ExecuteTransaction(SqlInternalConnection.TransactionRequest transactionRequest, string name, System.Data.IsolationLevel iso) { this.ExecuteTransaction(transactionRequest, name, iso, null, false); }
internal override void ExecuteTransaction(SqlInternalConnection.TransactionRequest transactionRequest, string name, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { if (base.IsConnectionDoomed) { if ((transactionRequest != SqlInternalConnection.TransactionRequest.Rollback) && (transactionRequest != SqlInternalConnection.TransactionRequest.IfRollback)) { throw SQL.ConnectionDoomed(); } } else { if ((((transactionRequest == SqlInternalConnection.TransactionRequest.Commit) || (transactionRequest == SqlInternalConnection.TransactionRequest.Rollback)) || (transactionRequest == SqlInternalConnection.TransactionRequest.IfRollback)) && (!this.Parser.MARSOn && this.Parser._physicalStateObj.BcpLock)) { throw SQL.ConnectionLockedForBcpEvent(); } string transactionName = (name == null) ? string.Empty : name; if (!this._parser.IsYukonOrNewer) { this.ExecuteTransactionPreYukon(transactionRequest, transactionName, iso, internalTransaction); } else { this.ExecuteTransactionYukon(transactionRequest, transactionName, iso, internalTransaction, isDelegateControlRequest); } } }
internal void ExecuteTransactionPreYukon(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction) { StringBuilder builder = new StringBuilder(); switch (iso) { case System.Data.IsolationLevel.Unspecified: break; case System.Data.IsolationLevel.Chaos: throw SQL.NotSupportedIsolationLevel(iso); case System.Data.IsolationLevel.ReadUncommitted: builder.Append("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"); builder.Append(";"); break; case System.Data.IsolationLevel.Serializable: builder.Append("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"); builder.Append(";"); break; case System.Data.IsolationLevel.Snapshot: throw SQL.SnapshotNotSupported(System.Data.IsolationLevel.Snapshot); case System.Data.IsolationLevel.ReadCommitted: builder.Append("SET TRANSACTION ISOLATION LEVEL READ COMMITTED"); builder.Append(";"); break; case System.Data.IsolationLevel.RepeatableRead: builder.Append("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"); builder.Append(";"); break; default: throw ADP.InvalidIsolationLevel(iso); } if (!ADP.IsEmpty(transactionName)) { transactionName = " " + SqlConnection.FixupDatabaseTransactionName(transactionName); } switch (transactionRequest) { case SqlInternalConnection.TransactionRequest.Begin: builder.Append("BEGIN TRANSACTION"); builder.Append(transactionName); break; case SqlInternalConnection.TransactionRequest.Commit: builder.Append("COMMIT TRANSACTION"); builder.Append(transactionName); break; case SqlInternalConnection.TransactionRequest.Rollback: builder.Append("ROLLBACK TRANSACTION"); builder.Append(transactionName); break; case SqlInternalConnection.TransactionRequest.IfRollback: builder.Append("IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"); builder.Append(transactionName); break; case SqlInternalConnection.TransactionRequest.Save: builder.Append("SAVE TRANSACTION"); builder.Append(transactionName); break; } this._parser.TdsExecuteSQLBatch(builder.ToString(), base.ConnectionOptions.ConnectTimeout, null, this._parser._physicalStateObj); this._parser.Run(RunBehavior.UntilDone, null, null, null, this._parser._physicalStateObj); if (transactionRequest == SqlInternalConnection.TransactionRequest.Begin) { this._parser.CurrentTransaction = internalTransaction; } }
internal void Zombie() { // Called by several places in the code to ensure that the outer // transaction object has been zombied and the parser has broken // it's reference to us. // NOTE: we'll be called from the TdsParser when it gets appropriate // ENVCHANGE events that indicate the transaction has completed, however // we cannot rely upon those events occurring in the case of pre-Yukon // servers (and when we don't go to the wire because the connection // is broken) so we can also be called from the Commit/Rollback/Save // methods to handle that case as well. // There are two parts to a full zombie: // 1) Zombie parent and disconnect outer transaction from internal transaction // 2) Disconnect internal transaction from connection and parser // Number 1 needs to be done whenever a SqlTransaction object is completed. Number // 2 is only done when a transaction is actually completed. Since users can begin // transactions both in and outside of the API, and since nested begins are not actual // transactions we need to distinguish between #1 and #2. ZombieParent(); SqlInternalConnection innerConnection = _innerConnection; _innerConnection = null; if (null != innerConnection) { innerConnection.DisconnectTransaction(this); } }
// Called by the transaction to initiate commit sequence public void SinglePhaseCommit(SysTx.SinglePhaseEnlistment enlistment) { Debug.Assert(null != enlistment, "null enlistment?"); SqlInternalConnection connection = GetValidConnection(); SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.SinglePhaseCommit|RES|CPOOL> %d#, Connection %d#, committing 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 the connection is dooomed, we can be certain that the // transaction will eventually be rolled back, and we shouldn't // attempt to commit it. if (connection.IsConnectionDoomed) { lock (connection) { _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. _connection = null; } enlistment.Aborted(SQL.ConnectionDoomed()); } else { Exception commitException; lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); _active = false; // set to inactive first, doesn't matter how the rest completes, this transaction is done. _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, IsolationLevel.Unspecified, _internalTransaction, true); commitException = null; } catch (SqlException e) { commitException = e; ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); } catch (InvalidOperationException e) { commitException = e; ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } if (commitException != null) { // connection.ExecuteTransaction failed with exception if (_internalTransaction.IsCommitted) { // Even though we got an exception, the transaction // was committed by the server. enlistment.Committed(); } else if (_internalTransaction.IsAborted) { // The transaction was aborted, report that to // SysTx. enlistment.Aborted(commitException); } else { // The transaction is still active, we cannot // know the state of the transaction. enlistment.InDoubt(commitException); } // We eat the exception. This is called on the SysTx // thread, not the applications thread. If we don't // eat the exception an UnhandledException will occur, // causing the process to FailFast. } connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); if (commitException == null) { // connection.ExecuteTransaction succeeded enlistment.Committed(); } } } #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; } }
internal override void ExecuteTransaction(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.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(), (transactionName != null) ? transactionName : "null", iso.ToString(), (internalTransaction != null) ? internalTransaction.ObjectID : 0, (internalTransaction != null) ? internalTransaction.TransactionId : 0L); } switch (transactionRequest) { case SqlInternalConnection.TransactionRequest.Begin: try { this._pendingTransaction = internalTransaction; this._smiConnection.BeginTransaction(transactionName, iso, this._smiEventSink); goto Label_0121; } finally { this._pendingTransaction = null; } break; case SqlInternalConnection.TransactionRequest.Promote: base.PromotedDTCToken = this._smiConnection.PromoteTransaction(this._currentTransaction.TransactionId, this._smiEventSink); goto Label_0121; case SqlInternalConnection.TransactionRequest.Commit: break; case SqlInternalConnection.TransactionRequest.Rollback: case SqlInternalConnection.TransactionRequest.IfRollback: this._smiConnection.RollbackTransaction(this._currentTransaction.TransactionId, transactionName, this._smiEventSink); goto Label_0121; case SqlInternalConnection.TransactionRequest.Save: this._smiConnection.CreateTransactionSavePoint(this._currentTransaction.TransactionId, transactionName, this._smiEventSink); goto Label_0121; default: goto Label_0121; } this._smiConnection.CommitTransaction(this._currentTransaction.TransactionId, this._smiEventSink); Label_0121: this._smiEventSink.ProcessMessagesAndThrow(); }
internal void TransactionEnded(System.Transactions.Transaction transaction) { SqlInternalConnection connection = this._connection; if (connection != null) { Bid.Trace("<sc.SqlDelegatedTransaction.TransactionEnded|RES|CPOOL> %d#, Connection %d#, transaction completed externally.\n", this.ObjectID, connection.ObjectID); lock (connection) { if (this._atomicTransaction.Equals(transaction)) { this._active = false; this._connection = null; } } } }
// Event notification that transaction ended. This comes from the subscription to the Transaction's // ended event via the internal connection. If it occurs without a prior Rollback or SinglePhaseCommit call, // it indicates the transaction was ended externally (generally that one the the DTC participants aborted // the transaction). internal void TransactionEnded(SysTx.Transaction transaction) { SqlInternalConnection connection = _connection; if (connection != null) { Bid.Trace("<sc.SqlDelegatedTransaction.TransactionEnded|RES|CPOOL> %d#, Connection %d#, transaction completed externally.\n", ObjectID, connection.ObjectID); lock (connection) { if (_atomicTransaction.Equals(transaction)) { // No need to validate active on connection, this operation can be called on completed transactions _active = false; _connection = null; } } } }
// Dooms connection and throws and error if not a valid, active, delegated transaction for the given // connection. Designed to be called AFTER a lock is placed on the connection, otherwise a normal return // may not be trusted. private void ValidateActiveOnConnection(SqlInternalConnection connection) { bool valid = _active && (connection == _connection) && (connection.DelegatedTransaction == this); if (!valid) { // Invalid indicates something BAAAD happened (Commit after TransactionEnded, for instance) // Doom anything remotely involved. if (null != connection) { connection.DoomThisConnection(); } if (connection != _connection && null != _connection) { _connection.DoomThisConnection(); } throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // } }
public void SinglePhaseCommit(SinglePhaseEnlistment enlistment) { SqlInternalConnection validConnection = this.GetValidConnection(); SqlConnection connection = validConnection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.SinglePhaseCommit|RES|CPOOL> %d#, Connection %d#, committing transaction.\n", this.ObjectID, validConnection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { if (validConnection.IsConnectionDoomed) { lock (validConnection) { this._active = false; this._connection = null; } enlistment.Aborted(SQL.ConnectionDoomed()); } else { Exception exception; lock (validConnection) { try { this.ValidateActiveOnConnection(validConnection); this._active = false; this._connection = null; validConnection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Commit, null, System.Data.IsolationLevel.Unspecified, this._internalTransaction, true); exception = null; } catch (SqlException exception3) { exception = exception3; ADP.TraceExceptionWithoutRethrow(exception3); validConnection.DoomThisConnection(); } catch (InvalidOperationException exception2) { exception = exception2; ADP.TraceExceptionWithoutRethrow(exception2); validConnection.DoomThisConnection(); } } if (exception != null) { if (this._internalTransaction.IsCommitted) { enlistment.Committed(); } else if (this._internalTransaction.IsAborted) { enlistment.Aborted(exception); } else { enlistment.InDoubt(exception); } } validConnection.CleanupConnectionOnTransactionCompletion(this._atomicTransaction); if (exception == null) { enlistment.Committed(); } } } catch (OutOfMemoryException exception6) { connection.Abort(exception6); throw; } catch (StackOverflowException exception5) { connection.Abort(exception5); throw; } catch (ThreadAbortException exception4) { connection.Abort(exception4); throw; } }
internal void ExecuteTransactionYukon(SqlInternalConnection.TransactionRequest transactionRequest, string transactionName, System.Data.IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest) { TdsEnums.TransactionManagerRequestType begin = TdsEnums.TransactionManagerRequestType.Begin; TdsEnums.TransactionManagerIsolationLevel readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted; switch (iso) { case System.Data.IsolationLevel.Unspecified: readCommitted = TdsEnums.TransactionManagerIsolationLevel.Unspecified; break; case System.Data.IsolationLevel.Chaos: throw SQL.NotSupportedIsolationLevel(iso); case System.Data.IsolationLevel.ReadUncommitted: readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadUncommitted; break; case System.Data.IsolationLevel.Serializable: readCommitted = TdsEnums.TransactionManagerIsolationLevel.Serializable; break; case System.Data.IsolationLevel.Snapshot: readCommitted = TdsEnums.TransactionManagerIsolationLevel.Snapshot; break; case System.Data.IsolationLevel.ReadCommitted: readCommitted = TdsEnums.TransactionManagerIsolationLevel.ReadCommitted; break; case System.Data.IsolationLevel.RepeatableRead: readCommitted = TdsEnums.TransactionManagerIsolationLevel.RepeatableRead; break; default: throw ADP.InvalidIsolationLevel(iso); } TdsParserStateObject session = this._parser._physicalStateObj; TdsParser parser = this._parser; bool flag = false; bool lockTaken = false; try { switch (transactionRequest) { case SqlInternalConnection.TransactionRequest.Begin: begin = TdsEnums.TransactionManagerRequestType.Begin; break; case SqlInternalConnection.TransactionRequest.Promote: begin = TdsEnums.TransactionManagerRequestType.Promote; break; case SqlInternalConnection.TransactionRequest.Commit: begin = TdsEnums.TransactionManagerRequestType.Commit; break; case SqlInternalConnection.TransactionRequest.Rollback: case SqlInternalConnection.TransactionRequest.IfRollback: begin = TdsEnums.TransactionManagerRequestType.Rollback; break; case SqlInternalConnection.TransactionRequest.Save: begin = TdsEnums.TransactionManagerRequestType.Save; break; } if ((internalTransaction != null) && internalTransaction.IsDelegated) { if (!this._parser.MARSOn) { if (internalTransaction.OpenResultsCount != 0) { throw SQL.CannotCompleteDelegatedTransactionWithOpenResults(); } Monitor.Enter(session, ref lockTaken); if (internalTransaction.OpenResultsCount != 0) { throw SQL.CannotCompleteDelegatedTransactionWithOpenResults(); } } else { session = this._parser.GetSession(this); flag = true; } } this._parser.TdsExecuteTransactionManagerRequest(null, begin, transactionName, readCommitted, base.ConnectionOptions.ConnectTimeout, internalTransaction, session, isDelegateControlRequest); } finally { if (flag) { parser.PutSession(session); } if (lockTaken) { Monitor.Exit(session); } } }
internal SqlInternalTransaction(SqlInternalConnection innerConnection, TransactionType type, SqlTransaction outerTransaction) : this(innerConnection, type, outerTransaction, NullTransactionId) { }
// Called by transaction to initiate abort sequence public void Rollback(SysTx.SinglePhaseEnlistment enlistment) { Debug.Assert(null != enlistment, "null enlistment?"); SqlInternalConnection connection = GetValidConnection(); SqlConnection usersConnection = connection.Connection; Bid.Trace("<sc.SqlDelegatedTransaction.Rollback|RES|CPOOL> %d#, Connection %d#, aborting transaction.\n", ObjectID, connection.ObjectID); RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG lock (connection) { try { // Now that we've acquired the lock, make sure we still have valid state for this operation. ValidateActiveOnConnection(connection); _active = false; // set to inactive first, doesn't matter how the execute completes, this transaction is done. _connection = null; // Set prior to ExecuteTransaction call in case this initiates a TransactionEnd event // If we haven't already rolled back (or aborted) then tell the SQL Server to roll back if (!_internalTransaction.IsAborted) { connection.ExecuteTransaction(SqlInternalConnection.TransactionRequest.Rollback, null, IsolationLevel.Unspecified, _internalTransaction, true); } } catch (SqlException e) { ADP.TraceExceptionWithoutRethrow(e); // Doom the connection, to make sure that the transaction is // eventually rolled back. // VSTS 144562: doom the connection while having the lock on it to prevent race condition with "Transaction Ended" Event connection.DoomThisConnection(); // Unlike SinglePhaseCommit, a rollback is a rollback, regardless // of how it happens, so SysTx won't throw an exception, and we // don't want to throw an exception either, because SysTx isn't // handling it and it may create a fail fast scenario. In the end, // there is no way for us to communicate to the consumer that this // failed for more serious reasons than usual. // // This is a bit like "should you throw if Close fails", however, // it only matters when you really need to know. In that case, // we have the tracing that we're doing to fallback on for the // investigation. } catch (InvalidOperationException e) { ADP.TraceExceptionWithoutRethrow(e); connection.DoomThisConnection(); } } // it doesn't matter whether the rollback succeeded or not, we presume // that the transaction is aborted, because it will be eventually. connection.CleanupConnectionOnTransactionCompletion(_atomicTransaction); enlistment.Aborted(); } #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; } }
internal void FailoverCheck(SqlInternalConnection connection, bool actualUseFailoverPartner, SqlConnectionString userConnectionOptions, string actualFailoverPartner) { if (UseFailoverPartner != actualUseFailoverPartner) { // Bid.Trace("<sc.SqlConnectionPoolGroupProviderInfo|INFO> Failover detected. failover partner='%ls'. Clearing PoolGroup\n", actualFailoverPartner); base.PoolGroup.Clear(); _useFailoverPartner = actualUseFailoverPartner; } // Only construct a new permission set when we're connecting to the // primary data source, not the failover partner. if (!_useFailoverPartner && _failoverPartner != actualFailoverPartner) { // NOTE: we optimisitically generate the permission set to keep // lock short, but we only do this when we get a new // failover partner. // System.Security.PermissionSet failoverPermissionSet = CreateFailoverPermission(userConnectionOptions, actualFailoverPartner); lock (this) { if (_failoverPartner != actualFailoverPartner) { _failoverPartner = actualFailoverPartner; _failoverPermissionSet = failoverPermissionSet; } } } }
internal void Zombie() { this.ZombieParent(); SqlInternalConnection connection = this._innerConnection; this._innerConnection = null; if (connection != null) { connection.DisconnectTransaction(this); } }