} // AdvanXID /* ** Name: AdvanXID ** ** Description: ** Class constructor for an XA XID using XID structure. ** ** Input: ** fid XA Format ID. ** gtid XA Global Transaction ID. ** bqual XA Branch Qualifier. ** ** Output: ** None. ** ** Returns: ** None. ** ** History: ** 13-Oct-03 (thoda04) ** Created. */ internal AdvanXID(XAXIDStruct xid) { this.type = XID_XA; this.fid = xid.formatID; this.gtid = new Byte[xid.gtridLength]; this.bqual = new Byte[xid.bqualLength]; Array.Copy(xid.data, 0, this.gtid, 0, xid.gtridLength); Array.Copy(xid.data, xid.gtridLength, this.bqual, 0, xid.bqualLength); } // AdvanXID
/* ** Name: AdvanXID ** ** Description: ** Class constructor for an XA XID using XID structure. ** ** Input: ** fid XA Format ID. ** gtid XA Global Transaction ID. ** bqual XA Branch Qualifier. ** ** Output: ** None. ** ** Returns: ** None. ** ** History: ** 13-Oct-03 (thoda04) ** Created. */ internal AdvanXID(XAXIDStruct xid) { this.type = XID_XA; this.fid = xid.formatID; this.gtid = new Byte[xid.gtridLength]; this.bqual= new Byte[xid.bqualLength]; Array.Copy(xid.data, 0, this.gtid, 0, xid.gtridLength); Array.Copy(xid.data,xid.gtridLength, this.bqual,0, xid.bqualLength); }
/* ** Name: Enlist ** ** Description: ** Enlist in the Microsoft Distributed Transaction Coordinator (MSDTC). ** Called by Connection.EnlistDistributedTransaction(ITransaction). ** ** History: ** 01-Oct-03 (thoda04) ** Created. */ /// <summary> /// Enlist in the Microsoft Distributed Transaction Coordinator (MSDTC). /// </summary> /// <param name="advanConnection">Internal connection.</param> /// <param name="tx">ITransaction interface of object.</param> /// <param name="nv">Connection string parameter values list.</param> internal void Enlist( AdvanConnect advanConnection, ITransaction tx, ConnectStringConfig nv) { this.advanConnect = advanConnection; this.Transaction = tx; trace.write(3, title + ": Enlist()"); if (debugging) Console.WriteLine(title + ": Enlist() begins..."); /* Call DtcGetTransactionManager in MS DTC proxy to establish a connection to the Transaction Manager. From the TM, get the XATM's Single Pipe Helper interface that will help establish an enlistment in MSDTC using the XA protocol (XaSwitch and XIDs). */ XaHelperSinglePipe = GetDtcToXaHelperSinglePipe(); /* Obtain the Resource Manager (RM) cookie. The XARMCreate method is invoked once per connection. The information provided makes it possible for the transaction manager to connect to the database to perform recovery. The transaction manager durably records this information in it's log file. If recovery is necessary, the transaction manager reads the log file, reconnects to the database, and initiates XA recovery. Calling XARMCreate results in a message from the DTC proxy to the XA Transaction Manager (TM). When the XA TM receives a message that contains the DSN and the name of the client DLL, TM will: 1) LoadLibrary the client dll (Ingres.Support.dll which will drag in the referenced Ingres.ProviderInternals from the GAC). 2) GetProcAddress the GetXaSwitch function in the dll. 3) Call the GetXaSwitch function to obtain the XA_Switch. 4) Call the xa_open function to open an XA connection with the resource manager (Ingres). When the our xa_open function is called, the DTC TM passes in the DSN parm as the OPEN_STRING. It then closes the connection by calling xa_close. (It's just testing the connection information so that it won't be surprised when it's in the middle of recovery later.) 5) Generate a RM GUID for the connection. 6) Write a record to the DTCXATM.LOG file indicating that a new resource manager is being established. The log record contains the DSN parm, the name of our RM (Ingres.Support.dll), and the RM GUID. This information will be used to reconnect to Ingres should recovery be necessary. XARMCreate method also causes the MS DTC proxy to create a resource manager object and returns an opaque pointer to that object as the RMCookie. This RMCookie represents the connection to the TM. */ nv = new ConnectStringConfig(nv); // create a working copy // Connection attempts with MSG_P_DTMC will raise error: // GC000B_RMT_LOGIN_FAIL Login failure: invalid username/password // if you try to send login information nv.Remove(DrvConst.DRV_PROP_USR); // remove "user="******"password="******"group=" nv.Remove(DrvConst.DRV_PROP_ROLE); // remove "role=" string xa_open_string = ConnectStringConfig.ToConnectionString(nv); int trace_level = trace.getTraceLevel("XA"); if (trace_level > 0) { xa_open_string += // tell MSDTC process to trace XASwitch ";Trace=XA;TraceLevel=" + trace_level.ToString(); } // Locate the Ingres.Support.dll that holds our XASwitch // support. The dll should be in the GAC so use a type from // the Ingres.Support assembly, qualified by the same // Version and PublicKeyToken that the currently executing // Ingres.Support assembly is using. System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); string fullname = assembly.FullName; string version; int index = fullname.IndexOf(','); // locate ", Verison=..." if (index != -1) version = fullname.Substring(index); else // should not happen unless in a debugging environment version = ", Version=2.0.0.0, Culture=neutral" + ", PublicKeyToken=1234567890123456"; Type type = Type.GetType( "Ingres.Support.XAProvider" + ", Ingres.Support" + version); // BTW, type will be null if Ingres.Support is not properly // in the GAC or has a different version number from // Ingres.Client. A NullReferenceException would follow. string dll = type.Assembly.Location; XaHelperSinglePipe_XARMCreate( xa_open_string, dll, out this.RMCookie); /* Obtain an XID from an ITransaction interface pointer. The ITransaction pointer is offered by a transaction object. The transaction object contains a DTC transaction that is identified by a transaction identifier (TRID) which is a globally unique identifier (GUID). Given a TRID, one can always create an XID. The MS DTC proxy generates an XID and returns it. Into the XID's formatID, MS puts 0x00445443 ("DTC"). Into the XID's gtrid (length=0x10), MS puts a GUID identifying the global transaction identifier. (Same as Transaction.Current.TransactionInformation.DistributedIdentifier.) Into the XID's bqual (length=0x30), MS puts a second GUID identifying the TM that is coordinating the transaction and also a third GUID identifying the database connection. If two components in the same transaction have their own connections, then they will be loosely coupled XA threads of control (different bquals). MS goes beyond the XA spec and expects that the two loosely coupled threads will not deadlock on resource locks. */ XAXIDStruct xaXIDstruct = new XAXIDStruct(-1,0,0,new byte[128]); XaHelperSinglePipe_ConvertTridToXID( Transaction, this.RMCookie, ref xaXIDstruct); advanXID = new AdvanXID(xaXIDstruct); /* Tell the DTC proxy to enlist on behalf of the XA resource manager. EnlistWithRM is called for every transaction that the connection is requested to be enlisted in. The provider is responsible for implementing the ITransactionResourceAsync interface. This interface includes the PrepareRequest, CommitRequest, AbortRequest, and TMDown callbacks. The transaction manager will invoke these callback methods to deliver phase one and phase two notifications to the provider. The MS DTC proxy informs the transaction manager that the provider wishes to enlist in the transaction. The transaction manager creates an internal enlistment object to record the fact that the provider is participating in the transaction. Upon return from EnlistWithRM, the MS DTC proxy will have created an enlistment object and returns the pITransactionEnlistmentAsync interface pointer of the enlistment object back to the provider. */ try { StartMSDTCRequest(MSDTCRequest.ENLIST); // start worker thread if (EnlistmentException != null) throw EnlistmentException; // wait until EnlistWithRM is completed under the worker thread advanConnect.msg.LockConnection(); advanConnect.msg.UnlockConnection(); advanConnect.startTransaction(advanXID); TxBranchState = TXBRANCHSTATE.Active; } catch { // release our bad connection to MS DTC and // shutdown our worker thread to MS DTC. XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie); StartMSDTCRequest(MSDTCRequest.DELIST); throw; } // At this point we have a good MSDTC enlistment! // The advanConnect internal connection object is now being used by // two threads: the application thread and the MSDTC proxy thread. // The advanConnect usage count will block release of the internal // connection advanConnect object back into the connection pool // until each is finished and calls // advanConnect.CloseOrPutBackIntoConnectionPool() method. // See IngresConnection.Open() method for application's claim stake. advanConnect.ReferenceCountIncrement(); // MSDTC proxy thread stakes it claim trace.write(3, title + ": Enlist() complete"); if (debugging) Console.WriteLine(title + ": Enlist() complete"); }
/* ** Name: XaHelperSinglePipe_ConvertTridToXID ** ** Description: ** Convert a ITransaction to an XID. ** ** History: ** 01-Oct-03 (thoda04) ** Created. */ /// <summary> /// Convert a ITransaction to an XID. /// </summary> /// <param name="pITransaction"></param> /// <param name="dwRMCookie"></param> /// <param name="xid"></param> private void XaHelperSinglePipe_ConvertTridToXID( ITransaction pITransaction, uint dwRMCookie, ref XAXIDStruct xid) { try { XaHelperSinglePipe.ConvertTridToXID( pITransaction, dwRMCookie, ref xid); } catch (COMException comex) { throw SqlEx.get( "ConvertTridToXID failed during enlistment in " + "MS Distributed Transaction Coordinator. " + HResultToString(comex.ErrorCode) +" " + comex.Message, "HY000", comex.ErrorCode ); } }