//// NOTE: This is just a private helper because OracleClient V1.1 shipped //// with a different argument name and it's a breaking change to not use //// the same argument names in V2.0 (VB Named Parameter Binding--Ick) //private void EnlistDistributedTransactionHelper(System.EnterpriseServices.ITransaction transaction) { // SysTx.Transaction indigoTransaction = null; // if (null != transaction) { // indigoTransaction = SysTx.TransactionInterop.GetTransactionFromDtcTransaction((SysTx.IDtcTransaction)transaction); // } // RepairInnerConnection(); // // NOTE: since transaction enlistment involves round trips to the // // server, we don't want to lock here, we'll handle the race conditions // // elsewhere. // InnerConnection.EnlistTransaction(indigoTransaction); // // NOTE: If this outer connection were to be GC'd while we're // // enlisting, the pooler would attempt to reclaim the inner connection // // while we're attempting to enlist; not sure how likely that is but // // we should consider a GC.KeepAlive(this) here. // GC.KeepAlive(this); //} public override void EnlistTransaction(SysTx.Transaction?transaction) { // If we're currently enlisted in a transaction and we were called // on the EnlistTransaction method (Whidbey) we're not allowed to // enlist in a different transaction. DbConnectionInternal innerConnection = InnerConnection; // NOTE: since transaction enlistment involves round trips to the // server, we don't want to lock here, we'll handle the race conditions // elsewhere. SysTx.Transaction?enlistedTransaction = innerConnection.EnlistedTransaction; if (enlistedTransaction != null) { // Allow calling enlist if already enlisted (no-op) if (enlistedTransaction.Equals(transaction)) { return; } // Allow enlisting in a different transaction if the enlisted transaction has completed. if (enlistedTransaction.TransactionInformation.Status == SysTx.TransactionStatus.Active) { throw ADP.TransactionPresent(); } } RepairInnerConnection(); InnerConnection.EnlistTransaction(transaction); // NOTE: If this outer connection were to be GC'd while we're // enlisting, the pooler would attempt to reclaim the inner connection // while we're attempting to enlist; not sure how likely that is but // we should consider a GC.KeepAlive(this) here. GC.KeepAlive(this); }
public override void EnlistTransaction(SysTx.Transaction?transaction) { if (null != LocalTransaction) { throw ADP.LocalTransactionPresent(); } EnlistTransactionInternal(transaction); }
internal void ActivateConnection(SysTx.Transaction?transaction) { // Internal method called from the connection pooler so we don't expose // the Activate method publicly. #if DEBUG int activateCount = Interlocked.Increment(ref _activateCount); Debug.Assert(1 == activateCount, "activated multiple times?"); #endif // DEBUG Activate(transaction); PerformanceCounters !.NumberOfActiveConnections.Increment(); }
internal void EnlistTransactionInternal(SysTx.Transaction?transaction) { SysTx.IDtcTransaction?oleTxTransaction = ADP.GetOletxTransaction(transaction); using (ITransactionJoinWrapper transactionJoin = ITransactionJoin()) { if (null == transactionJoin.Value) { throw ODB.TransactionsNotSupported(Provider, null); } transactionJoin.Value.JoinTransaction(oleTxTransaction, (int)IsolationLevel.Unspecified, 0, IntPtr.Zero); _unEnlistDuringDeactivate = (null != transaction); } EnlistedTransaction = transaction; }
public virtual void Dispose() { _connectionPool = null; _performanceCounters = null; _connectionIsDoomed = true; _enlistedTransactionOriginal = null; // should not be disposed // Dispose of the _enlistedTransaction since it is a clone // of the original reference. // _enlistedTransaction can be changed by another thread (TX end event) SysTx.Transaction?enlistedTransaction = Interlocked.Exchange(ref _enlistedTransaction, null); if (enlistedTransaction != null) { enlistedTransaction.Dispose(); } }
internal void DetachCurrentTransactionIfEnded() { SysTx.Transaction?enlistedTransaction = EnlistedTransaction; if (enlistedTransaction != null) { bool transactionIsDead; try { transactionIsDead = (SysTx.TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status); } catch (SysTx.TransactionException) { // If the transaction is being processed (i.e. is part way through a rollback\commit\etc then TransactionInformation.Status will throw an exception) transactionIsDead = true; } if (transactionIsDead) { DetachTransaction(enlistedTransaction, true); } } }
// Detach transaction from connection. internal void DetachTransaction(SysTx.Transaction transaction, bool isExplicitlyReleasing) { // potentially a multi-threaded event, so lock the connection to make sure we don't enlist in a new // transaction between compare and assignment. No need to short circuit outside of lock, since failed comparisons should // be the exception, not the rule. lock (this) { // Detach if detach-on-end behavior, or if outer connection was closed DbConnection?owner = (DbConnection?)Owner; if (isExplicitlyReleasing || UnbindOnTransactionCompletion || null == owner) { SysTx.Transaction?currentEnlistedTransaction = _enlistedTransaction; if (currentEnlistedTransaction != null && transaction.Equals(currentEnlistedTransaction)) { EnlistedTransaction = null; if (IsTxRootWaitingForTxEnd) { DelegatedTransactionEnded(); } } } } }
protected override void Activate(SysTx.Transaction?transaction) { throw ADP.NotSupported(); }
public abstract void EnlistTransaction(SysTx.Transaction?transaction);
protected abstract void Activate(SysTx.Transaction?transaction);
public override void EnlistTransaction(SysTx.Transaction?transaction) { throw ADP.ClosedConnectionError(); }
protected override void Activate(SysTx.Transaction?transaction) { throw ADP.ClosedConnectionError(); }