/* ** Name: TxResourceAsyncThreadProcessRequest ** ** Description: ** Perform the prepare-to-commit, commit, or ** rollback on the database. ** ** History: ** 01-Oct-03 (thoda04) ** Created. */ /// <summary> /// Perform the prepare-to-commit, commit, or rollback on the database. /// </summary> void TxResourceAsyncThreadProcessRequest(MSDTCRequest request) { uint hr=S_OK; switch(request) { case MSDTCRequest.ENLIST: try { trace.write(4, title + ": MSDTCRequest.Enlisting with RM..."); if (debugging) Console.WriteLine(title + ": MSDTCRequest.Enlisting with RM..."); TxResourceAsync = (ITransactionResourceAsync) this; XaHelperSinglePipe_EnlistWithRM( RMCookie, Transaction, // pass on the incoming ITransaction TxResourceAsync, // implements ITransactionResourceAsync out TxEnlistmentAsync); // receive ITransactionEnlistmentAsync TxState = TXSTATE.TX_ENLISTED; trace.write(4, title + ": MSDTCRequest.Enlisted with RM successfully"); if (debugging) Console.WriteLine(title + ": MSDTCRequest.Enlisted with RM"); } catch (Exception ex) { EnlistmentException = ex; string s = ex.ToString(); // debugging // release and clear the RMCookie XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); break; } break; case MSDTCRequest.DELIST: if (debugging) Console.WriteLine(title + ": MSDTCRequest.DELIST..."); // make sure the RMCookie is released and cleared XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); break; case MSDTCRequest.PREPARE: { if (debugging) Console.WriteLine(title + ": MSDTCRequest.PREPARE..."); hr = PrepareTx(); /* call Ingres to prepare-to-commit */ if (hr==S_OK) /* transaction is prepared */ { TxState = TXSTATE.TX_PREPARED; } else { RollbackTx(); /* prepare failed; abort the transaction */ TxState = TXSTATE.TX_INVALID_STATE; } try { TxEnlistmentAsync.PrepareRequestDone( hr, IntPtr.Zero, IntPtr.Zero); trace.write(3, title + ": TxEnlistmentAsync.PrepareRequestDone(0X" + hr.ToString("X8") + ")"); if (debugging) Console.WriteLine(title + ": PrepareRequestDone called"); /* if hr==S_OK then MS DTC will dispatch the user application after the pITransaction->commit(); else hr==E_FAIL then DTC will pITransactionResourceAsync->Release() */ if (TxState != TXSTATE.TX_PREPARED) { XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); } } catch (COMException ex) { string s = ex.ToString(); trace.write(3, title + ": MSDTCRequest.PREPARE catches COMException. Message=" + "\"" + ex.Message +"\""); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); // throw; } catch (Exception ex) { string s = ex.ToString(); trace.write(3, title + ": MSDTCRequest.PREPARE catches Exception. Message=" + "\"" + ex.Message + "\""); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); // throw; } break; } case MSDTCRequest.PREPARE_E_FAIL: if (debugging) Console.WriteLine(title + ": MSDTCRequest.PREPARE_E_FAIL..."); TxEnlistmentAsync.PrepareRequestDone( E_FAIL, IntPtr.Zero, IntPtr.Zero); trace.write(3, title + ": TxEnlistmentAsync.PrepareRequestDone(E_FAIL)"); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); break; case MSDTCRequest.PREPARE_E_UNEXPECTED: if (debugging) Console.WriteLine(title + ": MSDTCRequest.PREPARE_E_UNEXPECTED..."); TxEnlistmentAsync.PrepareRequestDone( E_UNEXPECTED, IntPtr.Zero, IntPtr.Zero); trace.write(3, title + ": TxEnlistmentAsync.PrepareRequestDone(E_FAIL)"); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); break; case MSDTCRequest.PREPARE_SINGLE_PHASE: { if (debugging) Console.WriteLine(title + ": MSDTCRequest.PREPARE_SINGLE_PHASE..."); hr = CommitTx(TMONEPHASE); /* single phase commit optimization */ if (hr == S_OK) { hr=XACT_S_SINGLEPHASE; TxState = TXSTATE.TX_ENLISTED; } else TxState = TXSTATE.TX_INVALID_STATE; try { TxEnlistmentAsync.PrepareRequestDone( hr, IntPtr.Zero, IntPtr.Zero); trace.write(4, title + ": TxEnlistmentAsync.PrepareRequestDone(0X" + hr.ToString("X8") + ")"); if (debugging) Console.WriteLine(title + ": PrepareRequestDone called"); if (hr == XACT_S_SINGLEPHASE) { if (debugging) Console.WriteLine(title + ": MSDTCRequest.PREPARE_SINGLE_PHASE releasing RMCookie..."); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); } } catch (Exception ex) { string s = ex.ToString(); trace.write(3, title + ": MSDTCRequest.PREPARE_SINGLE_PHASE catches Exception. Message=" + "\"" + ex.Message + "\""); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); // throw; } break; } case MSDTCRequest.COMMIT: { if (debugging) Console.WriteLine(title + ": MSDTCRequest.COMMIT..."); hr = CommitTx(); if (hr == S_OK) TxState = TXSTATE.TX_ENLISTED; else TxState = TXSTATE.TX_INVALID_STATE; try { TxEnlistmentAsync.CommitRequestDone(hr); trace.write(3, title + ": TxEnlistmentAsync.CommitRequestDone(0X" + hr.ToString("X8") + ")"); if (debugging) Console.WriteLine(title + ": CommitRequestDone called... Releasing RMCookie..."); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); } catch (Exception ex) { string s = ex.ToString(); // for debugging; and ign ex trace.write(3, title + ": MSDTCRequest.COMMIT catches Exception. Message=" + "\"" + ex.Message + "\""); } break; } case MSDTCRequest.ABORT: { if (debugging) Console.WriteLine(title + ": MSDTCRequest.ABORT..."); hr = RollbackTx(); TxState = TXSTATE.TX_ABORTED; try { TxEnlistmentAsync.AbortRequestDone(hr); trace.write(3, title + ": TxEnlistmentAsync.AbortRequestDone(0X" + hr.ToString("X8") + ")"); if (debugging) Console.WriteLine(title + ": AbortRequestDone called... Releasing RMCookie..."); XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); } catch (Exception ex) { string s = ex.ToString(); // for debugging; and ign ex trace.write(3, title + ": MSDTCRequest.ABORT catches Exception. Message=" + "\"" + ex.Message + "\""); } break; } case MSDTCRequest.TMDOWN: { if (debugging) Console.WriteLine(title + ": MSDTCRequest.TMDOWN..."); RollbackTx(); TxState = TXSTATE.TX_TMDOWN; XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); break; } default: break; } /* end switch */ }
/* ** Name: StartMSDTCRequest ** ** Description: ** Start the TxResourceAsync thread that will asynchronously ** perform the transaction work. ** Called by one of our implentations under MSDTC Proxy thread. ** PrepareRequest() start prepare-to-commit ** CommitRequest() start commit ** AbortRequest() start rollback ** TMDown() notification that Transaction Monitor is down ** ** History: ** 01-Oct-03 (thoda04) ** Created. */ /// <summary> /// Start a MSDTC request on a worker thread. /// </summary> /// <param name="request"></param> /// <returns>True if request was successfully queued.</returns> bool StartMSDTCRequest(MSDTCRequest request) { lock(MSDTCRequestQueue) { // first time start the worker thread if (txResourceAsyncThread == null || txResourceAsyncThread.IsAlive == false) { // only start the thread if doing the ENLIST // (which should be the first call). if (request != MSDTCRequest.ENLIST) return false; // should not happen, but bulletproof it // fire up the thread ThreadStart start = new ThreadStart(TxResourceAsyncThreadMethod); txResourceAsyncThread = new Thread(start); //Set ApartmentState to STA to minimize //any COM object creation issues. txResourceAsyncThread.TrySetApartmentState(ApartmentState.STA); txResourceAsyncThread.Start(); } // put the request on the dispatch queue MSDTCRequestQueue.Enqueue(request); // wait for TxResourceAsync thread to start and give it // a chance to lock DBC connection before MSDTC Proxy might // return async control back to application which might try to // fire off another provider call before COMMIT has a // chance to finish. Monitor.Pulse(MSDTCRequestQueue); Monitor.Wait(MSDTCRequestQueue); } // end lock return true; // indicate request was successfully queued }