/// <summary> /// Start the recovery scan for XIDs and position cursor at start of list. /// </summary> /// <param name="rm">Resource manager to start scan for.</param> /// <returns>Count of XIDs in whole list or XAER* error code.</returns> private int xa_recover_startrscan(RM rm) { const string MASTER_DB = "iidbdb"; int rc = XA_OK; rm.Xids = new AdvanXID[0]; // init to empty in case bad things happen AdvanXID[] xids = rm.Xids; AdvanConnect conn; ConnectStringConfig config = // make a copy new ConnectStringConfig(rm.Config); // XIDs need to come from iidbdb database config.Set(DrvConst.DRV_PROP_DB, MASTER_DB); try { conn = new AdvanConnect( null, rm.Host, config, trace, (AdvanXID)null); } catch (Exception ex) { trace.write("xa_recover: Exception thrown on Connection open: "+ ex.ToString()); return XAER_RMFAIL; // could not connect } try { xids = conn.getPreparedTransactionIDs(rm.DatabaseName); } catch (Exception ex) { trace.write("xa_recover: Exception thrown on GetXIDs: "+ ex.ToString()); rc = XAER_RMERR; // could not connect } finally { try { conn.close(); } catch(Exception /* ignore */) {} } if (rc != XA_OK) return rc; rm.Cursor =0; // reset cursor to XID list back to start if (xids != null) // safety check rm.Xids = xids; // new list of XIDs return rm.Xids.Length; }
/* ** Name: xa_open - Open an RMI, registered earlier with the TP system. ** ** Description: ** ** Inputs: ** xa_info - character string, contains the RMI open string. ** rmid - RMI identifier, assigned by the TP system, unique to the ** AS process w/which LIBQXA is linked in. ** flags - TP system-specified flags, one of TMASYNC/TMNOFLAGS. ** ** Outputs: ** Returns: ** XA_OK - normal execution. ** XAER_ASYNC - if TMASYNC was specified. Currently, we don't ** support TMASYNC (post-Ingres65 feature). ** XAER_RMERR - various internal errors. ** XAER_INVAL - illegal input arguments. ** XAER_PROTO - if the RMI is in the wrong state. Enforces the ** state tables in the XA spec. ** ** History: ** 18-Aug-03 (thoda04) ** Created. Rich description copied from front/embed/libqxa. */ /// <summary> /// xa_open is called by the transaction manager to initialize /// the resource manager. This method is called first, before /// any other xa_ methods are called. xa_open is loaded and /// called at MSDTC enlistment. It allows MSDTC to /// test that the connection parameters work while running under /// the MSDTC user identity and authorization. If there is a /// problem, we want to know at enlistment time and not at /// a recovery situation. MSDTC also calls xa_open /// when it wants to xa_recover and commit/rollback /// in-doubt transactions. Unfortunately, these connections have /// different connection parms depending on the recover or /// commit/rollback. Therefore, we can't re-use the connection /// and we immediately close the connection after the successful /// test of the xa_open. /// </summary> /// <param name="xa_info">XA OpenString containing information to /// connect to the host and database. Max length is 256 characters.</param> /// <param name="rmid">An integer, assigned by the transaction manager, /// uniquely identifies the called resource manager within the thread /// of control. The TM passes this rmid on subsequent calls to XA /// routines to identify the RM. This identifier remains constant /// until the TM in this thread closes the RM.</param> /// <param name="flags">TMASYNC if function to be performed async. /// TMNOFLAGS is no other flags are set.</param> /// <returns>XA_OK for normal execution or an XAER* error code.</returns> public int xa_open( [MarshalAs(UnmanagedType.LPStr)] string xa_info, int rmid, long flags) { int rc = XA_OK; int trace_level = 0; string sanitizedString; IConfig config; if (xa_info == null) { trace.write("xa_open: xa_info = <null>"+ ", rmid = " + rmid.ToString()); return XAER_INVAL; // invalid arguments were specified } if (xa_info.Length == 0) { trace.write("xa_open: xid = <Empty String>"+ ", rmid = " + rmid.ToString()); return XAER_INVAL; // invalid arguments were specified } try { config = ConnectStringConfig.ParseConnectionString( xa_info, out sanitizedString, true); } catch (Exception) { trace.write("xa_open: xa_info = <invalid connection string>"+ ", rmid = " + rmid.ToString()); return XAER_INVAL; // invalid arguments were specified } // propagate the XA tracing from the application process // to this MSDTC process and send output to event log. string strValue; // Check for XA tracing strValue = config.get(DrvConst.DRV_PROP_TRACE); if (strValue != null && strValue.ToUpper( System.Globalization.CultureInfo.InvariantCulture)=="XA") { strValue = config.get(DrvConst.DRV_PROP_TRACELVL); if (strValue != null) { try { trace_level = Int32.Parse(strValue); if (trace_level < 0) trace_level = 0; } catch {} } } if (trace_level >= 3) // until tracing is setup, do this manually { System.Text.StringBuilder sb = new System.Text.StringBuilder(100); sb.Append("xa_info = "); sb.Append("\""); sb.Append(sanitizedString); sb.Append(", rmid = "); sb.Append(rmid); sb.Append(", flags = "); sb.Append(XAFlagsToString(flags)); trace.write("xa_open: " + sb.ToString()); } string host; host = config.get(DrvConst.DRV_PROP_HOST); if (host == null) // default to local host = ""; if (host == null) { trace.write("xa_open: Error: host specification missing"+ ", rmid = " + rmid.ToString()); return XAER_INVAL; // invalid connection string was specified } // if not "servername:port" format then // get the port number from keyword=value NameValueCollection if (host.IndexOf(":") == -1) { string port = config.get(DrvConst.DRV_PROP_PORT); if (port == null || port.Length == 0) port = "II7"; // no "Port=" then default to "II7" host += ":" + port.ToString(); // add ":portid" to host } AdvanConnect conn; try { conn = new AdvanConnect(null, host, config, trace, (AdvanXID) null); } catch (Exception ex) { if (trace_level >= 1) // until tracing is setup, do this manually trace.write("xa_open: Exception thrown on Connection open: "+ ex.ToString()); return XAER_RMERR; // could not connect } RM rm = new RM(rmid, conn, host, config, trace_level); lock(RMcollection) { RMcollection[rmid] = rm; if (trace_level > 0) // if tracing requested, turn if on { int old_trace_level = trace.setTraceLevel(trace_level); if (old_trace_level > trace_level) // if old > new trace.setTraceLevel(old_trace_level); // set it back CountOfRMsTracing++; } } try { // we don't need this connection, close it. We just needed // to test that it could open and get its values for later. // We don't want to find out that the connection string // is bad for the MSDTC user context at real recovery. conn.close(); // we don't need this connection, close it. } catch (Exception /* ignore any close errors*/) {} return rc; }
/// <summary> /// Common code for xa_commit and xa_rollback /// </summary> /// <param name="isCommit">If commit then true, else rollback.</param> /// <param name="xid">XID to perform the work on.</param> /// <param name="rmid">An integer, assigned by the transaction manager, /// uniquely identifies the called resource manager within the thread /// of control.</param> /// <param name="flags"></param> /// <returns>XA_OK for normal execution or an XAER* error code.</returns> private int xa_commit_or_rollback( bool isCommit, AdvanXID xid, int rmid, long flags) { string title = isCommit?"xa_commit":"xa_rollback"; RM rm = FindRM(rmid); if (rm == null) // if RM not found, error return XAER_INVAL; AdvanConnect conn; try { conn = new AdvanConnect( null, rm.Host, rm.Config, trace, xid); } catch (Exception ex) { trace.write(title+": Exception thrown on Connection open: "+ ex.ToString()); return XAER_RMERR; // could not connect } try { if (isCommit) conn.commit(); else conn.rollback(); } catch (Exception ex) { trace.write(title+": Exception thrown on "+ (isCommit?"commit()":"rollback()") + ": " + ex.ToString()); return XAER_RMERR; // could not connect } try { conn.close(); } catch {} return XA_OK; }