// --------------------------------------------------------------- // forget_heur_branches // Purpose : Heuristic forget // -------------------------------------------------------------- int32 CTmTxBranches::forget_heur_branches (CTmTxBase *pp_txn, int64 pv_flags) { int32 lv_error = FEOK; TMTrace (2, ("CTmTxBranches::forget_heur_branches ENTRY : ID (%d,%d), flags " PFLL "\n", pp_txn->node(), pp_txn->seqnum(), pv_flags)); tm_log_event(DTM_TMTX_FORGET_HEURISTIC, SQ_LOG_WARNING, "DTM_TMTX_FORGET_HEURISTIC", -1,-1,pp_txn->node(), pp_txn->seqnum()); gv_tm_info.write_trans_state (pp_txn->transid(), TM_TX_STATE_FORGOTTEN_HEUR, pp_txn->abort_flags(), false); pp_txn->wrote_trans_state(true); if (pp_txn->tx_state() != TM_TX_STATE_FORGOTTEN_HEUR) { lv_error = forget_branches (pp_txn, pv_flags); switch (lv_error) { case XA_OK: pp_txn->tx_state(TM_TX_STATE_FORGOTTEN_HEUR); break; case XAER_RMFAIL: //TODO recovery case, what to do here? abort(); default: tm_log_event(DTM_TMTX_INVALID_BRANCH, SQ_LOG_CRIT, "DTM_TMTX_INVALID_BRANCH"); TMTrace (1, ("CTmTxBranches::forget_heur_branches - Invalid branch state\n")); abort (); break; } } return lv_error; } // forget_heur_branches
// -------------------------------------------------------------- // CxaTM_RMMessage::send_rm // Purpose - send the message to the RM // Caller may lock. // -------------------------------------------------------------- int CxaTM_RMMessage::send_rm() { short lv_ret = -1; int lv_xaError = XA_OK; XATrace(XATM_TraceExit, ("XATM: CxaTM_RMMessage::send_rm ENTRY. msgid=%d, retries=%d/%d.\n", iv_msgid, sendAttempts(), RM()->maxSendRetries())); lock(); // Make sure that this CxaTM_RMMessage object doesn't already have a link outstanding if (msgid()) { tm_log_event(DTM_XATM_SENDTORM_FAILED, SQ_LOG_CRIT, "DTM_XATM_SENDTORM_FAILED", -1, RM()->getRmid(), -1, -1, msgid()); XATrace(XATM_TraceError, ("XATM: CxaTM_RMMessage::send_rm : XATM Message object " "already has a link outstanding, msgid %d\n", msgid())); abort(); } if (iv_reqLen > RM_MAX_DATA || iv_rspLen > RM_MAX_DATA) { // EMS DTM_XATM_SENDTORM_FAILED tm_log_event(DTM_XATM_SENDTORM_FAILED2, SQ_LOG_CRIT, "DTM_XATM_SENDTORM_FAILED2", -1,RM()->getRmid(),-1,-1,-1,XAER_RMFAIL,-1,-1,-1,-1,-1,-1,-1, RM_MAX_DATA,iv_reqLen,iv_rspLen); XATrace(XATM_TraceError, ("XATM: CxaTM_RMMessage::send_rm : " " Request or reply buffer too large, returning XAER_RMFAIL.\n")); lv_xaError = XAER_RMFAIL; } else { inc_sendAttempts(); lv_ret = link(); } if (lv_ret) { // EMS DTM_XATM_SENDTORM_FAILED tm_log_event(DTM_XATM_SENDTORM_FAILED, SQ_LOG_CRIT, "DTM_XATM_SENDTORM_FAILED", lv_ret, ip_RM->getRmid()); lv_xaError = XAER_RMFAIL; } unlock(); XATrace((lv_xaError?XATM_TraceExitError:XATM_TraceExit), ("XATM: CxaTM_RMMessage::send_rm EXIT returning %s, BMSG_LINK_ returned %d, msgid=%d, retries=%d/%d.\n", XAtoa(lv_xaError), lv_ret, iv_msgid, sendAttempts(), RM()->maxSendRetries())); return lv_xaError; } //CxaTM_RMMessage::send_rm
//---------------------------------------------------------------------------- // CxaTM_RMMessage::constructPoolElement // Purpose : Callback for CTmPool elements. // This method is called to construct a CxaTM_RMMessage object by CTmPool::newElement. //---------------------------------------------------------------------------- CxaTM_RMMessage * CxaTM_RMMessage::constructPoolElement(int64 pv_msgNum) { XATrace (XATM_TraceRMMsg, ("CxaTM_RMMessage::constructPoolElement : ENTRY Instantiating new RMMessage object, msgNum " PFLL ".\n", pv_msgNum)); CxaTM_RMMessage *lp_msg = new CxaTM_RMMessage(pv_msgNum); if (!lp_msg) { tm_log_event(DTM_LOGIC_ERROR_RM_OBJ, SQ_LOG_CRIT, "DTM_LOGIC_ERROR_RM_OBJ"); XATrace (XATM_TraceError, ("CxaTM_RMMessage::constructPoolElement : Failed to instantiate " " RMMessage object.\n")); abort(); } XATrace (XATM_TraceRMMsg, ("CxaTM_RMMessage::constructPoolElement : EXIT RMMessage object %p, msgNum " PFLL " instantiated.\n", (void *) lp_msg, pv_msgNum)); return lp_msg; } //CxaTM_RMMessage::constructPoolElement
// -------------------------------------------------------------- // CTmTimer::eventQ_push // Purpose - push a new event to the timer event queue. // These are pushed in FIFO order. // -------------------------------------------------------------- void CTmTimer::eventQ_push(CTmEvent * pp_event) { char la_buf[DTM_STRING_BUF_SIZE]; CTmTimerEvent *lp_tevent = (CTmTimerEvent *) pp_event; if (lp_tevent == NULL) { sprintf(la_buf, "Timer request to be queued is NULL.\n"); tm_log_event(DTM_TMTIMER_BAD_EVENT, SQ_LOG_CRIT, "DTM_TMTIMER_BAD_EVENT"); TMTIME_TRACE (1, XATM_TraceTimerExitError,("CTmTimer::eventQ_push - %s", la_buf)); abort (); } eventQ()->push(lp_tevent); if (lp_tevent->transaction()) { TMTIME_TRACE (3, XATM_TraceTimerExit, ("CTmTimer::eventQ_push : signaling timer thread, event %p, " "cmd %d, trans obj %p, request %d, wakeup interval %d, repeat %d.\n", (void *) lp_tevent, lp_tevent->command(), (void *) lp_tevent->transaction(), lp_tevent->requestType(), lp_tevent->wakeupInterval(), lp_tevent->wakeupRepeat())); } else { TMTIME_TRACE (3, XATM_TraceTimerExit, ("CTmTimer::eventQ_push : signaling timer thread, event %p, " "cmd %d, request %d, wakeup interval %d, repeat %d.\n", (void *) lp_tevent, lp_tevent->command(), lp_tevent->requestType(), lp_tevent->wakeupInterval(), lp_tevent->wakeupRepeat())); } eventQ_CV()->signal(true /*lock*/); } //CTmTimer::eventQ_push
// --------------------------------------------------------------------------- // CxaTM_RMMessage::link // Purpose : Call to BMSG_LINK_. // This function will retry any retriable errors such as FENOLCB (30). // Parameters: // pv_maxretries - maximum retries for retriable errors. // Returns error from BMSG_LINK_ call. // --------------------------------------------------------------------------- short CxaTM_RMMessage::link(int32 pv_maxretries) { short lv_ret = 0; int32 lv_retries = 0; bool lv_exit = false; TM_Txid_Internal *lp_transid = (TM_Txid_Internal *) &xid()->data[0]; XATrace(XATM_TraceExit, ("CxaTM_RMMessage::link ENTRY : ID (%d,%d), linker " "tag(rmid) %d.\n", lp_transid->iv_node, lp_transid->iv_seq_num, ip_RM->getRmid())); do { lv_ret = BMSG_LINK_(ip_RM->getRmPhandle(), // phandle, &iv_msgid, // msgid NULL, // reqctrl 0, // reqctrlsize NULL, // replyctrl 0, // replyctrlmax (char *) Req(), // reqdata ReqLen(), // reqdatasize (char *) Rsp(), // replydata RspLen(), // replydatamax ip_RM->getRmid(), // linkertag TSE_LINK_PRIORITY, // pri 0, // xmitclass BMSG_LINK_LDONEQ); // linkopts lv_retries++; if (lv_ret == FENOLCB && //((pv_maxretries == -1 && (lv_retries % TM_LINKRETRY_RETRIES == 0)) || (pv_maxretries == -1 || (pv_maxretries > 0 && (lv_retries <= pv_maxretries)))) { // Message Descriptor depletion. This means we ran out of MDs. // This is retriable, and we want to slow down the TM to allow // some of the outstanding requests to complete. XATrace(XATM_TraceError, ("CxaTM_RMMessage::link BMSG_LINK_ error %d, " "linker tag(rmid) %d, retires %d/%d - Pausing thread for " "%dms before retrying.\n", lv_ret, ip_RM->getRmid(), lv_retries, pv_maxretries, TM_LINKRETRY_PAUSE)); tm_log_event(DTM_TM_LINK_PAUSED, SQ_LOG_WARNING, "DTM_TM_LINK_PAUSED", lv_ret, -1, lp_transid->iv_node, lp_transid->iv_seq_num, -1, -1, -1, -1, lv_retries, -1, -1, -1, -1, TM_LINKRETRY_PAUSE /*pause in ms*/, ip_RM->getRmid()); SB_Thread::Sthr::sleep(TM_LINKRETRY_PAUSE); // in msec } if (lv_ret != FENOLCB) lv_exit = true; else if (pv_maxretries > 0 && lv_retries >= pv_maxretries) lv_exit = true; } while (!lv_exit); if (lv_ret) { XATrace(XATM_TraceExit, ("CxaTM_RMMessage::link EXIT : returning error %d.\n", lv_ret)); } else { XATrace(XATM_TraceExit, ("CxaTM_RMMessage::link EXIT : returning msgid %d.\n", iv_msgid)); } return lv_ret; } //CxaTM_RMMessage::link
// -------------------------------------------------------------- // CxaTM_RM::checkError // Check the error returned by BMSG_BREAK_ and determine whether // to retry the LINK. // If break returns an error we retry the link - resend the // message to the RM. // We don't need to cancel/abandon the message. If Seabed // returned an error it already abandoned it. // pv_breakError - return code from BMSG_BREAK_. // pp_xaError will contain the XA error code on return. // pv_softRetry - true (default) Will retry true (retry link) if an // XA_RETRY occurs. This happens if a // FEPATHDOWN, FENOLCB, or an XA_RETRY occur. // false Will return retry = false if one of these // errors occurs. This allows the XA_RETRY to // be passed up to the next level for xa_recover. // pv_transid only used for event messages (error reporting). // return code // true = retry link. // false = Don't retry. Retries exceeded or error is not // retryable. // -------------------------------------------------------------- bool CxaTM_RMMessage::checkError(short pv_breakError, int *pp_xaError, bool pv_softRetry, int64 pv_transid) { bool lv_retryLink = false; *pp_xaError = XA_OK; char la_buf[DTM_STRING_BUF_SIZE]; CTmTxKey lv_txn = (CTmTxKey) pv_transid; XATrace(XATM_TraceExit, ("XATM: CxaTM_RMMessage::checkError ENTRY txn ID (%d,%d) msgid=%d, breakError=%d, " "rmid=%d, softRetry=%d.\n", lv_txn.node(), lv_txn.seqnum(), iv_msgid, pv_breakError, RM()->getRmid(), pv_softRetry)); lock(); // For XARM clients connecting to a DTM TM, we always retry the error. // DTM TMs don't run as process pairs, but we are attempting to send to // a specific node which might go down and switch to a spare. Also the // TSE might switch to it's backup. // If it's a retryable error (FEPATHDOWN (201) or FEOWNERSHIP (200)) or // FENOLCB (30) from a TSE then we'll retry. if ((tm_XARM_generic_library() && pv_breakError) || pv_breakError == FEPATHDOWN || pv_breakError == FEOWNERSHIP || pv_breakError == FENOLCB ) { // Retry sending the request to the RM. This is used to deal with failovers. if (ip_RM->inc_totalRetries()) { sprintf(la_buf, "Retrying send to RM. BMSG_BREAK_ failed for Txn ID (%d,%d) with " "error %d, rmid=%d, msgid=%d, retries=%d/%d\n", lv_txn.node(), lv_txn.seqnum(), pv_breakError, RM()->getRmid(), msgid(), sendAttempts(), RM()->maxSendRetries()); tm_log_event(DTM_TM_INFO_MSGBRK_FAIL3, SQ_LOG_WARNING, "DTM_TM_INFO_MSGBRK_FAIL3", pv_breakError, RM()->getRmid(),lv_txn.node(),lv_txn.seqnum(), msgid(),-1,-1,-1, sendAttempts(),-1,-1,-1,-1,-1,-1,-1,RM()->getRMnameDetail()); XATrace(XATM_TraceError,("XATM: CxaTM_RMMessage::checkError : %s", la_buf)); } if ((pv_breakError == FEPATHDOWN) || (pv_breakError == FENOLCB)) *pp_xaError = XA_RETRY; lv_retryLink = can_we_retrySend(pp_xaError); } else { if (pv_breakError == FEOK) { *pp_xaError = getRmError(); if (*pp_xaError != XA_OK) { XATrace(XATM_TraceDetail,("XATM: CxaTM_RMMessage::checkError : " "XA error %s encountered.\n", XAtoa(*pp_xaError))); // If the RM responds XA_RETRY, we retry as for a break error, but allow // this to retry forever. if (*pp_xaError == XA_RETRY) { lv_retryLink = can_we_retrySend(pp_xaError); clear_sendAttempts(); } } } else { sprintf(la_buf, "RM connection error. txn ID (%d,%d) BMSG_BREAK_ failed with " "error %d, rmid=%d, msgid=%d, retries=%d/%d\n", lv_txn.node(), lv_txn.seqnum(), pv_breakError, RM()->getRmid(), msgid(), sendAttempts(), RM()->maxSendRetries()); tm_log_event(DTM_TM_INFO_MSGBRK_FAIL4, SQ_LOG_WARNING, "DTM_TM_INFO_MSGBRK_FAIL4",pv_breakError, RM()->getRmid(), lv_txn.node(),lv_txn.seqnum(),msgid(),-1,-1,-1, sendAttempts(), -1,-1,-1,-1,-1,-1,-1,RM()->getRMnameDetail()); XATrace(XATM_TraceError,("XATM: CxaTM_RMMessage::checkError : %s", la_buf)); *pp_xaError = XAER_RMFAIL; } } unlock(); if (!pv_softRetry && *pp_xaError == XA_RETRY) lv_retryLink = false; XATrace(XATM_TraceExit, ("XATM: CxaTM_RMMessage::checkError EXIT txn ID (%d,%d) msgid=%d, returning " "retryLink=%d, xaError=%s.\n", lv_txn.node(), lv_txn.seqnum(), msgid(), lv_retryLink, XAtoa(*pp_xaError))); return lv_retryLink; } //CxaTM_RMMessage::checkError
// ------------------------------------------------------------- // tmTimer_RecoveryWait // Purpose : Wait for transaction count to be 0 before continuing // ------------------------------------------------------------- void tmTimer_RecoveryWait(CTmTimerEvent * pp_event) { int32 lv_nid = pp_event->request()->u.iv_tmrecovery_internal.iv_nid; if (lv_nid == -1) //Cluster recovery { int32 lv_activeTxns = gv_tm_info.transactionPool()->get_inUseList()->size(); int32 lv_queuedTxns = gv_tm_info.ClusterRecov()->txnStateList()->size(); TMTrace(2, ("tmTimer_RecoveryWait : Cluster ENTRY. Indoubt queued: %d, in progress %d.\n", lv_queuedTxns, lv_activeTxns)); //Check the number of in doubt transactions if (lv_activeTxns + lv_queuedTxns > 0 ) { int32 lv_availableTxnObjs = MIN(gv_tm_info.transactionPool()->get_maxPoolSize(), gv_tm_info.maxRecoveringTxns()) - lv_activeTxns; if (lv_availableTxnObjs > 0) { gv_tm_info.ClusterRecov()->queueTxnObjects(); gv_tm_info.ClusterRecov()->resolve_in_doubt_txs(-1/*all tms*/, false/*no delay*/); } else gv_tm_info.addTMRecoveryWait(lv_nid, 1000 /*1 sec*/); } else { gv_tm_info.ClusterRecov()->completeRecovery(); delete gv_tm_info.ClusterRecov(); gv_tm_info.ClusterRecov(NULL); tm_log_event(DTM_RECOVERY_COMPLETED, SQ_LOG_NOTICE, "DTM_RECOVERY_COMPLETED", -1, -1, gv_tm_info.nid()); TMTrace(1, ("System recover : DTM%d System startup recovery completed.\n", gv_tm_info.nid())); } } else { int32 lv_queuedTxns = gv_tm_info.NodeRecov(lv_nid)->txnStateList()->size(); TMTrace(2, ("tmTimer_RecoveryWait : Node ENTRY. Node %d has indoubt queued: %d.\n", lv_nid, lv_queuedTxns)); //Check the number of in doubt transactions if (lv_queuedTxns > 0 ) { int32 lv_availableTxnObjs = gv_tm_info.transactionPool()->get_maxPoolSize() - gv_tm_info.num_active_txs(); if (lv_availableTxnObjs) { gv_tm_info.NodeRecov(lv_nid)->queueTxnObjects(); gv_tm_info.NodeRecov(lv_nid)->resolve_in_doubt_txs(lv_nid, 1000 /*1 sec*/); } else gv_tm_info.addTMRecoveryWait(lv_nid, 1000 /*1 sec*/); } else { gv_tm_info.NodeRecov(lv_nid)->update_registry_txs_to_recover(0); } } TMTrace(2, ("tmTimer_RecoveryWait : EXIT.\n")); }
//---------------------------------------------------------------------------- // timerThread_main // Purpose : Main for timer thread //---------------------------------------------------------------------------- void * timerThread_main(void *arg) { CTmTimerEvent *lp_event; CTmTimer *lp_timerTh; bool lv_exit = false; bool lv_deleteEvent = false; arg = arg; CTmTxMessage *lp_msg; TMTrace(2, ("timerThread_main : ENTRY.\n")); while (gv_tm_info.tmTimer() == NULL || gv_tm_info.tmTimer()->state() != TmTimer_Up || gv_tm_info.tmAuditObj() == NULL) { SB_Thread::Sthr::usleep(10); } // Now we can set a pointer to the CTmTimer object because it exits lp_timerTh = gv_tm_info.tmTimer(); TMTrace(2, ("timerThread_main : Thread %s(%p) State Up.\n", lp_timerTh->get_name(), (void *) lp_timerTh)); while (!lv_exit) { lp_event = (CTmTimerEvent *) lp_timerTh->eventQ_pop(); if (lp_event) { switch (lp_event->command()) { case TmTimerCmd_Queue: { // Queue request to timer list TMTrace(3, ("timerThread_main : TmTimerCmd_Queue: Queue timer event. " "Txn ID %d, Wakeup interval %d, repeat %d, Request %d\n", ((lp_event->transaction())?lp_event->transaction()->seqnum():0), lp_event->wakeupInterval(), lp_event->wakeupRepeat(), lp_event->requestType())); lp_event->command(TmTimerCmd_Timer); //Change to timer event lp_timerTh->timerList()->add(lp_event); break; } //case TmTimerCmd_Queue Incoming request case TmTimerCmd_Timer: { // A timer popped, queue request to the transactions event queue TMTrace(3, ("timerThread_main : TmTimerCmd_Timer: Timer pop. " "Txn ID %d, Wakeup interval %d, repeat %d, Request %d, msgid %d\n", ((lp_event->transaction())?lp_event->transaction()->seqnum():0), lp_event->wakeupInterval(), lp_event->wakeupRepeat(), lp_event->requestType(), lp_event->msg()->msgid())); lp_timerTh->lock(); switch (lp_event->requestType()) { case TM_MSG_TXINTERNAL_CONTROLPOINT: // Control Point (must be Lead TM). lp_timerTh->last_cp_written(SB_Thread::Sthr::time()); tmTimer_initiate_cp(); break; case TM_MSG_TXINTERNAL_STATS: tmTimer_stats(); break; case TM_MSG_TXINTERNAL_RMRETRY: break; case TM_MSG_TXINTERNAL_TMRESTART_RETRY: // If this is the first and only event or the last of several - then service it. If // it is not the last one (of duplicate events), then ignore it. if (gv_tm_info.get_restartTimerEvent(lp_event->request()->u.iv_tmrestart_internal.iv_nid) == lp_event) { gv_tm_info.reset_restartTimerEvent (lp_event->request()->u.iv_tmrestart_internal.iv_nid); tmTimer_TMRestartRetry(lp_event); } lv_deleteEvent = true; break; case TM_MSG_TXINTERNAL_SHUTDOWNP1_WAIT: lp_msg = (CTmTxMessage *) lp_event; gv_tm_info.ShutdownPhase1Wait(lp_msg); break; case TM_MSG_TYPE_ATTACHRM: lp_msg = new CTmTxMessage(lp_event->request()); gv_tm_info.attachRm(lp_msg); lv_deleteEvent = true; delete lp_msg; break; case TM_MSG_TYPE_ENABLETRANS: lp_msg = new CTmTxMessage(lp_event->request()); gv_tm_info.enableTrans(lp_msg); lv_deleteEvent = true; delete lp_msg; break; case TM_MSG_TYPE_DISABLETRANS: lp_msg = new CTmTxMessage(lp_event->request()); gv_tm_info.disableTrans(lp_msg); lv_deleteEvent = true; delete lp_msg; break; case TM_MSG_TXINTERNAL_RECOVERY_WAIT: tmTimer_RecoveryWait(lp_event); lv_deleteEvent = true; break; case TM_MSG_TXINTERNAL_INITIALIZE_RMS: tmTimer_initializeRMs(); lv_deleteEvent = true; break; case TM_MSG_TXINTERNAL_SYSTEM_RECOVERY: tmTimer_recoverSystem(); lv_deleteEvent = true; break; default: { if (lp_event->transaction()) { // Notify transaction object CTmTxMessage *lp_msg = new CTmTxMessage(lp_event->request()); lp_event->transaction()->queueToTransaction(lp_event->transaction()->transid(), lp_msg); lv_deleteEvent = true; } else if (lp_event->thread()) // Notify non-transactional thread lp_event->thread()->eventQ_push((CTmEvent *) lp_event); else { TMTrace(1, ("timerThread_main : Timer Thread %p. No transaction or " "thread pointer for event %p, Txn ptr %p, cmd %d, reqType %d, Wakeup interval %d, repeat %d.\n", (void *) lp_timerTh, (void *) lp_event, (void *) lp_event->transaction(), lp_event->command(), lp_event->requestType(), lp_event->wakeupInterval(), lp_event->wakeupRepeat())); tm_log_event (DTM_TMTIMER_BAD_EVENT2, SQ_LOG_WARNING, "DTM_TMTIMER_BAD_EVENT2", lp_event->request()->iv_msg_hdr.miv_err.error, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, lp_event->requestType(), lp_event->request()->iv_msg_hdr.dialect_type, -1, NULL, -1, lp_event->wakeupInterval(), lp_event->wakeupRepeat()); // abort(); Don't want to abort, just discard event. lv_deleteEvent = true; } } //default } //switch if (lp_event->wakeupRepeat() != 0 && lv_deleteEvent == false) { lp_event->dec_wakeupRepeat(); lp_timerTh->timerList()->add(lp_event); } lp_timerTh->unlock(); break; } //case TmTimerCmd_Timer timer pop case TmTimerCmd_Stop: { lp_timerTh->lock(); lv_exit = true; TMTrace(1, ("timerThread_main : Stop thread received.\n")); lv_deleteEvent = true; lp_timerTh->state(TmTimer_Down); // Unlock on exit break; } //case TmTimerCmd_Stop the timer thread case TmTimerCmd_Cancelled: { TMTrace(1, ("timerThread_main : Cancelled timer event %p popped.\n", (void *) lp_event)); lv_deleteEvent = true; break; } //case TmTimerCmd_Cancelled default: { // EMS DTM_TXTHREAD_BAD_EVENT TMTrace(1, ("timerThread_main: Timer Thread (0x%p) main received an " "unexpected event %p, reqType %d, cmd %d, terminating.\n", (void *) lp_timerTh, (void *) lp_event, lp_event->requestType(), lp_event->command())); tm_log_event(DTM_TMTIMER_UNEXP_EVENT, SQ_LOG_CRIT, "DTM_TMTIMER_UNEXP_EVENT", -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,lp_event->requestType(),lp_event->command()); abort(); } } //switch if (lv_deleteEvent) { TMTrace(2, ("timerThread_main : thread_deleted p_event (0x%p), cmd %d, type %d.\n", (void *) lp_event, lp_event->command(), lp_event->requestType())); delete lp_event; lv_deleteEvent = false; } } // if lp_event } //while TMTrace(2, ("timerThread_main : EXIT.\n")); lp_timerTh->unlock(); return NULL; } //timerThread_main
// ----------------------------------------------------------- // adp_send_audit // Purpose - send audit buffer to adp // return values : 0 - nothing to do // 1 - rollover // 2 - threshold hit // ------------------------------------------------------------ int32 TM_Audit::adp_send_audit(char *pp_buffer, int32 pv_length, int64 pv_vsn, bool pv_force) { int32 lv_notify = 0; int64 lv_old_seq = 0; int32 lv_error = FEEOF; // Set to non-zero for first pass to make sure we enter the while loop. int32 lv_error2 = 0; int32 lv_send_count = 0; const int lc_adp_send_retry_delay = 100; // .1 sec const int lc_adp_send_retry_maxretries = 30; if (!iv_initialized) return -1; TMTrace(2, ("TM_Audit::adp_send_audit: ENTER\n")); //If we all in state Quiesce, we can no longer talk to the ADP if (gv_tm_info.state() == TM_STATE_QUIESCE) { TMTrace(2, ("TM_Audit::adp_send_audit: Quiesced so not sending audit EXIT\n")); return 0; } iv_mutex.lock(); TMTrace(4, ("TM_Audit::adp_send_audit: lock obtained\n")); AuditTrailPosition_Struct lv_buffer_pos; lv_buffer_pos.Sequence = lv_buffer_pos.rba = 0; while ((gv_tm_info.state() != TM_STATE_QUIESCE) && (lv_error) && (++lv_send_count < lc_adp_send_retry_maxretries)) { // We only force control points and commit/abort records. Forgotten // ones we allow TSEs to buffer if they choose if (lv_error && (lv_send_count < lc_adp_send_retry_maxretries) && (lv_send_count > 0)) SB_Thread::Sthr::sleep(lc_adp_send_retry_delay); } if (gv_tm_info.state() == TM_STATE_QUIESCE) { TMTrace(2, ("TM_Audit::adp_send_audit: Quiesced so not sending audit EXIT(2)\n")); return 0; } if (lv_error) { // if after our retries and the ASE lib retries, we still can't write a record, // we have no choice but to die. tm_log_event(DTM_AUDIT_FAILED_WRITE, SQ_LOG_CRIT, "DTM_AUDIT_FAILED_WRITE", lv_error); TMTrace(1, ("TM_Audit::adp_send_audit: Failed to write audit to adp. Error " "%d Shutting down Seaquest.\n", lv_error)); msg_mon_shutdown(MS_Mon_ShutdownLevel_Abrupt); // Abort without core - don't need the core in this case. struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; setrlimit(RLIMIT_CORE, &limit); abort(); } // we rolled over, this will initiate a cp if (pv_force) // we'll have a buffer position { if (iv_position != lv_buffer_pos.Sequence) { TMTrace(3, ("adp_send_audit: ROLLING OVER from " PFLL " to %d\n", iv_position, lv_buffer_pos.Sequence)); lv_old_seq = iv_position; iv_position = lv_buffer_pos.Sequence; if (lv_old_seq != -1) { iv_vsn = 1; lv_notify = 1; iv_notified_threshold = false; // rolled over, under threshold lv_error2 = gv_tm_info.write_rollover_control_point(); if(lv_error2) { // Unable to inform lead TM to write control point tm_log_event(DTM_ROLLOVER_CP_ERROR, SQ_LOG_CRIT, "DTM_ROLLOVER_CP_ERROR", -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,lv_error2); TMTrace(1, ("TM_Audit::adp_send_audit: Error occurred attempting to write rollover control point" " %d.\n", lv_error2)); abort(); } } } else if ((!iv_notified_threshold) && (lv_buffer_pos.rba > CP_THRESHOLD)) { TMTrace(3, ("adp_send_audit: THRESHOLD from " PFLL " to %d\n", iv_position, lv_buffer_pos.Sequence)); lv_notify = 2; iv_notified_threshold = true; } } iv_mutex.unlock(); TMTrace(2, ("TM_Audit::adp_send_audit: EXIT. notify=%d, vsn=" PFLL ", notified threshold=%d\n", lv_notify, iv_vsn, iv_notified_threshold)); return lv_notify; }
// ------------------------------------------------------------- // adp_module_init // Purpose - initialize module for use // ------------------------------------------------------------- void TM_Audit::adp_module_init() { TMTrace(2, ("TM_Audit::adp_module_init: ENTER\n")); MS_Mon_Reg_Get_Type lv_info; char lv_my_pname[8+1]; char lv_tlog_pname[8+1]; int lv_len = 8; int lv_err = 0; int32 lv_oid = 0; TPT_DECL (lv_phandle); int lv_TLOG_index = TLOG_AuditTrailIndex; if (iv_initialized) return; msg_mon_get_my_process_name(lv_my_pname,lv_len); lv_err = msg_mon_reg_get(MS_Mon_ConfigType_Process, false, lv_my_pname, (char *)"TMASE", &lv_info); if ((lv_err == 0) && (lv_info.num_returned == 1)) { strncpy (lv_tlog_pname, lv_info.list[0].value, 8); TMTrace(3, ("TM_Audit::adp_module_init: %s opening TLOG %s\n", lv_my_pname, lv_tlog_pname)); lv_err = msg_mon_open_process(lv_tlog_pname, &lv_phandle, &lv_oid); if (!lv_err) { memcpy (&iv_adp_phandle, &lv_phandle, sizeof (SB_Phandle_Type)); // If we using multiple TLOGs, we need to set the correct index (= nid) if (gv_tm_info.TLOGperTM()) lv_TLOG_index = gv_tm_info.nid(); iv_initialized = true; } else { TMTrace(1, ("TM_Audit::adp_module_init: error %d opening TLOG %s\n", lv_err, lv_tlog_pname)); tm_log_event(DTM_AUDIT_FAILED_ADPOPEN, SQ_LOG_CRIT, "DTM_AUDIT_FAILED_ADPOPEN", lv_err, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, lv_my_pname); // Fast fail here if $TLOG is gone as we can't continue in M8. if (lv_err == FENOSUCHDEV) { gv_tm_info.error_shutdown_abrupt(lv_err); // Abort without core - don't need the core in this case. struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; setrlimit(RLIMIT_CORE, &limit); abort(); } iv_initialized = false; } } // lv_err = 0 else iv_initialized = false; if (gv_tm_info.TLOGperTM()) { TMTrace(2, ("TM_Audit::adp_module_init: EXIT, initialized = %d, name %s, TLOG%d.\n", iv_initialized, ia_vol_name2, lv_TLOG_index)); } else { TMTrace(2, ("TM_Audit::adp_module_init: EXIT, initialized = %d, name %s, single TLOG.\n", iv_initialized, ia_vol_name2)); } }
bool TM_Audit::prepare_trans_state(Audit_Transaction_State *pp_state_rec, char *pp_write_buffer, TM_Transid_Type *pv_transid, int32 pv_nid, int32 pv_state, int32 pv_abort_flags, int64 *pp_vsn=0) { int32 lv_rec_type = -1; bool lv_force = true; if (gv_tm_info.iv_trace_level >= 2) { TM_Txid_Internal *lp_transid = (TM_Txid_Internal *) pv_transid; trace_printf("TM_Audit::prepare_trans_state : ENTRY, txn ID (%d,%d), state=%d.\n", lp_transid->iv_node, lp_transid->iv_seq_num, pv_state); } pv_nid = pv_nid; //810 switch (pv_state) { case TM_TX_STATE_BEGINNING: case TM_TX_STATE_ACTIVE: case TM_TX_STATE_IDLE: //XARM only case TM_TX_STATE_NOTX: case TM_TX_STATE_PREPARING: { lv_rec_type = Active_Trans_State; break; } case TM_TX_STATE_FORGOTTEN: case TM_TX_STATE_FORGOTTEN_HEUR: case TM_TX_STATE_FORGETTING: case TM_TX_STATE_TERMINATING: //XARM only { lv_rec_type = Forgotten_Trans_State; lv_force = false; break; } case TM_TX_STATE_COMMITTED: case TM_TX_STATE_COMMITTING: { lv_rec_type = Committed_Trans_State; break; } case TM_TX_STATE_ABORTING: case TM_TX_STATE_ABORTING_PART2: { lv_rec_type = Aborting_Trans_State; break; } case TM_TX_STATE_ABORTED: { lv_rec_type = Aborted_Trans_State; break; } case TM_TX_STATE_HUNGCOMMITTED: { lv_rec_type = HungCommitted_Trans_State; break; } case TM_TX_STATE_HUNGABORTED: { lv_rec_type = HungAborted_Trans_State; break; } default: { // bad transaction state record. very, very bad! tm_log_event(DTM_TM_AUD_INVALID_TRANS_STATE, SQ_LOG_CRIT, "DTM_TM_AUD_INVALID_TRANS_STATE", -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,pv_state); TMTrace(2, ("TM_Audit::prepare_trans_state : Invalid transaction state %d reached.\n", pv_state)); abort(); } } initialize_hdr(&pp_state_rec->iv_hdr, REC_SIZE, TM_Transaction_State, pv_transid); pp_state_rec->iv_time_stamp = SB_Thread::Sthr::time(); pp_state_rec->iv_state = (short) lv_rec_type; pp_state_rec->iv_abort_flags = pv_abort_flags; pp_state_rec->iv_length = pp_state_rec->iv_hdr.iv_length; iv_mutex.lock(); memcpy (&pp_state_rec->iv_hdr.iv_vsn, &iv_vsn, sizeof (iv_vsn)); if (pp_vsn != NULL) *pp_vsn = iv_vsn; iv_vsn++; iv_mutex.unlock(); memcpy (pp_write_buffer, pp_state_rec, REC_SIZE); TMTrace(2, ("TM_Audit::prepare_trans_state : EXIT\n")); return lv_force; }